All files / src/domains/inventory/counts/services count.service.ts

0% Statements 0/33
0% Branches 0/20
0% Functions 0/5
0% Lines 0/29

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                                                                                                                                                     
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { InventoryCountSession } from '../schemas/count.schema';
import { LedgerService } from '../../stock-ledger/services/ledger.service';
 
@Injectable()
export class CountService {
  constructor(
    @InjectModel(InventoryCountSession.name)
    private readonly countModel: Model<InventoryCountSession>,
    private readonly ledgerService: LedgerService
  ) {}
 
  async createCountSession(tenantId: string, data: any): Promise<InventoryCountSession> {
    const count = await this.countModel.countDocuments({ tenantId }).exec();
    const sessionNumber = `CNT-${new Date().getFullYear()}-${(count + 1).toString().padStart(5, '0')}`;
 
    return this.countModel.create({
      ...data,
      tenantId,
      sessionNumber,
      status: 'active',
    });
  }
 
  async enterCount(tenantId: string, id: string, countedLines: any[]): Promise<InventoryCountSession> {
    const session = await this.countModel.findOne({ _id: id, tenantId, status: 'active' }).exec();
    if (!session) throw new NotFoundException('Active count session not found');
 
    session.lines = countedLines;
    session.status = 'completed';
    await session.save();
 
    return session;
  }
 
  async approveCountSession(tenantId: string, id: string, userId: string): Promise<InventoryCountSession> {
    const session = await this.countModel.findOne({ _id: id, tenantId, status: 'completed' }).exec();
    if (!session) throw new NotFoundException('Completed count session not found');
 
    // Post variance adjustments to ledger
    for (const line of session.lines) {
      const variance = line.countedQuantity - line.systemQuantity;
      if (variance !== 0) {
        await this.ledgerService.postLedgerEntry(tenantId, {
          itemCode: line.itemCode,
          warehouseId: line.warehouseId,
          locationId: line.locationId || null,
          transactionType: 'Cycle Count Adjustment',
          quantityChange: variance,
          unitCost: 0,
          totalCost: 0,
          batchNumber: line.batchNumber || null,
          serialNumber: line.serialNumber || null,
          sourceEntityId: session._id.toString(),
          sourceEntityType: 'InventoryCountSession',
          correlationId: `${session._id.toString()}-${line.itemCode}`,
        }, userId);
      }
    }
 
    session.status = 'approved';
    session.approvedBy = userId;
    session.approvalDate = new Date();
    await session.save();
 
    return session;
  }
 
  async getCountSessions(tenantId: string): Promise<InventoryCountSession[]> {
    return this.countModel.find({ tenantId }).exec();
  }
}