All files / src/domains/mdm/application/services calendar-period.service.ts

0% Statements 0/36
0% Branches 0/30
0% Functions 0/6
0% Lines 0/33

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                                                                                                                                                                                                                                                         
import {
  Injectable,
  Logger,
  NotFoundException,
  BadRequestException,
} from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model, Types } from 'mongoose';
import {
  CalendarDefinition,
  FinancialYear,
  FinancialPeriod,
  AccountingPeriod,
  PeriodLockDefinition,
} from '../../infrastructure/schemas/calendar-period.schema';
 
@Injectable()
export class CalendarPeriodService {
  private readonly logger = new Logger(CalendarPeriodService.name);
 
  constructor(
    @InjectModel(CalendarDefinition.name)
    private readonly calendarModel: Model<CalendarDefinition>,
    @InjectModel(FinancialYear.name)
    private readonly fyModel: Model<FinancialYear>,
    @InjectModel(FinancialPeriod.name)
    private readonly periodModel: Model<FinancialPeriod>,
    @InjectModel(AccountingPeriod.name)
    private readonly accPeriodModel: Model<AccountingPeriod>,
    @InjectModel(PeriodLockDefinition.name)
    private readonly lockModel: Model<PeriodLockDefinition>,
  ) {}
 
  async createCalendar(params: any): Promise<any> {
    return this.calendarModel.create(params);
  }
 
  async createFinancialYear(params: {
    yearCode: string;
    yearLabel: string;
    startDate: Date;
    endDate: Date;
    calendarYear: number;
    tenantId?: string;
  }): Promise<any> {
    const fy = await this.fyModel.create({
      ...params,
      tenantId: params.tenantId
        ? new Types.ObjectId(params.tenantId)
        : undefined,
      status: 'open',
      isCurrent: true,
    });
 
    // Auto-create monthly periods
    const start = new Date(params.startDate);
    const end = new Date(params.endDate);
    let count = 1;
    const current = new Date(start);
 
    while (current < end) {
      const pStart = new Date(current);
      const pEnd = new Date(current.getFullYear(), current.getMonth() + 1, 0); // last day of month
 
      await this.periodModel.create({
        periodCode: `P${String(count).padStart(2, '0')}-${params.yearCode}`,
        periodName: current.toLocaleString('default', {
          month: 'long',
          year: 'numeric',
        }),
        yearCode: params.yearCode,
        financialYearId: fy._id,
        tenantId: params.tenantId
          ? new Types.ObjectId(params.tenantId)
          : undefined,
        periodType: 'month',
        periodNumber: count,
        startDate: pStart,
        endDate: pEnd,
        status: 'open',
      });
 
      current.setMonth(current.getMonth() + 1);
      count++;
    }
 
    return fy.toObject();
  }
 
  async listFinancialYears(tenantId?: string): Promise<any[]> {
    return this.fyModel
      .find({
        ...(tenantId
          ? { tenantId: new Types.ObjectId(tenantId) }
          : { tenantId: null }),
      })
      .sort({ startDate: -1 })
      .lean()
      .exec();
  }
 
  async getPeriods(fyCode: string, tenantId?: string): Promise<any[]> {
    return this.periodModel
      .find({
        yearCode: fyCode,
        ...(tenantId
          ? { tenantId: new Types.ObjectId(tenantId) }
          : { tenantId: null }),
      })
      .sort({ periodNumber: 1 })
      .lean()
      .exec();
  }
 
  async lockPeriod(periodId: string, userId: string): Promise<any> {
    const period = await this.periodModel.findById(periodId).exec();
    if (!period) throw new NotFoundException('Period not found');
    period.status = 'locked';
    period.closedBy = new Types.ObjectId(userId) as any;
    period.closedAt = new Date();
    await period.save();
    return period.toObject();
  }
}