feat: add swagger docs for responses

This commit is contained in:
Ahmed Bouhuolia
2025-06-16 13:50:30 +02:00
parent 88ef60ef28
commit c4668d7d22
30 changed files with 1363 additions and 64 deletions

View File

@@ -12,7 +12,14 @@ import { AccountsApplication } from './AccountsApplication.service';
import { CreateAccountDTO } from './CreateAccount.dto';
import { EditAccountDTO } from './EditAccount.dto';
import { IAccountsFilter, IAccountsTransactionsFilter } from './Accounts.types';
import { ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
import {
ApiOperation,
ApiParam,
ApiResponse,
ApiTags,
getSchemaPath,
} from '@nestjs/swagger';
import { AccountResponseDto } from './dtos/AccountResponse.dto';
@Controller('accounts')
@ApiTags('Accounts')
@@ -133,6 +140,11 @@ export class AccountsController {
type: Number,
description: 'The account id',
})
@ApiResponse({
status: 200,
description: 'The account details have been successfully retrieved.',
schema: { $ref: getSchemaPath(AccountResponseDto) },
})
async getAccount(@Param('id', ParseIntPipe) id: number) {
return this.accountsApplication.getAccount(id);
}
@@ -142,7 +154,12 @@ export class AccountsController {
@ApiResponse({
status: 200,
description: 'The accounts have been successfully retrieved.',
schema: {
type: 'array',
items: { $ref: getSchemaPath(AccountResponseDto) },
},
})
@ApiResponse({})
async getAccounts(@Query() filter: Partial<IAccountsFilter>) {
return this.accountsApplication.getAccounts(filter);
}

View File

@@ -6,6 +6,7 @@ import { TransformerInjectable } from '../Transformer/TransformerInjectable.serv
import { EventEmitter2 } from '@nestjs/event-emitter';
import { events } from '@/common/events/events';
import { TenantModelProxy } from '../System/models/TenantBaseModel';
import { AccountResponseDto } from './dtos/AccountResponse.dto';
@Injectable()
export class GetAccount {
@@ -19,9 +20,10 @@ export class GetAccount {
/**
* Retrieve the given account details.
* @param {number} accountId
* @param {number} accountId - The account id.
* @returns {Promise<IAccount>} - The account details.
*/
public getAccount = async (accountId: number) => {
public async getAccount(accountId: number): Promise<AccountResponseDto> {
// Find the given account or throw not found error.
const account = await this.accountModel()
.query()
@@ -43,5 +45,5 @@ export class GetAccount {
await this.eventEmitter.emitAsync(events.accounts.onViewed, eventPayload);
return transformed;
};
}
}

View File

@@ -0,0 +1,171 @@
import { ApiProperty } from '@nestjs/swagger';
export class AccountResponseDto {
@ApiProperty({
description: 'The unique identifier of the account',
example: 1,
})
id: number;
@ApiProperty({
description: 'The name of the account',
example: 'Cash Account',
})
name: string;
@ApiProperty({
description: 'The slug of the account',
example: 'cash-account',
})
slug: string;
@ApiProperty({
description: 'The code of the account',
example: '1001',
})
code: string;
@ApiProperty({
description: 'The index of the account',
example: 1,
})
index: number;
@ApiProperty({
description: 'The type of the account',
example: 'bank',
})
accountType: string;
@ApiProperty({
description: 'The formatted account type label',
example: 'Bank Account',
})
accountTypeLabel: string;
@ApiProperty({
description: 'The parent account ID',
example: null,
})
parentAccountId: number | null;
@ApiProperty({
description: 'Whether the account is predefined',
example: false,
})
predefined: boolean;
@ApiProperty({
description: 'The currency code of the account',
example: 'USD',
})
currencyCode: string;
@ApiProperty({
description: 'Whether the account is active',
example: true,
})
active: boolean;
@ApiProperty({
description: 'The bank balance of the account',
example: 5000.0,
})
bankBalance: number;
@ApiProperty({
description: 'The formatted bank balance',
example: '$5,000.00',
})
bankBalanceFormatted: string;
@ApiProperty({
description: 'The last feeds update timestamp',
example: '2024-03-20T10:30:00Z',
})
lastFeedsUpdatedAt: string | Date | null;
@ApiProperty({
description: 'The formatted last feeds update timestamp',
example: 'Mar 20, 2024 10:30 AM',
})
lastFeedsUpdatedAtFormatted: string;
@ApiProperty({
description: 'The amount of the account',
example: 5000.0,
})
amount: number;
@ApiProperty({
description: 'The formatted amount',
example: '$5,000.00',
})
formattedAmount: string;
@ApiProperty({
description: 'The Plaid item ID',
example: 'plaid-item-123',
})
plaidItemId: string;
@ApiProperty({
description: 'The Plaid account ID',
example: 'plaid-account-456',
})
plaidAccountId: string | null;
@ApiProperty({
description: 'Whether the feeds are active',
example: true,
})
isFeedsActive: boolean;
@ApiProperty({
description: 'Whether the account is syncing owner',
example: true,
})
isSyncingOwner: boolean;
@ApiProperty({
description: 'Whether the feeds are paused',
example: false,
})
isFeedsPaused: boolean;
@ApiProperty({
description: 'The account normal',
example: 'debit',
})
accountNormal: string;
@ApiProperty({
description: 'The formatted account normal',
example: 'Debit',
})
accountNormalFormatted: string;
@ApiProperty({
description: 'The flatten name with all dependant accounts names',
example: 'Assets: Cash Account',
})
flattenName: string;
@ApiProperty({
description: 'The account level in the hierarchy',
example: 2,
})
accountLevel?: number;
@ApiProperty({
description: 'The creation timestamp',
example: '2024-03-20T10:00:00Z',
})
createdAt: Date;
@ApiProperty({
description: 'The update timestamp',
example: '2024-03-20T10:30:00Z',
})
updatedAt: Date;
}

View File

@@ -1,4 +1,10 @@
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import {
ApiOperation,
ApiTags,
ApiResponse,
getSchemaPath,
ApiExtraModels,
} from '@nestjs/swagger';
import {
Body,
Controller,
@@ -9,20 +15,28 @@ import {
Put,
} from '@nestjs/common';
import { BankRulesApplication } from './BankRulesApplication';
import { BankRule } from './models/BankRule';
import { CreateBankRuleDto } from './dtos/BankRule.dto';
import { EditBankRuleDto } from './dtos/BankRule.dto';
import { BankRuleResponseDto } from './dtos/BankRuleResponse.dto';
@Controller('banking/rules')
@ApiTags('Bank Rules')
@ApiExtraModels(BankRuleResponseDto)
export class BankRulesController {
constructor(private readonly bankRulesApplication: BankRulesApplication) {}
@Post()
@ApiOperation({ summary: 'Create a new bank rule.' })
@ApiResponse({
status: 201,
description: 'The bank rule has been successfully created.',
schema: {
$ref: getSchemaPath(BankRuleResponseDto),
},
})
async createBankRule(
@Body() createRuleDTO: CreateBankRuleDto,
): Promise<BankRule> {
): Promise<BankRuleResponseDto> {
return this.bankRulesApplication.createBankRule(createRuleDTO);
}
@@ -37,19 +51,36 @@ export class BankRulesController {
@Delete(':id')
@ApiOperation({ summary: 'Delete the given bank rule.' })
@ApiResponse({
status: 200,
description: 'The bank rule has been successfully deleted.',
})
async deleteBankRule(@Param('id') ruleId: number): Promise<void> {
return this.bankRulesApplication.deleteBankRule(ruleId);
}
@Get(':id')
@ApiOperation({ summary: 'Retrieves the bank rule details.' })
async getBankRule(@Param('id') ruleId: number): Promise<any> {
@ApiResponse({
status: 200,
description: 'The bank rule details have been successfully retrieved.',
schema: { $ref: getSchemaPath(BankRuleResponseDto) },
})
async getBankRule(@Param('id') ruleId: number): Promise<BankRuleResponseDto> {
return this.bankRulesApplication.getBankRule(ruleId);
}
@Get()
@ApiOperation({ summary: 'Retrieves the bank rules.' })
async getBankRules(): Promise<any> {
@ApiResponse({
status: 200,
description: 'The bank rules have been successfully retrieved.',
schema: {
type: 'array',
items: { $ref: getSchemaPath(BankRuleResponseDto) },
},
})
async getBankRules(): Promise<BankRuleResponseDto[]> {
return this.bankRulesApplication.getBankRules();
}
}

View File

@@ -0,0 +1,140 @@
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { BankRuleAssignCategory, BankRuleConditionType } from '../types';
class BankRuleConditionResponseDto {
@ApiProperty({
description: 'The unique identifier of the bank rule condition',
example: 1,
})
id: number;
@ApiProperty({
description: 'The field to check in the condition',
example: 'description',
enum: ['description', 'amount'],
})
field: string;
@ApiProperty({
description: 'The comparison operator to use',
example: 'contains',
enum: [
'equals',
'equal',
'contains',
'not_contain',
'bigger',
'bigger_or_equal',
'smaller',
'smaller_or_equal',
],
})
comparator: string;
@ApiProperty({
description: 'The value to compare against',
example: 'Salary',
})
value: string;
}
export class BankRuleResponseDto {
@ApiProperty({
description: 'The unique identifier of the bank rule',
example: 1,
})
id: number;
@ApiProperty({
description: 'The name of the bank rule',
example: 'Monthly Salary',
})
name: string;
@ApiProperty({
description: 'The order in which the rule should be applied',
example: 1,
})
order: number;
@ApiProperty({
description: 'The account ID to apply the rule if',
example: 1,
})
applyIfAccountId: number;
@ApiProperty({
description: 'The transaction type to apply the rule if',
example: 'deposit',
enum: ['deposit', 'withdrawal'],
})
applyIfTransactionType: string;
@ApiProperty({
description: 'The conditions type to apply the rule if',
example: 'and',
enum: ['and', 'or'],
})
conditionsType: BankRuleConditionType;
@ApiProperty({
description: 'The conditions to apply the rule if',
type: [BankRuleConditionResponseDto],
example: [
{
id: 1,
field: 'description',
comparator: 'contains',
value: 'Salary',
},
],
})
@Type(() => BankRuleConditionResponseDto)
conditions: BankRuleConditionResponseDto[];
@ApiProperty({
description: 'The category to assign the rule if',
example: 'InterestIncome',
enum: [
'InterestIncome',
'OtherIncome',
'Deposit',
'Expense',
'OwnerDrawings',
],
})
assignCategory: BankRuleAssignCategory;
@ApiProperty({
description: 'The account ID to assign the rule if',
example: 1,
})
assignAccountId: number;
@ApiProperty({
description: 'The payee to assign the rule if',
example: 'Employer Inc.',
required: false,
})
assignPayee?: string;
@ApiProperty({
description: 'The memo to assign the rule if',
example: 'Monthly Salary',
required: false,
})
assignMemo?: string;
@ApiProperty({
description: 'The creation timestamp of the bank rule',
example: '2024-03-20T10:00:00Z',
})
createdAt: string;
@ApiProperty({
description: 'The last update timestamp of the bank rule',
example: '2024-03-20T10:00:00Z',
})
updatedAt: string;
}

View File

@@ -2,8 +2,9 @@ import { BaseModel } from '@/models/Model';
import { Model } from 'objection';
import { BankRuleCondition } from './BankRuleCondition';
import { BankRuleAssignCategory, BankRuleConditionType } from '../types';
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
export class BankRule extends BaseModel {
export class BankRule extends TenantBaseModel {
public readonly id!: number;
public readonly name!: string;
public readonly order!: number;
@@ -17,6 +18,9 @@ export class BankRule extends BaseModel {
public readonly conditions!: BankRuleCondition[];
public readonly createdAt: string;
public readonly updatedAt: string;
/**
* Table name
*/
@@ -28,7 +32,7 @@ export class BankRule extends BaseModel {
* Timestamps columns.
*/
static get timestamps() {
return ['created_at', 'updated_at'];
return ['createdAt', 'updatedAt'];
}
/**

View File

@@ -47,7 +47,7 @@ class AttachmentDto {
export class CommandBillDto {
@ApiProperty({
description: 'Unique bill number',
example: 'BILL-0001',
example: 'BILL-2024-001',
required: false,
})
@IsOptional()
@@ -56,7 +56,7 @@ export class CommandBillDto {
@ApiProperty({
description: 'Reference number',
example: 'REF-12345',
example: 'PO-2024-001',
required: false,
})
@IsOptional()
@@ -65,7 +65,7 @@ export class CommandBillDto {
@ApiProperty({
description: 'Date the bill was issued',
example: '2025-06-01',
example: '2024-03-15',
})
@IsNotEmpty()
@IsDateString()
@@ -73,7 +73,7 @@ export class CommandBillDto {
@ApiProperty({
description: 'Date the bill is due',
example: '2025-07-01',
example: '2024-04-15',
required: false,
})
@IsOptional()
@@ -82,7 +82,7 @@ export class CommandBillDto {
@ApiProperty({
description: 'Vendor identifier',
example: 10,
example: 1001,
})
@IsInt()
@IsNotEmpty()
@@ -90,7 +90,7 @@ export class CommandBillDto {
@ApiProperty({
description: 'Exchange rate applied to bill amounts',
example: 3.67,
example: 1.25,
required: false,
})
@IsOptional()
@@ -101,7 +101,7 @@ export class CommandBillDto {
@ApiProperty({
description: 'Warehouse identifier',
example: 4,
example: 101,
required: false,
})
@IsOptional()
@@ -111,7 +111,7 @@ export class CommandBillDto {
@ApiProperty({
description: 'Branch identifier',
example: 2,
example: 201,
required: false,
})
@IsOptional()
@@ -121,7 +121,7 @@ export class CommandBillDto {
@ApiProperty({
description: 'Project identifier',
example: 5,
example: 301,
required: false,
})
@IsOptional()
@@ -131,7 +131,7 @@ export class CommandBillDto {
@ApiProperty({
description: 'Additional notes about the bill',
example: 'Payment due next month',
example: 'Office supplies and equipment for Q2 2024',
required: false,
})
@IsOptional()

View File

@@ -9,10 +9,18 @@ import {
} from '@nestjs/common';
import { BranchesApplication } from './BranchesApplication.service';
import { CreateBranchDto, EditBranchDto } from './dtos/Branch.dto';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import {
ApiExtraModels,
ApiOperation,
ApiResponse,
ApiTags,
getSchemaPath,
} from '@nestjs/swagger';
import { BranchResponseDto } from './dtos/BranchResponse.dto';
@Controller('branches')
@ApiTags('Branches')
@ApiExtraModels(BranchResponseDto)
export class BranchesController {
constructor(private readonly branchesApplication: BranchesApplication) {}
@@ -21,6 +29,12 @@ export class BranchesController {
@ApiResponse({
status: 200,
description: 'The branches have been successfully retrieved.',
schema: {
type: 'array',
items: {
$ref: getSchemaPath(BranchResponseDto),
},
},
})
getBranches() {
return this.branchesApplication.getBranches();
@@ -31,6 +45,9 @@ export class BranchesController {
@ApiResponse({
status: 200,
description: 'The branch details have been successfully retrieved.',
schema: {
$ref: getSchemaPath(BranchResponseDto),
},
})
@ApiResponse({ status: 404, description: 'The branch not found.' })
getBranch(@Param('id') id: string) {
@@ -42,6 +59,9 @@ export class BranchesController {
@ApiResponse({
status: 200,
description: 'The branch has been successfully created.',
schema: {
$ref: getSchemaPath(BranchResponseDto),
},
})
@ApiResponse({ status: 404, description: 'The branch not found.' })
createBranch(@Body() createBranchDTO: CreateBranchDto) {
@@ -53,6 +73,9 @@ export class BranchesController {
@ApiResponse({
status: 200,
description: 'The branch has been successfully edited.',
schema: {
$ref: getSchemaPath(BranchResponseDto),
},
})
@ApiResponse({ status: 404, description: 'The branch not found.' })
editBranch(@Param('id') id: string, @Body() editBranchDTO: EditBranchDto) {
@@ -90,6 +113,9 @@ export class BranchesController {
@ApiResponse({
status: 200,
description: 'The branch has been successfully marked as primary.',
schema: {
$ref: getSchemaPath(BranchResponseDto),
},
})
@ApiResponse({ status: 404, description: 'The branch not found.' })
markBranchAsPrimary(@Param('id') id: string) {

View File

@@ -0,0 +1,75 @@
import { ApiProperty } from '@nestjs/swagger';
export class BranchResponseDto {
@ApiProperty({
description: 'Branch ID',
example: 1,
})
id: number;
@ApiProperty({
description: 'Branch name',
example: 'Main Branch',
})
name: string;
@ApiProperty({
description: 'Branch code',
example: 'BR001',
})
code: string;
@ApiProperty({
description: 'Branch address',
example: '123 Main Street',
})
address: string;
@ApiProperty({
description: 'Branch city',
example: 'New York',
})
city: string;
@ApiProperty({
description: 'Branch country',
example: 'USA',
})
country: string;
@ApiProperty({
description: 'Branch phone number',
example: '+1-555-123-4567',
})
phoneNumber: string;
@ApiProperty({
description: 'Branch email',
example: 'branch@example.com',
})
email: string;
@ApiProperty({
description: 'Branch website',
example: 'https://www.example.com/branch',
})
website: string;
@ApiProperty({
description: 'Whether this is the primary branch',
example: true,
})
primary: boolean;
@ApiProperty({
description: 'Creation timestamp',
example: '2024-03-20T10:00:00Z',
})
createdAt: Date;
@ApiProperty({
description: 'Last update timestamp',
example: '2024-03-20T10:00:00Z',
})
updatedAt: Date;
}

View File

@@ -16,13 +16,17 @@ import {
ApiParam,
ApiOkResponse,
ApiNotFoundResponse,
ApiExtraModels,
getSchemaPath,
} from '@nestjs/swagger';
import { CurrenciesApplication } from './CurrenciesApplication.service';
import { CreateCurrencyDto } from './dtos/CreateCurrency.dto';
import { EditCurrencyDto } from './dtos/EditCurrency.dto';
import { CurrencyResponseDto } from './dtos/CurrencyResponse.dto';
@ApiTags('Currencies')
@Controller('/currencies')
@ApiExtraModels(CurrencyResponseDto)
export class CurrenciesController {
constructor(private readonly currenciesApp: CurrenciesApplication) {}
@@ -31,6 +35,9 @@ export class CurrenciesController {
@ApiBody({ type: CreateCurrencyDto })
@ApiCreatedResponse({
description: 'The currency has been successfully created.',
schema: {
$ref: getSchemaPath(CurrencyResponseDto),
},
})
@ApiBadRequestResponse({ description: 'Invalid input data.' })
create(@Body() dto: CreateCurrencyDto) {
@@ -41,7 +48,12 @@ export class CurrenciesController {
@ApiOperation({ summary: 'Edit an existing currency' })
@ApiParam({ name: 'id', type: Number, description: 'Currency ID' })
@ApiBody({ type: EditCurrencyDto })
@ApiOkResponse({ description: 'The currency has been successfully updated.' })
@ApiOkResponse({
description: 'The currency has been successfully updated.',
schema: {
$ref: getSchemaPath(CurrencyResponseDto),
},
})
@ApiNotFoundResponse({ description: 'Currency not found.' })
@ApiBadRequestResponse({ description: 'Invalid input data.' })
edit(@Param('id') id: number, @Body() dto: EditCurrencyDto) {
@@ -59,7 +71,15 @@ export class CurrenciesController {
@Get()
@ApiOperation({ summary: 'Get all currencies' })
@ApiOkResponse({ description: 'List of all currencies.' })
@ApiOkResponse({
description: 'List of all currencies.',
schema: {
type: 'array',
items: {
$ref: getSchemaPath(CurrencyResponseDto),
},
},
})
findAll() {
return this.currenciesApp.getCurrencies();
}
@@ -71,7 +91,12 @@ export class CurrenciesController {
type: String,
description: 'Currency code',
})
@ApiOkResponse({ description: 'The currency details.' })
@ApiOkResponse({
description: 'The currency details.',
schema: {
$ref: getSchemaPath(CurrencyResponseDto),
},
})
@ApiNotFoundResponse({ description: 'Currency not found.' })
findOne(@Param('currencyCode') currencyCode: string) {
return this.currenciesApp.getCurrency(currencyCode);

View File

@@ -0,0 +1,45 @@
import { ApiProperty } from '@nestjs/swagger';
export class CurrencyResponseDto {
@ApiProperty({
description: 'The unique identifier of the currency',
example: 1,
})
id: number;
@ApiProperty({
description: 'The name of the currency',
example: 'US Dollar',
})
currencyName: string;
@ApiProperty({
description: 'The code of the currency',
example: 'USD',
})
currencyCode: string;
@ApiProperty({
description: 'The sign/symbol of the currency',
example: '$',
})
currencySign: string;
@ApiProperty({
description: 'Whether this is the base currency for the organization',
example: true,
})
isBaseCurrency: boolean;
@ApiProperty({
description: 'The creation timestamp',
example: '2024-03-20T10:00:00Z',
})
createdAt: Date;
@ApiProperty({
description: 'The last update timestamp',
example: '2024-03-20T10:00:00Z',
})
updatedAt: Date;
}

View File

@@ -13,35 +13,66 @@ import {
ICustomerOpeningBalanceEditDTO,
ICustomersFilter,
} from './types/Customers.types';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import {
ApiOperation,
ApiResponse,
ApiTags,
ApiExtraModels,
getSchemaPath,
} from '@nestjs/swagger';
import { CreateCustomerDto } from './dtos/CreateCustomer.dto';
import { EditCustomerDto } from './dtos/EditCustomer.dto';
import { CustomerResponseDto } from './dtos/CustomerResponse.dto';
@Controller('customers')
@ApiTags('Customers')
@ApiExtraModels(CustomerResponseDto)
export class CustomersController {
constructor(private customersApplication: CustomersApplication) {}
@Get(':id')
@ApiOperation({ summary: 'Retrieves the customer details.' })
@ApiResponse({
status: 200,
description: 'The customer details have been successfully retrieved.',
schema: { $ref: getSchemaPath(CustomerResponseDto) },
})
getCustomer(@Param('id') customerId: number) {
return this.customersApplication.getCustomer(customerId);
}
@Get()
@ApiOperation({ summary: 'Retrieves the customers paginated list.' })
@ApiResponse({
status: 200,
description: 'The customers have been successfully retrieved.',
schema: {
type: 'array',
items: { $ref: getSchemaPath(CustomerResponseDto) },
},
})
getCustomers(@Query() filterDTO: Partial<ICustomersFilter>) {
return this.customersApplication.getCustomers(filterDTO);
}
@Post()
@ApiOperation({ summary: 'Create a new customer.' })
@ApiResponse({
status: 201,
description: 'The customer has been successfully created.',
schema: { $ref: getSchemaPath(CustomerResponseDto) },
})
createCustomer(@Body() customerDTO: CreateCustomerDto) {
return this.customersApplication.createCustomer(customerDTO);
}
@Put(':id')
@ApiOperation({ summary: 'Edit the given customer.' })
@ApiResponse({
status: 200,
description: 'The customer has been successfully updated.',
schema: { $ref: getSchemaPath(CustomerResponseDto) },
})
editCustomer(
@Param('id') customerId: number,
@Body() customerDTO: EditCustomerDto,
@@ -51,12 +82,21 @@ export class CustomersController {
@Delete(':id')
@ApiOperation({ summary: 'Delete the given customer.' })
@ApiResponse({
status: 200,
description: 'The customer has been successfully deleted.',
})
deleteCustomer(@Param('id') customerId: number) {
return this.customersApplication.deleteCustomer(customerId);
}
@Put(':id/opening-balance')
@ApiOperation({ summary: 'Edit the opening balance of the given customer.' })
@ApiResponse({
status: 200,
description: 'The customer opening balance has been successfully updated.',
schema: { $ref: getSchemaPath(CustomerResponseDto) },
})
editOpeningBalance(
@Param('id') customerId: number,
@Body() openingBalanceDTO: ICustomerOpeningBalanceEditDTO,

View File

@@ -36,7 +36,7 @@ import { DynamicListModule } from '../DynamicListing/DynamicList.module';
GetCustomerService,
CustomersExportable,
CustomersImportable,
GetCustomers
GetCustomers,
],
})
export class CustomersModule {}

View File

@@ -10,22 +10,38 @@ import { ApiProperty } from '@nestjs/swagger';
import { ContactAddressDto } from './ContactAddress.dto';
export class CreateCustomerDto extends ContactAddressDto {
@ApiProperty({ required: true, description: 'Customer type' })
@ApiProperty({
required: true,
description: 'Customer type',
example: 'business',
})
@IsString()
@IsNotEmpty()
customerType: string;
@ApiProperty({ required: true, description: 'Currency code' })
@ApiProperty({
required: true,
description: 'Currency code',
example: 'USD',
})
@IsString()
@IsNotEmpty()
currencyCode: string;
@ApiProperty({ required: false, description: 'Opening balance' })
@ApiProperty({
required: false,
description: 'Opening balance',
example: 5000.0,
})
@IsOptional()
@IsNumber()
openingBalance?: number;
@ApiProperty({ required: false, description: 'Opening balance date' })
@ApiProperty({
required: false,
description: 'Opening balance date',
example: '2024-01-01',
})
@IsOptional()
@IsString()
openingBalanceAt?: string;
@@ -33,52 +49,89 @@ export class CreateCustomerDto extends ContactAddressDto {
@ApiProperty({
required: false,
description: 'Opening balance exchange rate',
example: 1.0,
})
@IsOptional()
@IsNumber()
openingBalanceExchangeRate?: number;
@ApiProperty({ required: false, description: 'Opening balance branch ID' })
@ApiProperty({
required: false,
description: 'Opening balance branch ID',
example: 101,
})
@IsOptional()
@IsNumber()
openingBalanceBranchId?: number;
@ApiProperty({ required: false, description: 'Salutation' })
@ApiProperty({
required: false,
description: 'Salutation',
example: 'Mr.',
})
@IsOptional()
@IsString()
salutation?: string;
@ApiProperty({ required: false, description: 'First name' })
@ApiProperty({
required: false,
description: 'First name',
example: 'John',
})
@IsOptional()
@IsString()
firstName?: string;
@ApiProperty({ required: false, description: 'Last name' })
@ApiProperty({
required: false,
description: 'Last name',
example: 'Smith',
})
@IsOptional()
@IsString()
lastName?: string;
@ApiProperty({ required: false, description: 'Company name' })
@ApiProperty({
required: false,
description: 'Company name',
example: 'Acme Corporation',
})
@IsOptional()
@IsString()
companyName?: string;
@ApiProperty({ required: true, description: 'Display name' })
@ApiProperty({
required: true,
description: 'Display name',
example: 'Acme Corporation',
})
@IsString()
@IsNotEmpty()
displayName: string;
@ApiProperty({ required: false, description: 'Website' })
@ApiProperty({
required: false,
description: 'Website',
example: 'https://www.acmecorp.com',
})
@IsOptional()
@IsString()
website?: string;
@ApiProperty({ required: false, description: 'Email' })
@ApiProperty({
required: false,
description: 'Email',
example: 'contact@acmecorp.com',
})
@IsOptional()
@IsEmail()
email?: string;
@ApiProperty({ required: false, description: 'Work phone' })
@ApiProperty({
required: false,
description: 'Work phone',
example: '+1 (555) 123-4567',
})
@IsOptional()
@IsString()
workPhone?: string;

View File

@@ -0,0 +1,118 @@
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
export class CustomerResponseDto {
@ApiProperty({ example: 1500.0 })
balance: number;
@ApiProperty({ example: 'USD' })
currencyCode: string;
@ApiProperty({ example: 1000.0 })
openingBalance: number;
@ApiProperty({ example: '2024-01-01T00:00:00Z' })
@Type(() => Date)
openingBalanceAt: Date;
@ApiProperty({ example: 1.0 })
openingBalanceExchangeRate: number;
@ApiProperty({ required: false, example: 1 })
openingBalanceBranchId?: number;
@ApiProperty({ required: false, example: 'Mr.' })
salutation?: string;
@ApiProperty({ required: false, example: 'John' })
firstName?: string;
@ApiProperty({ required: false, example: 'Doe' })
lastName?: string;
@ApiProperty({ required: false, example: 'Acme Corporation' })
companyName?: string;
@ApiProperty({ example: 'John Doe - Acme Corporation' })
displayName: string;
@ApiProperty({ required: false, example: 'john.doe@acme.com' })
email?: string;
@ApiProperty({ required: false, example: '+1 (555) 123-4567' })
workPhone?: string;
@ApiProperty({ required: false, example: '+1 (555) 987-6543' })
personalPhone?: string;
@ApiProperty({ required: false, example: 'https://www.acme.com' })
website?: string;
@ApiProperty({ required: false, example: '123 Business Ave' })
billingAddress1?: string;
@ApiProperty({ required: false, example: 'Suite 100' })
billingAddress2?: string;
@ApiProperty({ required: false, example: 'New York' })
billingAddressCity?: string;
@ApiProperty({ required: false, example: 'United States' })
billingAddressCountry?: string;
@ApiProperty({ required: false, example: 'billing@acme.com' })
billingAddressEmail?: string;
@ApiProperty({ required: false, example: '10001' })
billingAddressPostcode?: string;
@ApiProperty({ required: false, example: '+1 (555) 111-2222' })
billingAddressPhone?: string;
@ApiProperty({ required: false, example: 'NY' })
billingAddressState?: string;
@ApiProperty({ required: false, example: '456 Shipping St' })
shippingAddress1?: string;
@ApiProperty({ required: false, example: 'Unit 200' })
shippingAddress2?: string;
@ApiProperty({ required: false, example: 'Los Angeles' })
shippingAddressCity?: string;
@ApiProperty({ required: false, example: 'United States' })
shippingAddressCountry?: string;
@ApiProperty({ required: false, example: 'shipping@acme.com' })
shippingAddressEmail?: string;
@ApiProperty({ required: false, example: '90001' })
shippingAddressPostcode?: string;
@ApiProperty({ required: false, example: '+1 (555) 333-4444' })
shippingAddressPhone?: string;
@ApiProperty({ required: false, example: 'CA' })
shippingAddressState?: string;
@ApiProperty({ example: 'Important client with regular monthly orders' })
note: string;
@ApiProperty({ example: true })
active: boolean;
@ApiProperty({ example: '2024-01-01T00:00:00Z' })
@Type(() => Date)
createdAt: Date;
@ApiProperty({ example: '2024-01-01T00:00:00Z' })
@Type(() => Date)
updatedAt: Date;
@ApiProperty({ example: 1000.0 })
localOpeningBalance: number;
@ApiProperty({ example: 1500.0 })
closingBalance: number;
}

View File

@@ -13,14 +13,22 @@ import {
GetItemCategoriesResponse,
IItemCategoriesFilter,
} from './ItemCategory.interfaces';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import {
ApiExtraModels,
ApiOperation,
ApiResponse,
ApiTags,
getSchemaPath,
} from '@nestjs/swagger';
import {
CreateItemCategoryDto,
EditItemCategoryDto,
} from './dtos/ItemCategory.dto';
import { ItemCategoryResponseDto } from './dtos/ItemCategoryResponse.dto';
@Controller('item-categories')
@ApiTags('Item Categories')
@ApiExtraModels(ItemCategoryResponseDto)
export class ItemCategoryController {
constructor(
private readonly itemCategoryApplication: ItemCategoryApplication,
@@ -34,6 +42,14 @@ export class ItemCategoryController {
@Get()
@ApiOperation({ summary: 'Retrieves the item categories.' })
@ApiResponse({
status: 200,
description: 'The item categories have been successfully retrieved.',
schema: {
type: 'array',
items: { $ref: getSchemaPath(ItemCategoryResponseDto) },
},
})
async getItemCategories(
@Query() filterDTO: Partial<IItemCategoriesFilter>,
): Promise<GetItemCategoriesResponse> {
@@ -51,6 +67,11 @@ export class ItemCategoryController {
@Get(':id')
@ApiOperation({ summary: 'Retrieves the item category details.' })
@ApiResponse({
status: 200,
description: 'The item category details have been successfully retrieved.',
schema: { $ref: getSchemaPath(ItemCategoryResponseDto) },
})
async getItemCategory(@Param('id') id: number) {
return this.itemCategoryApplication.getItemCategory(id);
}

View File

@@ -0,0 +1,74 @@
import { ApiProperty } from '@nestjs/swagger';
export class ItemCategoryResponseDto {
@ApiProperty({
example: 1,
description: 'The unique identifier of the item category',
})
id: number;
@ApiProperty({
example: 'Electronics',
description: 'The name of the item category',
})
name: string;
@ApiProperty({
example: 'Electronic devices and accessories',
description: 'The description of the item category',
required: false,
})
description?: string;
@ApiProperty({
example: 1,
description: 'The cost account ID',
required: false,
})
costAccountId?: number;
@ApiProperty({
example: 1,
description: 'The sell account ID',
required: false,
})
sellAccountId?: number;
@ApiProperty({
example: 1,
description: 'The inventory account ID',
required: false,
})
inventoryAccountId?: number;
@ApiProperty({
example: 'FIFO',
description: 'The cost method',
required: false,
})
costMethod?: string;
@ApiProperty({
example: 1,
description: 'The user ID who created the category',
})
userId: number;
@ApiProperty({
example: '2024-03-20T10:00:00Z',
description: 'The creation date of the category',
})
createdAt: Date;
@ApiProperty({
example: '2024-03-20T10:00:00Z',
description: 'The last update date of the category',
})
updatedAt: Date;
@ApiProperty({
example: 5,
description: 'The number of items in this category',
})
count?: number;
}

View File

@@ -25,8 +25,8 @@ import { CreateItemDto, EditItemDto } from './dtos/Item.dto';
import { GetItemsQueryDto } from './dtos/GetItemsQuery.dto';
@Controller('/items')
@UseGuards(SubscriptionGuard)
@ApiTags('Items')
@UseGuards(SubscriptionGuard)
export class ItemsController extends TenantController {
constructor(private readonly itemsApplication: ItemsApplicationService) {
super();

View File

@@ -17,7 +17,10 @@ export class CommandItemDto {
@IsString()
@IsNotEmpty()
@MaxLength(255)
@ApiProperty({ description: 'Item name', example: 'Office Chair' })
@ApiProperty({
description: 'Item name',
example: 'Ergonomic Office Chair Model X-2000',
})
name: string;
@IsString()
@@ -36,7 +39,7 @@ export class CommandItemDto {
@ApiProperty({
description: 'Item code/SKU',
required: false,
example: 'ITEM-001',
example: 'CHAIR-X2000',
})
code?: string;
@@ -59,7 +62,7 @@ export class CommandItemDto {
description: 'Cost price of the item',
required: false,
minimum: 0,
example: 100.5,
example: 299.99,
})
costPrice?: number;
@@ -72,7 +75,7 @@ export class CommandItemDto {
description: 'ID of the cost account',
required: false,
minimum: 0,
example: 1,
example: 1001,
})
costAccountId?: number;
@@ -95,7 +98,7 @@ export class CommandItemDto {
description: 'Selling price of the item',
required: false,
minimum: 0,
example: 150.75,
example: 399.99,
})
sellPrice?: number;
@@ -108,7 +111,7 @@ export class CommandItemDto {
description: 'ID of the sell account',
required: false,
minimum: 0,
example: 2,
example: 2001,
})
sellAccountId?: number;
@@ -121,7 +124,7 @@ export class CommandItemDto {
description: 'ID of the inventory account (required for inventory items)',
required: false,
minimum: 0,
example: 3,
example: 3001,
})
inventoryAccountId?: number;
@@ -130,7 +133,8 @@ export class CommandItemDto {
@ApiProperty({
description: 'Description shown on sales documents',
required: false,
example: 'High-quality ergonomic office chair',
example:
'Premium ergonomic office chair with adjustable height, lumbar support, and breathable mesh back',
})
sellDescription?: string;
@@ -139,7 +143,7 @@ export class CommandItemDto {
@ApiProperty({
description: 'Description shown on purchase documents',
required: false,
example: 'Ergonomic office chair with adjustable height',
example: 'Ergonomic office chair - Model X-2000 with standard features',
})
purchaseDescription?: string;
@@ -180,7 +184,8 @@ export class CommandItemDto {
@ApiProperty({
description: 'Additional notes about the item',
required: false,
example: 'Available in multiple colors',
example:
'Available in black, gray, and navy colors. 5-year warranty included.',
})
note?: string;

View File

@@ -8,7 +8,10 @@ import {
CommonMailOptionsDTO,
} from '../MailNotification/MailNotification.types';
import { TenantJobPayload } from '@/interfaces/Tenant';
import { CreateSaleInvoiceDto, EditSaleInvoiceDto } from './dtos/SaleInvoice.dto';
import {
CreateSaleInvoiceDto,
EditSaleInvoiceDto,
} from './dtos/SaleInvoice.dto';
export interface PaymentIntegrationTransactionLink {
id: number;
@@ -301,10 +304,6 @@ export interface InvoicePdfTemplateAttributes {
statement: string;
}
export interface ISaleInvocieState {
defaultTemplateId: number;
}
export interface SaleInvoiceSendMailData {
saleInvoiceId: number;
messageOptions: SendInvoiceMailDTO;

View File

@@ -27,15 +27,19 @@ import {
ApiQuery,
ApiResponse,
ApiTags,
ApiExtraModels,
getSchemaPath,
} from '@nestjs/swagger';
import {
CreateSaleInvoiceDto,
EditSaleInvoiceDto,
} from './dtos/SaleInvoice.dto';
import { AcceptType } from '@/constants/accept-type';
import { SaleInvoiceResponseDto } from './dtos/SaleInvoiceResponse.dto';
@Controller('sale-invoices')
@ApiTags('Sale Invoices')
@ApiExtraModels(SaleInvoiceResponseDto)
@ApiHeader({
name: 'organization-id',
description: 'The organization id',
@@ -150,6 +154,9 @@ export class SaleInvoicesController {
@ApiResponse({
status: 200,
description: 'The sale invoice details have been successfully retrieved.',
schema: {
$ref: getSchemaPath(SaleInvoiceResponseDto),
},
})
@ApiResponse({ status: 404, description: 'The sale invoice not found.' })
@ApiParam({

View File

@@ -21,10 +21,18 @@ enum DiscountType {
Amount = 'amount',
}
class PaymentMethodDto {
export class PaymentMethodDto {
@ApiProperty({
description: 'The ID of the payment integration',
example: 1,
})
@IsInt()
paymentIntegrationId: number;
@ApiProperty({
description: 'Whether the payment method is enabled',
example: true,
})
@IsBoolean()
enable: boolean;
}

View File

@@ -0,0 +1,237 @@
import { ApiProperty } from '@nestjs/swagger';
import { ItemEntryDto } from '@/modules/TransactionItemEntry/dto/ItemEntry.dto';
import { AttachmentLinkDto } from '@/modules/Attachments/dtos/Attachment.dto';
import { PaymentMethodDto } from '../dtos/SaleInvoice.dto';
import { DiscountType } from '@/common/types/Discount';
export class SaleInvoiceResponseDto {
@ApiProperty({
description: 'The unique identifier of the sale invoice',
example: 1,
})
id: number;
@ApiProperty({
description: 'The date of the invoice',
example: '2023-01-01T00:00:00Z',
})
invoiceDate: Date;
@ApiProperty({
description: 'The due date of the invoice',
example: '2023-01-15T00:00:00Z',
})
dueDate: Date;
@ApiProperty({
description: 'The invoice number',
example: 'INV-001',
})
invoiceNo: string;
@ApiProperty({
description: 'The reference number',
example: 'REF-001',
required: false,
})
referenceNo?: string;
@ApiProperty({
description: 'The ID of the customer',
example: 1,
})
customerId: number;
@ApiProperty({
description: 'The exchange rate for currency conversion',
example: 1.0,
required: false,
})
exchangeRate?: number;
@ApiProperty({
description: 'The currency code',
example: 'USD',
required: false,
})
currencyCode?: string;
@ApiProperty({
description: 'Custom message on the invoice',
example: 'Thank you for your business',
required: false,
})
invoiceMessage?: string;
@ApiProperty({
description: 'Terms and conditions of the invoice',
example: 'Payment due within 14 days',
required: false,
})
termsConditions?: string;
@ApiProperty({
description: 'Whether tax is inclusive in the item rates',
example: false,
required: false,
})
isInclusiveTax?: boolean;
@ApiProperty({
description: 'The line items of the invoice',
type: [ItemEntryDto],
})
entries: ItemEntryDto[];
@ApiProperty({
description: 'Whether the invoice has been delivered',
example: false,
})
delivered: boolean;
@ApiProperty({
description: 'The date when the invoice was delivered',
example: '2023-01-02T00:00:00Z',
required: false,
})
deliveredAt?: Date;
@ApiProperty({
description: 'The ID of the warehouse',
example: 1,
required: false,
})
warehouseId?: number;
@ApiProperty({
description: 'The ID of the branch',
example: 1,
required: false,
})
branchId?: number;
@ApiProperty({
description: 'The ID of the project',
example: 1,
required: false,
})
projectId?: number;
@ApiProperty({
description: 'The attachments of the invoice',
type: [AttachmentLinkDto],
required: false,
})
attachments?: AttachmentLinkDto[];
@ApiProperty({
description: 'The payment methods associated with the invoice',
type: [PaymentMethodDto],
required: false,
})
paymentMethods?: PaymentMethodDto[];
@ApiProperty({
description: 'The discount value',
example: 10,
required: false,
})
discount?: number;
@ApiProperty({
description: 'The type of discount (percentage or fixed)',
enum: DiscountType,
example: DiscountType.Percentage,
required: false,
})
discountType?: DiscountType;
@ApiProperty({
description: 'The adjustment amount',
example: 5,
required: false,
})
adjustment?: number;
@ApiProperty({
description: 'The ID of the PDF template',
example: 1,
required: false,
})
pdfTemplateId?: number;
@ApiProperty({
description: 'The total amount of tax withheld',
example: 50,
required: false,
})
taxAmountWithheld?: number;
@ApiProperty({
description: 'The balance of the invoice',
example: 1000,
})
balance: number;
@ApiProperty({
description: 'The amount paid',
example: 500,
})
paymentAmount: number;
@ApiProperty({
description: 'The amount credited',
example: 0,
required: false,
})
creditedAmount?: number;
@ApiProperty({
description: 'The subtotal amount before tax and adjustments',
example: 900,
})
subtotal: number;
@ApiProperty({
description: 'The total amount including tax and adjustments',
example: 1000,
})
total: number;
@ApiProperty({
description: 'The due amount remaining to be paid',
example: 500,
})
dueAmount: number;
@ApiProperty({
description: 'Whether the invoice is overdue',
example: false,
})
isOverdue: boolean;
@ApiProperty({
description: 'Whether the invoice is partially paid',
example: true,
})
isPartiallyPaid: boolean;
@ApiProperty({
description: 'Whether the invoice is fully paid',
example: false,
})
isFullyPaid: boolean;
@ApiProperty({
description: 'The date when the invoice was created',
example: '2023-01-01T00:00:00Z',
})
createdAt: Date;
@ApiProperty({
description: 'The date when the invoice was last updated',
example: '2023-01-02T00:00:00Z',
required: false,
})
updatedAt?: Date;
}

View File

@@ -0,0 +1,11 @@
import { ApiProperty } from '@nestjs/swagger';
export class SaleInvoiceStateResponseDto {
@ApiProperty({
description: 'The ID of the default PDF template for sale invoices',
example: 1,
type: Number,
nullable: true,
})
defaultTemplateId: number;
}

View File

@@ -6,6 +6,7 @@ import { SaleInvoiceTransformer } from './SaleInvoice.transformer';
import { CommandSaleInvoiceValidators } from '../commands/CommandSaleInvoiceValidators.service';
import { events } from '@/common/events/events';
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
import { SaleInvoiceResponseDto } from '../dtos/SaleInvoiceResponse.dto';
@Injectable()
export class GetSaleInvoice {
@@ -24,7 +25,9 @@ export class GetSaleInvoice {
* @param {ISystemUser} authorizedUser -
* @return {Promise<ISaleInvoice>}
*/
public async getSaleInvoice(saleInvoiceId: number): Promise<SaleInvoice> {
public async getSaleInvoice(
saleInvoiceId: number,
): Promise<SaleInvoiceResponseDto> {
const saleInvoice = await this.saleInvoiceModel()
.query()
.findById(saleInvoiceId)

View File

@@ -1,7 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { PdfTemplateModel } from '@/modules/PdfTemplate/models/PdfTemplate';
import { ISaleInvocieState } from '../SaleInvoice.types';
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
import { SaleInvoiceStateResponseDto } from '../dtos/SaleInvoiceState.dto';
@Injectable()
export class GetSaleInvoiceState {
@@ -12,9 +12,9 @@ export class GetSaleInvoiceState {
/**
* Retrieves the create/edit invoice state.
* @return {Promise<ISaleInvoice>}
* @returns {Promise<SaleInvoiceStateResponseDto>}
*/
public async getSaleInvoiceState(): Promise<ISaleInvocieState> {
public async getSaleInvoiceState(): Promise<SaleInvoiceStateResponseDto> {
const defaultPdfTemplate = await this.pdfTemplateModel()
.query()
.findOne({ resource: 'SaleInvoice' })

View File

@@ -8,22 +8,42 @@ import {
Put,
} from '@nestjs/common';
import { TaxRatesApplication } from './TaxRate.application';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import {
ApiExtraModels,
ApiOperation,
ApiResponse,
ApiTags,
getSchemaPath,
} from '@nestjs/swagger';
import { CreateTaxRateDto, EditTaxRateDto } from './dtos/TaxRate.dto';
import { TaxRateResponseDto } from './dtos/TaxRateResponse.dto';
@Controller('tax-rates')
@ApiTags('Tax Rates')
@ApiExtraModels(TaxRateResponseDto)
export class TaxRatesController {
constructor(private readonly taxRatesApplication: TaxRatesApplication) {}
@Post()
@ApiOperation({ summary: 'Create a new tax rate.' })
@ApiResponse({
status: 201,
description: 'The tax rate has been successfully created.',
schema: { $ref: getSchemaPath(TaxRateResponseDto) },
})
public createTaxRate(@Body() createTaxRateDTO: CreateTaxRateDto) {
return this.taxRatesApplication.createTaxRate(createTaxRateDTO);
}
@Put(':id')
@ApiOperation({ summary: 'Edit the given tax rate.' })
@ApiResponse({
status: 200,
description: 'The tax rate has been successfully updated.',
schema: {
$ref: getSchemaPath(TaxRateResponseDto),
},
})
public editTaxRate(
@Param('id') taxRateId: number,
@Body() editTaxRateDTO: EditTaxRateDto,
@@ -33,30 +53,68 @@ export class TaxRatesController {
@Delete(':id')
@ApiOperation({ summary: 'Delete the given tax rate.' })
@ApiResponse({
status: 200,
description: 'The tax rate has been successfully deleted.',
schema: {
$ref: getSchemaPath(TaxRateResponseDto),
},
})
public deleteTaxRate(@Param('id') taxRateId: number) {
return this.taxRatesApplication.deleteTaxRate(taxRateId);
}
@Get(':id')
@ApiOperation({ summary: 'Retrieves the tax rate details.' })
@ApiResponse({
status: 200,
description: 'The tax rate details have been successfully retrieved.',
schema: {
$ref: getSchemaPath(TaxRateResponseDto),
},
})
public getTaxRate(@Param('id') taxRateId: number) {
return this.taxRatesApplication.getTaxRate(taxRateId);
}
@Get()
@ApiOperation({ summary: 'Retrieves the tax rates.' })
@ApiResponse({
status: 200,
description: 'The tax rates have been successfully retrieved.',
schema: {
type: 'array',
items: {
$ref: getSchemaPath(TaxRateResponseDto),
},
},
})
public getTaxRates() {
return this.taxRatesApplication.getTaxRates();
}
@Put(':id/activate')
@ApiOperation({ summary: 'Activate the given tax rate.' })
@ApiResponse({
status: 200,
description: 'The tax rate has been successfully activated.',
schema: {
$ref: getSchemaPath(TaxRateResponseDto),
},
})
public activateTaxRate(@Param('id') taxRateId: number) {
return this.taxRatesApplication.activateTaxRate(taxRateId);
}
@Put(':id/inactivate')
@ApiOperation({ summary: 'Inactivate the given tax rate.' })
@ApiResponse({
status: 200,
description: 'The tax rate has been successfully inactivated.',
schema: {
$ref: getSchemaPath(TaxRateResponseDto),
},
})
public inactivateTaxRate(@Param('id') taxRateId: number) {
return this.taxRatesApplication.inactivateTaxRate(taxRateId);
}

View File

@@ -0,0 +1,77 @@
import { ApiProperty } from '@nestjs/swagger';
export class TaxRateResponseDto {
@ApiProperty({
description: 'The unique identifier of the tax rate',
example: 1,
})
id: number;
@ApiProperty({
description: 'The name of the tax rate',
example: 'VAT',
})
name: string;
@ApiProperty({
description:
'The formatted name of the tax rate including the rate percentage',
example: 'VAT [10%]',
})
nameFormatted: string;
@ApiProperty({
description: 'The code of the tax rate',
example: 'VAT',
})
code: string;
@ApiProperty({
description: 'The rate of the tax rate as a decimal number',
example: 10,
})
rate: number;
@ApiProperty({
description: 'The formatted rate of the tax rate with percentage symbol',
example: '10%',
})
rateFormatted: string;
@ApiProperty({
description: 'The description of the tax rate',
example: 'Value Added Tax',
required: false,
})
description?: string;
@ApiProperty({
description: 'Whether the tax is non-recoverable',
example: false,
})
isNonRecoverable: boolean;
@ApiProperty({
description: 'Whether the tax is compound',
example: false,
})
isCompound: boolean;
@ApiProperty({
description: 'Whether the tax rate is active',
example: true,
})
active: boolean;
@ApiProperty({
description: 'The date when the tax rate was created',
example: '2024-03-20T10:00:00Z',
})
createdAt: Date;
@ApiProperty({
description: 'The date when the tax rate was last updated',
example: '2024-03-20T10:00:00Z',
})
updatedAt: Date;
}

View File

@@ -8,11 +8,19 @@ import {
Put,
} from '@nestjs/common';
import { WarehousesApplication } from './WarehousesApplication.service';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import {
ApiExtraModels,
ApiOperation,
ApiResponse,
ApiTags,
getSchemaPath,
} from '@nestjs/swagger';
import { CreateWarehouseDto, EditWarehouseDto } from './dtos/Warehouse.dto';
import { WarehouseResponseDto } from './dtos/WarehouseResponse.dto';
@Controller('warehouses')
@ApiTags('Warehouses')
@ApiExtraModels(WarehouseResponseDto)
export class WarehousesController {
constructor(private warehousesApplication: WarehousesApplication) {}
@@ -41,6 +49,11 @@ export class WarehousesController {
@Get(':id')
@ApiOperation({ summary: 'Get a warehouse' })
@ApiResponse({
status: 200,
description: 'The warehouse details have been successfully retrieved.',
schema: { $ref: getSchemaPath(WarehouseResponseDto) },
})
getWarehouse(@Param('id') warehouseId: string) {
return this.warehousesApplication.getWarehouse(Number(warehouseId));
}

View File

@@ -0,0 +1,39 @@
import { ApiProperty } from '@nestjs/swagger';
export class WarehouseResponseDto {
@ApiProperty({
description: 'The name of the warehouse',
example: 'Main Warehouse',
})
name!: string;
@ApiProperty({
description: 'The unique code identifier for the warehouse',
example: 'WH-001',
})
code!: string;
@ApiProperty({
description: 'The city where the warehouse is located',
example: 'New York',
})
city!: string;
@ApiProperty({
description: 'The country where the warehouse is located',
example: 'United States',
})
country!: string;
@ApiProperty({
description: 'The full address of the warehouse',
example: '123 Warehouse Street, New York, NY 10001',
})
address!: string;
@ApiProperty({
description: 'Indicates if this is the primary warehouse',
example: true,
})
primary!: boolean;
}