feat: endpoints swagger document

This commit is contained in:
Ahmed Bouhuolia
2025-06-22 23:46:39 +02:00
parent 9aa1ed93ca
commit 6a39e9d71f
8 changed files with 390 additions and 3 deletions

View File

@@ -8,27 +8,55 @@ import { INumberFormatQuery } from '../../types/Report.types';
import { Transform, Type } from 'class-transformer';
import { NumberFormatQueryDto } from '@/modules/BankingTransactions/dtos/NumberFormatQuery.dto';
import { parseBoolean } from '@/utils/parse-boolean';
import { ApiPropertyOptional } from '@nestjs/swagger';
export class ContactBalanceSummaryQueryDto {
@ApiPropertyOptional({
description: 'The date as of which the balance summary is calculated',
example: '2024-01-01',
type: String,
})
@IsDateString()
@IsOptional()
asDate: Date;
@ApiPropertyOptional({
description: 'Number formatting options for the summary',
type: NumberFormatQueryDto,
})
@ValidateNested()
@Type(() => NumberFormatQueryDto)
@IsOptional()
numberFormat: INumberFormatQuery;
@ApiPropertyOptional({
description: 'Whether to show the percentage column in the summary',
example: false,
type: Boolean,
default: false,
})
@IsBoolean()
@Transform(({ value }) => parseBoolean(value, false))
@IsOptional()
percentageColumn: boolean;
@ApiPropertyOptional({
description: 'Whether to exclude contacts with no transactions',
example: false,
type: Boolean,
default: false,
})
@IsBoolean()
@Transform(({ value }) => parseBoolean(value, false))
@IsOptional()
noneTransactions: boolean;
@ApiPropertyOptional({
description: 'Whether to exclude contacts with zero balance',
example: false,
type: Boolean,
default: false,
})
@IsBoolean()
@Transform(({ value }) => parseBoolean(value, false))
@IsOptional()

View File

@@ -1,7 +1,13 @@
import { IsArray, IsOptional } from 'class-validator';
import { ContactBalanceSummaryQueryDto } from '../ContactBalanceSummary/ContactBalanceSummaryQuery.dto';
import { ApiPropertyOptional } from '@nestjs/swagger';
export class CustomerBalanceSummaryQueryDto extends ContactBalanceSummaryQueryDto {
@ApiPropertyOptional({
description: 'Array of customer IDs to filter the summary',
type: [Number],
example: [1, 2, 3],
})
@IsArray()
@IsOptional()
customersIds: number[];

View File

@@ -9,6 +9,7 @@ import {
ApiTags,
} from '@nestjs/swagger';
import { ProfitLossSheetQueryDto } from './ProfitLossSheetQuery.dto';
import { ProfitLossSheetResponseExample } from './ProfitLossSheet.swagger';
@Controller('/reports/profit-loss-sheet')
@ApiTags('Reports')
@@ -24,7 +25,11 @@ export class ProfitLossSheetController {
* @param {string} acceptHeader
*/
@Get('/')
@ApiResponse({ status: 200, description: 'Profit & loss statement' })
@ApiResponse({
status: 200,
description: 'Profit & loss statement',
example: ProfitLossSheetResponseExample,
})
@ApiOperation({ summary: 'Get profit/loss statement report' })
@ApiProduces(
AcceptType.ApplicationJson,

View File

@@ -0,0 +1,240 @@
export const ProfitLossSheetResponseExample = {
query: {
from_date: '2025-01-01',
to_date: '2025-06-22',
number_format: {
divide_on1000: false,
negative_format: 'mines',
show_zero: false,
format_money: 'total',
precision: 2,
},
basis: 'accrual',
none_zero: false,
none_transactions: false,
display_columns_type: 'total',
display_columns_by: 'year',
accounts_ids: [],
percentage_column: false,
percentage_row: false,
percentage_income: false,
percentage_expense: false,
previous_period: false,
previous_period_amount_change: false,
previous_period_percentage_change: false,
previous_year: false,
previous_year_amount_change: false,
previous_year_percentage_change: false,
},
data: [
{
id: 'INCOME',
name: 'Income',
node_type: 'ACCOUNTS',
total: {
amount: 3931,
formatted_amount: '$3,931.00',
},
children: [
{
id: 1025,
name: 'Sales of Product Income',
node_type: 'ACCOUNT',
total: {
amount: 3931,
formatted_amount: '3,931.00',
},
},
{
id: 1026,
name: 'Sales of Service Income',
node_type: 'ACCOUNT',
total: {
amount: 0,
formatted_amount: '',
},
},
{
id: 1027,
name: 'Uncategorized Income',
node_type: 'ACCOUNT',
total: {
amount: 0,
formatted_amount: '',
},
},
],
},
{
id: 'COST_OF_SALES',
name: 'Cost of sales',
node_type: 'ACCOUNTS',
total: {
amount: 800,
formatted_amount: '$800.00',
},
children: [
{
id: 1019,
name: 'Cost of Goods Sold',
node_type: 'ACCOUNT',
total: {
amount: 800,
formatted_amount: '800.00',
},
},
],
},
{
id: 'GROSS_PROFIT',
name: 'GROSS PROFIT',
node_type: 'EQUATION',
total: {
amount: 3131,
formatted_amount: '$3,131.00',
},
},
{
id: 'EXPENSES',
name: 'Expenses',
node_type: 'ACCOUNTS',
total: {
amount: -111563,
formatted_amount: '-$111,563.00',
},
children: [
{
id: 1020,
name: 'Office expenses',
node_type: 'ACCOUNT',
total: {
amount: 0,
formatted_amount: '',
},
},
{
id: 1021,
name: 'Rent',
node_type: 'ACCOUNT',
total: {
amount: -92831,
formatted_amount: '-92,831.00',
},
},
{
id: 1023,
name: 'Bank Fees and Charges',
node_type: 'ACCOUNT',
total: {
amount: -8732,
formatted_amount: '-8,732.00',
},
},
{
id: 1024,
name: 'Depreciation Expense',
node_type: 'ACCOUNT',
total: {
amount: -10000,
formatted_amount: '-10,000.00',
},
},
],
},
{
id: 'NET_OPERATING_INCOME',
name: 'NET OPERATING INCOME',
node_type: 'EQUATION',
total: {
amount: 114694,
formatted_amount: '$114,694.00',
},
},
{
id: 'OTHER_INCOME',
name: 'Other income',
node_type: 'ACCOUNTS',
total: {
amount: 0,
formatted_amount: '$0.00',
},
children: [
{
id: 1031,
name: 'Discount',
node_type: 'ACCOUNT',
total: {
amount: 0,
formatted_amount: '',
},
},
{
id: 1033,
name: 'Other Charges',
node_type: 'ACCOUNT',
total: {
amount: 0,
formatted_amount: '',
},
},
],
},
{
id: 'OTHER_EXPENSES',
name: 'Other expenses',
node_type: 'ACCOUNTS',
total: {
amount: 119149,
formatted_amount: '$119,149.00',
},
children: [
{
id: 1018,
name: 'Other Expenses',
node_type: 'ACCOUNT',
total: {
amount: -1243,
formatted_amount: '-1,243.00',
},
},
{
id: 1022,
name: 'Exchange Gain or Loss',
node_type: 'ACCOUNT',
total: {
amount: 123123,
formatted_amount: '123,123.00',
},
},
{
id: 1032,
name: 'Purchase Discount',
node_type: 'ACCOUNT',
total: {
amount: -2731,
formatted_amount: '-2,731.00',
},
},
],
},
{
id: 'NET_INCOME',
name: 'NET INCOME',
node_type: 'EQUATION',
total: {
amount: -4455,
formatted_amount: '-$4,455.00',
},
},
],
meta: {
organization_name: 'BIGCAPITAL, INC',
base_currency: 'USD',
date_format: 'DD MMM yyyy',
is_cost_compute_running: false,
sheet_name: 'Cashflow Statement',
formatted_from_date: '2025/01/01',
formatted_to_date: '2025/06/22',
formatted_date_range: 'From 2025/01/01 | To 2025/06/22',
},
};

View File

@@ -9,29 +9,61 @@ import { INumberFormatQuery } from '../../types/Report.types';
import { NumberFormatQueryDto } from '@/modules/BankingTransactions/dtos/NumberFormatQuery.dto';
import { Transform, Type } from 'class-transformer';
import { parseBoolean } from '@/utils/parse-boolean';
import { ApiPropertyOptional } from '@nestjs/swagger';
export class PurchasesByItemsQueryDto {
@ApiPropertyOptional({
description: 'Start date for the purchases by items report',
example: '2024-01-01',
type: String,
})
@IsDateString()
@IsOptional()
fromDate: Date | string;
@ApiPropertyOptional({
description: 'End date for the purchases by items report',
example: '2024-01-31',
type: String,
})
@IsDateString()
@IsOptional()
toDate: Date | string;
@ApiPropertyOptional({
description: 'Array of item IDs to filter the purchases report',
type: [Number],
example: [1, 2, 3],
})
@IsArray()
@IsOptional()
itemsIds: number[];
@ApiPropertyOptional({
description: 'Number formatting options for the report',
type: NumberFormatQueryDto,
})
@ValidateNested()
@Type(() => NumberFormatQueryDto)
@IsOptional()
numberFormat: INumberFormatQuery;
@ApiPropertyOptional({
description: 'Whether to exclude items with no transactions',
example: false,
type: Boolean,
default: false,
})
@IsBoolean()
@Transform(({ value }) => parseBoolean(value, false))
noneTransactions: boolean;
@ApiPropertyOptional({
description: 'Whether to include only active items',
example: false,
type: Boolean,
default: false,
})
@IsBoolean()
@Transform(({ value }) => parseBoolean(value, false))
onlyActive: boolean;

View File

@@ -9,31 +9,63 @@ import { INumberFormatQuery } from '../../types/Report.types';
import { Transform, Type } from 'class-transformer';
import { NumberFormatQueryDto } from '@/modules/BankingTransactions/dtos/NumberFormatQuery.dto';
import { parseBoolean } from '@/utils/parse-boolean';
import { ApiPropertyOptional } from '@nestjs/swagger';
export class SalesByItemsQueryDto {
@ApiPropertyOptional({
description: 'Start date for the sales by items report',
example: '2024-01-01',
type: String,
})
@IsDateString()
@IsOptional()
fromDate: Date | string;
@ApiPropertyOptional({
description: 'End date for the sales by items report',
example: '2024-01-31',
type: String,
})
@IsDateString()
@IsOptional()
toDate: Date | string;
@ApiPropertyOptional({
description: 'Number formatting options for the report',
type: NumberFormatQueryDto,
})
@ValidateNested()
@Type(() => NumberFormatQueryDto)
@IsOptional()
numberFormat: INumberFormatQuery;
@ApiPropertyOptional({
description: 'Whether to exclude items with no transactions',
example: false,
type: Boolean,
default: false,
})
@IsBoolean()
@Transform(({ value }) => parseBoolean(value, false))
@IsOptional()
noneTransactions: boolean;
@ApiPropertyOptional({
description: 'Whether to include only active items',
example: false,
type: Boolean,
default: false,
})
@IsBoolean()
@Transform(({ value }) => parseBoolean(value, false))
@IsOptional()
onlyActive: boolean;
@ApiPropertyOptional({
description: 'Array of item IDs to filter the sales report',
type: [Number],
example: [1, 2, 3],
})
@IsArray()
@IsOptional()
itemsIds: number[];

View File

@@ -1,8 +1,14 @@
import { IsArray, IsOptional } from 'class-validator';
import { ContactBalanceSummaryQueryDto } from '../ContactBalanceSummary/ContactBalanceSummaryQuery.dto';
import { ApiPropertyOptional } from '@nestjs/swagger';
export class VendorBalanceSummaryQueryDto extends ContactBalanceSummaryQueryDto {
@IsArray()
@IsOptional()
@ApiPropertyOptional({
description: 'Array of vendor IDs to filter the summary',
type: [Number],
example: [1, 2, 3],
})
vendorsIds: number[];
}

View File

@@ -8,7 +8,7 @@ import {
Put,
Query,
} from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { ApiOperation, ApiTags, ApiResponse } from '@nestjs/swagger';
import { UsersApplication } from './Users.application';
import { EditUserDto } from './dtos/EditUser.dto';
@@ -22,6 +22,13 @@ export class UsersController {
*/
@Post(':id')
@ApiOperation({ summary: 'Edit details of the given user.' })
@ApiResponse({
status: 200,
description: 'The user has been edited successfully.',
schema: {
example: { id: 1, message: 'The user has been edited successfully.' },
},
})
async editUser(
@Param('id') userId: number,
@Body() editUserDTO: EditUserDto,
@@ -39,6 +46,13 @@ export class UsersController {
*/
@Delete(':id')
@ApiOperation({ summary: 'Soft deleting the given user.' })
@ApiResponse({
status: 200,
description: 'The user has been deleted successfully.',
schema: {
example: { id: 1, message: 'The user has been deleted successfully.' },
},
})
async deleteUser(@Param('id') userId: number) {
await this.usersApplication.deleteUser(userId);
@@ -53,6 +67,10 @@ export class UsersController {
*/
@Get(':id')
@ApiOperation({ summary: 'Retrieve user details of the given user id.' })
@ApiResponse({
status: 200,
description: 'User details retrieved successfully.',
})
async getUser(@Param('id') userId: number) {
return this.usersApplication.getUser(userId);
}
@@ -62,6 +80,10 @@ export class UsersController {
*/
@Get()
@ApiOperation({ summary: 'Retrieve the list of users.' })
@ApiResponse({
status: 200,
description: 'List of users retrieved successfully.',
})
async listUsers(
@Query('page_size') pageSize?: number,
@Query('page') page?: number,
@@ -74,6 +96,13 @@ export class UsersController {
*/
@Put(':id/activate')
@ApiOperation({ summary: 'Activate the given user.' })
@ApiResponse({
status: 200,
description: 'The user has been activated successfully.',
schema: {
example: { id: 1, message: 'The user has been activated successfully.' },
},
})
async activateUser(@Param('id') userId: number) {
await this.usersApplication.activateUser(userId);
@@ -88,6 +117,16 @@ export class UsersController {
*/
@Put(':id/inactivate')
@ApiOperation({ summary: 'Inactivate the given user.' })
@ApiResponse({
status: 200,
description: 'The user has been inactivated successfully.',
schema: {
example: {
id: 1,
message: 'The user has been inactivated successfully.',
},
},
})
async inactivateUser(@Param('id') userId: number) {
await this.usersApplication.inactivateUser(userId);
@@ -96,5 +135,4 @@ export class UsersController {
message: 'The user has been inactivated successfully.',
};
}
}