Initial Mento CRM: portal OTP, reports, SMS, and deploy for crm.montzar.ir.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-29 21:06:30 +03:30
co-authored by Cursor
commit 29a040c21d
195 changed files with 39430 additions and 0 deletions
+257
View File
@@ -0,0 +1,257 @@
import {
ArrayMinSize,
IsArray,
IsIn,
IsNumber,
IsOptional,
IsString,
MaxLength,
Min,
MinLength,
ValidateNested,
} from 'class-validator';
import { Type } from 'class-transformer';
const INVOICE_STATUSES = [
'draft',
'issued',
'partially_paid',
'paid',
'canceled',
] as const;
const PAYMENT_METHODS = [
'cash',
'transfer',
'card',
'check',
'other',
] as const;
export class InvoiceLineItemInputDto {
@IsOptional()
@IsString()
productId?: string | null;
@IsString()
@MinLength(1)
@MaxLength(200)
name!: string;
@Type(() => Number)
@IsNumber()
@Min(0.01)
quantity!: number;
@Type(() => Number)
@IsNumber()
@Min(0)
unitPrice!: number;
@IsOptional()
@IsString()
@MaxLength(8)
currency?: string;
}
export class InvoiceInstallmentInputDto {
@IsString()
dueDate!: string;
@Type(() => Number)
@IsNumber()
@Min(0.01)
amount!: number;
@IsOptional()
@IsString()
@MaxLength(8)
currency?: string;
}
export class CreateInvoiceDto {
@IsString()
@MinLength(2)
@MaxLength(200)
title!: string;
@IsOptional()
@IsIn(INVOICE_STATUSES)
status?: (typeof INVOICE_STATUSES)[number];
@IsOptional()
@IsString()
@MaxLength(8)
currency?: string;
@IsOptional()
@IsString()
@MaxLength(4000)
notes?: string;
@IsOptional()
@IsString()
issuedAt?: string | null;
@IsOptional()
@IsString()
dueDate?: string | null;
@IsOptional()
@IsString()
personId?: string | null;
@IsOptional()
@IsString()
companyId?: string | null;
@IsOptional()
@IsString()
dealId?: string | null;
@IsOptional()
@IsString()
quoteId?: string | null;
@IsOptional()
@IsString()
fromDealId?: string | null;
@IsOptional()
@IsString()
fromQuoteId?: string | null;
@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => InvoiceLineItemInputDto)
@ArrayMinSize(0)
lineItems?: InvoiceLineItemInputDto[];
@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => InvoiceInstallmentInputDto)
installments?: InvoiceInstallmentInputDto[];
}
export class UpdateInvoiceDto {
@IsOptional()
@IsString()
@MinLength(2)
@MaxLength(200)
title?: string;
@IsOptional()
@IsIn(INVOICE_STATUSES)
status?: (typeof INVOICE_STATUSES)[number];
@IsOptional()
@IsString()
@MaxLength(8)
currency?: string;
@IsOptional()
@IsString()
@MaxLength(4000)
notes?: string | null;
@IsOptional()
@IsString()
issuedAt?: string | null;
@IsOptional()
@IsString()
dueDate?: string | null;
@IsOptional()
@IsString()
personId?: string | null;
@IsOptional()
@IsString()
companyId?: string | null;
@IsOptional()
@IsString()
dealId?: string | null;
@IsOptional()
@IsString()
quoteId?: string | null;
@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => InvoiceLineItemInputDto)
lineItems?: InvoiceLineItemInputDto[];
@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => InvoiceInstallmentInputDto)
installments?: InvoiceInstallmentInputDto[];
}
export class CreatePaymentDto {
@Type(() => Number)
@IsNumber()
@Min(0.01)
amount!: number;
@IsOptional()
@IsString()
@MaxLength(8)
currency?: string;
@IsOptional()
@IsIn(PAYMENT_METHODS)
method?: (typeof PAYMENT_METHODS)[number];
@IsOptional()
@IsString()
paidAt?: string;
@IsOptional()
@IsString()
@MaxLength(2000)
notes?: string;
@IsOptional()
@IsString()
installmentId?: string | null;
}
export class ListInvoicesQueryDto {
@IsOptional()
@IsString()
q?: string;
@IsOptional()
@IsIn(INVOICE_STATUSES)
status?: (typeof INVOICE_STATUSES)[number];
@IsOptional()
@IsString()
dealId?: string;
@IsOptional()
@IsString()
personId?: string;
@IsOptional()
@IsString()
quoteId?: string;
@IsOptional()
@Type(() => Number)
@IsNumber()
@Min(1)
page?: number;
@IsOptional()
@Type(() => Number)
@IsNumber()
@Min(1)
limit?: number;
}