Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { StockTransfer } from '../schemas/movement.schema'; import { LedgerService } from '../../stock-ledger/services/ledger.service'; import { ConfigurationService } from '../../configuration/services/configuration.service'; @Injectable() export class MovementService { constructor( @InjectModel(StockTransfer.name) private readonly transferModel: Model<StockTransfer>, private readonly ledgerService: LedgerService, private readonly configService: ConfigurationService ) {} async createTransfer(tenantId: string, data: any): Promise<StockTransfer> { const count = await this.transferModel.countDocuments({ tenantId }).exec(); const transferNumber = `TO-${new Date().getFullYear()}-${(count + 1).toString().padStart(5, '0')}`; return this.transferModel.create({ ...data, tenantId, transferNumber, status: 'approved', }); } async dispatchTransfer(tenantId: string, id: string, userId: string): Promise<StockTransfer> { const transfer = await this.transferModel.findOne({ _id: id, tenantId, status: 'approved' }).exec(); if (!transfer) throw new NotFoundException('Approved transfer request not found'); const config = await this.configService.getConfiguration(tenantId); // Post dispatch ledger entries: deduct from source warehouse, add to transit warehouse for (const line of transfer.lines) { // Deduct from source warehouse await this.ledgerService.postLedgerEntry(tenantId, { itemCode: line.itemCode, warehouseId: transfer.fromWarehouseId, transactionType: 'Warehouse Transfer Dispatch', quantityChange: -line.quantityRequested, batchNumber: line.batchNumber || null, serialNumber: line.serialNumber || null, sourceEntityId: transfer._id.toString(), sourceEntityType: 'StockTransfer', correlationId: `${transfer._id.toString()}-dispatch-from-${line.itemCode}`, }, userId); // Add to transit warehouse (e.g. WH-TRANSIT) await this.ledgerService.postLedgerEntry(tenantId, { itemCode: line.itemCode, warehouseId: config.defaultTransitWarehouseId || 'WH-TRANSIT', transactionType: 'Warehouse Transfer Dispatch', quantityChange: line.quantityRequested, batchNumber: line.batchNumber || null, serialNumber: line.serialNumber || null, sourceEntityId: transfer._id.toString(), sourceEntityType: 'StockTransfer', correlationId: `${transfer._id.toString()}-dispatch-transit-${line.itemCode}`, }, userId); line.quantityDispatched = line.quantityRequested; } transfer.status = 'dispatched'; transfer.dispatchedDate = new Date(); await transfer.save(); return transfer; } async receiveTransfer(tenantId: string, id: string, receivedLines: any[], userId: string): Promise<StockTransfer> { const transfer = await this.transferModel.findOne({ _id: id, tenantId, status: 'dispatched' }).exec(); if (!transfer) throw new NotFoundException('Dispatched transfer request not found'); const config = await this.configService.getConfiguration(tenantId); // Post receive ledger entries: deduct from transit warehouse, add to destination warehouse for (const lineInput of receivedLines) { const line = transfer.lines.find(l => l.itemCode === lineInput.itemCode); if (!line) continue; line.quantityReceived = lineInput.quantityReceived; // Deduct from transit warehouse await this.ledgerService.postLedgerEntry(tenantId, { itemCode: line.itemCode, warehouseId: config.defaultTransitWarehouseId || 'WH-TRANSIT', transactionType: 'Warehouse Transfer Receipt', quantityChange: -line.quantityDispatched, batchNumber: line.batchNumber || null, serialNumber: line.serialNumber || null, sourceEntityId: transfer._id.toString(), sourceEntityType: 'StockTransfer', correlationId: `${transfer._id.toString()}-receive-from-transit-${line.itemCode}`, }, userId); // Add to destination warehouse await this.ledgerService.postLedgerEntry(tenantId, { itemCode: line.itemCode, warehouseId: transfer.toWarehouseId, transactionType: 'Warehouse Transfer Receipt', quantityChange: line.quantityReceived, batchNumber: line.batchNumber || null, serialNumber: line.serialNumber || null, sourceEntityId: transfer._id.toString(), sourceEntityType: 'StockTransfer', correlationId: `${transfer._id.toString()}-receive-to-${line.itemCode}`, }, userId); } // Determine status (check if discrepancy exists) const hasDiscrepancy = transfer.lines.some(l => l.quantityReceived !== l.quantityDispatched); transfer.status = hasDiscrepancy ? 'partially_received' : 'received'; transfer.receivedDate = new Date(); await transfer.save(); return transfer; } async getTransfers(tenantId: string): Promise<StockTransfer[]> { return this.transferModel.find({ tenantId }).exec(); } async getTransferById(tenantId: string, id: string): Promise<StockTransfer> { const transfer = await this.transferModel.findOne({ tenantId, _id: id }).exec(); if (!transfer) throw new NotFoundException('Transfer order not found'); return transfer; } } |