| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- /**
- * * **Current State:** The `AppController` seeder includes a dynamic regex and fallback system to resolve and assign a `phaseCode` attribute to blocks during block seeding (lines 75-94).
- * * **Intended Mutation:** Remove the dynamic regex resolution block and `phaseCode` mapping from `mappedBlock` within the `2. BLOCK SEEDING` loop to achieve flat block seeding.
- * * **Risk Mitigation:** Cross-entity validation is entirely shifted to the `FFB Production` ledger level, making the master block seeder 100% independent.
- */
- import { Controller, Get, Logger, BadRequestException } from '@nestjs/common';
- import { AppService } from './app.service';
- import { PhaseService } from './site/services/phase.service';
- import { BlockService } from './site/services/block.service';
- import { FFBProductionService } from './FFB/services/ffb-production.service';
- import * as fs from 'fs';
- import * as path from 'path';
- @Controller()
- export class AppController {
- private readonly logger: Logger = new Logger('AppController');
- constructor(
- private readonly service: AppService,
- private readonly phaseService: PhaseService,
- private readonly blockService: BlockService,
- private readonly ffbService: FFBProductionService,
- ) { }
- @Get()
- getHello(): string {
- return this.service.getHello();
- }
- @Get('seed')
- async seedSystemData() {
- this.logger.log('🚀 Starting chronological seeding...');
- // Resolve JSON data file locations dynamically relative to process.cwd()
- const rootDir = process.cwd();
- const phaseDataPath = path.resolve(rootDir, '../mongo stuff/PhaseData.json');
- const blockDataPath = path.resolve(rootDir, '../mongo stuff/BlockData.json');
- const ffbDataPath = path.resolve(rootDir, '../mongo stuff/FFBProductionData.json');
- // 1. PHASE SEEDING
- if (!fs.existsSync(phaseDataPath)) {
- throw new BadRequestException(`PhaseData.json not found at ${phaseDataPath}`);
- }
- const rawPhases = JSON.parse(fs.readFileSync(phaseDataPath, 'utf8'));
- this.logger.log(`Found ${rawPhases.length} phases to process.`);
- for (const rawPhase of rawPhases) {
- try {
- const mappedPhase = {
- locId: Number(rawPhase.loc_id),
- phaseCode: rawPhase.name,
- description: rawPhase.description,
- locType: rawPhase.loc_type,
- };
- await this.phaseService.create(mappedPhase);
- } catch (err) {
- this.logger.error(`Error inserting Phase ${rawPhase.name}: ${err.message}`);
- }
- }
- console.log('[SEED] Phase collection initialization pass complete.');
- // 2. BLOCK SEEDING
- if (!fs.existsSync(blockDataPath)) {
- throw new BadRequestException(`BlockData.json not found at ${blockDataPath}`);
- }
- const rawBlocks = JSON.parse(fs.readFileSync(blockDataPath, 'utf8'));
- this.logger.log(`Found ${rawBlocks.length} blocks to process.`);
- for (const rawBlock of rawBlocks) {
- try {
- const mappedBlock = {
- locId: Number(rawBlock.loc_id),
- blockCode: rawBlock.blockCode,
- blockDesc: rawBlock.blockDesc,
- locType: rawBlock.loc_type,
- entryNo: Number(rawBlock.entry_no),
- entryYear: Number(rawBlock.entry_year),
- quarterPlanted: Number(rawBlock.quater_planted),
- monthPlanted: rawBlock.month_planted,
- totalTrees: Number(rawBlock.numOfTreesPlanted),
- totalMaturedTrees: Number(rawBlock.totalTreeMatured),
- totalImmaturedTrees: Number(rawBlock.totalTreeImmatured),
- totalDeadTrees: Number(rawBlock.totalTreeDead),
- plantedArea: Number(rawBlock.totalPlantedArea),
- initialPlantedArea: Number(rawBlock.initalPlantedArea),
- plantedLocUOM: rawBlock.plantedLocUOM,
- soilCondition: rawBlock.loc_soil_condition,
- };
- await this.blockService.create(mappedBlock);
- } catch (err) {
- this.logger.error(`Error inserting Block ${rawBlock.blockCode}: ${err.message}`);
- }
- }
- console.log('[SEED] Block collection initialization pass complete.');
- // 3. FFB TRANSACTION INGESTION & VECTOR ENRICHMENT STREAM
- if (!fs.existsSync(ffbDataPath)) {
- throw new BadRequestException(`FFBProductionData.json not found at ${ffbDataPath}`);
- }
- const rawFfbs = JSON.parse(fs.readFileSync(ffbDataPath, 'utf8'));
-
- // Trigger background seeder worker to prevent HTTP timeout
- this.runBackgroundFfbSeed(rawFfbs);
- this.logger.log(`[SEED] Ingestion worker spawned for all ${rawFfbs.length} records.`);
- return {
- status: 'success',
- message: `Chronological seeding initiated for ${rawFfbs.length} transaction records in the background. Monitor server logs for live updates.`,
- };
- }
- private async runBackgroundFfbSeed(records: any[]) {
- const CHUNK_SIZE = 5; // Adjust down if CPU is weak, up to 10 if using a dedicated GPU
- const COOL_DOWN_MS = 1000; // 1 second pause between chunks to let the CPU breathe
-
- this.logger.log(`[WORKER] Beginning processing matrix for ${records.length} items...`);
-
- for (let i = 0; i < records.length; i += CHUNK_SIZE) {
- const chunk = records.slice(i, i + CHUNK_SIZE);
- this.logger.log(`[WORKER] Processing batch chunk ${Math.floor(i / CHUNK_SIZE) + 1} of ${Math.ceil(records.length / CHUNK_SIZE)}...`);
-
- for (const rawFfb of chunk) {
- try {
- const mappedFfb = {
- productionDate: rawFfb.productionDate ? new Date(rawFfb.productionDate) : new Date('2024-01-01'),
- prjCode: rawFfb.prj_code,
- actCode: rawFfb.act_code,
- actName: rawFfb.act_name,
- entityCode: rawFfb.entitycode,
- orgnId: rawFfb.orgn_id ? Number(rawFfb.orgn_id) : 0,
- orgnCode: rawFfb.orgn_code,
- orgnFullName: rawFfb.orgn_full_name,
- orgnAddress: rawFfb.orgn_address,
- orgnCompRegNo: rawFfb.orgn_comp_reg_no,
- phaseCode: rawFfb.phaseCode || 'PH01',
- phaseName: rawFfb.phaseName || 'PHASE 01',
- phaseDesc: rawFfb.phaseDesc || 'PHASE 01',
- blockCode: rawFfb.blockCode,
- blockName: rawFfb.blockName || null,
- blockDesc: rawFfb.blockDesc || null,
- truckNo: rawFfb.truck_no,
- millNo: rawFfb.mill_no,
- actEntryNo: rawFfb.act_entry_no ? Number(rawFfb.act_entry_no) : 0,
- actRound: rawFfb.act_round ? Number(rawFfb.act_round) : 0,
- weightChitNo: rawFfb.weight_chit_no,
- ownNetWeight: rawFfb.own_net_weight ? Number(rawFfb.own_net_weight) : null,
- netWeight: rawFfb.net_weight ? Number(rawFfb.net_weight) : 0,
- actUom: rawFfb.act_uom,
- noOfBunches: rawFfb.no_of_bunches ? Number(rawFfb.no_of_bunches) : 0,
- qtyUom: rawFfb.qty_uom,
- docActQty: rawFfb.doc_act_qty ? Number(rawFfb.doc_act_qty) : 0,
- locArea: rawFfb.loc_area ? Number(rawFfb.loc_area) : 0,
- locUom: rawFfb.loc_uom,
- budgetedFfb: rawFfb.budgeted_ffb ? Number(rawFfb.budgeted_ffb) : null,
- remarks: rawFfb.remarks || '',
- issues: rawFfb.issues || null,
- };
-
- await this.ffbService.create(mappedFfb);
- } catch (err) {
- this.logger.error(`[WORKER ERROR] Step failed for record entry: ${err.message}`);
- }
- }
-
- // Enforce the event-loop cool down period
- if (i + CHUNK_SIZE < records.length) {
- await new Promise(resolve => setTimeout(resolve, COOL_DOWN_MS));
- }
- }
- this.logger.log(`[WORKER] ✅ SUCCESS! Full ledger dataset vectorization and seeder run complete.`);
- }
- }
|