invoice update
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
import { PartialType } from '@nestjs/swagger';
|
||||
import { IsOptional, IsString } from 'class-validator';
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { CreateInvoiceItemDto } from './create-invoice.dto';
|
||||
|
||||
export class UpdateInvoiceItemDto extends PartialType(CreateInvoiceItemDto) {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@ApiPropertyOptional({ description: 'Invoice item ID - when provided, updates existing item; when omitted, creates new item' })
|
||||
id?: string;
|
||||
}
|
||||
@@ -1,4 +1,23 @@
|
||||
import { PartialType } from '@nestjs/swagger';
|
||||
import { IntersectionType, OmitType, PartialType } from '@nestjs/swagger';
|
||||
import { IsArray, IsOptional } from 'class-validator';
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import { CreateInvoiceDto } from './create-invoice.dto';
|
||||
import { UpdateInvoiceItemDto } from './update-invoice-item.dto';
|
||||
|
||||
export class UpdateInvoiceDto extends PartialType(CreateInvoiceDto) {}
|
||||
class UpdateInvoiceBaseDto extends PartialType(
|
||||
OmitType(CreateInvoiceDto, ['items']),
|
||||
) {}
|
||||
|
||||
class UpdateInvoiceItemsDto {
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@Type(() => UpdateInvoiceItemDto)
|
||||
@ApiPropertyOptional({ type: [UpdateInvoiceItemDto] })
|
||||
items?: UpdateInvoiceItemDto[];
|
||||
}
|
||||
|
||||
export class UpdateInvoiceDto extends IntersectionType(
|
||||
UpdateInvoiceBaseDto,
|
||||
UpdateInvoiceItemsDto,
|
||||
) {}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Request } from '../request/entities/request.entity';
|
||||
import { ProductService } from '../product/providers/product.service';
|
||||
import { InvoiceRepository } from './repositories/invoice.repository';
|
||||
|
||||
const TAX_RATE = 0.09;
|
||||
const TAX_RATE = 0.1;
|
||||
|
||||
@Injectable()
|
||||
export class InvoiceService {
|
||||
@@ -127,6 +127,72 @@ export class InvoiceService {
|
||||
if (updateInvoiceDto.approvalDeadline !== undefined) {
|
||||
invoice.approvalDeadline = new Date(updateInvoiceDto.approvalDeadline);
|
||||
}
|
||||
if (updateInvoiceDto.items !== undefined && updateInvoiceDto.items.length > 0) {
|
||||
for (const item of updateInvoiceDto.items) {
|
||||
if (item.id) {
|
||||
const existingItem = await this.em.findOne(InvoiceItem, {
|
||||
id: item.id,
|
||||
invoice: { id: invoice.id },
|
||||
});
|
||||
if (!existingItem) {
|
||||
throw new NotFoundException(`Invoice item ${item.id} not found`);
|
||||
}
|
||||
if (item.productId !== undefined) {
|
||||
existingItem.product = await this.productService.findOneOrFail(
|
||||
item.productId,
|
||||
);
|
||||
}
|
||||
if (item.quantity !== undefined) existingItem.quantity = item.quantity;
|
||||
if (item.unitPrice !== undefined)
|
||||
existingItem.unitPrice = item.unitPrice;
|
||||
if (item.discount !== undefined) existingItem.discount = item.discount;
|
||||
if (item.description !== undefined)
|
||||
existingItem.description = item.description;
|
||||
} else {
|
||||
if (
|
||||
item.productId === undefined ||
|
||||
item.quantity === undefined ||
|
||||
item.unitPrice === undefined
|
||||
) {
|
||||
throw new BadRequestException(
|
||||
'New invoice items must have productId, quantity and unitPrice',
|
||||
);
|
||||
}
|
||||
const product = await this.productService.findOneOrFail(item.productId);
|
||||
const itemDiscount = item.discount ?? 0;
|
||||
const invoiceItem = this.em.create(InvoiceItem, {
|
||||
invoice,
|
||||
product,
|
||||
quantity: item.quantity,
|
||||
unitPrice: item.unitPrice,
|
||||
discount: itemDiscount || undefined,
|
||||
description: item.description,
|
||||
});
|
||||
invoice.items.add(invoiceItem);
|
||||
}
|
||||
}
|
||||
|
||||
const allItems = invoice.items.getItems();
|
||||
let subTotal = 0;
|
||||
let discount = 0;
|
||||
for (const item of allItems) {
|
||||
const itemTotal = Math.max(
|
||||
0,
|
||||
item.unitPrice * item.quantity - (item.discount ?? 0),
|
||||
);
|
||||
subTotal += itemTotal;
|
||||
discount += item.discount ?? 0;
|
||||
}
|
||||
invoice.discount = discount;
|
||||
const taxAmount = invoice.enableTax
|
||||
? Math.round((subTotal - discount) * TAX_RATE)
|
||||
: 0;
|
||||
const total = Math.max(0, subTotal - discount + taxAmount);
|
||||
invoice.subTotal = subTotal;
|
||||
invoice.taxAmount = taxAmount;
|
||||
invoice.total = total;
|
||||
invoice.balance = total - invoice.paidAmount;
|
||||
}
|
||||
await this.em.flush();
|
||||
return invoice;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user