add: title to bill

This commit is contained in:
2026-02-18 09:01:35 +03:30
parent a9c6854772
commit a3be4e9ea9
6 changed files with 58 additions and 9 deletions
@@ -321,6 +321,15 @@
"length": 6, "length": 6,
"mappedType": "datetime" "mappedType": "datetime"
}, },
"title": {
"name": "title",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"type": { "type": {
"name": "type", "name": "type",
"type": "text", "type": "text",
@@ -0,0 +1,12 @@
import { Migration } from "@mikro-orm/migrations";
export class Migration20250218120000_add_bill_title extends Migration {
override async up(): Promise<void> {
this.addSql(`alter table "bill" add column "title" text not null default '';`);
this.addSql(`alter table "bill" alter column "title" drop default;`);
}
override async down(): Promise<void> {
this.addSql(`alter table "bill" drop column "title";`);
}
}
+17 -7
View File
@@ -24,6 +24,9 @@ import { IFile } from "../utils/interfaces/IFile";
@Injectable() @Injectable()
export class BillsService { export class BillsService {
readonly SEWAGE_RATE = 0.3;
readonly TAX_RATE = 0.1;
constructor( constructor(
private readonly em: EntityManager, private readonly em: EntityManager,
private readonly companiesService: CompaniesService, private readonly companiesService: CompaniesService,
@@ -40,7 +43,7 @@ export class BillsService {
try { try {
await em.begin(); await em.begin();
const bill = em.create(Bill, { type: BillType.WATER_BILL, business }); const bill = em.create(Bill, { type: BillType.WATER_BILL, business, title: dto.title });
em.persist(bill); em.persist(bill);
const dueDate = dayjs().add(dueDays, "day").toDate(); const dueDate = dayjs().add(dueDays, "day").toDate();
@@ -50,10 +53,10 @@ export class BillsService {
for (const value of values) { for (const value of values) {
const waterCost = new Decimal(waterRate).mul(value.waterUsage); const waterCost = new Decimal(waterRate).mul(value.waterUsage);
const sewageCost = waterCost.mul(0.3); const sewageCost = waterCost.mul(this.SEWAGE_RATE);
const subtotal = waterCost.plus(sewageCost); const subtotal = waterCost.plus(sewageCost);
const tax = subtotal.mul(0.1); const tax = subtotal.mul(this.TAX_RATE);
const totalPrice = subtotal.plus(tax); const totalPrice = subtotal.plus(tax);
const company = companyMap.get(value.companyId); const company = companyMap.get(value.companyId);
if (!company) { if (!company) {
@@ -72,7 +75,7 @@ export class BillsService {
const invoiceItem = em.create(InvoiceItem, { const invoiceItem = em.create(InvoiceItem, {
name: "قبض آب", name: "قبض آب",
count: value.waterUsage, count: 1,
unitPrice: totalPrice, unitPrice: totalPrice,
discount: new Decimal(0), discount: new Decimal(0),
totalPrice, totalPrice,
@@ -83,9 +86,13 @@ export class BillsService {
em.persist(invoice); em.persist(invoice);
} }
await em.flush();
await em.commit(); await em.commit();
// Ensure bill.id is available
if (!bill.id) {
await em.refresh(bill);
}
await this.addInvoiceReminderJobs(bill.id); await this.addInvoiceReminderJobs(bill.id);
return bill; return bill;
@@ -159,7 +166,7 @@ export class BillsService {
try { try {
await em.begin(); await em.begin();
const bill = em.create(Bill, { type: BillType.MONTHLY_CHARGE, business }); const bill = em.create(Bill, { type: BillType.MONTHLY_CHARGE, business, title: dto.title });
em.persist(bill); em.persist(bill);
const dueDate = dayjs().add(dueDays, "day").toDate(); const dueDate = dayjs().add(dueDays, "day").toDate();
@@ -192,8 +199,11 @@ export class BillsService {
em.persist(invoice); em.persist(invoice);
} }
await em.flush();
await em.commit(); await em.commit();
// Ensure bill.id is available
if (!bill.id) {
await em.refresh(bill);
}
await this.addInvoiceReminderJobs(bill.id); await this.addInvoiceReminderJobs(bill.id);
@@ -1,7 +1,12 @@
import { ApiProperty } from "@nestjs/swagger"; import { ApiProperty } from "@nestjs/swagger";
import { IsInt } from "class-validator"; import { IsInt, IsNotEmpty, IsString } from "class-validator";
export class CreateChargeBillDto { export class CreateChargeBillDto {
@ApiProperty({ description: "Bill title" })
@IsString()
@IsNotEmpty()
title: string;
@ApiProperty() @ApiProperty()
@IsInt() @IsInt()
chargeRate: number; chargeRate: number;
+11 -1
View File
@@ -1,6 +1,6 @@
import { ApiProperty } from "@nestjs/swagger"; import { ApiProperty } from "@nestjs/swagger";
import { Type } from "class-transformer"; import { Type } from "class-transformer";
import { ArrayMinSize, IsArray, IsInt, IsNotEmpty, IsUUID, ValidateNested } from "class-validator"; import { ArrayMinSize, IsArray, IsInt, IsNotEmpty, IsString, IsUUID, ValidateNested } from "class-validator";
export class ValueDto { export class ValueDto {
@IsNotEmpty({ message: " BillMessage.COMPANY_ID_REQUIRED" }) @IsNotEmpty({ message: " BillMessage.COMPANY_ID_REQUIRED" })
@@ -16,6 +16,11 @@ export class ValueDto {
} }
export class CreateWaterBillDto { export class CreateWaterBillDto {
@ApiProperty({ description: "Bill title" })
@IsString()
@IsNotEmpty()
title: string;
@ApiProperty() @ApiProperty()
@IsInt() @IsInt()
waterRate: number; waterRate: number;
@@ -33,6 +38,11 @@ export class CreateWaterBillDto {
} }
export class CreateWaterBillFromExcelDto { export class CreateWaterBillFromExcelDto {
@ApiProperty({ description: "Bill title" })
@IsString()
@IsNotEmpty()
title: string;
@ApiProperty() @ApiProperty()
@Type(() => Number) @Type(() => Number)
@IsInt() @IsInt()
@@ -8,6 +8,9 @@ import { BillsRepository } from "../repositories/bill.repository";
@Entity({ repository: () => BillsRepository }) @Entity({ repository: () => BillsRepository })
export class Bill extends BaseEntity { export class Bill extends BaseEntity {
@Property({ columnType: "text" })
title!: string;
@Enum({ items: () => BillType }) @Enum({ items: () => BillType })
type: BillType; type: BillType;