All files / src/domains/inventory/valuation/services valuation.service.ts

0% Statements 0/29
0% Branches 0/12
0% Functions 0/4
0% Lines 0/25

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                                                                                                                                           
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { InventoryCostLayer } from '../schemas/valuation.schema';
import { EventBusService } from '../../../../platform/events/event-bus.service';
 
@Injectable()
export class ValuationService {
  constructor(
    @InjectModel(InventoryCostLayer.name)
    private readonly costLayerModel: Model<InventoryCostLayer>,
    private readonly eventBus: EventBusService
  ) {}
 
  async addCostLayer(tenantId: string, itemCode: string, warehouseId: string, quantity: number, unitCost: number, sourceReceiptId: string): Promise<InventoryCostLayer> {
    const layer = await this.costLayerModel.create({
      tenantId,
      itemCode,
      warehouseId,
      quantityTotal: quantity,
      quantityRemaining: quantity,
      unitCost,
      sourceReceiptId,
      receiptDate: new Date(),
    });
 
    await this.eventBus.publish('inventory.valuation-posting-ready.v1', {
      tenantId,
      itemCode,
      layerId: layer._id.toString(),
      valuationMethod: 'FIFO',
      quantityChange: quantity,
      unitCost,
      occurredAt: new Date(),
    }, tenantId);
 
    return layer;
  }
 
  async consumeCostLayerFifo(tenantId: string, itemCode: string, warehouseId: string, quantityToConsume: number): Promise<number> {
    const layers = await this.costLayerModel.find({
      tenantId,
      itemCode,
      warehouseId,
      quantityRemaining: { $gt: 0 }
    }).sort({ receiptDate: 1 }).exec();
 
    let remainingToConsume = quantityToConsume;
    let totalConsumedCost = 0;
 
    for (const layer of layers) {
      if (remainingToConsume <= 0) break;
 
      const take = Math.min(layer.quantityRemaining, remainingToConsume);
      layer.quantityRemaining -= take;
      remainingToConsume -= take;
      totalConsumedCost += take * layer.unitCost;
      await layer.save();
    }
 
    return totalConsumedCost;
  }
 
  async getCostLayers(tenantId: string, itemCode?: string): Promise<InventoryCostLayer[]> {
    const filter: any = { tenantId };
    if (itemCode) filter.itemCode = itemCode;
    return this.costLayerModel.find(filter).exec();
  }
}