Passed
Push — master ( deb1f6...0e29a7 )
by Mathieu
02:21 queued 35s
created

GenerateInvoiceCommandHandler.execute   B

Complexity

Conditions 5

Size

Total Lines 45
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 38
dl 0
loc 45
c 0
b 0
f 0
rs 8.5013
cc 5
1
import { CommandHandler } from '@nestjs/cqrs';
2
import { Inject } from '@nestjs/common';
3
import { GenerateInvoiceCommand } from './GenerateInvoiceCommand';
4
import { IEventRepository } from 'src/Domain/FairCalendar/Repository/IEventRepository';
5
import { Invoice } from 'src/Domain/Accounting/Invoice.entity';
6
import { InvoiceItem } from 'src/Domain/Accounting/InvoiceItem.entity';
7
import { IInvoiceRepository } from 'src/Domain/Accounting/Repository/IInvoiceRepository';
8
import { IInvoiceItemRepository } from 'src/Domain/Accounting/Repository/IInvoiceItemRepository';
9
import { InvoiceIdGenerator } from 'src/Domain/Accounting/Generators/InvoiceIdGenerator';
10
import { NoBillableEventsFoundException } from 'src/Domain/Accounting/Exception/NoBillableEventsFoundException';
11
import { IDateUtils } from 'src/Application/IDateUtils';
12
import { IProjectRepository } from 'src/Domain/Project/Repository/IProjectRepository';
13
import { ProjectNotFoundException } from 'src/Domain/Project/Exception/ProjectNotFoundException';
14
import { Project } from 'src/Domain/Project/Project.entity';
15
import { ICooperativeRepository } from 'src/Domain/Settings/Repository/ICooperativeRepository';
16
import { CooperativeNotFoundException } from 'src/Domain/Settings/Repository/CooperativeNotFoundException';
17
import { Cooperative } from 'src/Domain/Settings/Cooperative.entity';
18
19
@CommandHandler(GenerateInvoiceCommand)
20
export class GenerateInvoiceCommandHandler {
21
  constructor(
22
    @Inject('IProjectRepository')
23
    private readonly projectRepository: IProjectRepository,
24
    @Inject('ICooperativeRepository')
25
    private readonly cooperativeRepository: ICooperativeRepository,
26
    @Inject('IEventRepository')
27
    private readonly eventRepository: IEventRepository,
28
    @Inject('IInvoiceRepository')
29
    private readonly invoiceRepository: IInvoiceRepository,
30
    @Inject('IInvoiceItemRepository')
31
    private readonly invoiceItemRepository: IInvoiceItemRepository,
32
    @Inject('IDateUtils')
33
    private readonly dateUtils: IDateUtils,
34
    private readonly invoiceIdGenerator: InvoiceIdGenerator
35
  ) {}
36
37
  public async execute(command: GenerateInvoiceCommand): Promise<string> {
38
    const { projectId, status, user, expireInDays } = command;
39
40
    const cooperative = await this.cooperativeRepository.find();
41
    if (!cooperative) {
42
      throw new CooperativeNotFoundException();
43
    }
44
45
    const project = await this.projectRepository.findOneById(projectId);
46
    if (!project) {
47
      throw new ProjectNotFoundException();
48
    }
49
50
    const currentDate = this.dateUtils.getCurrentDate();
51
    const [invoiceId, events] = await Promise.all([
52
      this.invoiceIdGenerator.generate(),
53
      this.eventRepository.findBillableEventsByMonthAndProject(
54
        currentDate,
55
        project
56
      )
57
    ]);
58
59
    if (0 === events.length) {
60
      throw new NoBillableEventsFoundException();
61
    }
62
63
    const expiryDate = this.dateUtils.addDaysToDate(currentDate, expireInDays);
64
    const invoiceItems: InvoiceItem[] = [];
65
    const invoice = new Invoice(
66
      invoiceId,
67
      status,
68
      expiryDate.toISOString(),
69
      user,
70
      project
71
    );
72
73
    for (const event of events) {
74
      invoiceItems.push(this.buildInvoiceItem(invoice, cooperative, event));
75
    }
76
77
    const savedInvoice = await this.invoiceRepository.save(invoice);
78
    await this.invoiceItemRepository.save(invoiceItems);
79
80
    return savedInvoice.getId();
81
  }
82
83
  private buildInvoiceItem(
84
    invoice: Invoice,
85
    cooperative: Cooperative,
86
    { time_spent, billable, task_name, first_name, last_name, daily_rate }
87
  ): InvoiceItem {
88
    const quantity =
89
      Math.round((time_spent / cooperative.getDayDuration()) * 100) / 100;
90
91
    return new InvoiceItem(
92
      invoice,
93
      `${task_name} - ${first_name} ${last_name}`,
94
      Math.round(quantity * 100),
95
      daily_rate ? daily_rate : 0,
96
      billable ? 0 : 10000
97
    );
98
  }
99
}
100