diff --git a/database/migrations/.snapshot-dzone-db.json b/database/migrations/.snapshot-dzone-db.json index af2c0be..9a22717 100644 --- a/database/migrations/.snapshot-dzone-db.json +++ b/database/migrations/.snapshot-dzone-db.json @@ -321,6 +321,15 @@ "length": 6, "mappedType": "datetime" }, + "title": { + "name": "title", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, "type": { "name": "type", "type": "text", diff --git a/database/migrations/Migration20250218120000_add_bill_title.ts b/database/migrations/Migration20250218120000_add_bill_title.ts new file mode 100644 index 0000000..3b19ca0 --- /dev/null +++ b/database/migrations/Migration20250218120000_add_bill_title.ts @@ -0,0 +1,12 @@ +import { Migration } from "@mikro-orm/migrations"; + +export class Migration20250218120000_add_bill_title extends Migration { + override async up(): Promise { + 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 { + this.addSql(`alter table "bill" drop column "title";`); + } +} diff --git a/src/modules/bills/bills.service.ts b/src/modules/bills/bills.service.ts index 2194957..7c63c56 100644 --- a/src/modules/bills/bills.service.ts +++ b/src/modules/bills/bills.service.ts @@ -24,6 +24,9 @@ import { IFile } from "../utils/interfaces/IFile"; @Injectable() export class BillsService { + readonly SEWAGE_RATE = 0.3; + readonly TAX_RATE = 0.1; + constructor( private readonly em: EntityManager, private readonly companiesService: CompaniesService, @@ -40,7 +43,7 @@ export class BillsService { try { 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); const dueDate = dayjs().add(dueDays, "day").toDate(); @@ -50,10 +53,10 @@ export class BillsService { for (const value of values) { 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 tax = subtotal.mul(0.1); + const tax = subtotal.mul(this.TAX_RATE); const totalPrice = subtotal.plus(tax); const company = companyMap.get(value.companyId); if (!company) { @@ -72,7 +75,7 @@ export class BillsService { const invoiceItem = em.create(InvoiceItem, { name: "قبض آب", - count: value.waterUsage, + count: 1, unitPrice: totalPrice, discount: new Decimal(0), totalPrice, @@ -83,9 +86,13 @@ export class BillsService { em.persist(invoice); } - await em.flush(); await em.commit(); + // Ensure bill.id is available + if (!bill.id) { + await em.refresh(bill); + } + await this.addInvoiceReminderJobs(bill.id); return bill; @@ -159,7 +166,7 @@ export class BillsService { try { 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); const dueDate = dayjs().add(dueDays, "day").toDate(); @@ -192,8 +199,11 @@ export class BillsService { em.persist(invoice); } - await em.flush(); await em.commit(); + // Ensure bill.id is available + if (!bill.id) { + await em.refresh(bill); + } await this.addInvoiceReminderJobs(bill.id); diff --git a/src/modules/bills/dto/create-charge-bill.dto.ts b/src/modules/bills/dto/create-charge-bill.dto.ts index 31a656a..2276745 100644 --- a/src/modules/bills/dto/create-charge-bill.dto.ts +++ b/src/modules/bills/dto/create-charge-bill.dto.ts @@ -1,7 +1,12 @@ import { ApiProperty } from "@nestjs/swagger"; -import { IsInt } from "class-validator"; +import { IsInt, IsNotEmpty, IsString } from "class-validator"; export class CreateChargeBillDto { + @ApiProperty({ description: "Bill title" }) + @IsString() + @IsNotEmpty() + title: string; + @ApiProperty() @IsInt() chargeRate: number; diff --git a/src/modules/bills/dto/create-water-bill.dto.ts b/src/modules/bills/dto/create-water-bill.dto.ts index 89c59e2..52413e1 100644 --- a/src/modules/bills/dto/create-water-bill.dto.ts +++ b/src/modules/bills/dto/create-water-bill.dto.ts @@ -1,6 +1,6 @@ import { ApiProperty } from "@nestjs/swagger"; 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 { @IsNotEmpty({ message: " BillMessage.COMPANY_ID_REQUIRED" }) @@ -16,6 +16,11 @@ export class ValueDto { } export class CreateWaterBillDto { + @ApiProperty({ description: "Bill title" }) + @IsString() + @IsNotEmpty() + title: string; + @ApiProperty() @IsInt() waterRate: number; @@ -33,6 +38,11 @@ export class CreateWaterBillDto { } export class CreateWaterBillFromExcelDto { + @ApiProperty({ description: "Bill title" }) + @IsString() + @IsNotEmpty() + title: string; + @ApiProperty() @Type(() => Number) @IsInt() diff --git a/src/modules/bills/entities/bill.entity.ts b/src/modules/bills/entities/bill.entity.ts index 6784a27..c226f97 100644 --- a/src/modules/bills/entities/bill.entity.ts +++ b/src/modules/bills/entities/bill.entity.ts @@ -8,6 +8,9 @@ import { BillsRepository } from "../repositories/bill.repository"; @Entity({ repository: () => BillsRepository }) export class Bill extends BaseEntity { + @Property({ columnType: "text" }) + title!: string; + @Enum({ items: () => BillType }) type: BillType;