refactor(nestjs): validation schema dtos

This commit is contained in:
Ahmed Bouhuolia
2025-05-25 23:39:54 +02:00
parent 2b3f98d8fe
commit 24bf3dd06d
24 changed files with 247 additions and 135 deletions

View File

@@ -12,6 +12,7 @@ import {
} from 'class-validator';
import { BankRuleComparator } from '../types';
import { ApiProperty } from '@nestjs/swagger';
import { ToNumber } from '@/common/decorators/Validators';
class BankRuleConditionDto {
@IsNotEmpty()
@@ -44,6 +45,8 @@ export class CommandBankRuleDto {
})
name: string;
@IsNotEmpty()
@ToNumber()
@IsInt()
@Min(0)
@ApiProperty({
@@ -53,6 +56,7 @@ export class CommandBankRuleDto {
order: number;
@IsOptional()
@ToNumber()
@IsInt()
@Min(0)
@ApiProperty({
@@ -61,6 +65,7 @@ export class CommandBankRuleDto {
})
applyIfAccountId?: number;
@IsNotEmpty()
@IsIn(['deposit', 'withdrawal'])
@ApiProperty({
description: 'The transaction type to apply the rule if',
@@ -82,11 +87,14 @@ export class CommandBankRuleDto {
@Type(() => BankRuleConditionDto)
@ApiProperty({
description: 'The conditions to apply the rule if',
example: [{ field: 'description', comparator: 'contains', value: 'Salary' }],
example: [
{ field: 'description', comparator: 'contains', value: 'Salary' },
],
})
conditions: BankRuleConditionDto[];
@IsString()
@IsNotEmpty()
@ApiProperty({
description: 'The category to assign the rule if',
example: 'Income:Salary',
@@ -95,6 +103,8 @@ export class CommandBankRuleDto {
@IsInt()
@Min(0)
@ToNumber()
@IsNotEmpty()
@ApiProperty({
description: 'The account ID to assign the rule if',
example: 1,

View File

@@ -24,7 +24,7 @@ export class TriggerRecognizedTransactionsSubscriber {
* @param {IBankRuleEventEditedPayload} payload -
*/
@OnEvent(events.bankRules.onEdited)
private async recognizedTransactionsOnRuleEdited({
async recognizedTransactionsOnRuleEdited({
editRuleDTO,
oldBankRule,
bankRule,

View File

@@ -7,6 +7,8 @@ import { GetCreditNotePdf } from './queries/GetCreditNotePdf.serivce';
import { ICreditNotesQueryDTO } from './types/CreditNotes.types';
import { GetCreditNotesService } from './queries/GetCreditNotes.service';
import { CreateCreditNoteDto, EditCreditNoteDto } from './dtos/CreditNote.dto';
import { GetCreditNoteState } from './queries/GetCreditNoteState.service';
import { GetCreditNoteService } from './queries/GetCreditNote.service';
@Injectable()
export class CreditNoteApplication {
@@ -17,6 +19,8 @@ export class CreditNoteApplication {
private readonly deleteCreditNoteService: DeleteCreditNoteService,
private readonly getCreditNotePdfService: GetCreditNotePdf,
private readonly getCreditNotesService: GetCreditNotesService,
private readonly getCreditNoteStateService: GetCreditNoteState,
private readonly getCreditNoteService: GetCreditNoteService
) {}
/**
@@ -76,4 +80,21 @@ export class CreditNoteApplication {
getCreditNotes(creditNotesQuery: ICreditNotesQueryDTO) {
return this.getCreditNotesService.getCreditNotesList(creditNotesQuery);
}
/**
* Retrieves the create/edit initial state of the credit note.
* @returns {Promise<ICreditNoteState>}
*/
getCreditNoteState() {
return this.getCreditNoteStateService.getCreditNoteState();
}
/**
* Retrieves the credit note.
* @param {number} creditNoteId
* @returns {Promise<CreditNote>}
*/
getCreditNote(creditNoteId: number) {
return this.getCreditNoteService.getCreditNote(creditNoteId);
}
}

View File

@@ -1,4 +1,4 @@
import { ApiTags } from '@nestjs/swagger';
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
import {
Body,
Controller,
@@ -22,16 +22,42 @@ export class CreditNotesController {
constructor(private creditNoteApplication: CreditNoteApplication) {}
@Post()
@ApiOperation({ summary: 'Create a new credit note' })
@ApiResponse({ status: 201, description: 'Credit note successfully created' })
@ApiResponse({ status: 400, description: 'Invalid input data' })
createCreditNote(@Body() creditNoteDTO: CreateCreditNoteDto) {
return this.creditNoteApplication.createCreditNote(creditNoteDTO);
}
@Get('state')
@ApiOperation({ summary: 'Get credit note state' })
@ApiResponse({ status: 200, description: 'Returns the credit note state' })
getCreditNoteState() {
return this.creditNoteApplication.getCreditNoteState();
}
@Get(':id')
@ApiOperation({ summary: 'Get a specific credit note by ID' })
@ApiParam({ name: 'id', description: 'Credit note ID', type: 'number' })
@ApiResponse({ status: 200, description: 'Returns the credit note' })
@ApiResponse({ status: 404, description: 'Credit note not found' })
getCreditNote(@Param('id') creditNoteId: number) {
return this.creditNoteApplication.getCreditNote(creditNoteId);
}
@Get()
@ApiOperation({ summary: 'Get all credit notes' })
@ApiResponse({ status: 200, description: 'Returns a list of credit notes' })
getCreditNotes(@Query() creditNotesQuery: ICreditNotesQueryDTO) {
return this.creditNoteApplication.getCreditNotes(creditNotesQuery);
}
@Put(':id')
@ApiOperation({ summary: 'Update a credit note' })
@ApiParam({ name: 'id', description: 'Credit note ID', type: 'number' })
@ApiResponse({ status: 200, description: 'Credit note successfully updated' })
@ApiResponse({ status: 404, description: 'Credit note not found' })
@ApiResponse({ status: 400, description: 'Invalid input data' })
editCreditNote(
@Param('id') creditNoteId: number,
@Body() creditNoteDTO: EditCreditNoteDto,
@@ -43,11 +69,19 @@ export class CreditNotesController {
}
@Put(':id/open')
@ApiOperation({ summary: 'Open a credit note' })
@ApiParam({ name: 'id', description: 'Credit note ID', type: 'number' })
@ApiResponse({ status: 200, description: 'Credit note successfully opened' })
@ApiResponse({ status: 404, description: 'Credit note not found' })
openCreditNote(@Param('id') creditNoteId: number) {
return this.creditNoteApplication.openCreditNote(creditNoteId);
}
@Delete(':id')
@ApiOperation({ summary: 'Delete a credit note' })
@ApiParam({ name: 'id', description: 'Credit note ID', type: 'number' })
@ApiResponse({ status: 200, description: 'Credit note successfully deleted' })
@ApiResponse({ status: 404, description: 'Credit note not found' })
deleteCreditNote(@Param('id') creditNoteId: number) {
return this.creditNoteApplication.deleteCreditNote(creditNoteId);
}

View File

@@ -15,7 +15,7 @@ import { WarehousesModule } from '../Warehouses/Warehouses.module';
import { PdfTemplatesModule } from '../PdfTemplate/PdfTemplates.module';
import { ChromiumlyTenancyModule } from '../ChromiumlyTenancy/ChromiumlyTenancy.module';
import { TemplateInjectableModule } from '../TemplateInjectable/TemplateInjectable.module';
import { GetCreditNote } from './queries/GetCreditNote.service';
import { GetCreditNoteService } from './queries/GetCreditNote.service';
import { CreditNoteBrandingTemplate } from './queries/CreditNoteBrandingTemplate.service';
import { AutoIncrementOrdersModule } from '../AutoIncrementOrders/AutoIncrementOrders.module';
import { CreditNoteGLEntries } from './commands/CreditNoteGLEntries';
@@ -52,7 +52,7 @@ import { CreditNotesApplyInvoiceModule } from '../CreditNotesApplyInvoice/Credit
],
providers: [
CreateCreditNoteService,
GetCreditNote,
GetCreditNoteService,
CommandCreditNoteDTOTransform,
EditCreditNoteService,
OpenCreditNoteService,
@@ -74,7 +74,7 @@ import { CreditNotesApplyInvoiceModule } from '../CreditNotesApplyInvoice/Credit
],
exports: [
CreateCreditNoteService,
GetCreditNote,
GetCreditNoteService,
CommandCreditNoteDTOTransform,
EditCreditNoteService,
OpenCreditNoteService,

View File

@@ -1,3 +1,4 @@
import { ToNumber } from '@/common/decorators/Validators';
import { ItemEntryDto } from '@/modules/TransactionItemEntry/dto/ItemEntry.dto';
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
@@ -5,9 +6,10 @@ import {
ArrayMinSize,
IsArray,
IsBoolean,
IsDate,
IsDateString,
IsEnum,
IsInt,
IsNotEmpty,
IsNumber,
IsOptional,
IsPositive,
@@ -25,21 +27,25 @@ export class CreditNoteEntryDto extends ItemEntryDto {}
class AttachmentDto {
@IsString()
@IsNotEmpty()
key: string;
}
export class CommandCreditNoteDto {
@ToNumber()
@IsInt()
@IsNotEmpty()
@ApiProperty({ example: 1, description: 'The customer ID' })
customerId: number;
@IsOptional()
@ToNumber()
@IsPositive()
@ApiProperty({ example: 3.43, description: 'The exchange rate' })
exchangeRate?: number;
@IsDate()
@Type(() => Date)
@IsNotEmpty()
@IsDateString()
@ApiProperty({ example: '2021-09-01', description: 'The credit note date' })
creditNoteDate: Date;
@@ -64,26 +70,19 @@ export class CommandCreditNoteDto {
termsConditions?: string;
@IsBoolean()
@ApiProperty({
example: false,
description: 'The credit note is open',
})
@ApiProperty({ example: false, description: 'The credit note is open' })
open: boolean = false;
@IsOptional()
@ToNumber()
@IsInt()
@ApiProperty({
example: 1,
description: 'The warehouse ID',
})
@ApiProperty({ example: 1, description: 'The warehouse ID' })
warehouseId?: number;
@IsOptional()
@ToNumber()
@IsInt()
@ApiProperty({
example: 1,
description: 'The branch ID',
})
@ApiProperty({ example: 1, description: 'The branch ID' })
branchId?: number;
@IsArray()
@@ -91,14 +90,7 @@ export class CommandCreditNoteDto {
@Type(() => CreditNoteEntryDto)
@ArrayMinSize(1)
@ApiProperty({
example: [
{
itemId: 1,
quantity: 1,
rate: 10,
taxRateId: 1,
},
],
example: [{ itemId: 1, quantity: 1, rate: 10, taxRateId: 1 }],
description: 'The credit note entries',
})
entries: CreditNoteEntryDto[];
@@ -110,19 +102,15 @@ export class CommandCreditNoteDto {
attachments?: AttachmentDto[];
@IsOptional()
@ToNumber()
@IsInt()
@ApiProperty({
example: 1,
description: 'The pdf template ID',
})
@ApiProperty({ example: 1, description: 'The pdf template ID' })
pdfTemplateId?: number;
@IsOptional()
@ToNumber()
@IsNumber()
@ApiProperty({
example: 10,
description: 'The discount amount',
})
@ApiProperty({ example: 10, description: 'The discount amount' })
discount?: number;
@IsOptional()
@@ -135,6 +123,7 @@ export class CommandCreditNoteDto {
discountType?: DiscountType;
@IsOptional()
@ToNumber()
@IsNumber()
adjustment?: number;
}

View File

@@ -7,7 +7,7 @@ import { ServiceError } from '@/modules/Items/ServiceError';
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
@Injectable()
export class GetCreditNote {
export class GetCreditNoteService {
constructor(
private readonly transformer: TransformerInjectable,

View File

@@ -1,5 +1,5 @@
import { Inject, Injectable } from '@nestjs/common';
import { GetCreditNote } from './GetCreditNote.service';
import { GetCreditNoteService } from './GetCreditNote.service';
import { CreditNoteBrandingTemplate } from './CreditNoteBrandingTemplate.service';
import { transformCreditNoteToPdfTemplate } from '../utils';
import { CreditNote } from '../models/CreditNote';
@@ -25,7 +25,7 @@ export class GetCreditNotePdf {
constructor(
private readonly chromiumlyTenancy: ChromiumlyTenancy,
private readonly templateInjectable: TemplateInjectable,
private readonly getCreditNoteService: GetCreditNote,
private readonly getCreditNoteService: GetCreditNoteService,
private readonly creditNoteBrandingTemplate: CreditNoteBrandingTemplate,
private readonly eventPublisher: EventEmitter2,

View File

@@ -1,7 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice';
import { GetCreditNote } from '../../CreditNotes/queries/GetCreditNote.service';
import { GetCreditNoteService } from '../../CreditNotes/queries/GetCreditNote.service';
import { CreditNoteWithInvoicesToApplyTransformer } from './CreditNoteWithInvoicesToApplyTransformer';
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
@@ -14,7 +14,7 @@ export class GetCreditNoteAssociatedInvoicesToApply {
*/
constructor(
private transformer: TransformerInjectable,
private getCreditNote: GetCreditNote,
private getCreditNote: GetCreditNoteService,
@Inject(SaleInvoice.name)
private saleInvoiceModel: TenantModelProxy<typeof SaleInvoice>,

View File

@@ -1,6 +1,6 @@
import { TenantModel } from "@/modules/System/models/TenantModel";
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
export class Currency extends TenantModel {
export class Currency extends TenantBaseModel {
public readonly currencySign: string;
public readonly currencyName: string;
public readonly currencyCode: string;
@@ -22,4 +22,4 @@ export class Currency extends TenantModel {
static get resourceable() {
return true;
}
}
}

View File

@@ -394,7 +394,5 @@ export abstract class DynamicFilterRoleAbstractor implements IDynamicFilter {
/**
* Retrieves the response meta.
*/
getResponseMeta() {
throw new Error('Method not implemented.');
}
getResponseMeta() {}
}

View File

@@ -1,10 +1,12 @@
import { ToNumber } from '@/common/decorators/Validators';
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import {
IsArray,
IsBoolean,
IsDate,
IsDateString,
IsInt,
IsISO4217CurrencyCode,
IsNotEmpty,
IsNumber,
IsOptional,
@@ -23,10 +25,12 @@ export class ExpenseCategoryDto {
@IsNotEmpty()
index: number;
@IsInt()
@IsNotEmpty()
@ToNumber()
@IsInt()
expenseAccountId: number;
@ToNumber()
@IsNumber()
@IsOptional()
amount?: number;
@@ -40,6 +44,7 @@ export class ExpenseCategoryDto {
@IsOptional()
landedCost?: boolean;
@ToNumber()
@IsInt()
@IsOptional()
projectId?: number;
@@ -55,7 +60,7 @@ export class CommandExpenseDto {
})
referenceNo?: string;
@IsDate()
@IsDateString()
@IsNotEmpty()
@ApiProperty({
description: 'The payment date of the expense',
@@ -63,8 +68,9 @@ export class CommandExpenseDto {
})
paymentDate: Date;
@IsInt()
@IsNotEmpty()
@ToNumber()
@IsInt()
@ApiProperty({
description: 'The payment account id of the expense',
example: 1,
@@ -80,31 +86,22 @@ export class CommandExpenseDto {
})
description?: string;
@ToNumber()
@IsNumber()
@IsOptional()
@ApiProperty({
description: 'The exchange rate of the expense',
example: 1,
})
@ApiProperty({ description: 'The exchange rate of the expense', example: 1 })
exchangeRate?: number;
@IsString()
@MaxLength(3)
@IsOptional()
@IsISO4217CurrencyCode()
@ApiProperty({
description: 'The currency code of the expense',
example: 'USD',
})
currencyCode?: string;
@IsNumber()
@IsOptional()
@ApiProperty({
description: 'The exchange rate of the expense',
example: 1,
})
exchange_rate?: number;
@IsBoolean()
@IsOptional()
@ApiProperty({
@@ -113,14 +110,16 @@ export class CommandExpenseDto {
})
publish?: boolean;
@IsInt()
@IsOptional()
@ToNumber()
@IsInt()
@ApiProperty({
description: 'The payee id of the expense',
example: 1,
})
payeeId?: number;
@ToNumber()
@IsInt()
@IsOptional()
@ApiProperty({

View File

@@ -108,11 +108,7 @@ export class ManualJournalsController {
description: 'The manual journal details have been successfully retrieved.',
})
@ApiResponse({ status: 404, description: 'The manual journal not found.' })
public getManualJournals(
@Query() filterDto: Partial<IManualJournalsFilter>
) {
public getManualJournals(@Query() filterDto: Partial<IManualJournalsFilter>) {
return this.manualJournalsApplication.getManualJournals(filterDto);
}
}

View File

@@ -1,10 +1,13 @@
import { ToNumber } from '@/common/decorators/Validators';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import {
IsArray,
IsBoolean,
IsDate,
IsDateString,
IsInt,
IsNotEmpty,
IsNumber,
IsOptional,
IsPositive,
@@ -20,18 +23,21 @@ export class ManualJournalEntryDto {
index: number;
@ApiPropertyOptional({ description: 'Credit amount' })
@ToNumber()
@IsOptional()
@IsNumber()
@Min(0)
credit?: number;
@ApiPropertyOptional({ description: 'Debit amount' })
@ToNumber()
@IsOptional()
@IsNumber()
@Min(0)
debit?: number;
@ApiProperty({ description: 'Account ID' })
@IsNotEmpty()
@IsInt()
accountId: number;
@@ -41,16 +47,19 @@ export class ManualJournalEntryDto {
note?: string;
@ApiPropertyOptional({ description: 'Contact ID' })
@IsOptional()
@ToNumber()
@IsInt()
@IsOptional()
contactId?: number;
@ApiPropertyOptional({ description: 'Branch ID' })
@ToNumber()
@IsOptional()
@IsInt()
branchId?: number;
@ApiPropertyOptional({ description: 'Project ID' })
@ToNumber()
@IsOptional()
@IsInt()
projectId?: number;
@@ -64,8 +73,7 @@ class AttachmentDto {
export class CommandManualJournalDto {
@ApiProperty({ description: 'Journal date' })
@IsDate()
@Type(() => Date)
@IsDateString()
date: Date;
@ApiPropertyOptional({ description: 'Currency code' })
@@ -74,6 +82,7 @@ export class CommandManualJournalDto {
currencyCode?: string;
@ApiPropertyOptional({ description: 'Exchange rate' })
@ToNumber()
@IsOptional()
@IsNumber()
@IsPositive()
@@ -103,6 +112,7 @@ export class CommandManualJournalDto {
description?: string;
@ApiPropertyOptional({ description: 'Branch ID' })
@ToNumber()
@IsOptional()
@IsInt()
branchId?: number;

View File

@@ -18,6 +18,7 @@ import {
IPaymentsReceivedFilter,
PaymentReceiveMailOptsDTO,
} from './types/PaymentReceived.types';
import { CreatePaymentReceivedDto, EditPaymentReceivedDto } from './dtos/PaymentReceived.dto';
@Controller('payments-received')
@ApiTags('payments-received')
@@ -57,7 +58,7 @@ export class PaymentReceivesController {
@Post()
@ApiOperation({ summary: 'Create a new payment received.' })
public createPaymentReceived(
@Body() paymentReceiveDTO: IPaymentReceivedCreateDTO,
@Body() paymentReceiveDTO: CreatePaymentReceivedDto,
) {
return this.paymentReceivesApplication.createPaymentReceived(
paymentReceiveDTO,
@@ -68,7 +69,7 @@ export class PaymentReceivesController {
@ApiOperation({ summary: 'Edit the given payment received.' })
public editPaymentReceive(
@Param('id', ParseIntPipe) paymentReceiveId: number,
@Body() paymentReceiveDTO: IPaymentReceivedEditDTO,
@Body() paymentReceiveDTO: EditPaymentReceivedDto,
) {
return this.paymentReceivesApplication.editPaymentReceive(
paymentReceiveId,

View File

@@ -1,16 +1,25 @@
import { AttachmentLinkDto } from '@/modules/Attachments/dtos/Attachment.dto';
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { IsArray, IsNotEmpty, ValidateNested } from 'class-validator';
import { IsString } from 'class-validator';
import { IsDateString, IsNumber, IsOptional } from 'class-validator';
import { IsInt } from 'class-validator';
import {
IsString,
IsDateString,
IsNumber,
IsOptional,
IsArray,
IsNotEmpty,
IsInt,
ValidateNested,
} from 'class-validator';
import { ToNumber } from '@/common/decorators/Validators';
import { AttachmentLinkDto } from '@/modules/Attachments/dtos/Attachment.dto';
export class PaymentReceivedEntryDto {
@ToNumber()
@IsOptional()
@IsInt()
id?: number;
@ToNumber()
@IsOptional()
@IsInt()
index?: number;
@@ -20,13 +29,16 @@ export class PaymentReceivedEntryDto {
paymentReceiveId?: number;
@IsInt()
@IsNotEmpty()
invoiceId: number;
@IsNumber()
@IsNotEmpty()
paymentAmount: number;
}
export class CommandPaymentReceivedDto {
@ToNumber()
@IsInt()
@IsNotEmpty()
@ApiProperty({ description: 'The id of the customer', example: 1 })
@@ -40,6 +52,7 @@ export class CommandPaymentReceivedDto {
paymentDate: Date | string;
@IsOptional()
@ToNumber()
@IsNumber()
@ApiProperty({
description: 'The amount of the payment received',
@@ -48,6 +61,7 @@ export class CommandPaymentReceivedDto {
amount?: number;
@IsOptional()
@ToNumber()
@IsNumber()
@ApiProperty({
description: 'The exchange rate of the payment received',
@@ -63,6 +77,7 @@ export class CommandPaymentReceivedDto {
})
referenceNo?: string;
@ToNumber()
@IsInt()
@IsNotEmpty()
@ApiProperty({
@@ -72,6 +87,7 @@ export class CommandPaymentReceivedDto {
depositAccountId: number;
@IsOptional()
@ToNumber()
@IsString()
@ApiProperty({
description: 'The payment receive number of the payment received',
@@ -97,6 +113,7 @@ export class CommandPaymentReceivedDto {
entries: PaymentReceivedEntryDto[];
@IsOptional()
@ToNumber()
@IsInt()
@ApiProperty({
description: 'The id of the branch',

View File

@@ -5,16 +5,16 @@ import {
ArrayMinSize,
IsArray,
IsBoolean,
IsDate,
IsDateString,
IsEmail,
IsEnum,
IsNotEmpty,
IsNumber,
IsOptional,
IsString,
Min,
MinLength,
ValidateNested,
} from 'class-validator';
import { IsOptional, ToNumber } from '@/common/decorators/Validators';
enum DiscountType {
Percentage = 'percentage',
@@ -28,24 +28,22 @@ class AttachmentDto {
key: string;
}
export class CommandSaleEstimateDto {
@IsNumber()
@IsNotEmpty()
@ApiProperty({
description: 'The id of the customer',
example: 1,
})
@ToNumber()
@IsNumber()
@ApiProperty({ description: 'The id of the customer', example: 1 })
customerId: number;
@IsDate()
@Type(() => Date)
@IsNotEmpty()
@IsDateString()
@ApiProperty({
description: 'The date of the estimate',
example: '2021-01-01',
})
estimateDate: Date;
@IsDate()
@Type(() => Date)
@IsNotEmpty()
@IsDateString()
@ApiProperty({
description: 'The expiration date of the estimate',
example: '2021-01-01',
@@ -65,31 +63,26 @@ export class CommandSaleEstimateDto {
estimateNumber?: string;
@IsBoolean()
delivered: boolean = false;
@IsOptional()
delivered?: boolean = false;
@IsOptional()
@ToNumber()
@IsNumber()
@Min(0.01)
@IsOptional()
@ApiProperty({
description: 'The exchange rate of the estimate',
example: 1,
})
@ApiProperty({ description: 'The exchange rate of the estimate', example: 1 })
exchangeRate?: number;
@IsNumber()
@IsOptional()
@ApiProperty({
description: 'The id of the warehouse',
example: 1,
})
@ToNumber()
@IsNumber()
@ApiProperty({ description: 'The id of the warehouse', example: 1 })
warehouseId?: number;
@IsNumber()
@IsOptional()
@ApiProperty({
description: 'The id of the branch',
example: 1,
})
@ToNumber()
@IsNumber()
@ApiProperty({ description: 'The id of the branch', example: 1 })
branchId?: number;
@IsArray()
@@ -110,32 +103,33 @@ export class CommandSaleEstimateDto {
})
entries: SaleEstimateEntryDto[];
@IsString()
@IsOptional()
@IsString()
@ApiProperty({
description: 'The note of the estimate',
example: 'This is a note',
})
note?: string;
@IsString()
@IsOptional()
@IsString()
@ApiProperty({
description: 'The terms and conditions of the estimate',
example: 'This is a terms and conditions',
})
termsConditions?: string;
@IsString()
@IsOptional()
@IsString()
@IsEmail()
@ApiProperty({
description: 'The email to send the estimate to',
example: 'test@test.com',
})
sendToEmail?: string;
@IsArray()
@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => AttachmentDto)
@ApiProperty({
@@ -146,22 +140,26 @@ export class CommandSaleEstimateDto {
},
],
})
@IsNumber()
@IsOptional()
@ToNumber()
@IsNumber()
@ApiProperty({
description: 'The id of the pdf template',
example: 1,
})
pdfTemplateId?: number;
@IsNumber()
@IsOptional()
@ToNumber()
@IsNumber()
@ApiProperty({
description: 'The discount of the estimate',
example: 1,
})
discount?: number;
@IsOptional()
@IsEnum(DiscountType)
@ApiProperty({
description: 'The type of the discount',
@@ -169,8 +167,9 @@ export class CommandSaleEstimateDto {
})
discountType: DiscountType = DiscountType.Amount;
@IsNumber()
@ToNumber()
@IsOptional()
@IsNumber()
@ApiProperty({
description: 'The adjustment of the estimate',
example: 1,

View File

@@ -21,6 +21,7 @@ import {
ApiHeader,
ApiOperation,
ApiParam,
ApiQuery,
ApiResponse,
ApiTags,
} from '@nestjs/swagger';
@@ -111,7 +112,7 @@ export class SaleInvoicesController {
return this.saleInvoiceApplication.deleteSaleInvoice(id);
}
@Get('receivable/:customerId?')
@Get('receivable')
@ApiOperation({ summary: 'Retrieves the receivable sale invoices.' })
@ApiResponse({
status: 200,
@@ -119,13 +120,13 @@ export class SaleInvoicesController {
'The receivable sale invoices have been successfully retrieved.',
})
@ApiResponse({ status: 404, description: 'The customer not found.' })
@ApiParam({
@ApiQuery({
name: 'customerId',
required: false,
type: Number,
description: 'The customer id',
})
getReceivableSaleInvoices(@Param('customerId') customerId?: number) {
getReceivableSaleInvoices(@Query('customerId') customerId?: number) {
return this.saleInvoiceApplication.getReceivableSaleInvoices(customerId);
}

View File

@@ -1,3 +1,4 @@
import { IsOptional, ToNumber } from '@/common/decorators/Validators';
import { ItemEntryDto } from '@/modules/TransactionItemEntry/dto/ItemEntry.dto';
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
@@ -5,12 +6,11 @@ import {
ArrayMinSize,
IsArray,
IsBoolean,
IsDate,
IsDateString,
IsEnum,
IsInt,
IsNotEmpty,
IsNumber,
IsOptional,
IsString,
Min,
ValidateNested,
@@ -29,26 +29,24 @@ class PaymentMethodDto {
enable: boolean;
}
class AttachmentDto {
@IsString()
key: string;
}
class CommandSaleInvoiceDto {
@ToNumber()
@IsInt()
@IsNotEmpty()
@ApiProperty({ description: 'Customer ID', example: 1 })
customerId: number;
@IsDate()
@Type(() => Date)
@IsDateString()
@IsNotEmpty()
@ApiProperty({ description: 'Invoice date', example: '2023-01-01T00:00:00Z' })
invoiceDate: Date;
@IsDate()
@Type(() => Date)
@IsDateString()
@IsNotEmpty()
@ApiProperty({ description: 'Due date', example: '2023-01-15T00:00:00Z' })
dueDate: Date;
@@ -99,6 +97,7 @@ class CommandSaleInvoiceDto {
termsConditions?: string;
@IsOptional()
@ToNumber()
@IsNumber()
@Min(0)
@ApiProperty({
@@ -110,16 +109,19 @@ class CommandSaleInvoiceDto {
exchangeRate?: number;
@IsOptional()
@ToNumber()
@IsInt()
@ApiProperty({ description: 'Warehouse ID', required: false, example: 1 })
warehouseId?: number;
@IsOptional()
@ToNumber()
@IsInt()
@ApiProperty({ description: 'Branch ID', required: false, example: 1 })
branchId?: number;
@IsOptional()
@ToNumber()
@IsInt()
@ApiProperty({ description: 'Project ID', required: false, example: 1 })
projectId?: number;
@@ -145,6 +147,7 @@ class CommandSaleInvoiceDto {
entries: ItemEntryDto[];
@IsOptional()
@ToNumber()
@IsInt()
@ApiProperty({ description: 'PDF template ID', required: false, example: 1 })
pdfTemplateId?: number;
@@ -161,6 +164,7 @@ class CommandSaleInvoiceDto {
paymentMethods?: PaymentMethodDto[];
@IsOptional()
@ToNumber()
@IsNumber()
@ApiProperty({ description: 'Discount value', required: false, example: 10 })
discount?: number;
@@ -176,6 +180,7 @@ class CommandSaleInvoiceDto {
discountType?: DiscountType;
@IsOptional()
@ToNumber()
@IsNumber()
@ApiProperty({
description: 'Adjustment amount',
@@ -185,6 +190,7 @@ class CommandSaleInvoiceDto {
adjustment?: number;
@IsOptional()
@ToNumber()
@IsInt()
@ApiProperty({
description: 'ID of the estimate this invoice is created from',

View File

@@ -1,10 +1,13 @@
import { ToNumber } from '@/common/decorators/Validators';
import { ItemEntryDto } from '@/modules/TransactionItemEntry/dto/ItemEntry.dto';
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import {
ArrayMinSize,
IsArray,
IsBoolean,
IsDate,
IsDateString,
IsEnum,
IsNotEmpty,
IsNumber,
@@ -28,8 +31,9 @@ class AttachmentDto {
}
export class CommandSaleReceiptDto {
@IsNumber()
@IsNotEmpty()
@ToNumber()
@IsNumber()
@ApiProperty({
description: 'The id of the customer',
example: 1,
@@ -37,6 +41,7 @@ export class CommandSaleReceiptDto {
customerId: number;
@IsOptional()
@ToNumber()
@IsNumber()
@IsPositive()
@ApiProperty({
@@ -46,11 +51,12 @@ export class CommandSaleReceiptDto {
exchangeRate?: number;
@IsNumber()
@ToNumber()
@IsNotEmpty()
@ApiProperty({ description: 'The id of the deposit account', example: 1 })
depositAccountId: number;
@IsDate()
@IsDateString()
@IsNotEmpty()
@ApiProperty({
description: 'The date of the sale receipt',
@@ -83,6 +89,7 @@ export class CommandSaleReceiptDto {
@IsOptional()
@IsNumber()
@ToNumber()
@ApiProperty({
description: 'The id of the warehouse',
example: 1,
@@ -90,6 +97,7 @@ export class CommandSaleReceiptDto {
warehouseId?: number;
@IsOptional()
@ToNumber()
@IsNumber()
@ApiProperty({
description: 'The id of the branch',
@@ -100,7 +108,7 @@ export class CommandSaleReceiptDto {
@IsArray()
@ValidateNested({ each: true })
@Type(() => SaleReceiptEntryDto)
@Min(1)
@ArrayMinSize(1)
@ApiProperty({
description: 'The entries of the sale receipt',
example: [{ key: '123456' }],
@@ -134,6 +142,7 @@ export class CommandSaleReceiptDto {
attachments?: AttachmentDto[];
@IsOptional()
@ToNumber()
@IsNumber()
@ApiProperty({
description: 'The id of the pdf template',
@@ -142,6 +151,7 @@ export class CommandSaleReceiptDto {
pdfTemplateId?: number;
@IsOptional()
@ToNumber()
@IsNumber()
@ApiProperty({
description: 'The discount of the sale receipt',
@@ -158,6 +168,7 @@ export class CommandSaleReceiptDto {
discountType?: DiscountType;
@IsOptional()
@ToNumber()
@IsNumber()
@ApiProperty({
description: 'The adjustment of the sale receipt',

View File

@@ -1,3 +1,4 @@
import { ToNumber } from '@/common/decorators/Validators';
import { DiscountType } from '@/common/types/Discount';
import { ApiProperty } from '@nestjs/swagger';
import {
@@ -12,30 +13,35 @@ import {
export class ItemEntryDto {
@IsInt()
@IsOptional()
@ApiProperty({
description: 'The index of the item entry',
example: 1,
})
index: number;
@IsInt()
@IsNotEmpty()
@IsInt()
@ApiProperty({
description: 'The id of the item',
example: 1,
})
itemId: number;
@IsNumber()
@IsOptional()
@IsNotEmpty()
@ToNumber()
@IsNumber()
@ApiProperty({
description: 'The rate of the item entry',
example: 1,
})
rate: number;
@IsNumber()
@IsOptional()
@IsNotEmpty()
@ToNumber()
@IsNumber()
@ApiProperty({
description: 'The quantity of the item entry',
example: 1,
@@ -43,7 +49,9 @@ export class ItemEntryDto {
quantity: number;
@IsOptional()
@IsNotEmpty()
@IsNumber()
@ToNumber()
@ApiProperty({
description: 'The discount of the item entry',
example: 1,
@@ -67,6 +75,7 @@ export class ItemEntryDto {
description?: string;
@IsOptional()
@IsNotEmpty()
@IsString()
@ApiProperty({
description: 'The tax code of the item entry',
@@ -75,6 +84,7 @@ export class ItemEntryDto {
taxCode?: string;
@IsOptional()
@IsNotEmpty()
@IsInt()
@ApiProperty({
description: 'The tax rate id of the item entry',
@@ -83,6 +93,7 @@ export class ItemEntryDto {
taxRateId?: number;
@IsOptional()
@IsNotEmpty()
@IsInt()
@ApiProperty({
description: 'The warehouse id of the item entry',
@@ -91,6 +102,7 @@ export class ItemEntryDto {
warehouseId?: number;
@IsOptional()
@IsNotEmpty()
@IsInt()
@ApiProperty({
description: 'The project id of the item entry',
@@ -99,6 +111,7 @@ export class ItemEntryDto {
projectId?: number;
@IsOptional()
@IsNotEmpty()
@IsInt()
@ApiProperty({
description: 'The project ref id of the item entry',
@@ -107,6 +120,7 @@ export class ItemEntryDto {
projectRefId?: number;
@IsOptional()
@IsNotEmpty()
@IsString()
@IsIn(['TASK', 'BILL', 'EXPENSE'])
@ApiProperty({
@@ -116,6 +130,7 @@ export class ItemEntryDto {
projectRefType?: string;
@IsOptional()
@IsNotEmpty()
@IsNumber()
@ApiProperty({
description: 'The project ref invoiced amount of the item entry',
@@ -124,6 +139,7 @@ export class ItemEntryDto {
projectRefInvoicedAmount?: number;
@IsOptional()
@IsNotEmpty()
@IsInt()
@ApiProperty({
description: 'The sell account id of the item entry',
@@ -132,6 +148,7 @@ export class ItemEntryDto {
sellAccountId?: number;
@IsOptional()
@IsNotEmpty()
@IsInt()
@ApiProperty({
description: 'The cost account id of the item entry',