Passed
Pull Request — master (#165)
by Mathieu
01:45
created

server/src/Application/Accounting/Command/Invoice/GenerateInvoiceCommandHandler.ts   A

Complexity

Total Complexity 7
Complexity/F 3.5

Size

Lines of Code 86
Function Count 2

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 70
dl 0
loc 86
rs 10
c 0
b 0
f 0
wmc 7
mnd 5
bc 5
fnc 2
bpm 2.5
cpm 3.5
noi 0

2 Functions

Rating   Name   Duplication   Size   Complexity  
A GenerateInvoiceCommandHandler.buildInvoiceItem 0 15 3
A GenerateInvoiceCommandHandler.execute 0 37 4
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
15
@CommandHandler(GenerateInvoiceCommand)
16
export class GenerateInvoiceCommandHandler {
17
  constructor(
18
    @Inject('IProjectRepository')
19
    private readonly projectRepository: IProjectRepository,
20
    @Inject('IEventRepository')
21
    private readonly eventRepository: IEventRepository,
22
    @Inject('IInvoiceRepository')
23
    private readonly invoiceRepository: IInvoiceRepository,
24
    @Inject('IInvoiceItemRepository')
25
    private readonly invoiceItemRepository: IInvoiceItemRepository,
26
    @Inject('IDateUtils')
27
    private readonly dateUtils: IDateUtils,
28
    private readonly invoiceIdGenerator: InvoiceIdGenerator
29
  ) {}
30
31
  public async execute(command: GenerateInvoiceCommand): Promise<string> {
32
    const { projectId, status, user, expireInDays } = command;
33
34
    const project = await this.projectRepository.findOneById(projectId);
35
    if (!project) {
36
      throw new ProjectNotFoundException();
37
    }
38
39
    const currentDate = this.dateUtils.getCurrentDate();
40
    const [ invoiceId, events ] = await Promise.all([
41
      this.invoiceIdGenerator.generate(),
42
      this.eventRepository.findBillableEventsByMonthAndProject(currentDate, project)
43
    ]);
44
45
    if (0 === events.length) {
46
      throw new NoBillableEventsFoundException();
47
    }
48
49
    const expiryDate = this.dateUtils.addDaysToDate(currentDate, expireInDays);
50
    const invoiceItems: InvoiceItem[] = [];
51
    const invoice = new Invoice(
52
      invoiceId,
53
      status,
54
      expiryDate.toISOString(),
55
      user,
56
      project
57
    );
58
59
    for (const event of events) {
60
      invoiceItems.push(this.buildInvoiceItem(invoice, event));
61
    }
62
63
    const savedInvoice = await this.invoiceRepository.save(invoice);
64
    await this.invoiceItemRepository.save(invoiceItems);
65
66
    return savedInvoice.getId();
67
  }
68
69
  private buildInvoiceItem(invoice: Invoice, {
70
    time_spent,
71
    billable,
72
    task_name,
73
    first_name,
74
    last_name,
75
    amount
76
  }): InvoiceItem {
77
    return new InvoiceItem(
78
      invoice,
79
      `${task_name} - ${first_name} ${last_name}`,
80
      Number(time_spent),
81
      amount ? Number(amount) : 0,
82
      billable ? 0 : 100
83
    );
84
  }
85
}
86