invoice item total and subtotal
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
node_modules
|
||||
dist
|
||||
.git
|
||||
.gitignore
|
||||
*.md
|
||||
.env*
|
||||
coverage
|
||||
.nyc_output
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
+3
-4
@@ -1,9 +1,8 @@
|
||||
# Stage 1: Base
|
||||
FROM node:22-alpine AS base
|
||||
|
||||
# Install timezone support
|
||||
RUN apk add --no-cache tzdata
|
||||
RUN cp /usr/share/zoneinfo/Asia/Tehran /etc/localtime && echo "Asia/Tehran" > /etc/timezone
|
||||
# Set timezone (Node.js respects TZ env variable natively)
|
||||
ENV TZ=Asia/Tehran
|
||||
|
||||
# Set workdir for clarity
|
||||
WORKDIR /app
|
||||
@@ -12,7 +11,7 @@ WORKDIR /app
|
||||
FROM base AS deps
|
||||
WORKDIR /temp-deps
|
||||
COPY package*.json ./
|
||||
RUN npm ci --ignore-scripts
|
||||
RUN npm ci --ignore-scripts --no-fund --no-audit
|
||||
|
||||
# Stage 3: Build
|
||||
FROM base AS builder
|
||||
|
||||
@@ -2831,6 +2831,16 @@
|
||||
"nullable": false,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"sub_total": {
|
||||
"name": "sub_total",
|
||||
"type": "int",
|
||||
"generated": "(COALESCE(unit_price, 0) * quantity) STORED",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"discount": {
|
||||
"name": "discount",
|
||||
"type": "int",
|
||||
@@ -2840,6 +2850,16 @@
|
||||
"nullable": true,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"total": {
|
||||
"name": "total",
|
||||
"type": "int",
|
||||
"generated": "((COALESCE(unit_price, 0) * quantity) - COALESCE(discount, 0)) STORED",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20260516121012 extends Migration {
|
||||
|
||||
override async up(): Promise<void> {
|
||||
this.addSql(`alter table "invoice_items" add column "sub_total" int generated always as (COALESCE(unit_price, 0) * quantity) STORED not null, add column "total" int generated always as ((COALESCE(unit_price, 0) * quantity) - COALESCE(discount, 0)) STORED not null;`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -88,7 +88,8 @@ export class CreateInvoiceDto {
|
||||
description?: string;
|
||||
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
@Type(() => IAttachmentDto)
|
||||
@ApiProperty({ type: [IAttachmentDto] })
|
||||
attachments: IAttachmentDto[];
|
||||
attachments?: IAttachmentDto[];
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ export class InvoiceItem extends BaseEntity {
|
||||
@Property({
|
||||
type: 'int',
|
||||
columnType: 'int GENERATED ALWAYS AS (COALESCE(unit_price, 0) * quantity) STORED',
|
||||
persist: false,
|
||||
})
|
||||
subTotal!: number & Opt;
|
||||
|
||||
@@ -42,7 +41,6 @@ export class InvoiceItem extends BaseEntity {
|
||||
@Property({
|
||||
type: 'int',
|
||||
columnType: 'int GENERATED ALWAYS AS ((COALESCE(unit_price, 0) * quantity) - COALESCE(discount, 0)) STORED',
|
||||
persist: false
|
||||
})
|
||||
total!: number & Opt;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ export class InvoiceService {
|
||||
private readonly productService: ProductService,
|
||||
private readonly invoiceRepository: InvoiceRepository,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
|
||||
async create(dto: CreateInvoiceDto) {
|
||||
@@ -59,13 +59,16 @@ export class InvoiceService {
|
||||
...(request && { request }),
|
||||
enableTax,
|
||||
approvalDeadline,
|
||||
// discount,
|
||||
discount: 0,
|
||||
paidAmount: 0,
|
||||
// balance: 0,
|
||||
attachments: [],
|
||||
balance: 0,
|
||||
attachments: dto.attachments ?? [],
|
||||
paymentMethod: dto.paymentMethod,
|
||||
invoiceNumber: 20, // TODO : invoice number
|
||||
description: dto.description
|
||||
description: dto.description,
|
||||
subTotal: 0,
|
||||
taxAmount: 0,
|
||||
total: 0,
|
||||
});
|
||||
em.persist(invoice);
|
||||
|
||||
@@ -95,7 +98,7 @@ export class InvoiceService {
|
||||
// const total = Math.max(0, subTotal - discount + taxAmount);
|
||||
|
||||
// invoice.subTotal = subTotal;
|
||||
invoice.attachments = dto.attachments;
|
||||
// invoice.attachments = dto.attachments;
|
||||
// invoice.taxAmount = taxAmount;
|
||||
// invoice.total = total;
|
||||
// invoice.balance = total - invoice.paidAmount;
|
||||
@@ -114,7 +117,7 @@ export class InvoiceService {
|
||||
await em.flush();
|
||||
return invoice;
|
||||
});
|
||||
// TODO : maybe it is needed to get a fresh instance.
|
||||
// TODO : maybe it is needed to get a fresh instance.
|
||||
this.eventEmitter.emit(
|
||||
InvoiceCreatedEvent.name,
|
||||
new InvoiceCreatedEvent(
|
||||
@@ -184,9 +187,9 @@ export class InvoiceService {
|
||||
if (dto.approvalDeadline !== undefined) {
|
||||
invoice.approvalDeadline = new Date(dto.approvalDeadline);
|
||||
}
|
||||
if(dto.paymentMethod !== undefined) invoice.paymentMethod = dto.paymentMethod;
|
||||
if(dto.description !== undefined) invoice.description = dto.description;
|
||||
if(dto.attachments !== undefined) invoice.attachments = dto.attachments;
|
||||
if (dto.paymentMethod !== undefined) invoice.paymentMethod = dto.paymentMethod;
|
||||
if (dto.description !== undefined) invoice.description = dto.description;
|
||||
if (dto.attachments !== undefined) invoice.attachments = dto.attachments;
|
||||
|
||||
if (dto.items !== undefined) {
|
||||
// Items in dto.items represent the full list: delete any existing items not in the list
|
||||
|
||||
Reference in New Issue
Block a user