@@ -1,13 +0,0 @@
|
|||||||
import { Migration } from '@mikro-orm/migrations';
|
|
||||||
|
|
||||||
export class Migration20260626120000 extends Migration {
|
|
||||||
|
|
||||||
override async up(): Promise<void> {
|
|
||||||
this.addSql(`alter table "requests" drop column if exists "status";`);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async down(): Promise<void> {
|
|
||||||
this.addSql(`alter table "requests" add column "status" text check ("status" in ('pending', 'invoiced')) not null default 'pending';`);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+22
-2
@@ -1,8 +1,13 @@
|
|||||||
import { Migration } from '@mikro-orm/migrations';
|
import { Migration } from '@mikro-orm/migrations';
|
||||||
|
|
||||||
export class Migration20260526120100 extends Migration {
|
export class Migration20260626140000 extends Migration {
|
||||||
|
|
||||||
override async up(): Promise<void> {
|
override async up(): Promise<void> {
|
||||||
|
this.addSql(`
|
||||||
|
alter table "invoices"
|
||||||
|
add column "confirm_status" text check ("confirm_status" in ('pending', 'confirmed')) not null default 'pending';
|
||||||
|
`);
|
||||||
|
|
||||||
this.addSql(`
|
this.addSql(`
|
||||||
CREATE OR REPLACE FUNCTION recalc_invoice_totals()
|
CREATE OR REPLACE FUNCTION recalc_invoice_totals()
|
||||||
RETURNS TRIGGER AS $$
|
RETURNS TRIGGER AS $$
|
||||||
@@ -14,6 +19,7 @@ export class Migration20260526120100 extends Migration {
|
|||||||
v_total int;
|
v_total int;
|
||||||
v_paid int;
|
v_paid int;
|
||||||
v_enable_tax boolean;
|
v_enable_tax boolean;
|
||||||
|
v_confirm_status text;
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
v_invoice_id := COALESCE(NEW.invoice_id, OLD.invoice_id);
|
v_invoice_id := COALESCE(NEW.invoice_id, OLD.invoice_id);
|
||||||
@@ -48,6 +54,18 @@ export class Migration20260526120100 extends Migration {
|
|||||||
AND status = 'paid'
|
AND status = 'paid'
|
||||||
AND deleted_at IS NULL;
|
AND deleted_at IS NULL;
|
||||||
|
|
||||||
|
SELECT CASE
|
||||||
|
WHEN EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM invoice_items
|
||||||
|
WHERE invoice_id = v_invoice_id
|
||||||
|
AND deleted_at IS NULL
|
||||||
|
AND confirmed_at IS NOT NULL
|
||||||
|
) THEN 'confirmed'
|
||||||
|
ELSE 'pending'
|
||||||
|
END
|
||||||
|
INTO v_confirm_status;
|
||||||
|
|
||||||
UPDATE invoices
|
UPDATE invoices
|
||||||
SET
|
SET
|
||||||
sub_total = v_subtotal,
|
sub_total = v_subtotal,
|
||||||
@@ -55,7 +73,8 @@ export class Migration20260526120100 extends Migration {
|
|||||||
tax_amount = v_tax,
|
tax_amount = v_tax,
|
||||||
total = v_total,
|
total = v_total,
|
||||||
paid_amount = v_paid,
|
paid_amount = v_paid,
|
||||||
balance = v_total - v_paid
|
balance = v_total - v_paid,
|
||||||
|
confirm_status = v_confirm_status
|
||||||
WHERE id = v_invoice_id;
|
WHERE id = v_invoice_id;
|
||||||
|
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
@@ -119,6 +138,7 @@ export class Migration20260526120100 extends Migration {
|
|||||||
this.addSql(`DROP TRIGGER IF EXISTS trg_payments_recalc ON payments;`);
|
this.addSql(`DROP TRIGGER IF EXISTS trg_payments_recalc ON payments;`);
|
||||||
this.addSql(`DROP FUNCTION IF EXISTS recalc_invoice_totals();`);
|
this.addSql(`DROP FUNCTION IF EXISTS recalc_invoice_totals();`);
|
||||||
this.addSql(`DROP FUNCTION IF EXISTS recalc_invoice_payments();`);
|
this.addSql(`DROP FUNCTION IF EXISTS recalc_invoice_payments();`);
|
||||||
|
this.addSql(`alter table "invoices" drop column if exists "confirm_status";`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ export class AuthService {
|
|||||||
|
|
||||||
await this.otpService.set(phone, code)
|
await this.otpService.set(phone, code)
|
||||||
|
|
||||||
await this.smsService.sendotp(phone, code);
|
// await this.smsService.sendotp(phone, code);
|
||||||
|
|
||||||
return { code };
|
return { code };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import {
|
|||||||
IsIn,
|
IsIn,
|
||||||
IsDateString,
|
IsDateString,
|
||||||
IsBoolean,
|
IsBoolean,
|
||||||
|
IsEnum,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
|
import { InvoiceConfirmStatusEnum } from '../enum/invoice-confirm-status.enum';
|
||||||
import { Type, Transform } from 'class-transformer';
|
import { Type, Transform } from 'class-transformer';
|
||||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
|
||||||
@@ -65,6 +67,14 @@ export class FindInvoicesDto {
|
|||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
enableTax?: boolean;
|
enableTax?: boolean;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
enum: InvoiceConfirmStatusEnum,
|
||||||
|
description: 'Filter by invoice confirmation status',
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
@IsEnum(InvoiceConfirmStatusEnum)
|
||||||
|
confirmStatus?: InvoiceConfirmStatusEnum;
|
||||||
|
|
||||||
@ApiPropertyOptional({ default: 'createdAt' })
|
@ApiPropertyOptional({ default: 'createdAt' })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { User } from '../../user/entities/user.entity';
|
|||||||
import { Payment } from 'src/modules/payment/entities/payment.entity';
|
import { Payment } from 'src/modules/payment/entities/payment.entity';
|
||||||
import { ulid } from 'ulid';
|
import { ulid } from 'ulid';
|
||||||
import { BaseEntity } from 'src/common/entities/base.entity';
|
import { BaseEntity } from 'src/common/entities/base.entity';
|
||||||
import { InvoiceStatusEnum } from '../enum/invoice-status.enum';
|
import { InvoiceConfirmStatusEnum } from '../enum/invoice-confirm-status.enum';
|
||||||
import { InvoiceItem } from './invoice-item.entity';
|
import { InvoiceItem } from './invoice-item.entity';
|
||||||
import { Request } from 'src/modules/request/entities/request.entity';
|
import { Request } from 'src/modules/request/entities/request.entity';
|
||||||
import { IAttachment } from 'src/modules/order/interface/order.interface';
|
import { IAttachment } from 'src/modules/order/interface/order.interface';
|
||||||
@@ -24,7 +24,7 @@ import { IAttachment } from 'src/modules/order/interface/order.interface';
|
|||||||
@Entity({ tableName: 'invoices' })
|
@Entity({ tableName: 'invoices' })
|
||||||
@Index({ properties: ['user'] })
|
@Index({ properties: ['user'] })
|
||||||
export class Invoice extends BaseEntity {
|
export class Invoice extends BaseEntity {
|
||||||
[OptionalProps]?: 'createdAt' | 'deletedAt' | 'invoiceNumber'
|
[OptionalProps]?: 'createdAt' | 'deletedAt' | 'invoiceNumber' | 'confirmStatus'
|
||||||
|
|
||||||
@PrimaryKey({ type: 'string', columnType: 'char(26)' })
|
@PrimaryKey({ type: 'string', columnType: 'char(26)' })
|
||||||
id: string = ulid()
|
id: string = ulid()
|
||||||
@@ -80,9 +80,8 @@ export class Invoice extends BaseEntity {
|
|||||||
balance: number & Opt;
|
balance: number & Opt;
|
||||||
|
|
||||||
|
|
||||||
// @Enum(() => InvoiceStatusEnum)
|
@Enum({ items: () => InvoiceConfirmStatusEnum, persist: false })
|
||||||
// status: InvoiceStatusEnum = InvoiceStatusEnum.PENDING;
|
confirmStatus!: InvoiceConfirmStatusEnum & Opt;
|
||||||
|
|
||||||
|
|
||||||
@Property({ type: 'boolean', default: false })
|
@Property({ type: 'boolean', default: false })
|
||||||
enableTax?: boolean = false
|
enableTax?: boolean = false
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export enum InvoiceConfirmStatusEnum {
|
||||||
|
PENDING = 'pending',
|
||||||
|
CONFIRMED = 'confirmed',
|
||||||
|
}
|
||||||
@@ -69,6 +69,14 @@ export class InvoiceService {
|
|||||||
if (!requestEntity) {
|
if (!requestEntity) {
|
||||||
throw new NotFoundException('Request not found');
|
throw new NotFoundException('Request not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const existingInvoice = await this.em.findOne(Invoice, {
|
||||||
|
request: { id: dto.requestId },
|
||||||
|
});
|
||||||
|
if (existingInvoice) {
|
||||||
|
throw new BadRequestException('An invoice already exists for this request');
|
||||||
|
}
|
||||||
|
|
||||||
user = requestEntity.user;
|
user = requestEntity.user;
|
||||||
request = requestEntity;
|
request = requestEntity;
|
||||||
} else if (dto.userId) {
|
} else if (dto.userId) {
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ export class InvoiceRepository extends EntityRepository<Invoice> {
|
|||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
enableTax,
|
enableTax,
|
||||||
requestId
|
requestId,
|
||||||
|
confirmStatus,
|
||||||
} = opts;
|
} = opts;
|
||||||
|
|
||||||
const offset = (page - 1) * limit;
|
const offset = (page - 1) * limit;
|
||||||
@@ -45,6 +46,10 @@ export class InvoiceRepository extends EntityRepository<Invoice> {
|
|||||||
where.enableTax = enableTax;
|
where.enableTax = enableTax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (confirmStatus) {
|
||||||
|
where.confirmStatus = confirmStatus;
|
||||||
|
}
|
||||||
|
|
||||||
if (from || to) {
|
if (from || to) {
|
||||||
where.createdAt = {};
|
where.createdAt = {};
|
||||||
if (from) {
|
if (from) {
|
||||||
|
|||||||
Reference in New Issue
Block a user