mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 12:20:31 +00:00
feat(nestjs): migrate to NestJS
This commit is contained in:
117
packages/server/src/modules/Customers/CustomerGLEntries.ts
Normal file
117
packages/server/src/modules/Customers/CustomerGLEntries.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
// import { Service, Inject } from 'typedi';
|
||||
// import { AccountNormal, ICustomer, ILedgerEntry } from '@/interfaces';
|
||||
// import Ledger from '@/services/Accounting/Ledger';
|
||||
|
||||
// @Service()
|
||||
// export class CustomerGLEntries {
|
||||
// /**
|
||||
// * Retrieves the customer opening balance common entry attributes.
|
||||
// * @param {ICustomer} customer
|
||||
// */
|
||||
// private getCustomerOpeningGLCommonEntry = (customer: ICustomer) => {
|
||||
// return {
|
||||
// exchangeRate: customer.openingBalanceExchangeRate,
|
||||
// currencyCode: customer.currencyCode,
|
||||
|
||||
// transactionType: 'CustomerOpeningBalance',
|
||||
// transactionId: customer.id,
|
||||
|
||||
// date: customer.openingBalanceAt,
|
||||
// userId: customer.userId,
|
||||
// contactId: customer.id,
|
||||
|
||||
// credit: 0,
|
||||
// debit: 0,
|
||||
|
||||
// branchId: customer.openingBalanceBranchId,
|
||||
// };
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Retrieves the customer opening GL credit entry.
|
||||
// * @param {number} ARAccountId
|
||||
// * @param {ICustomer} customer
|
||||
// * @returns {ILedgerEntry}
|
||||
// */
|
||||
// private getCustomerOpeningGLCreditEntry = (
|
||||
// ARAccountId: number,
|
||||
// customer: ICustomer
|
||||
// ): ILedgerEntry => {
|
||||
// const commonEntry = this.getCustomerOpeningGLCommonEntry(customer);
|
||||
|
||||
// return {
|
||||
// ...commonEntry,
|
||||
// credit: 0,
|
||||
// debit: customer.localOpeningBalance,
|
||||
// accountId: ARAccountId,
|
||||
// accountNormal: AccountNormal.DEBIT,
|
||||
// index: 1,
|
||||
// };
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Retrieves the customer opening GL debit entry.
|
||||
// * @param {number} incomeAccountId
|
||||
// * @param {ICustomer} customer
|
||||
// * @returns {ILedgerEntry}
|
||||
// */
|
||||
// private getCustomerOpeningGLDebitEntry = (
|
||||
// incomeAccountId: number,
|
||||
// customer: ICustomer
|
||||
// ): ILedgerEntry => {
|
||||
// const commonEntry = this.getCustomerOpeningGLCommonEntry(customer);
|
||||
|
||||
// return {
|
||||
// ...commonEntry,
|
||||
// credit: customer.localOpeningBalance,
|
||||
// debit: 0,
|
||||
// accountId: incomeAccountId,
|
||||
// accountNormal: AccountNormal.CREDIT,
|
||||
|
||||
// index: 2,
|
||||
// };
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Retrieves the customer opening GL entries.
|
||||
// * @param {number} ARAccountId
|
||||
// * @param {number} incomeAccountId
|
||||
// * @param {ICustomer} customer
|
||||
// * @returns {ILedgerEntry[]}
|
||||
// */
|
||||
// public getCustomerOpeningGLEntries = (
|
||||
// ARAccountId: number,
|
||||
// incomeAccountId: number,
|
||||
// customer: ICustomer
|
||||
// ) => {
|
||||
// const debitEntry = this.getCustomerOpeningGLDebitEntry(
|
||||
// incomeAccountId,
|
||||
// customer
|
||||
// );
|
||||
// const creditEntry = this.getCustomerOpeningGLCreditEntry(
|
||||
// ARAccountId,
|
||||
// customer
|
||||
// );
|
||||
// return [debitEntry, creditEntry];
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Retrieves the customer opening balance ledger.
|
||||
// * @param {number} ARAccountId
|
||||
// * @param {number} incomeAccountId
|
||||
// * @param {ICustomer} customer
|
||||
// * @returns {ILedger}
|
||||
// */
|
||||
// public getCustomerOpeningLedger = (
|
||||
// ARAccountId: number,
|
||||
// incomeAccountId: number,
|
||||
// customer: ICustomer
|
||||
// ) => {
|
||||
// const entries = this.getCustomerOpeningGLEntries(
|
||||
// ARAccountId,
|
||||
// incomeAccountId,
|
||||
// customer
|
||||
// );
|
||||
// return new Ledger(entries);
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,90 @@
|
||||
// import { Knex } from 'knex';
|
||||
// import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
|
||||
// import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||
// import { Service, Inject } from 'typedi';
|
||||
// import { CustomerGLEntries } from './CustomerGLEntries';
|
||||
|
||||
// @Service()
|
||||
// export class CustomerGLEntriesStorage {
|
||||
// @Inject()
|
||||
// private tenancy: HasTenancyService;
|
||||
|
||||
// @Inject()
|
||||
// private ledegrRepository: LedgerStorageService;
|
||||
|
||||
// @Inject()
|
||||
// private customerGLEntries: CustomerGLEntries;
|
||||
|
||||
// /**
|
||||
// * Customer opening balance journals.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} customerId
|
||||
// * @param {Knex.Transaction} trx
|
||||
// */
|
||||
// public writeCustomerOpeningBalance = async (
|
||||
// tenantId: number,
|
||||
// customerId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// const { Customer } = this.tenancy.models(tenantId);
|
||||
// const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
|
||||
// const customer = await Customer.query(trx).findById(customerId);
|
||||
|
||||
// // Finds the income account.
|
||||
// const incomeAccount = await accountRepository.findOne({
|
||||
// slug: 'other-income',
|
||||
// });
|
||||
// // Find or create the A/R account.
|
||||
// const ARAccount = await accountRepository.findOrCreateAccountReceivable(
|
||||
// customer.currencyCode,
|
||||
// {},
|
||||
// trx
|
||||
// );
|
||||
// // Retrieves the customer opening balance ledger.
|
||||
// const ledger = this.customerGLEntries.getCustomerOpeningLedger(
|
||||
// ARAccount.id,
|
||||
// incomeAccount.id,
|
||||
// customer
|
||||
// );
|
||||
// // Commits the ledger entries to the storage.
|
||||
// await this.ledegrRepository.commit(tenantId, ledger, trx);
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Reverts the customer opening balance GL entries.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} customerId
|
||||
// * @param {Knex.Transaction} trx
|
||||
// */
|
||||
// public revertCustomerOpeningBalance = async (
|
||||
// tenantId: number,
|
||||
// customerId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// await this.ledegrRepository.deleteByReference(
|
||||
// tenantId,
|
||||
// customerId,
|
||||
// 'CustomerOpeningBalance',
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Writes the customer opening balance GL entries.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} customerId
|
||||
// * @param {Knex.Transaction} trx
|
||||
// */
|
||||
// public rewriteCustomerOpeningBalance = async (
|
||||
// tenantId: number,
|
||||
// customerId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// // Reverts the customer opening balance entries.
|
||||
// await this.revertCustomerOpeningBalance(tenantId, customerId, trx);
|
||||
|
||||
// // Write the customer opening balance entries.
|
||||
// await this.writeCustomerOpeningBalance(tenantId, customerId, trx);
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,59 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Param,
|
||||
Post,
|
||||
Put,
|
||||
} from '@nestjs/common';
|
||||
import { CustomersApplication } from './CustomersApplication.service';
|
||||
import { ICustomerOpeningBalanceEditDTO } from './types/Customers.types';
|
||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import { CreateCustomerDto } from './dtos/CreateCustomer.dto';
|
||||
import { EditCustomerDto } from './dtos/EditCustomer.dto';
|
||||
|
||||
@Controller('customers')
|
||||
@ApiTags('customers')
|
||||
export class CustomersController {
|
||||
constructor(private customersApplication: CustomersApplication) {}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Retrieves the customer details.' })
|
||||
getCustomer(@Param('id') customerId: number) {
|
||||
return this.customersApplication.getCustomer(customerId);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Create a new customer.' })
|
||||
createCustomer(@Body() customerDTO: CreateCustomerDto) {
|
||||
return this.customersApplication.createCustomer(customerDTO);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@ApiOperation({ summary: 'Edit the given customer.' })
|
||||
editCustomer(
|
||||
@Param('id') customerId: number,
|
||||
@Body() customerDTO: EditCustomerDto,
|
||||
) {
|
||||
return this.customersApplication.editCustomer(customerId, customerDTO);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: 'Delete the given customer.' })
|
||||
deleteCustomer(@Param('id') customerId: number) {
|
||||
return this.customersApplication.deleteCustomer(customerId);
|
||||
}
|
||||
|
||||
@Put(':id/opening-balance')
|
||||
@ApiOperation({ summary: 'Edit the opening balance of the given customer.' })
|
||||
editOpeningBalance(
|
||||
@Param('id') customerId: number,
|
||||
@Body() openingBalanceDTO: ICustomerOpeningBalanceEditDTO,
|
||||
) {
|
||||
return this.customersApplication.editOpeningBalance(
|
||||
customerId,
|
||||
openingBalanceDTO,
|
||||
);
|
||||
}
|
||||
}
|
||||
35
packages/server/src/modules/Customers/Customers.module.ts
Normal file
35
packages/server/src/modules/Customers/Customers.module.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TenancyContext } from '../Tenancy/TenancyContext.service';
|
||||
import { TenancyDatabaseModule } from '../Tenancy/TenancyDB/TenancyDB.module';
|
||||
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
|
||||
import { ActivateCustomer } from './commands/ActivateCustomer.service';
|
||||
import { CreateCustomer } from './commands/CreateCustomer.service';
|
||||
import { CustomerValidators } from './commands/CustomerValidators.service';
|
||||
import { EditCustomer } from './commands/EditCustomer.service';
|
||||
import { EditOpeningBalanceCustomer } from './commands/EditOpeningBalanceCustomer.service';
|
||||
import { GetCustomerService } from './queries/GetCustomer.service';
|
||||
import { CreateEditCustomerDTO } from './commands/CreateEditCustomerDTO.service';
|
||||
import { CustomersController } from './Customers.controller';
|
||||
import { CustomersApplication } from './CustomersApplication.service';
|
||||
import { DeleteCustomer } from './commands/DeleteCustomer.service';
|
||||
|
||||
@Module({
|
||||
imports: [TenancyDatabaseModule],
|
||||
controllers: [CustomersController],
|
||||
providers: [
|
||||
ActivateCustomer,
|
||||
CreateCustomer,
|
||||
CustomerValidators,
|
||||
EditCustomer,
|
||||
EditOpeningBalanceCustomer,
|
||||
CustomerValidators,
|
||||
CreateEditCustomerDTO,
|
||||
GetCustomerService,
|
||||
CustomersApplication,
|
||||
DeleteCustomer,
|
||||
TenancyContext,
|
||||
TransformerInjectable,
|
||||
GetCustomerService
|
||||
],
|
||||
})
|
||||
export class CustomersModule {}
|
||||
@@ -0,0 +1,86 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { GetCustomerService } from './queries/GetCustomer.service';
|
||||
import { CreateCustomer } from './commands/CreateCustomer.service';
|
||||
import { EditCustomer } from './commands/EditCustomer.service';
|
||||
import { DeleteCustomer } from './commands/DeleteCustomer.service';
|
||||
import { EditOpeningBalanceCustomer } from './commands/EditOpeningBalanceCustomer.service';
|
||||
import { ICustomerOpeningBalanceEditDTO } from './types/Customers.types';
|
||||
import { CreateCustomerDto } from './dtos/CreateCustomer.dto';
|
||||
import { EditCustomerDto } from './dtos/EditCustomer.dto';
|
||||
|
||||
@Injectable()
|
||||
export class CustomersApplication {
|
||||
constructor(
|
||||
private getCustomerService: GetCustomerService,
|
||||
private createCustomerService: CreateCustomer,
|
||||
private editCustomerService: EditCustomer,
|
||||
private deleteCustomerService: DeleteCustomer,
|
||||
private editOpeningBalanceService: EditOpeningBalanceCustomer,
|
||||
// private getCustomersService: GetCustomers,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Retrieves the given customer details.
|
||||
* @param {number} tenantId
|
||||
* @param {number} customerId
|
||||
*/
|
||||
public getCustomer = (customerId: number) => {
|
||||
return this.getCustomerService.getCustomer(customerId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new customer.
|
||||
* @param {ICustomerNewDTO} customerDTO
|
||||
* @returns {Promise<ICustomer>}
|
||||
*/
|
||||
public createCustomer = (customerDTO: CreateCustomerDto) => {
|
||||
return this.createCustomerService.createCustomer(customerDTO);
|
||||
};
|
||||
|
||||
/**
|
||||
* Edits details of the given customer.
|
||||
* @param {number} customerId - Customer id.
|
||||
* @param {ICustomerEditDTO} customerDTO - Customer edit DTO.
|
||||
* @return {Promise<ICustomer>}
|
||||
*/
|
||||
public editCustomer = (customerId: number, customerDTO: EditCustomerDto) => {
|
||||
return this.editCustomerService.editCustomer(customerId, customerDTO);
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes the given customer and associated transactions.
|
||||
* @param {number} tenantId
|
||||
* @param {number} customerId
|
||||
* @param {ISystemUser} authorizedUser
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public deleteCustomer = (customerId: number) => {
|
||||
return this.deleteCustomerService.deleteCustomer(customerId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Changes the opening balance of the given customer.
|
||||
* @param {number} tenantId
|
||||
* @param {number} customerId
|
||||
* @param {Date|string} openingBalanceEditDTO
|
||||
* @returns {Promise<ICustomer>}
|
||||
*/
|
||||
public editOpeningBalance = (
|
||||
customerId: number,
|
||||
openingBalanceEditDTO: ICustomerOpeningBalanceEditDTO,
|
||||
) => {
|
||||
return this.editOpeningBalanceService.changeOpeningBalance(
|
||||
customerId,
|
||||
openingBalanceEditDTO,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve customers paginated list.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {ICustomersFilter} filter - Cusotmers filter.
|
||||
*/
|
||||
// public getCustomers = (filterDTO: ICustomersFilter) => {
|
||||
// return this.getCustomersService.getCustomersList(filterDTO);
|
||||
// };
|
||||
}
|
||||
30
packages/server/src/modules/Customers/CustomersExportable.ts
Normal file
30
packages/server/src/modules/Customers/CustomersExportable.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { IItemsFilter } from '@/interfaces';
|
||||
// import { CustomersApplication } from './CustomersApplication';
|
||||
// import { Exportable } from '@/services/Export/Exportable';
|
||||
// import { EXPORT_SIZE_LIMIT } from '@/services/Export/constants';
|
||||
|
||||
// @Service()
|
||||
// export class CustomersExportable extends Exportable {
|
||||
// @Inject()
|
||||
// private customersApplication: CustomersApplication;
|
||||
|
||||
// /**
|
||||
// * Retrieves the accounts data to exportable sheet.
|
||||
// * @param {number} tenantId
|
||||
// * @returns
|
||||
// */
|
||||
// public exportable(tenantId: number, query: IItemsFilter) {
|
||||
// const parsedQuery = {
|
||||
// sortOrder: 'DESC',
|
||||
// columnSortBy: 'created_at',
|
||||
// ...query,
|
||||
// page: 1,
|
||||
// pageSize: EXPORT_SIZE_LIMIT,
|
||||
// } as IItemsFilter;
|
||||
|
||||
// return this.customersApplication
|
||||
// .getCustomers(tenantId, parsedQuery)
|
||||
// .then((output) => output.customers);
|
||||
// }
|
||||
// }
|
||||
34
packages/server/src/modules/Customers/CustomersImportable.ts
Normal file
34
packages/server/src/modules/Customers/CustomersImportable.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { Importable } from '@/services/Import/Importable';
|
||||
// import { CreateCustomer } from './CRUD/CreateCustomer';
|
||||
// import { Knex } from 'knex';
|
||||
// import { ICustomer, ICustomerNewDTO } from '@/interfaces';
|
||||
// import { CustomersSampleData } from './_SampleData';
|
||||
|
||||
// @Service()
|
||||
// export class CustomersImportable extends Importable {
|
||||
// @Inject()
|
||||
// private createCustomerService: CreateCustomer;
|
||||
|
||||
// /**
|
||||
// * Mapps the imported data to create a new customer service.
|
||||
// * @param {number} tenantId
|
||||
// * @param {ICustomerNewDTO} createDTO
|
||||
// * @param {Knex.Transaction} trx
|
||||
// * @returns {Promise<void>}
|
||||
// */
|
||||
// public async importable(
|
||||
// tenantId: number,
|
||||
// createDTO: ICustomerNewDTO,
|
||||
// trx?: Knex.Transaction<any, any[]>
|
||||
// ): Promise<void> {
|
||||
// await this.createCustomerService.createCustomer(tenantId, createDTO, trx);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Retrieves the sample data of customers used to download sample sheet.
|
||||
// */
|
||||
// public sampleData(): any[] {
|
||||
// return CustomersSampleData;
|
||||
// }
|
||||
// }
|
||||
158
packages/server/src/modules/Customers/_SampleData.ts
Normal file
158
packages/server/src/modules/Customers/_SampleData.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
|
||||
export const CustomersSampleData = [
|
||||
{
|
||||
"Customer Type": "Business",
|
||||
"First Name": "Nicolette",
|
||||
"Last Name": "Schamberger",
|
||||
"Company Name": "Homenick - Hane",
|
||||
"Display Name": "Rowland Rowe",
|
||||
"Email": "cicero86@yahoo.com",
|
||||
"Personal Phone Number": "811-603-2235",
|
||||
"Work Phone Number": "906-993-5190",
|
||||
"Website": "http://google.com",
|
||||
"Opening Balance": 54302.23,
|
||||
"Opening Balance At": "2022-02-02",
|
||||
"Opening Balance Ex. Rate": 2,
|
||||
"Currency": "LYD",
|
||||
"Active": "F",
|
||||
"Note": "Doloribus autem optio temporibus dolores mollitia sit.",
|
||||
"Billing Address 1": "862 Jessika Well",
|
||||
"Billing Address 2": "1091 Dorthy Mount",
|
||||
"Billing Address City": "Deckowfort",
|
||||
"Billing Address Country": "Ghana",
|
||||
"Billing Address Phone": "825-011-5207",
|
||||
"Billing Address Postcode": "38228",
|
||||
"Billing Address State": "Oregon",
|
||||
"Shipping Address 1": "37626 Thiel Villages",
|
||||
"Shipping Address 2": "132 Batz Avenue",
|
||||
"Shipping Address City": "Pagacburgh",
|
||||
"Shipping Address Country": "Albania",
|
||||
"Shipping Address Phone": "171-546-3701",
|
||||
"Shipping Address Postcode": "13709",
|
||||
"Shipping Address State": "Georgia"
|
||||
},
|
||||
{
|
||||
"Customer Type": "Business",
|
||||
"First Name": "Hermann",
|
||||
"Last Name": "Crooks",
|
||||
"Company Name": "Veum - Schaefer",
|
||||
"Display Name": "Harley Veum",
|
||||
"Email": "immanuel56@hotmail.com",
|
||||
"Personal Phone Number": "449-780-9999",
|
||||
"Work Phone Number": "970-473-5785",
|
||||
"Website": "http://google.com",
|
||||
"Opening Balance": 54302.23,
|
||||
"Opening Balance At": "2022-02-02",
|
||||
"Opening Balance Ex. Rate": 2,
|
||||
"Currency": "LYD",
|
||||
"Active": "T",
|
||||
"Note": "Doloribus dolore dolor dicta vitae in fugit nisi quibusdam.",
|
||||
"Billing Address 1": "532 Simonis Spring",
|
||||
"Billing Address 2": "3122 Nicolas Inlet",
|
||||
"Billing Address City": "East Matteofort",
|
||||
"Billing Address Country": "Holy See (Vatican City State)",
|
||||
"Billing Address Phone": "366-084-8629",
|
||||
"Billing Address Postcode": "41607",
|
||||
"Billing Address State": "Montana",
|
||||
"Shipping Address 1": "2889 Tremblay Plaza",
|
||||
"Shipping Address 2": "71355 Kutch Isle",
|
||||
"Shipping Address City": "D'Amorehaven",
|
||||
"Shipping Address Country": "Monaco",
|
||||
"Shipping Address Phone": "614-189-3328",
|
||||
"Shipping Address Postcode": "09634-0435",
|
||||
"Shipping Address State": "Nevada"
|
||||
},
|
||||
{
|
||||
"Customer Type": "Business",
|
||||
"First Name": "Nellie",
|
||||
"Last Name": "Gulgowski",
|
||||
"Company Name": "Boyle, Heller and Jones",
|
||||
"Display Name": "Randall Kohler",
|
||||
"Email": "anibal_frami@yahoo.com",
|
||||
"Personal Phone Number": "498-578-0740",
|
||||
"Work Phone Number": "394-550-6827",
|
||||
"Website": "http://google.com",
|
||||
"Opening Balance": 54302.23,
|
||||
"Opening Balance At": "2022-02-02",
|
||||
"Opening Balance Ex. Rate": 2,
|
||||
"Currency": "LYD",
|
||||
"Active": "T",
|
||||
"Note": "Vero quibusdam rem fugit aperiam est modi.",
|
||||
"Billing Address 1": "214 Sauer Villages",
|
||||
"Billing Address 2": "30687 Kacey Square",
|
||||
"Billing Address City": "Jayceborough",
|
||||
"Billing Address Country": "Benin",
|
||||
"Billing Address Phone": "332-820-1127",
|
||||
"Billing Address Postcode": "16425-3887",
|
||||
"Billing Address State": "Mississippi",
|
||||
"Shipping Address 1": "562 Diamond Loaf",
|
||||
"Shipping Address 2": "9595 Satterfield Trafficway",
|
||||
"Shipping Address City": "Alexandrinefort",
|
||||
"Shipping Address Country": "Puerto Rico",
|
||||
"Shipping Address Phone": "776-500-8456",
|
||||
"Shipping Address Postcode": "30258",
|
||||
"Shipping Address State": "South Dakota"
|
||||
},
|
||||
{
|
||||
"Customer Type": "Business",
|
||||
"First Name": "Stone",
|
||||
"Last Name": "Jerde",
|
||||
"Company Name": "Cassin, Casper and Maggio",
|
||||
"Display Name": "Clint McLaughlin",
|
||||
"Email": "nathanael22@yahoo.com",
|
||||
"Personal Phone Number": "562-790-6059",
|
||||
"Work Phone Number": "686-838-0027",
|
||||
"Website": "http://google.com",
|
||||
"Opening Balance": 54302.23,
|
||||
"Opening Balance At": "2022-02-02",
|
||||
"Opening Balance Ex. Rate": 2,
|
||||
"Currency": "LYD",
|
||||
"Active": "F",
|
||||
"Note": "Quis cumque molestias rerum.",
|
||||
"Billing Address 1": "22590 Cathy Harbor",
|
||||
"Billing Address 2": "24493 Brycen Brooks",
|
||||
"Billing Address City": "Elnorashire",
|
||||
"Billing Address Country": "Andorra",
|
||||
"Billing Address Phone": "701-852-8005",
|
||||
"Billing Address Postcode": "5680",
|
||||
"Billing Address State": "Nevada",
|
||||
"Shipping Address 1": "5355 Erdman Bridge",
|
||||
"Shipping Address 2": "421 Jeanette Camp",
|
||||
"Shipping Address City": "East Philip",
|
||||
"Shipping Address Country": "Venezuela",
|
||||
"Shipping Address Phone": "426-119-0858",
|
||||
"Shipping Address Postcode": "34929-0501",
|
||||
"Shipping Address State": "Tennessee"
|
||||
},
|
||||
{
|
||||
"Customer Type": "Individual",
|
||||
"First Name": "Lempi",
|
||||
"Last Name": "Kling",
|
||||
"Company Name": "Schamberger, O'Connell and Bechtelar",
|
||||
"Display Name": "Alexie Barton",
|
||||
"Email": "eulah.kreiger@hotmail.com",
|
||||
"Personal Phone Number": "745-756-1063",
|
||||
"Work Phone Number": "965-150-1945",
|
||||
"Website": "http://google.com",
|
||||
"Opening Balance": 54302.23,
|
||||
"Opening Balance At": "2022-02-02",
|
||||
"Opening Balance Ex. Rate": 2,
|
||||
"Currency": "LYD",
|
||||
"Active": "F",
|
||||
"Note": "Maxime laboriosam hic voluptate maiores est officia.",
|
||||
"Billing Address 1": "0851 Jones Flat",
|
||||
"Billing Address 2": "845 Bailee Drives",
|
||||
"Billing Address City": "Kamrenport",
|
||||
"Billing Address Country": "Niger",
|
||||
"Billing Address Phone": "220-125-0608",
|
||||
"Billing Address Postcode": "30311",
|
||||
"Billing Address State": "Delaware",
|
||||
"Shipping Address 1": "929 Ferry Row",
|
||||
"Shipping Address 2": "020 Adam Plaza",
|
||||
"Shipping Address City": "West Carmellaside",
|
||||
"Shipping Address Country": "Ghana",
|
||||
"Shipping Address Phone": "053-333-6679",
|
||||
"Shipping Address Postcode": "79221-4681",
|
||||
"Shipping Address State": "Illinois"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { CustomerValidators } from './CustomerValidators.service';
|
||||
import {
|
||||
ICustomerActivatedPayload,
|
||||
ICustomerActivatingPayload,
|
||||
} from '../types/Customers.types';
|
||||
import { Customer } from '@/modules/Customers/models/Customer';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class ActivateCustomer {
|
||||
/**
|
||||
* @param {UnitOfWork} uow - Unit of work service.
|
||||
* @param {EventEmitter2} eventPublisher - Event emitter service.
|
||||
* @param {CustomerValidators} validators - Customer validators service.
|
||||
* @param {typeof Customer} customerModel - Customer model.
|
||||
*/
|
||||
constructor(
|
||||
private uow: UnitOfWork,
|
||||
private eventPublisher: EventEmitter2,
|
||||
private validators: CustomerValidators,
|
||||
|
||||
@Inject(Customer.name)
|
||||
private customerModel: TenantModelProxy<typeof Customer>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Inactive the given contact.
|
||||
* @param {number} customerId - Customer id.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async activateCustomer(customerId: number): Promise<void> {
|
||||
// Retrieves the customer or throw not found error.
|
||||
const oldCustomer = await this.customerModel()
|
||||
.query()
|
||||
.findById(customerId)
|
||||
.throwIfNotFound();
|
||||
|
||||
this.validators.validateNotAlreadyPublished(oldCustomer);
|
||||
|
||||
// Edits the given customer with associated transactions on unit-of-work environment.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onCustomerActivating` event.
|
||||
await this.eventPublisher.emitAsync(events.customers.onActivating, {
|
||||
trx,
|
||||
oldCustomer,
|
||||
} as ICustomerActivatingPayload);
|
||||
|
||||
// Update the given customer details.
|
||||
const customer = await this.customerModel()
|
||||
.query(trx)
|
||||
.findById(customerId)
|
||||
.updateAndFetchById(customerId, { active: true });
|
||||
|
||||
// Triggers `onCustomerActivated` event.
|
||||
await this.eventPublisher.emitAsync(events.customers.onActivated, {
|
||||
trx,
|
||||
oldCustomer,
|
||||
customer,
|
||||
} as ICustomerActivatedPayload);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import { CreateEditCustomerDTO } from './CreateEditCustomerDTO.service';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Customer } from '../models/Customer';
|
||||
import { events } from '@/common/events/events';
|
||||
import {
|
||||
ICustomerEventCreatedPayload,
|
||||
ICustomerEventCreatingPayload,
|
||||
} from '../types/Customers.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { CreateCustomerDto } from '../dtos/CreateCustomer.dto';
|
||||
|
||||
@Injectable()
|
||||
export class CreateCustomer {
|
||||
/**
|
||||
* @param {UnitOfWork} uow - Unit of work service.
|
||||
* @param {EventEmitter2} eventPublisher - Event emitter service.
|
||||
* @param {CreateEditCustomerDTO} customerDTO - Customer DTO.
|
||||
* @param {typeof Customer} customerModel - Customer model.
|
||||
*/
|
||||
constructor(
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
private readonly customerDTO: CreateEditCustomerDTO,
|
||||
|
||||
@Inject(Customer.name)
|
||||
private readonly customerModel: TenantModelProxy<typeof Customer>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates a new customer.
|
||||
* @param {ICustomerNewDTO} customerDTO
|
||||
* @return {Promise<ICustomer>}
|
||||
*/
|
||||
public async createCustomer(
|
||||
customerDTO: CreateCustomerDto,
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<Customer> {
|
||||
// Transformes the customer DTO to customer object.
|
||||
const customerObj = await this.customerDTO.transformCreateDTO(customerDTO);
|
||||
|
||||
// Creates a new customer under unit-of-work envirement.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onCustomerCreating` event.
|
||||
await this.eventPublisher.emitAsync(events.customers.onCreating, {
|
||||
customerDTO,
|
||||
trx,
|
||||
} as ICustomerEventCreatingPayload);
|
||||
|
||||
// Creates a new contact as customer.
|
||||
const customer = await this.customerModel()
|
||||
.query(trx)
|
||||
.insertAndFetch({
|
||||
...customerObj,
|
||||
});
|
||||
// Triggers `onCustomerCreated` event.
|
||||
await this.eventPublisher.emitAsync(events.customers.onCreated, {
|
||||
customer,
|
||||
customerId: customer.id,
|
||||
trx,
|
||||
} as ICustomerEventCreatedPayload);
|
||||
|
||||
return customer;
|
||||
}, trx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import * as moment from 'moment';
|
||||
import { defaultTo, omit, isEmpty } from 'lodash';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
import { ICustomerEditDTO, ICustomerNewDTO } from '../types/Customers.types';
|
||||
import { ContactService } from '@/modules/Contacts/types/Contacts.types';
|
||||
|
||||
@Injectable()
|
||||
export class CreateEditCustomerDTO {
|
||||
/**
|
||||
* @param {TenancyContext} tenancyContext - Tenancy context service.
|
||||
*/
|
||||
constructor(private readonly tenancyContext: TenancyContext) {}
|
||||
|
||||
/**
|
||||
* Transformes the create/edit DTO.
|
||||
* @param {ICustomerNewDTO | ICustomerEditDTO} customerDTO
|
||||
* @returns
|
||||
*/
|
||||
private transformCommonDTO = (
|
||||
customerDTO: ICustomerNewDTO | ICustomerEditDTO,
|
||||
) => {
|
||||
return {
|
||||
...omit(customerDTO, ['customerType']),
|
||||
contactType: customerDTO.customerType,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Transformes the create DTO.
|
||||
* @param {ICustomerNewDTO} customerDTO
|
||||
* @returns {Promise<Partial<Customer>>}
|
||||
*/
|
||||
public transformCreateDTO = async (customerDTO: ICustomerNewDTO) => {
|
||||
const commonDTO = this.transformCommonDTO(customerDTO);
|
||||
|
||||
// Retrieves the tenant metadata.
|
||||
const tenantMeta = await this.tenancyContext.getTenant(true);
|
||||
|
||||
return {
|
||||
...commonDTO,
|
||||
currencyCode:
|
||||
commonDTO.currencyCode || tenantMeta?.metadata?.baseCurrency,
|
||||
active: defaultTo(customerDTO.active, true),
|
||||
contactService: ContactService.Customer,
|
||||
...(!isEmpty(customerDTO.openingBalanceAt)
|
||||
? {
|
||||
openingBalanceAt: moment(
|
||||
customerDTO?.openingBalanceAt,
|
||||
).toMySqlDateTime(),
|
||||
}
|
||||
: {}),
|
||||
openingBalanceExchangeRate: defaultTo(
|
||||
customerDTO.openingBalanceExchangeRate,
|
||||
1,
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Transformes the edit DTO.
|
||||
* @param {ICustomerEditDTO} customerDTO
|
||||
* @returns
|
||||
*/
|
||||
public transformEditDTO = (customerDTO: ICustomerEditDTO) => {
|
||||
const commonDTO = this.transformCommonDTO(customerDTO);
|
||||
|
||||
return {
|
||||
...commonDTO,
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { ERRORS } from '../constants';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Customer } from '../models/Customer';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
|
||||
@Injectable()
|
||||
export class CustomerValidators {
|
||||
/**
|
||||
* Validates the given customer is not already published.
|
||||
* @param {ICustomer} customer
|
||||
*/
|
||||
public validateNotAlreadyPublished = (customer: Customer) => {
|
||||
if (customer.active) {
|
||||
throw new ServiceError(ERRORS.CUSTOMER_ALREADY_ACTIVE);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import {
|
||||
ICustomerDeletingPayload,
|
||||
ICustomerEventDeletedPayload,
|
||||
} from '../types/Customers.types';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { Customer } from '../models/Customer';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteCustomer {
|
||||
/**
|
||||
* @param {UnitOfWork} uow - Unit of work service.
|
||||
* @param {EventEmitter2} eventPublisher - Event emitter service.
|
||||
* @param {typeof Customer} contactModel - Customer model.
|
||||
*/
|
||||
constructor(
|
||||
private uow: UnitOfWork,
|
||||
private eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(Customer.name)
|
||||
private customerModel: TenantModelProxy<typeof Customer>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Deletes the given customer from the storage.
|
||||
* @param {number} customerId - Customer ID.
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
public async deleteCustomer(customerId: number): Promise<void> {
|
||||
// Retrieve the customer or throw not found service error.
|
||||
const oldCustomer = await this.customerModel()
|
||||
.query()
|
||||
.findById(customerId)
|
||||
.throwIfNotFound();
|
||||
// .queryAndThrowIfHasRelations({
|
||||
// type: ERRORS.CUSTOMER_HAS_TRANSACTIONS,
|
||||
// });
|
||||
|
||||
// Triggers `onCustomerDeleting` event.
|
||||
await this.eventPublisher.emitAsync(events.customers.onDeleting, {
|
||||
customerId,
|
||||
oldCustomer,
|
||||
} as ICustomerDeletingPayload);
|
||||
|
||||
// Deletes the customer and associated entities under UOW transaction.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Delete the customer from the storage.
|
||||
await this.customerModel().query(trx).findById(customerId).delete();
|
||||
|
||||
// Throws `onCustomerDeleted` event.
|
||||
await this.eventPublisher.emitAsync(events.customers.onDeleted, {
|
||||
customerId,
|
||||
oldCustomer,
|
||||
trx,
|
||||
} as ICustomerEventDeletedPayload);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import {
|
||||
ICustomerEditDTO,
|
||||
ICustomerEventEditedPayload,
|
||||
ICustomerEventEditingPayload,
|
||||
} from '../types/Customers.types';
|
||||
import { CreateEditCustomerDTO } from './CreateEditCustomerDTO.service';
|
||||
import { Customer } from '../models/Customer';
|
||||
import { events } from '@/common/events/events';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { EditCustomerDto } from '../dtos/EditCustomer.dto';
|
||||
|
||||
@Injectable()
|
||||
export class EditCustomer {
|
||||
/**
|
||||
* @param {UnitOfWork} uow - Unit of work service.
|
||||
* @param {EventEmitter2} eventPublisher - Event emitter service.
|
||||
* @param {CreateEditCustomerDTO} customerDTO - Customer DTO.
|
||||
* @param {TenantModelProxy<typeof Customer>} contactModel - Customer model.
|
||||
*/
|
||||
constructor(
|
||||
private uow: UnitOfWork,
|
||||
private eventPublisher: EventEmitter2,
|
||||
private customerDTO: CreateEditCustomerDTO,
|
||||
|
||||
@Inject(Customer.name)
|
||||
private customerModel: TenantModelProxy<typeof Customer>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Edits details of the given customer.
|
||||
* @param {number} customerId
|
||||
* @param {ICustomerEditDTO} customerDTO
|
||||
* @return {Promise<ICustomer>}
|
||||
*/
|
||||
public async editCustomer(
|
||||
customerId: number,
|
||||
customerDTO: EditCustomerDto,
|
||||
): Promise<Customer> {
|
||||
// Retrieve the customer or throw not found error.
|
||||
const oldCustomer = await this.customerModel()
|
||||
.query()
|
||||
.findById(customerId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Transforms the given customer DTO to object.
|
||||
const customerObj = this.customerDTO.transformEditDTO(customerDTO);
|
||||
|
||||
// Edits the given customer under unit-of-work environment.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onCustomerEditing` event.
|
||||
await this.eventPublisher.emitAsync(events.customers.onEditing, {
|
||||
customerDTO,
|
||||
customerId,
|
||||
trx,
|
||||
} as ICustomerEventEditingPayload);
|
||||
|
||||
// Edits the customer details on the storage.
|
||||
const customer = await this.customerModel()
|
||||
.query()
|
||||
.updateAndFetchById(customerId, {
|
||||
...customerObj,
|
||||
});
|
||||
// Triggers `onCustomerEdited` event.
|
||||
await this.eventPublisher.emitAsync(events.customers.onEdited, {
|
||||
customerId,
|
||||
customer,
|
||||
trx,
|
||||
} as ICustomerEventEditedPayload);
|
||||
|
||||
return customer;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import {
|
||||
ICustomerOpeningBalanceEditDTO,
|
||||
ICustomerOpeningBalanceEditedPayload,
|
||||
ICustomerOpeningBalanceEditingPayload,
|
||||
} from '../types/Customers.types';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { Customer } from '../models/Customer';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class EditOpeningBalanceCustomer {
|
||||
/**
|
||||
* @param {EventEmitter2} eventPublisher - Event emitter service.
|
||||
* @param {UnitOfWork} uow - Unit of work service.
|
||||
* @param {typeof Customer} customerModel - Customer model.
|
||||
*/
|
||||
constructor(
|
||||
private eventPublisher: EventEmitter2,
|
||||
private uow: UnitOfWork,
|
||||
|
||||
@Inject(Customer.name)
|
||||
private customerModel: TenantModelProxy<typeof Customer>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Changes the opening balance of the given customer.
|
||||
* @param {number} customerId - Customer ID.
|
||||
* @param {ICustomerOpeningBalanceEditDTO} openingBalanceEditDTO
|
||||
*/
|
||||
public async changeOpeningBalance(
|
||||
customerId: number,
|
||||
openingBalanceEditDTO: ICustomerOpeningBalanceEditDTO,
|
||||
): Promise<Customer> {
|
||||
// Retrieves the old customer or throw not found error.
|
||||
const oldCustomer = await this.customerModel()
|
||||
.query()
|
||||
.findById(customerId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Mutates the customer opening balance under unit-of-work.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onCustomerOpeningBalanceChanging` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.customers.onOpeningBalanceChanging,
|
||||
{
|
||||
oldCustomer,
|
||||
openingBalanceEditDTO,
|
||||
trx,
|
||||
} as ICustomerOpeningBalanceEditingPayload,
|
||||
);
|
||||
// Mutates the customer on the storage.
|
||||
const customer = await this.customerModel()
|
||||
.query()
|
||||
.patchAndFetchById(customerId, {
|
||||
...openingBalanceEditDTO,
|
||||
});
|
||||
// Triggers `onCustomerOpeingBalanceChanged` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.customers.onOpeningBalanceChanged,
|
||||
{
|
||||
customer,
|
||||
oldCustomer,
|
||||
openingBalanceEditDTO,
|
||||
trx,
|
||||
} as ICustomerOpeningBalanceEditedPayload,
|
||||
);
|
||||
return customer;
|
||||
});
|
||||
}
|
||||
}
|
||||
27
packages/server/src/modules/Customers/constants.ts
Normal file
27
packages/server/src/modules/Customers/constants.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
export const DEFAULT_VIEW_COLUMNS = [];
|
||||
|
||||
export const DEFAULT_VIEWS = [
|
||||
{
|
||||
name: 'Overdue',
|
||||
slug: 'overdue',
|
||||
rolesLogicExpression: '1',
|
||||
roles: [
|
||||
{ index: 1, fieldKey: 'status', comparator: 'equals', value: 'overdue' },
|
||||
],
|
||||
columns: DEFAULT_VIEW_COLUMNS,
|
||||
},
|
||||
{
|
||||
name: 'Unpaid',
|
||||
slug: 'unpaid',
|
||||
rolesLogicExpression: '1',
|
||||
roles: [
|
||||
{ index: 1, fieldKey: 'status', comparator: 'equals', value: 'unpaid' },
|
||||
],
|
||||
columns: DEFAULT_VIEW_COLUMNS,
|
||||
},
|
||||
];
|
||||
|
||||
export const ERRORS = {
|
||||
CUSTOMER_HAS_TRANSACTIONS: 'CUSTOMER_HAS_TRANSACTIONS',
|
||||
CUSTOMER_ALREADY_ACTIVE: 'CUSTOMER_ALREADY_ACTIVE',
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
import { IsEmail, IsOptional, IsString } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class ContactAddressDto {
|
||||
@ApiProperty({ required: false, description: 'Billing address line 1' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
billingAddress1?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Billing address line 2' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
billingAddress2?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Billing address city' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
billingAddressCity?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Billing address country' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
billingAddressCountry?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Billing address email' })
|
||||
@IsOptional()
|
||||
@IsEmail()
|
||||
billingAddressEmail?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Billing address zipcode' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
billingAddressZipcode?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Billing address phone' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
billingAddressPhone?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Billing address state' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
billingAddressState?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Shipping address line 1' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
shippingAddress1?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Shipping address line 2' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
shippingAddress2?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Shipping address city' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
shippingAddressCity?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Shipping address country' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
shippingAddressCountry?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Shipping address email' })
|
||||
@IsOptional()
|
||||
@IsEmail()
|
||||
shippingAddressEmail?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Shipping address zipcode' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
shippingAddressZipcode?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Shipping address phone' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
shippingAddressPhone?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Shipping address state' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
shippingAddressState?: string;
|
||||
}
|
||||
100
packages/server/src/modules/Customers/dtos/CreateCustomer.dto.ts
Normal file
100
packages/server/src/modules/Customers/dtos/CreateCustomer.dto.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import {
|
||||
IsBoolean,
|
||||
IsEmail,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { ContactAddressDto } from './ContactAddress.dto';
|
||||
|
||||
export class CreateCustomerDto extends ContactAddressDto {
|
||||
@ApiProperty({ required: true, description: 'Customer type' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
customerType: string;
|
||||
|
||||
@ApiProperty({ required: true, description: 'Currency code' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
currencyCode: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Opening balance' })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
openingBalance?: number;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Opening balance date' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
openingBalanceAt?: string;
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
description: 'Opening balance exchange rate',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
openingBalanceExchangeRate?: number;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Opening balance branch ID' })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
openingBalanceBranchId?: number;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Salutation' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
salutation?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'First name' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
firstName?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Last name' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
lastName?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Company name' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
companyName?: string;
|
||||
|
||||
@ApiProperty({ required: true, description: 'Display name' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
displayName: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Website' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
website?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Email' })
|
||||
@IsOptional()
|
||||
@IsEmail()
|
||||
email?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Work phone' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
workPhone?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Personal phone' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
personalPhone?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Note' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
note?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Active status', default: true })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
active?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { IsBoolean, IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { ContactAddressDto } from './ContactAddress.dto';
|
||||
|
||||
export class EditCustomerDto extends ContactAddressDto {
|
||||
@ApiProperty({ required: true, description: 'Customer type' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
customerType: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Salutation' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
salutation?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'First name' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
firstName?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Last name' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
lastName?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Company name' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
companyName?: string;
|
||||
|
||||
@ApiProperty({ required: true, description: 'Display name' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
displayName: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Website' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
website?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Email' })
|
||||
@IsOptional()
|
||||
@IsEmail()
|
||||
email?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Work phone' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
workPhone?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Personal phone' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
personalPhone?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Note' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
note?: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Active status' })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
active?: boolean;
|
||||
}
|
||||
216
packages/server/src/modules/Customers/models/Customer.ts
Normal file
216
packages/server/src/modules/Customers/models/Customer.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
|
||||
export class Customer extends TenantBaseModel{
|
||||
contactService: string;
|
||||
contactType: string;
|
||||
|
||||
balance: number;
|
||||
currencyCode: string;
|
||||
|
||||
openingBalance: number;
|
||||
openingBalanceAt: Date | string;
|
||||
openingBalanceExchangeRate: number;
|
||||
openingBalanceBranchId?: number;
|
||||
|
||||
salutation?: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
companyName?: string;
|
||||
|
||||
displayName: string;
|
||||
|
||||
email?: string;
|
||||
workPhone?: string;
|
||||
personalPhone?: string;
|
||||
website?: string;
|
||||
|
||||
billingAddress1?: string;
|
||||
billingAddress2?: string;
|
||||
billingAddressCity?: string;
|
||||
billingAddressCountry?: string;
|
||||
billingAddressEmail?: string;
|
||||
billingAddressPostcode?: string;
|
||||
billingAddressPhone?: string;
|
||||
billingAddressState?: string;
|
||||
|
||||
shippingAddress1?: string;
|
||||
shippingAddress2?: string;
|
||||
shippingAddressCity?: string;
|
||||
shippingAddressCountry?: string;
|
||||
shippingAddressEmail?: string;
|
||||
shippingAddressPostcode?: string;
|
||||
shippingAddressPhone?: string;
|
||||
shippingAddressState?: string;
|
||||
|
||||
note: string;
|
||||
active: boolean;
|
||||
|
||||
|
||||
/**
|
||||
* Query builder.
|
||||
*/
|
||||
// static get QueryBuilder() {
|
||||
// return CustomerQueryBuilder;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Table name
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'contacts';
|
||||
}
|
||||
|
||||
/**
|
||||
* Model timestamps.
|
||||
*/
|
||||
get timestamps() {
|
||||
return ['createdAt', 'updatedAt'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Defined virtual attributes.
|
||||
*/
|
||||
static get virtualAttributes() {
|
||||
return ['localOpeningBalance', 'closingBalance', 'contactNormal'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Closing balance attribute.
|
||||
*/
|
||||
get closingBalance() {
|
||||
return this.balance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the local opening balance.
|
||||
* @returns {number}
|
||||
*/
|
||||
get localOpeningBalance() {
|
||||
return this.openingBalance
|
||||
? this.openingBalance * this.openingBalanceExchangeRate
|
||||
: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the contact noraml;
|
||||
*/
|
||||
get contactNormal() {
|
||||
return 'debit';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
get contactAddresses() {
|
||||
return [
|
||||
{
|
||||
mail: this.email,
|
||||
label: this.displayName,
|
||||
primary: true
|
||||
},
|
||||
].filter((c) => c.mail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Model modifiers.
|
||||
*/
|
||||
static get modifiers() {
|
||||
return {
|
||||
/**
|
||||
* Inactive/Active mode.
|
||||
*/
|
||||
inactiveMode(query, active = false) {
|
||||
query.where('active', !active);
|
||||
},
|
||||
|
||||
/**
|
||||
* Filters the active customers.
|
||||
*/
|
||||
active(query) {
|
||||
query.where('active', 1);
|
||||
},
|
||||
/**
|
||||
* Filters the inactive customers.
|
||||
*/
|
||||
inactive(query) {
|
||||
query.where('active', 0);
|
||||
},
|
||||
/**
|
||||
* Filters the customers that have overdue invoices.
|
||||
*/
|
||||
overdue(query) {
|
||||
query.select(
|
||||
'*',
|
||||
Customer.relatedQuery('overDueInvoices', query.knex())
|
||||
.count()
|
||||
.as('countOverdue')
|
||||
);
|
||||
query.having('countOverdue', '>', 0);
|
||||
},
|
||||
/**
|
||||
* Filters the unpaid customers.
|
||||
*/
|
||||
unpaid(query) {
|
||||
query.whereRaw('`BALANCE` + `OPENING_BALANCE` <> 0');
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Relationship mapping.
|
||||
*/
|
||||
// static get relationMappings() {
|
||||
// const SaleInvoice = require('models/SaleInvoice');
|
||||
|
||||
// return {
|
||||
// salesInvoices: {
|
||||
// relation: Model.HasManyRelation,
|
||||
// modelClass: SaleInvoice.default,
|
||||
// join: {
|
||||
// from: 'contacts.id',
|
||||
// to: 'sales_invoices.customerId',
|
||||
// },
|
||||
// },
|
||||
|
||||
// overDueInvoices: {
|
||||
// relation: Model.HasManyRelation,
|
||||
// modelClass: SaleInvoice.default,
|
||||
// join: {
|
||||
// from: 'contacts.id',
|
||||
// to: 'sales_invoices.customerId',
|
||||
// },
|
||||
// filter: (query) => {
|
||||
// query.modify('overdue');
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
|
||||
// static get meta() {
|
||||
// return CustomerSettings;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Retrieve the default custom views, roles and columns.
|
||||
// */
|
||||
// static get defaultViews() {
|
||||
// return DEFAULT_VIEWS;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Model search attributes.
|
||||
*/
|
||||
static get searchRoles() {
|
||||
return [
|
||||
{ fieldKey: 'display_name', comparator: 'contains' },
|
||||
{ condition: 'or', fieldKey: 'first_name', comparator: 'contains' },
|
||||
{ condition: 'or', fieldKey: 'last_name', comparator: 'equals' },
|
||||
{ condition: 'or', fieldKey: 'company_name', comparator: 'equals' },
|
||||
{ condition: 'or', fieldKey: 'email', comparator: 'equals' },
|
||||
{ condition: 'or', fieldKey: 'work_phone', comparator: 'equals' },
|
||||
{ condition: 'or', fieldKey: 'personal_phone', comparator: 'equals' },
|
||||
{ condition: 'or', fieldKey: 'website', comparator: 'equals' },
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ContactTransfromer } from "../../Contacts/Contact.transformer";
|
||||
|
||||
export class CustomerTransfromer extends ContactTransfromer {
|
||||
/**
|
||||
* Include these attributes to expense object.
|
||||
* @returns {Array}
|
||||
*/
|
||||
public includeAttributes = (): string[] => {
|
||||
return [
|
||||
'formattedBalance',
|
||||
'formattedOpeningBalance',
|
||||
'formattedOpeningBalanceAt',
|
||||
'customerType',
|
||||
'formattedCustomerType',
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve customer type.
|
||||
* @returns {string}
|
||||
*/
|
||||
protected customerType = (customer): string => {
|
||||
return customer.contactType;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the formatted customer type.
|
||||
* @param customer
|
||||
* @returns {string}
|
||||
*/
|
||||
protected formattedCustomerType = (customer): string => {
|
||||
const keywords = {
|
||||
individual: 'customer.type.individual',
|
||||
business: 'customer.type.business',
|
||||
};
|
||||
return this.context.i18n.t(keywords[customer.contactType] || '');
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { CustomerTransfromer } from './CustomerTransformer';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { Customer } from '../models/Customer';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetCustomerService {
|
||||
constructor(
|
||||
private transformer: TransformerInjectable,
|
||||
|
||||
@Inject(Customer.name)
|
||||
private customerModel: TenantModelProxy<typeof Customer>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Retrieve the given customer details.
|
||||
* @param {number} customerId
|
||||
*/
|
||||
public async getCustomer(customerId: number) {
|
||||
// Retrieve the customer model or throw not found error.
|
||||
const customer = await this.customerModel()
|
||||
.query()
|
||||
.findById(customerId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Retrieves the transformered customers.
|
||||
return this.transformer.transform(customer, new CustomerTransfromer());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { DynamicListService } from '@/modules/DynamicListing/DynamicList.service';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import * as R from 'ramda';
|
||||
import { Customer } from '../models/Customer';
|
||||
import { CustomerTransfromer } from './CustomerTransformer';
|
||||
import {
|
||||
GetCustomersResponse,
|
||||
ICustomersFilter,
|
||||
} from '../types/Customers.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetCustomers {
|
||||
constructor(
|
||||
private dynamicListService: DynamicListService,
|
||||
private transformer: TransformerInjectable,
|
||||
|
||||
@Inject(Customer.name)
|
||||
private customerModel: TenantModelProxy<typeof Customer>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Parses customers list filter DTO.
|
||||
* @param filterDTO -
|
||||
*/
|
||||
private parseCustomersListFilterDTO(filterDTO) {
|
||||
return R.compose(this.dynamicListService.parseStringifiedFilter)(filterDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve customers paginated list.
|
||||
* @param {ICustomersFilter} filter - Cusotmers filter.
|
||||
* @returns {Promise<GetCustomersResponse>}
|
||||
*/
|
||||
public async getCustomersList(
|
||||
filterDTO: ICustomersFilter,
|
||||
): Promise<GetCustomersResponse> {
|
||||
// Parses customers list filter DTO.
|
||||
const filter = this.parseCustomersListFilterDTO(filterDTO);
|
||||
|
||||
const dynamicList = await this.dynamicListService.dynamicList(
|
||||
this.customerModel(),
|
||||
filter,
|
||||
);
|
||||
const { results, pagination } = await this.customerModel()
|
||||
.query()
|
||||
.onBuild((builder) => {
|
||||
dynamicList.buildQuery()(builder);
|
||||
builder.modify('inactiveMode', filter.inactiveMode);
|
||||
})
|
||||
.pagination(filter.page - 1, filter.pageSize);
|
||||
|
||||
// Retrieves the transformed customers.
|
||||
const customers = await this.transformer.transform(
|
||||
results,
|
||||
new CustomerTransfromer(),
|
||||
);
|
||||
return {
|
||||
customers,
|
||||
pagination,
|
||||
filterMeta: dynamicList.getResponseMeta(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
// import { Service, Inject } from 'typedi';
|
||||
// import {
|
||||
// ICustomerEventCreatedPayload,
|
||||
// ICustomerEventDeletedPayload,
|
||||
// ICustomerOpeningBalanceEditedPayload,
|
||||
// } from '@/interfaces';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { CustomerGLEntriesStorage } from '../CustomerGLEntriesStorage';
|
||||
|
||||
// @Service()
|
||||
// export class CustomerWriteGLOpeningBalanceSubscriber {
|
||||
// @Inject()
|
||||
// private customerGLEntries: CustomerGLEntriesStorage;
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.customers.onCreated,
|
||||
// this.handleWriteOpenBalanceEntries
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.customers.onDeleted,
|
||||
// this.handleRevertOpeningBalanceEntries
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.customers.onOpeningBalanceChanged,
|
||||
// this.handleRewriteOpeningEntriesOnChanged
|
||||
// );
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Handles the writing opening balance journal entries once the customer created.
|
||||
// * @param {ICustomerEventCreatedPayload} payload -
|
||||
// */
|
||||
// private handleWriteOpenBalanceEntries = async ({
|
||||
// tenantId,
|
||||
// customer,
|
||||
// trx,
|
||||
// }: ICustomerEventCreatedPayload) => {
|
||||
// // Writes the customer opening balance journal entries.
|
||||
// if (customer.openingBalance) {
|
||||
// await this.customerGLEntries.writeCustomerOpeningBalance(
|
||||
// tenantId,
|
||||
// customer.id,
|
||||
// trx
|
||||
// );
|
||||
// }
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Handles the deleting opeing balance journal entrise once the customer deleted.
|
||||
// * @param {ICustomerEventDeletedPayload} payload -
|
||||
// */
|
||||
// private handleRevertOpeningBalanceEntries = async ({
|
||||
// tenantId,
|
||||
// customerId,
|
||||
// trx,
|
||||
// }: ICustomerEventDeletedPayload) => {
|
||||
// await this.customerGLEntries.revertCustomerOpeningBalance(
|
||||
// tenantId,
|
||||
// customerId,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Handles the rewrite opening balance entries once opening balnace changed.
|
||||
// * @param {ICustomerOpeningBalanceEditedPayload} payload -
|
||||
// */
|
||||
// private handleRewriteOpeningEntriesOnChanged = async ({
|
||||
// tenantId,
|
||||
// customer,
|
||||
// trx,
|
||||
// }: ICustomerOpeningBalanceEditedPayload) => {
|
||||
// if (customer.openingBalance) {
|
||||
// await this.customerGLEntries.rewriteCustomerOpeningBalance(
|
||||
// tenantId,
|
||||
// customer.id,
|
||||
// trx
|
||||
// );
|
||||
// } else {
|
||||
// await this.customerGLEntries.revertCustomerOpeningBalance(
|
||||
// tenantId,
|
||||
// customer.id,
|
||||
// trx
|
||||
// );
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
146
packages/server/src/modules/Customers/types/Customers.types.ts
Normal file
146
packages/server/src/modules/Customers/types/Customers.types.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Customer } from '../models/Customer';
|
||||
import { IContactAddressDTO } from '@/modules/Contacts/types/Contacts.types';
|
||||
import { IDynamicListFilter } from '@/modules/DynamicListing/DynamicFilter/DynamicFilter.types';
|
||||
import { IFilterMeta, IPaginationMeta } from '@/interfaces/Model';
|
||||
import { CreateCustomerDto } from '../dtos/CreateCustomer.dto';
|
||||
import { EditCustomerDto } from '../dtos/EditCustomer.dto';
|
||||
|
||||
// Customer Interfaces.
|
||||
// ----------------------------------
|
||||
export interface ICustomerNewDTO extends IContactAddressDTO {
|
||||
customerType: string;
|
||||
|
||||
currencyCode: string;
|
||||
|
||||
openingBalance?: number;
|
||||
openingBalanceAt?: string;
|
||||
openingBalanceExchangeRate?: number;
|
||||
openingBalanceBranchId?: number;
|
||||
|
||||
salutation?: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
companyName?: string;
|
||||
displayName: string;
|
||||
|
||||
website?: string;
|
||||
email?: string;
|
||||
workPhone?: string;
|
||||
personalPhone?: string;
|
||||
|
||||
note?: string;
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
export interface ICustomerEditDTO extends IContactAddressDTO {
|
||||
customerType: string;
|
||||
|
||||
salutation?: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
companyName?: string;
|
||||
displayName: string;
|
||||
|
||||
website?: string;
|
||||
email?: string;
|
||||
workPhone?: string;
|
||||
personalPhone?: string;
|
||||
|
||||
note?: string;
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
export interface ICustomersFilter extends IDynamicListFilter {
|
||||
stringifiedFilterRoles?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
export interface GetCustomersResponse {
|
||||
customers: Customer[];
|
||||
pagination: IPaginationMeta;
|
||||
filterMeta: IFilterMeta;
|
||||
}
|
||||
// Customer Events.
|
||||
// ----------------------------------
|
||||
export interface ICustomerEventCreatedPayload {
|
||||
customerId: number;
|
||||
customer: Customer;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
export interface ICustomerEventCreatingPayload {
|
||||
customerDTO: CreateCustomerDto;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
export interface ICustomerEventEditedPayload {
|
||||
customerId: number;
|
||||
customer: Customer;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface ICustomerEventEditingPayload {
|
||||
customerDTO: EditCustomerDto;
|
||||
customerId: number;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface ICustomerDeletingPayload {
|
||||
customerId: number;
|
||||
oldCustomer: Customer;
|
||||
}
|
||||
|
||||
export interface ICustomerEventDeletedPayload {
|
||||
customerId: number;
|
||||
oldCustomer: Customer;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
export interface ICustomerEventCreatingPayload {
|
||||
customerDTO: CreateCustomerDto;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
export enum CustomerAction {
|
||||
Create = 'Create',
|
||||
Edit = 'Edit',
|
||||
Delete = 'Delete',
|
||||
View = 'View',
|
||||
}
|
||||
|
||||
export enum VendorAction {
|
||||
Create = 'Create',
|
||||
Edit = 'Edit',
|
||||
Delete = 'Delete',
|
||||
View = 'View',
|
||||
}
|
||||
|
||||
export interface ICustomerOpeningBalanceEditDTO {
|
||||
openingBalance: number;
|
||||
openingBalanceAt: Date | string;
|
||||
openingBalanceExchangeRate: number;
|
||||
openingBalanceBranchId?: number;
|
||||
}
|
||||
|
||||
export interface ICustomerOpeningBalanceEditingPayload {
|
||||
oldCustomer: Customer;
|
||||
openingBalanceEditDTO: ICustomerOpeningBalanceEditDTO;
|
||||
trx?: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface ICustomerOpeningBalanceEditedPayload {
|
||||
customer: Customer;
|
||||
oldCustomer: Customer;
|
||||
openingBalanceEditDTO: ICustomerOpeningBalanceEditDTO;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
|
||||
export interface ICustomerActivatingPayload {
|
||||
trx: Knex.Transaction,
|
||||
oldCustomer: Customer;
|
||||
}
|
||||
|
||||
export interface ICustomerActivatedPayload {
|
||||
trx?: Knex.Transaction;
|
||||
oldCustomer: Customer;
|
||||
customer: Customer;
|
||||
}
|
||||
Reference in New Issue
Block a user