From cb8fd68d462f43404275c11fec8ba23742f2db9c Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sat, 21 Dec 2024 00:10:09 +0200 Subject: [PATCH] refactor: branches and warehouses to nestjs --- .../server-nest/src/modules/App/App.module.ts | 2 + .../BranchIntegrationErrorsMiddleware.ts | 35 +++ .../modules/Branches/Branches.controller.ts | 51 +++++ .../src/modules/Branches/Branches.module.ts | 31 +++ .../src/modules/Branches/Branches.types.ts | 50 +++++ .../Branches/BranchesApplication.service.ts | 99 ++++++++ .../src/modules/Branches/BranchesSettings.ts | 29 +++ .../src/modules/Branches/CRUDBranch.ts | 30 +++ .../src/modules/Branches/EventsProvider.ts | 50 +++++ .../ActivateBranchesFeature.service.ts | 80 +++++++ .../BranchCommandValidator.service.ts | 50 +++++ .../Branches/commands/CreateBranch.service.ts | 55 +++++ .../Branches/commands/DeleteBranch.service.ts | 65 ++++++ .../Branches/commands/EditBranch.service.ts | 61 +++++ .../commands/MarkBranchAsPrimary.service.ts | 62 +++++ .../src/modules/Branches/constants.ts | 7 + .../BranchTransactionDTOTransform.ts | 35 +++ .../Cashflow/CashflowActivateBranches.ts | 26 +++ .../Expense/ExpensesActivateBranches.ts | 26 +++ .../ManualJournalBranchesActivate.ts | 26 +++ .../ManualJournalDTOTransformer.ts | 32 +++ .../ManualJournalsBranchesValidator.ts | 23 ++ .../integrations/ManualJournals/constants.ts | 4 + .../Purchases/BillBranchesActivate.ts | 26 +++ .../Purchases/PaymentMadeBranchesActivate.ts | 26 +++ .../Purchases/VendorCreditBranchesActivate.ts | 26 +++ .../Sales/CreditNoteBranchesActivate.ts | 26 +++ .../Sales/PaymentReceiveBranchesActivate.ts | 26 +++ .../Sales/SaleEstimatesBranchesActivate.ts | 26 +++ .../Sales/SaleInvoiceBranchesActivate.ts | 26 +++ .../Sales/SaleReceiptBranchesActivate.ts | 26 +++ .../integrations/ValidateBranchExistance.ts | 75 +++++++ .../Branches/integrations/constants.ts | 6 + .../modules/Branches/models/Branch.model.ts | 192 ++++++++++++++++ .../Branches/queries/GetBranch.service.ts | 25 +++ .../Branches/queries/GetBranches.service.ts | 20 ++ .../CashflowBranchesActivateSubscriber.ts | 38 ++++ .../CreditNoteBranchesActivateSubscriber.ts | 38 ++++ .../ExpenseBranchesActivateSubscriber.ts | 38 ++++ .../PaymentMadeBranchesActivateSubscriber.ts | 38 ++++ ...aymentReceiveBranchesActivateSubscriber.ts | 38 ++++ ...SaleEstiamtesBranchesActivateSubscriber.ts | 38 ++++ .../SaleInvoiceBranchesActivateSubscriber.ts | 38 ++++ .../SaleReceiptsBranchesActivateSubscriber.ts | 38 ++++ .../Branches/subscribers/Activate/index.ts | 8 + .../Validators/BillBranchSubscriber.ts | 53 +++++ .../CashflowBranchDTOValidatorSubscriber.ts | 35 +++ .../ContactOpeningBalanceBranchSubscriber.ts | 104 +++++++++ .../CreditNoteBranchesSubscriber.ts | 56 +++++ .../CreditNoteRefundBranchSubscriber.ts | 35 +++ .../Validators/ExpenseBranchSubscriber.ts | 56 +++++ ...toryAdjustmentBranchValidatorSubscriber.ts | 35 +++ .../InvoiceBranchValidatorSubscriber.ts | 56 +++++ .../ManualJournalBranchSubscriber.ts | 76 +++++++ .../Validators/PaymentMadeBranchSubscriber.ts | 56 +++++ .../PaymentReceiveBranchSubscriber.ts | 56 +++++ .../SaleEstimateMultiBranchesSubscriber.ts | 56 +++++ .../SaleReceiptBranchesSubscriber.ts | 56 +++++ .../VendorCreditBranchSubscriber.ts | 56 +++++ .../VendorCreditRefundBranchSubscriber.ts | 35 +++ .../Branches/subscribers/Validators/index.ts | 15 ++ .../commands/CreateExpense.service.ts | 8 + .../commands/DeleteExpense.service.ts | 7 + .../Expenses/commands/EditExpense.service.ts | 8 + .../commands/PublishExpense.service.ts | 6 + .../ItemCategory.application.ts | 6 + .../CommandItemCategoryValidator.service.ts | 4 + .../commands/CreateItemCategory.service.ts | 6 + .../commands/DeleteItemCategory.service.ts | 6 + .../commands/EditItemCategory.service.ts | 8 + .../queries/GetItemCategory.service.ts | 3 + .../TransformerInjectable.service.ts | 4 + .../Activate/BillWarehousesActivate.ts | 30 +++ .../Activate/CreditNoteWarehousesActivate.ts | 30 +++ .../Activate/EstimateWarehousesActivate.ts | 30 +++ ...InventoryTransactionsWarehousesActivate.ts | 31 +++ .../Activate/InvoiceWarehousesActivate.ts | 30 +++ .../Activate/ReceiptWarehousesActivate.ts | 30 +++ .../VendorCreditWarehousesActivate.ts | 30 +++ .../ActivateWarehousesSubscriber.ts | 58 +++++ .../src/modules/Warehouses/CRUDWarehouse.ts | 26 +++ .../CreateInitialWarehousesitemsQuantity.ts | 57 +++++ .../src/modules/Warehouses/EventsProvider.ts | 39 ++++ .../ValidateWarehouseExistance.ts | 79 +++++++ .../WarehouseTransactionDTOTransform.ts | 38 ++++ .../Integrations/WarehousesDTOValidators.ts | 66 ++++++ .../Integrations/WarehousesItemsQuantity.ts | 117 ++++++++++ .../WarehousesItemsQuantitySynSubscriber.ts | 74 ++++++ .../WarehousesItemsQuantitySync.ts | 131 +++++++++++ .../Warehouses/Integrations/constants.ts | 4 + .../Warehouses/Items/GetItemWarehouses.ts | 41 ++++ .../Items/GettItemWarehouseTransformer.ts | 46 ++++ ...pdateInventoryTransactionsWithWarehouse.ts | 21 ++ .../src/modules/Warehouses/Warehouse.types.ts | 212 ++++++++++++++++++ .../WarehousesApplication.service.ts | 111 +++++++++ .../modules/Warehouses/WarehousesSettings.ts | 25 +++ .../Warehouses/commands/ActivateWarehouses.ts | 60 +++++ .../CreateInitialWarehouse.service.ts | 27 +++ .../commands/CreateWarehouse.service.ts | 73 ++++++ .../commands/DeleteItemWarehousesQuantity.ts | 29 +++ .../commands/DeleteWarehouse.service.ts | 81 +++++++ .../commands/EditWarehouse.service.ts | 79 +++++++ .../commands/WarehouseMarkPrimary.service.ts | 53 +++++ .../commands/WarehouseValidator.service.ts | 51 +++++ .../src/modules/Warehouses/contants.ts | 7 + .../models/ItemWarehouseQuantity.ts | 38 ++++ .../Warehouses/models/Warehouse.model.ts | 178 +++++++++++++++ .../Warehouses/queries/GetWarehouse.ts | 23 ++ .../Warehouses/queries/GetWarehouses.ts | 22 ++ .../BillWarehousesActivateSubscriber.ts | 36 +++ .../CreditNoteWarehousesActivateSubscriber.ts | 36 +++ .../EstimateWarehousesActivateSubscriber.ts | 36 +++ ...ransactionsWarehousesActivateSubscriber.ts | 36 +++ .../InvoiceWarehousesActivateSubscriber.ts | 36 +++ .../ReceiptWarehousesActivateSubscriber.ts | 36 +++ ...endorCreditWarehousesActivateSubscriber.ts | 36 +++ .../Warehouses/subscribers/Activate/index.ts | 8 + .../DeleteItemWarehousesQuantitySubscriber.ts | 36 +++ ...yAdjustmentWarehouseValidatorSubscriber.ts | 35 +++ .../Purchases/BillWarehousesSubscriber.ts | 53 +++++ .../VendorCreditWarehousesSubscriber.ts | 56 +++++ .../Sales/CreditNoteWarehousesSubscriber.ts | 56 +++++ .../Sales/SaleEstimateWarehousesSubscriber.ts | 56 +++++ .../Sales/SaleInvoicesWarehousesSubscriber.ts | 56 +++++ .../Sales/SaleReceiptWarehousesSubscriber.ts | 56 +++++ .../subscribers/Validators/index.ts | 9 + 126 files changed, 5419 insertions(+) create mode 100644 packages/server-nest/src/modules/Branches/BranchIntegrationErrorsMiddleware.ts create mode 100644 packages/server-nest/src/modules/Branches/Branches.controller.ts create mode 100644 packages/server-nest/src/modules/Branches/Branches.module.ts create mode 100644 packages/server-nest/src/modules/Branches/Branches.types.ts create mode 100644 packages/server-nest/src/modules/Branches/BranchesApplication.service.ts create mode 100644 packages/server-nest/src/modules/Branches/BranchesSettings.ts create mode 100644 packages/server-nest/src/modules/Branches/CRUDBranch.ts create mode 100644 packages/server-nest/src/modules/Branches/EventsProvider.ts create mode 100644 packages/server-nest/src/modules/Branches/commands/ActivateBranchesFeature.service.ts create mode 100644 packages/server-nest/src/modules/Branches/commands/BranchCommandValidator.service.ts create mode 100644 packages/server-nest/src/modules/Branches/commands/CreateBranch.service.ts create mode 100644 packages/server-nest/src/modules/Branches/commands/DeleteBranch.service.ts create mode 100644 packages/server-nest/src/modules/Branches/commands/EditBranch.service.ts create mode 100644 packages/server-nest/src/modules/Branches/commands/MarkBranchAsPrimary.service.ts create mode 100644 packages/server-nest/src/modules/Branches/constants.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/BranchTransactionDTOTransform.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/Cashflow/CashflowActivateBranches.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/Expense/ExpensesActivateBranches.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/ManualJournals/ManualJournalBranchesActivate.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/ManualJournals/ManualJournalDTOTransformer.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/ManualJournals/ManualJournalsBranchesValidator.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/ManualJournals/constants.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/Purchases/BillBranchesActivate.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/Purchases/PaymentMadeBranchesActivate.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/Purchases/VendorCreditBranchesActivate.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/Sales/CreditNoteBranchesActivate.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/Sales/PaymentReceiveBranchesActivate.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/Sales/SaleEstimatesBranchesActivate.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/Sales/SaleInvoiceBranchesActivate.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/Sales/SaleReceiptBranchesActivate.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/ValidateBranchExistance.ts create mode 100644 packages/server-nest/src/modules/Branches/integrations/constants.ts create mode 100644 packages/server-nest/src/modules/Branches/models/Branch.model.ts create mode 100644 packages/server-nest/src/modules/Branches/queries/GetBranch.service.ts create mode 100644 packages/server-nest/src/modules/Branches/queries/GetBranches.service.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Activate/CashflowBranchesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Activate/CreditNoteBranchesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Activate/ExpenseBranchesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Activate/PaymentMadeBranchesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Activate/PaymentReceiveBranchesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Activate/SaleEstiamtesBranchesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Activate/SaleInvoiceBranchesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Activate/SaleReceiptsBranchesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Activate/index.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/BillBranchSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/CashflowBranchDTOValidatorSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/ContactOpeningBalanceBranchSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/CreditNoteBranchesSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/CreditNoteRefundBranchSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/ExpenseBranchSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/InventoryAdjustmentBranchValidatorSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/InvoiceBranchValidatorSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/ManualJournalBranchSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/PaymentMadeBranchSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/PaymentReceiveBranchSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/SaleEstimateMultiBranchesSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/SaleReceiptBranchesSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/VendorCreditBranchSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/VendorCreditRefundBranchSubscriber.ts create mode 100644 packages/server-nest/src/modules/Branches/subscribers/Validators/index.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Activate/BillWarehousesActivate.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Activate/CreditNoteWarehousesActivate.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Activate/EstimateWarehousesActivate.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Activate/InventoryTransactionsWarehousesActivate.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Activate/InvoiceWarehousesActivate.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Activate/ReceiptWarehousesActivate.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Activate/VendorCreditWarehousesActivate.ts create mode 100644 packages/server-nest/src/modules/Warehouses/ActivateWarehousesSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/CRUDWarehouse.ts create mode 100644 packages/server-nest/src/modules/Warehouses/CreateInitialWarehousesitemsQuantity.ts create mode 100644 packages/server-nest/src/modules/Warehouses/EventsProvider.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Integrations/ValidateWarehouseExistance.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Integrations/WarehouseTransactionDTOTransform.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Integrations/WarehousesDTOValidators.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Integrations/WarehousesItemsQuantity.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Integrations/WarehousesItemsQuantitySynSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Integrations/WarehousesItemsQuantitySync.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Integrations/constants.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Items/GetItemWarehouses.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Items/GettItemWarehouseTransformer.ts create mode 100644 packages/server-nest/src/modules/Warehouses/UpdateInventoryTransactionsWithWarehouse.ts create mode 100644 packages/server-nest/src/modules/Warehouses/Warehouse.types.ts create mode 100644 packages/server-nest/src/modules/Warehouses/WarehousesApplication.service.ts create mode 100644 packages/server-nest/src/modules/Warehouses/WarehousesSettings.ts create mode 100644 packages/server-nest/src/modules/Warehouses/commands/ActivateWarehouses.ts create mode 100644 packages/server-nest/src/modules/Warehouses/commands/CreateInitialWarehouse.service.ts create mode 100644 packages/server-nest/src/modules/Warehouses/commands/CreateWarehouse.service.ts create mode 100644 packages/server-nest/src/modules/Warehouses/commands/DeleteItemWarehousesQuantity.ts create mode 100644 packages/server-nest/src/modules/Warehouses/commands/DeleteWarehouse.service.ts create mode 100644 packages/server-nest/src/modules/Warehouses/commands/EditWarehouse.service.ts create mode 100644 packages/server-nest/src/modules/Warehouses/commands/WarehouseMarkPrimary.service.ts create mode 100644 packages/server-nest/src/modules/Warehouses/commands/WarehouseValidator.service.ts create mode 100644 packages/server-nest/src/modules/Warehouses/contants.ts create mode 100644 packages/server-nest/src/modules/Warehouses/models/ItemWarehouseQuantity.ts create mode 100644 packages/server-nest/src/modules/Warehouses/models/Warehouse.model.ts create mode 100644 packages/server-nest/src/modules/Warehouses/queries/GetWarehouse.ts create mode 100644 packages/server-nest/src/modules/Warehouses/queries/GetWarehouses.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Activate/BillWarehousesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Activate/CreditNoteWarehousesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Activate/EstimateWarehousesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Activate/InventoryTransactionsWarehousesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Activate/InvoiceWarehousesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Activate/ReceiptWarehousesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Activate/VendorCreditWarehousesActivateSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Activate/index.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/DeleteItemWarehousesQuantitySubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Validators/InventoryAdjustment/InventoryAdjustmentWarehouseValidatorSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Validators/Purchases/BillWarehousesSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Validators/Purchases/VendorCreditWarehousesSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/CreditNoteWarehousesSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/SaleEstimateWarehousesSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/SaleInvoicesWarehousesSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/SaleReceiptWarehousesSubscriber.ts create mode 100644 packages/server-nest/src/modules/Warehouses/subscribers/Validators/index.ts diff --git a/packages/server-nest/src/modules/App/App.module.ts b/packages/server-nest/src/modules/App/App.module.ts index 95b81a983..2f4f05022 100644 --- a/packages/server-nest/src/modules/App/App.module.ts +++ b/packages/server-nest/src/modules/App/App.module.ts @@ -36,6 +36,7 @@ import { ExpensesModule } from '../Expenses/Expenses.module'; import { ItemCategoryModule } from '../ItemCategories/ItemCategory.module'; import { TaxRatesModule } from '../TaxRates/TaxRate.module'; import { PdfTemplatesModule } from '../PdfTemplate/PdfTemplates.module'; +import { BranchesModule } from '../Branches/Branches.module'; @Module({ imports: [ @@ -95,6 +96,7 @@ import { PdfTemplatesModule } from '../PdfTemplate/PdfTemplates.module'; ExpensesModule, TaxRatesModule, PdfTemplatesModule, + BranchesModule, ], controllers: [AppController], providers: [ diff --git a/packages/server-nest/src/modules/Branches/BranchIntegrationErrorsMiddleware.ts b/packages/server-nest/src/modules/Branches/BranchIntegrationErrorsMiddleware.ts new file mode 100644 index 000000000..ea43c54f5 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/BranchIntegrationErrorsMiddleware.ts @@ -0,0 +1,35 @@ +// import { Request, Response, NextFunction } from 'express'; +// import { ServiceError } from '@/exceptions'; + +// /** +// * Handles branches integration service errors. +// * @param {Error} error +// * @param {Request} req +// * @param {Response} res +// * @param {NextFunction} next +// */ +// export function BranchIntegrationErrorsMiddleware( +// error: Error, +// req: Request, +// res: Response, +// next: NextFunction +// ) { +// if (error instanceof ServiceError) { +// if (error.errorType === 'WAREHOUSE_ID_NOT_FOUND') { +// return res.boom.badRequest(null, { +// errors: [{ type: 'WAREHOUSE_ID_NOT_FOUND', code: 5000 }], +// }); +// } +// if (error.errorType === 'BRANCH_ID_REQUIRED') { +// return res.boom.badRequest(null, { +// errors: [{ type: 'BRANCH_ID_REQUIRED', code: 5100 }], +// }); +// } +// if (error.errorType === 'BRANCH_ID_NOT_FOUND') { +// return res.boom.badRequest(null, { +// errors: [{ type: 'BRANCH_ID_NOT_FOUND', code: 5300 }], +// }); +// } +// } +// next(error); +// } diff --git a/packages/server-nest/src/modules/Branches/Branches.controller.ts b/packages/server-nest/src/modules/Branches/Branches.controller.ts new file mode 100644 index 000000000..7b22da837 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/Branches.controller.ts @@ -0,0 +1,51 @@ +import { + Controller, + Get, + Post, + Put, + Delete, + Body, + Param, +} from '@nestjs/common'; +import { BranchesApplication } from './BranchesApplication.service'; +import { ICreateBranchDTO, IEditBranchDTO } from './Branches.types'; + +@Controller('branches') +export class BranchesController { + constructor(private readonly branchesApplication: BranchesApplication) {} + + @Get() + getBranches() { + // return this.branchesApplication.getBranches(); + } + + @Get(':id') + getBranch(@Param('id') id: string) { + return this.branchesApplication.getBranch(Number(id)); + } + + @Post() + createBranch(@Body() createBranchDTO: ICreateBranchDTO) { + return this.branchesApplication.createBranch(createBranchDTO); + } + + @Put(':id') + editBranch(@Param('id') id: string, @Body() editBranchDTO: IEditBranchDTO) { + return this.branchesApplication.editBranch(Number(id), editBranchDTO); + } + + @Delete(':id') + deleteBranch(@Param('id') id: string) { + return this.branchesApplication.deleteBranch(Number(id)); + } + + @Post('activate') + activateBranches() { + return this.branchesApplication.activateBranches(); + } + + @Put(':id/mark-as-primary') + markBranchAsPrimary(@Param('id') id: string) { + return this.branchesApplication.markBranchAsPrimary(Number(id)); + } +} diff --git a/packages/server-nest/src/modules/Branches/Branches.module.ts b/packages/server-nest/src/modules/Branches/Branches.module.ts new file mode 100644 index 000000000..d60a124d6 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/Branches.module.ts @@ -0,0 +1,31 @@ +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 { BranchesController } from './Branches.controller'; +import { CreateBranchService } from './commands/CreateBranch.service'; +import { DeleteBranchService } from './commands/DeleteBranch.service'; +import { EditBranchService } from './commands/EditBranch.service'; +import { MarkBranchAsPrimaryService } from './commands/MarkBranchAsPrimary.service'; +import { GetBranchService } from './queries/GetBranch.service'; +import { GetBranchesService } from './queries/GetBranches.service'; +import { ActivateBranches } from './commands/ActivateBranchesFeature.service'; +import { BranchesApplication } from './BranchesApplication.service'; + +@Module({ + imports: [TenancyDatabaseModule], + controllers: [BranchesController], + providers: [ + CreateBranchService, + EditBranchService, + DeleteBranchService, + GetBranchService, + GetBranchesService, + MarkBranchAsPrimaryService, + ActivateBranches, + BranchesApplication, + TenancyContext, + TransformerInjectable, + ], +}) +export class BranchesModule {} diff --git a/packages/server-nest/src/modules/Branches/Branches.types.ts b/packages/server-nest/src/modules/Branches/Branches.types.ts new file mode 100644 index 000000000..99a04d42c --- /dev/null +++ b/packages/server-nest/src/modules/Branches/Branches.types.ts @@ -0,0 +1,50 @@ +import { Knex } from 'knex'; + +export interface IBranch { + id?: number; +} + +export interface ICreateBranchDTO { + name: string; + code: string; + + primary?: boolean; +} +export interface IEditBranchDTO { + code: string; +} + +export interface IBranchCreatePayload { + tenantId: number; + createBranchDTO: ICreateBranchDTO; + trx: Knex.Transaction; +} +export interface IBranchCreatedPayload {} + +export interface IBranchEditPayload {} +export interface IBranchEditedPayload {} + +export interface IBranchDeletePayload {} +export interface IBranchDeletedPayload {} + +export interface IBranchesActivatePayload { + // tenantId: number; + trx: Knex.Transaction; +} +export interface IBranchesActivatedPayload { + // tenantId: number; + primaryBranch: IBranch; + trx: Knex.Transaction; +} + +export interface IBranchMarkAsPrimaryPayload { + // tenantId: number; + oldBranch: IBranch; + trx: Knex.Transaction; +} +export interface IBranchMarkedAsPrimaryPayload { + // tenantId: number; + oldBranch: IBranch; + markedBranch: IBranch; + trx: Knex.Transaction; +} diff --git a/packages/server-nest/src/modules/Branches/BranchesApplication.service.ts b/packages/server-nest/src/modules/Branches/BranchesApplication.service.ts new file mode 100644 index 000000000..f474eb7fd --- /dev/null +++ b/packages/server-nest/src/modules/Branches/BranchesApplication.service.ts @@ -0,0 +1,99 @@ +import { IBranch, ICreateBranchDTO, IEditBranchDTO } from './Branches.types'; +import { ActivateBranches } from './commands/ActivateBranchesFeature.service'; +import { + CreateBranchService, +} from './commands/CreateBranch.service'; +import { + DeleteBranchService, +} from './commands/DeleteBranch.service'; +import { EditBranchService } from './commands/EditBranch.service'; +import { GetBranchService } from './queries/GetBranch.service'; +import { GetBranchesService } from './queries/GetBranches.service'; +import { MarkBranchAsPrimaryService } from './commands/MarkBranchAsPrimary.service'; +import { Branch } from './models/Branch.model'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BranchesApplication { + constructor( + private readonly createBranchService: CreateBranchService, + private readonly editBranchService: EditBranchService, + private readonly deleteBranchService: DeleteBranchService, + private readonly getBranchService: GetBranchService, + private readonly getBranchesService: GetBranchesService, + private readonly activateBranchesService: ActivateBranches, + private readonly markBranchAsPrimaryService: MarkBranchAsPrimaryService, + ) {} + + /** + * Retrieves branches list. + * @param {number} tenantId + * @returns {IBranch} + */ + // public getBranches = (): Promise => { + // // return this.getBranchesService.getBranches(tenantId); + // }; + + /** + * Retrieves the given branch details. + * @param {number} branchId - Branch id. + * @returns {Promise} + */ + public getBranch = (branchId: number): Promise => { + return this.getBranchService.getBranch(branchId); + }; + + /** + * Creates a new branch. + * @param {number} tenantId - + * @param {ICreateBranchDTO} createBranchDTO + * @returns {Promise} + */ + public createBranch = ( + createBranchDTO: ICreateBranchDTO, + ): Promise => { + return this.createBranchService.createBranch(createBranchDTO); + }; + + /** + * Edits the given branch. + * @param {number} branchId - Branch id. + * @param {IEditBranchDTO} editBranchDTO - Edit branch DTO. + * @returns {Promise} + */ + public editBranch = ( + branchId: number, + editBranchDTO: IEditBranchDTO, + ): Promise => { + return this.editBranchService.editBranch(branchId, editBranchDTO); + }; + + /** + * Deletes the given branch. + * @param {number} branchId - Branch id. + * @returns {Promise} + */ + public deleteBranch = (branchId: number): Promise => { + return this.deleteBranchService.deleteBranch(branchId); + }; + + /** + * Activates the given branches. + * @returns {Promise} + */ + public activateBranches = (): Promise => { + return this.activateBranchesService.activateBranches(); + }; + + /** + * Marks the given branch as primary. + * @param {number} tenantId + * @param {number} branchId + * @returns {Promise} + */ + public markBranchAsPrimary = async ( + branchId: number, + ): Promise => { + return this.markBranchAsPrimaryService.markAsPrimary(branchId); + }; +} diff --git a/packages/server-nest/src/modules/Branches/BranchesSettings.ts b/packages/server-nest/src/modules/Branches/BranchesSettings.ts new file mode 100644 index 000000000..ee1d6c1b9 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/BranchesSettings.ts @@ -0,0 +1,29 @@ +import { Service, Inject } from 'typedi'; +import { Features } from '@/interfaces'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; + +@Service() +export class BranchesSettings { + @Inject() + private tenancy: HasTenancyService; + + /** + * Marks multi-branches as activated. + * @param {number} tenantId - + */ + public markMultiBranchesAsActivated = (tenantId: number) => { + const settings = this.tenancy.settings(tenantId); + + settings.set({ group: 'features', key: Features.BRANCHES, value: 1 }); + }; + + /** + * Retrieves whether multi-branches is active. + * @param {number} tenantId + */ + public isMultiBranchesActive = (tenantId: number) => { + const settings = this.tenancy.settings(tenantId); + + return settings.get({ group: 'features', key: Features.BRANCHES }); + }; +} diff --git a/packages/server-nest/src/modules/Branches/CRUDBranch.ts b/packages/server-nest/src/modules/Branches/CRUDBranch.ts new file mode 100644 index 000000000..bceee5134 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/CRUDBranch.ts @@ -0,0 +1,30 @@ +// import { Inject } from "typedi"; +// import { ServiceError } from "exceptions"; +// import HasTenancyService from "services/Tenancy/TenancyService"; +// import { ERRORS } from "./constants"; + +// export class CURDBranch { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * +// * @param branch +// */ +// throwIfBranchNotFound = (branch) => { +// if (!branch) { +// throw new ServiceError(ERRORS.BRANCH_NOT_FOUND); +// } +// } + +// getBranchOrThrowNotFound = async (tenantId: number, branchId: number) => { +// const { Branch } = this.tenancy.models(tenantId); + +// const foundBranch = await Branch.query().findById(branchId); + +// if (!foundBranch) { +// throw new ServiceError(ERRORS.BRANCH_NOT_FOUND); +// } +// return foundBranch; +// } +// } \ No newline at end of file diff --git a/packages/server-nest/src/modules/Branches/EventsProvider.ts b/packages/server-nest/src/modules/Branches/EventsProvider.ts new file mode 100644 index 000000000..6aec5fa85 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/EventsProvider.ts @@ -0,0 +1,50 @@ +// import { +// CreditNoteActivateBranchesSubscriber, +// PaymentReceiveActivateBranchesSubscriber, +// SaleEstimatesActivateBranchesSubscriber, +// SaleInvoicesActivateBranchesSubscriber, +// PaymentMadeActivateBranchesSubscriber, +// SaleReceiptsActivateBranchesSubscriber, +// } from './Subscribers/Activate'; +// import { +// BillBranchValidateSubscriber, +// VendorCreditBranchValidateSubscriber, +// PaymentMadeBranchValidateSubscriber, +// SaleEstimateBranchValidateSubscriber, +// CreditNoteBranchValidateSubscriber, +// ExpenseBranchValidateSubscriber, +// SaleReceiptBranchValidateSubscriber, +// ManualJournalBranchValidateSubscriber, +// PaymentReceiveBranchValidateSubscriber, +// CreditNoteRefundBranchValidateSubscriber, +// CashflowBranchDTOValidatorSubscriber, +// VendorCreditRefundBranchValidateSubscriber, +// InvoiceBranchValidateSubscriber, +// ContactBranchValidateSubscriber, +// InventoryAdjustmentBranchValidateSubscriber +// } from './Subscribers/Validators'; + +// export default () => [ +// BillBranchValidateSubscriber, +// CreditNoteBranchValidateSubscriber, +// ExpenseBranchValidateSubscriber, +// PaymentMadeBranchValidateSubscriber, +// SaleReceiptBranchValidateSubscriber, +// VendorCreditBranchValidateSubscriber, +// SaleEstimateBranchValidateSubscriber, +// ManualJournalBranchValidateSubscriber, +// PaymentReceiveBranchValidateSubscriber, +// CreditNoteRefundBranchValidateSubscriber, +// VendorCreditRefundBranchValidateSubscriber, + +// CreditNoteActivateBranchesSubscriber, +// PaymentReceiveActivateBranchesSubscriber, +// SaleEstimatesActivateBranchesSubscriber, +// SaleInvoicesActivateBranchesSubscriber, +// PaymentMadeActivateBranchesSubscriber, +// SaleReceiptsActivateBranchesSubscriber, +// CashflowBranchDTOValidatorSubscriber, +// InvoiceBranchValidateSubscriber, +// ContactBranchValidateSubscriber, +// InventoryAdjustmentBranchValidateSubscriber +// ]; diff --git a/packages/server-nest/src/modules/Branches/commands/ActivateBranchesFeature.service.ts b/packages/server-nest/src/modules/Branches/commands/ActivateBranchesFeature.service.ts new file mode 100644 index 000000000..a31060e90 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/commands/ActivateBranchesFeature.service.ts @@ -0,0 +1,80 @@ +import { Knex } from 'knex'; +import { Inject, Injectable } from '@nestjs/common'; +import { I18nService } from 'nestjs-i18n'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { ERRORS } from '../constants'; +import { + IBranchesActivatedPayload, + IBranchesActivatePayload, +} from '../Branches.types'; +import { CreateBranchService } from './CreateBranch.service'; +import { BranchesSettings } from '../BranchesSettings'; +import { ServiceError } from '@/modules/Items/ServiceError'; +import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; +import { Branch } from '../models/Branch.model'; +import { events } from '@/common/events/events'; + +@Injectable() +export class ActivateBranches { + constructor( + private readonly uow: UnitOfWork, + private readonly eventPublisher: EventEmitter2, + private readonly createBranch: CreateBranchService, + private readonly branchesSettings: BranchesSettings, + private readonly i18n: I18nService, + + @Inject(Branch.name) + private readonly branchModel: typeof Branch, + ) {} + + /** + * Throws service error if multi-branches feature is already activated. + */ + private throwIfMultiBranchesActivated = (isActivated: boolean) => { + if (isActivated) { + throw new ServiceError(ERRORS.MUTLI_BRANCHES_ALREADY_ACTIVATED); + } + }; + + /** + * Creates a new initial branch. + */ + private createInitialBranch = () => { + return this.createBranch.createBranch({ + name: this.i18n.t('branches.head_branch'), + code: '10001', + primary: true, + }); + }; + + /** + * Activate multi-branches feature. + * @returns {Promise} + */ + public activateBranches = (): Promise => { + const isActivated = this.branchesSettings.isMultiBranchesActive(); + + // Throw error if mutli-branches is already activated. + this.throwIfMultiBranchesActivated(isActivated); + + // Activate multi-branches under unit-of-work environment. + return this.uow.withTransaction(async (trx: Knex.Transaction) => { + // Triggers `onBranchActivate` branch. + await this.eventPublisher.emitAsync(events.branch.onActivate, { + trx, + } as IBranchesActivatePayload); + + // Create a new branch as primary branch. + const primaryBranch = await this.createInitialBranch(); + + // Mark the mutli-branches is activated. + await this.branchesSettings.markMultiBranchesAsActivated(); + + // Triggers `onBranchActivated` branch. + await this.eventPublisher.emitAsync(events.branch.onActivated, { + primaryBranch, + trx, + } as IBranchesActivatedPayload); + }); + }; +} diff --git a/packages/server-nest/src/modules/Branches/commands/BranchCommandValidator.service.ts b/packages/server-nest/src/modules/Branches/commands/BranchCommandValidator.service.ts new file mode 100644 index 000000000..b23845414 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/commands/BranchCommandValidator.service.ts @@ -0,0 +1,50 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { ERRORS } from '../constants'; +import { Branch } from '../models/Branch.model'; + +import { ServiceError } from '../../Items/ServiceError'; +@Injectable() +export class BranchCommandValidator { + constructor( + @Inject(Branch.name) + private readonly branchModel: typeof Branch, + ) {} + + /** + * Validates the given branch whether is not only warehouse. + * @param {number} branchId + */ + public validateBranchNotOnlyWarehouse = async (branchId: number) => { + const warehouses = await this.branchModel.query().whereNot('id', branchId); + + if (warehouses.length === 0) { + throw new ServiceError(ERRORS.COULD_NOT_DELETE_ONLY_BRANCH); + } + }; + + /** + * Validates the given branch whether is unique. + * @param {string} code - Branch code. + * @param {number} exceptBranchId - Branch id to except. + */ + public validateBranchCodeUnique = async ( + code: string, + exceptBranchId?: number, + ): Promise => { + const branch = await this.branchModel + .query() + .onBuild((query) => { + query.select(['id']); + query.where('code', code); + + if (exceptBranchId) { + query.whereNot('id', exceptBranchId); + } + }) + .first(); + + if (branch) { + throw new ServiceError(ERRORS.BRANCH_CODE_NOT_UNIQUE); + } + }; +} diff --git a/packages/server-nest/src/modules/Branches/commands/CreateBranch.service.ts b/packages/server-nest/src/modules/Branches/commands/CreateBranch.service.ts new file mode 100644 index 000000000..140994177 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/commands/CreateBranch.service.ts @@ -0,0 +1,55 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Knex } from 'knex'; +import { + IBranchCreatedPayload, + IBranchCreatePayload, + ICreateBranchDTO, +} from '../Branches.types'; +import { BranchCommandValidator } from './BranchCommandValidator.service'; +import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { Branch } from '../models/Branch.model'; +import { events } from '@/common/events/events'; + +@Injectable() +export class CreateBranchService { + constructor( + private readonly uow: UnitOfWork, + private readonly eventPublisher: EventEmitter2, + private readonly validator: BranchCommandValidator, + + @Inject(Branch.name) + private readonly branchModel: typeof Branch, + ) {} + + /** + * Creates a new branch. + * @param {ICreateBranchDTO} createBranchDTO + * @returns {Promise} + */ + public createBranch = async ( + createBranchDTO: ICreateBranchDTO, + ): Promise => { + // Creates a new branch under unit-of-work. + return this.uow.withTransaction(async (trx: Knex.Transaction) => { + // Triggers `onBranchCreate` event. + await this.eventPublisher.emitAsync(events.warehouse.onEdit, { + createBranchDTO, + trx, + } as IBranchCreatePayload); + + const branch = await this.branchModel.query().insertAndFetch({ + ...createBranchDTO, + }); + + // Triggers `onBranchCreated` event. + await this.eventPublisher.emitAsync(events.warehouse.onEdited, { + createBranchDTO, + branch, + trx, + } as IBranchCreatedPayload); + + return branch; + }); + }; +} diff --git a/packages/server-nest/src/modules/Branches/commands/DeleteBranch.service.ts b/packages/server-nest/src/modules/Branches/commands/DeleteBranch.service.ts new file mode 100644 index 000000000..e55bb70f2 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/commands/DeleteBranch.service.ts @@ -0,0 +1,65 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Knex } from 'knex'; +import { IBranchDeletedPayload, IBranchDeletePayload } from './Branch.types'; +import { BranchCommandValidator } from './BranchCommandValidator.service'; +import { ERRORS } from '../constants'; +import { Branch } from '../models/Branch.model'; +import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { events } from '@/common/events/events'; + +@Injectable() +export class DeleteBranchService { + constructor( + @Inject(Branch.name) + private readonly branchModel: typeof Branch, + private readonly uow: UnitOfWork, + private readonly eventPublisher: EventEmitter2, + private readonly validator: BranchCommandValidator, + ) {} + + /** + * Validates the branch deleting. + * @param {number} branchId + * @returns {Promise} + */ + private authorize = async (branchId: number): Promise => { + await this.validator.validateBranchNotOnlyWarehouse(branchId); + }; + + /** + * Deletes branch. + * @param {number} branchId + * @returns {Promise} + */ + public deleteBranch = async (branchId: number): Promise => { + // Retrieves the old branch or throw not found service error. + const oldBranch = await this.branchModel + .query() + .findById(branchId) + .throwIfNotFound() + .queryAndThrowIfHasRelations({ + type: ERRORS.BRANCH_HAS_ASSOCIATED_TRANSACTIONS, + }); + + // Authorize the branch before deleting. + await this.authorize(branchId); + + // Deletes branch under unit-of-work. + return this.uow.withTransaction(async (trx: Knex.Transaction) => { + // Triggers `onBranchCreate` event. + await this.eventPublisher.emitAsync(events.warehouse.onEdit, { + oldBranch, + trx, + } as IBranchDeletePayload); + + await this.branchModel.query().findById(branchId).delete(); + + // Triggers `onBranchCreate` event. + await this.eventPublisher.emitAsync(events.warehouse.onEdited, { + oldBranch, + trx, + } as IBranchDeletedPayload); + }); + }; +} diff --git a/packages/server-nest/src/modules/Branches/commands/EditBranch.service.ts b/packages/server-nest/src/modules/Branches/commands/EditBranch.service.ts new file mode 100644 index 000000000..fc430dd01 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/commands/EditBranch.service.ts @@ -0,0 +1,61 @@ +import { Injectable } from '@nestjs/common'; +import { Knex } from 'knex'; +import { + IBranchEditedPayload, + IBranchEditPayload, + IEditBranchDTO, +} from '../Branches.types'; +import { Branch } from '../models/Branch.model'; +import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { events } from '@/common/events/events'; + +@Injectable() +export class EditBranchService { + constructor( + private readonly branchModel: typeof Branch, + private readonly uow: UnitOfWork, + private readonly eventPublisher: EventEmitter2, + ) {} + + /** + * Edits branch. + * @param {number} branchId - Branch id. + * @param {IEditBranchDTO} editBranchDTO - Edit branch data. + */ + public editBranch = async ( + branchId: number, + editBranchDTO: IEditBranchDTO, + ) => { + // Retrieves the old branch or throw not found service error. + const oldBranch = await this.branchModel + .query() + .findById(branchId) + .throwIfNotFound(); + + // Deletes branch under unit-of-work. + return this.uow.withTransaction(async (trx: Knex.Transaction) => { + // Triggers `onBranchEdit` event. + await this.eventPublisher.emitAsync(events.warehouse.onEdit, { + oldBranch, + trx, + } as IBranchEditPayload); + + // Edits the branch on the storage. + const branch = await this.branchModel + .query() + .patchAndFetchById(branchId, { + ...editBranchDTO, + }); + + // Triggers `onBranchEdited` event. + await this.eventPublisher.emitAsync(events.warehouse.onEdited, { + oldBranch, + branch, + trx, + } as IBranchEditedPayload); + + return branch; + }); + }; +} diff --git a/packages/server-nest/src/modules/Branches/commands/MarkBranchAsPrimary.service.ts b/packages/server-nest/src/modules/Branches/commands/MarkBranchAsPrimary.service.ts new file mode 100644 index 000000000..be68aebef --- /dev/null +++ b/packages/server-nest/src/modules/Branches/commands/MarkBranchAsPrimary.service.ts @@ -0,0 +1,62 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Knex } from 'knex'; +import { + IBranchMarkAsPrimaryPayload, + IBranchMarkedAsPrimaryPayload, +} from '../Branches.types'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service'; +import { Branch } from '../models/Branch.model'; +import { events } from '@/common/events/events'; + +@Injectable() +export class MarkBranchAsPrimaryService { + constructor( + private readonly uow: UnitOfWork, + private readonly eventPublisher: EventEmitter2, + + @Inject(Branch.name) + private readonly branchModel: typeof Branch, + ) {} + + /** + * Marks the given branch as primary. + * @param {number} branchId + * @returns {Promise} + */ + public async markAsPrimary(branchId: number): Promise { + // Retrieves the old branch or throw not found service error. + const oldBranch = await this.branchModel + .query() + .findById(branchId) + .throwIfNotFound(); + + // Updates the branches under unit-of-work environment. + return this.uow.withTransaction(async (trx: Knex.Transaction) => { + // Triggers `onBranchMarkPrimary` event. + await this.eventPublisher.emitAsync(events.branch.onMarkPrimary, { + oldBranch, + trx, + } as IBranchMarkAsPrimaryPayload); + + // Updates all branches as not primary. + await this.branchModel.query(trx).update({ primary: false }); + + // Updates the given branch as primary. + const markedBranch = await this.branchModel + .query(trx) + .patchAndFetchById(branchId, { + primary: true, + }); + + // Triggers `onBranchMarkedPrimary` event. + await this.eventPublisher.emitAsync(events.branch.onMarkedPrimary, { + markedBranch, + oldBranch, + trx, + } as IBranchMarkedAsPrimaryPayload); + + return markedBranch; + }); + } +} diff --git a/packages/server-nest/src/modules/Branches/constants.ts b/packages/server-nest/src/modules/Branches/constants.ts new file mode 100644 index 000000000..e0d80f876 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/constants.ts @@ -0,0 +1,7 @@ +export const ERRORS = { + BRANCH_NOT_FOUND: 'BRANCH_NOT_FOUND', + MUTLI_BRANCHES_ALREADY_ACTIVATED: 'MUTLI_BRANCHES_ALREADY_ACTIVATED', + COULD_NOT_DELETE_ONLY_BRANCH: 'COULD_NOT_DELETE_ONLY_BRANCH', + BRANCH_CODE_NOT_UNIQUE: 'BRANCH_CODE_NOT_UNIQUE', + BRANCH_HAS_ASSOCIATED_TRANSACTIONS: 'BRANCH_HAS_ASSOCIATED_TRANSACTIONS' +}; diff --git a/packages/server-nest/src/modules/Branches/integrations/BranchTransactionDTOTransform.ts b/packages/server-nest/src/modules/Branches/integrations/BranchTransactionDTOTransform.ts new file mode 100644 index 000000000..97c3329bc --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/BranchTransactionDTOTransform.ts @@ -0,0 +1,35 @@ +// import { Service, Inject } from 'typedi'; +// import { omit } from 'lodash'; +// import { BranchesSettings } from '../BranchesSettings'; + +// @Service() +// export class BranchTransactionDTOTransform { +// @Inject() +// branchesSettings: BranchesSettings; + +// /** +// * Excludes DTO branch id when mutli-warehouses feature is inactive. +// * @param {number} tenantId +// * @returns {any} +// */ +// private excludeDTOBranchIdWhenInactive = ( +// tenantId: number, +// DTO: T +// ): Omit | T => { +// const isActive = this.branchesSettings.isMultiBranchesActive(tenantId); + +// return !isActive ? omit(DTO, ['branchId']) : DTO; +// }; + +// /** +// * Transformes the input DTO for branches feature. +// * @param {number} tenantId - +// * @param {T} DTO - +// * @returns {Omit | T} +// */ +// public transformDTO = +// (tenantId: number) => +// (DTO: T): Omit | T => { +// return this.excludeDTOBranchIdWhenInactive(tenantId, DTO); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/Cashflow/CashflowActivateBranches.ts b/packages/server-nest/src/modules/Branches/integrations/Cashflow/CashflowActivateBranches.ts new file mode 100644 index 000000000..a3479673a --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/Cashflow/CashflowActivateBranches.ts @@ -0,0 +1,26 @@ +// import { Service, Inject } from 'typedi'; +// import { Knex } from 'knex'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// @Service() +// export class CashflowTransactionsActivateBranches { +// @Inject() +// private tenancy: HasTenancyService; + +// /** +// * Updates all cashflow transactions with the primary branch. +// * @param {number} tenantId +// * @param {number} primaryBranchId +// * @returns {Promise} +// */ +// public updateCashflowTransactionsWithBranch = async ( +// tenantId: number, +// primaryBranchId: number, +// trx?: Knex.Transaction +// ) => { +// const { CashflowTransaction } = this.tenancy.models(tenantId); + +// // Updates the cashflow transactions with primary branch. +// await CashflowTransaction.query(trx).update({ branchId: primaryBranchId }); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/Expense/ExpensesActivateBranches.ts b/packages/server-nest/src/modules/Branches/integrations/Expense/ExpensesActivateBranches.ts new file mode 100644 index 000000000..eb3af6cc6 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/Expense/ExpensesActivateBranches.ts @@ -0,0 +1,26 @@ +// import { Service, Inject } from 'typedi'; +// import { Knex } from 'knex'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// @Service() +// export class ExpensesActivateBranches { +// @Inject() +// private tenancy: HasTenancyService; + +// /** +// * Updates all expenses transactions with the primary branch. +// * @param {number} tenantId +// * @param {number} primaryBranchId +// * @returns {Promise} +// */ +// public updateExpensesWithBranch = async ( +// tenantId: number, +// primaryBranchId: number, +// trx?: Knex.Transaction +// ) => { +// const { Expense } = this.tenancy.models(tenantId); + +// // Updates the expenses with primary branch. +// await Expense.query(trx).update({ branchId: primaryBranchId }); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/ManualJournals/ManualJournalBranchesActivate.ts b/packages/server-nest/src/modules/Branches/integrations/ManualJournals/ManualJournalBranchesActivate.ts new file mode 100644 index 000000000..be145de2e --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/ManualJournals/ManualJournalBranchesActivate.ts @@ -0,0 +1,26 @@ +// import { Service, Inject } from 'typedi'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; +// import { Knex } from 'knex'; + +// @Service() +// export class ManualJournalsActivateBranches { +// @Inject() +// private tenancy: HasTenancyService; + +// /** +// * Updates all manual journals transactions with the primary branch. +// * @param {number} tenantId +// * @param {number} primaryBranchId +// * @returns {Promise} +// */ +// public updateManualJournalsWithBranch = async ( +// tenantId: number, +// primaryBranchId: number, +// trx?: Knex.Transaction +// ) => { +// const { ManualJournal } = this.tenancy.models(tenantId); + +// // Updates the manual journal with primary branch. +// await ManualJournal.query(trx).update({ branchId: primaryBranchId }); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/ManualJournals/ManualJournalDTOTransformer.ts b/packages/server-nest/src/modules/Branches/integrations/ManualJournals/ManualJournalDTOTransformer.ts new file mode 100644 index 000000000..37c89e722 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/ManualJournals/ManualJournalDTOTransformer.ts @@ -0,0 +1,32 @@ +// import { omit } from 'lodash'; +// import { Inject, Service } from 'typedi'; +// import { IManualJournal } from '@/interfaces'; +// import { BranchesSettings } from '../../BranchesSettings'; + +// @Service() +// export class ManualJournalBranchesDTOTransformer { +// @Inject() +// branchesSettings: BranchesSettings; + +// private excludeDTOBranchIdWhenInactive = ( +// tenantId: number, +// DTO: IManualJournal +// ): IManualJournal => { +// const isActive = this.branchesSettings.isMultiBranchesActive(tenantId); + +// if (isActive) return DTO; + +// return { +// ...DTO, +// entries: DTO.entries.map((e) => omit(e, ['branchId'])), +// }; +// }; +// /** +// * +// */ +// public transformDTO = +// (tenantId: number) => +// (DTO: IManualJournal): IManualJournal => { +// return this.excludeDTOBranchIdWhenInactive(tenantId, DTO); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/ManualJournals/ManualJournalsBranchesValidator.ts b/packages/server-nest/src/modules/Branches/integrations/ManualJournals/ManualJournalsBranchesValidator.ts new file mode 100644 index 000000000..26601344c --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/ManualJournals/ManualJournalsBranchesValidator.ts @@ -0,0 +1,23 @@ +// import { Service, Inject } from 'typedi'; +// import { ServiceError } from '@/exceptions'; +// import { IManualJournalDTO, IManualJournalEntryDTO } from '@/interfaces'; +// import { ERRORS } from './constants'; + +// @Service() +// export class ManualJournalBranchesValidator { +// /** +// * Validates the DTO entries should have branch id. +// * @param {IManualJournalDTO} manualJournalDTO +// */ +// public validateEntriesHasBranchId = async ( +// manualJournalDTO: IManualJournalDTO +// ) => { +// const hasNoIdEntries = manualJournalDTO.entries.filter( +// (entry: IManualJournalEntryDTO) => +// !entry.branchId && !manualJournalDTO.branchId +// ); +// if (hasNoIdEntries.length > 0) { +// throw new ServiceError(ERRORS.MANUAL_JOURNAL_ENTRIES_HAVE_NO_BRANCH_ID); +// } +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/ManualJournals/constants.ts b/packages/server-nest/src/modules/Branches/integrations/ManualJournals/constants.ts new file mode 100644 index 000000000..46e4327e5 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/ManualJournals/constants.ts @@ -0,0 +1,4 @@ +export const ERRORS = { + MANUAL_JOURNAL_ENTRIES_HAVE_NO_BRANCH_ID: + 'MANUAL_JOURNAL_ENTRIES_HAVE_NO_BRANCH_ID', +}; diff --git a/packages/server-nest/src/modules/Branches/integrations/Purchases/BillBranchesActivate.ts b/packages/server-nest/src/modules/Branches/integrations/Purchases/BillBranchesActivate.ts new file mode 100644 index 000000000..43ca23a88 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/Purchases/BillBranchesActivate.ts @@ -0,0 +1,26 @@ +// import { Service, Inject } from 'typedi'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; +// import { Knex } from 'knex'; + +// @Service() +// export class BillActivateBranches { +// @Inject() +// private tenancy: HasTenancyService; + +// /** +// * Updates all bills transactions with the primary branch. +// * @param {number} tenantId +// * @param {number} primaryBranchId +// * @returns {Promise} +// */ +// public updateBillsWithBranch = async ( +// tenantId: number, +// primaryBranchId: number, +// trx?: Knex.Transaction +// ) => { +// const { Bill } = this.tenancy.models(tenantId); + +// // Updates the sale invoice with primary branch. +// await Bill.query(trx).update({ branchId: primaryBranchId }); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/Purchases/PaymentMadeBranchesActivate.ts b/packages/server-nest/src/modules/Branches/integrations/Purchases/PaymentMadeBranchesActivate.ts new file mode 100644 index 000000000..c21553ac9 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/Purchases/PaymentMadeBranchesActivate.ts @@ -0,0 +1,26 @@ +// import { Service, Inject } from 'typedi'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; +// import { Knex } from 'knex'; + +// @Service() +// export class BillPaymentsActivateBranches { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all bills payments transcations with the primary branch. +// * @param {number} tenantId +// * @param {number} primaryBranchId +// * @returns {Promise} +// */ +// public updateBillPaymentsWithBranch = async ( +// tenantId: number, +// primaryBranchId: number, +// trx?: Knex.Transaction +// ) => { +// const { BillPayment } = this.tenancy.models(tenantId); + +// // Updates the bill payments with primary branch. +// await BillPayment.query(trx).update({ branchId: primaryBranchId }); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/Purchases/VendorCreditBranchesActivate.ts b/packages/server-nest/src/modules/Branches/integrations/Purchases/VendorCreditBranchesActivate.ts new file mode 100644 index 000000000..d50e2bc24 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/Purchases/VendorCreditBranchesActivate.ts @@ -0,0 +1,26 @@ +// import { Service, Inject } from 'typedi'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; +// import { Knex } from 'knex'; + +// @Service() +// export class VendorCreditActivateBranches { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all vendor credits transcations with the primary branch. +// * @param {number} tenantId +// * @param {number} primaryBranchId +// * @returns {Promise} +// */ +// public updateVendorCreditsWithBranch = async ( +// tenantId: number, +// primaryBranchId: number, +// trx?: Knex.Transaction +// ) => { +// const { VendorCredit } = this.tenancy.models(tenantId); + +// // Updates the vendors credits with primary branch. +// await VendorCredit.query(trx).update({ branchId: primaryBranchId }); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/Sales/CreditNoteBranchesActivate.ts b/packages/server-nest/src/modules/Branches/integrations/Sales/CreditNoteBranchesActivate.ts new file mode 100644 index 000000000..3997a495d --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/Sales/CreditNoteBranchesActivate.ts @@ -0,0 +1,26 @@ +// import { Service, Inject } from 'typedi'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; +// import { Knex } from 'knex'; + +// @Service() +// export class CreditNoteActivateBranches { +// @Inject() +// private tenancy: HasTenancyService; + +// /** +// * Updates all creidt notes transactions with the primary branch. +// * @param {number} tenantId +// * @param {number} primaryBranchId +// * @returns {Promise} +// */ +// public updateCreditsWithBranch = async ( +// tenantId: number, +// primaryBranchId: number, +// trx?: Knex.Transaction +// ) => { +// const { CreditNote } = this.tenancy.models(tenantId); + +// // Updates the sale invoice with primary branch. +// await CreditNote.query(trx).update({ branchId: primaryBranchId }); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/Sales/PaymentReceiveBranchesActivate.ts b/packages/server-nest/src/modules/Branches/integrations/Sales/PaymentReceiveBranchesActivate.ts new file mode 100644 index 000000000..8ef28913f --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/Sales/PaymentReceiveBranchesActivate.ts @@ -0,0 +1,26 @@ +// import { Service, Inject } from 'typedi'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; +// import { Knex } from 'knex'; + +// @Service() +// export class PaymentReceiveActivateBranches { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all creidt notes transactions with the primary branch. +// * @param {number} tenantId +// * @param {number} primaryBranchId +// * @returns {Promise} +// */ +// public updatePaymentsWithBranch = async ( +// tenantId: number, +// primaryBranchId: number, +// trx?: Knex.Transaction +// ) => { +// const { PaymentReceive } = this.tenancy.models(tenantId); + +// // Updates the sale invoice with primary branch. +// await PaymentReceive.query(trx).update({ branchId: primaryBranchId }); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/Sales/SaleEstimatesBranchesActivate.ts b/packages/server-nest/src/modules/Branches/integrations/Sales/SaleEstimatesBranchesActivate.ts new file mode 100644 index 000000000..3765d36fd --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/Sales/SaleEstimatesBranchesActivate.ts @@ -0,0 +1,26 @@ +// import { Service, Inject } from 'typedi'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; +// import { Knex } from 'knex'; + +// @Service() +// export class SaleEstimateActivateBranches { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all sale estimates transactions with the primary branch. +// * @param {number} tenantId +// * @param {number} primaryBranchId +// * @returns {Promise} +// */ +// public updateEstimatesWithBranch = async ( +// tenantId: number, +// primaryBranchId: number, +// trx?: Knex.Transaction +// ) => { +// const { PaymentReceive } = this.tenancy.models(tenantId); + +// // Updates the sale invoice with primary branch. +// await PaymentReceive.query(trx).update({ branchId: primaryBranchId }); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/Sales/SaleInvoiceBranchesActivate.ts b/packages/server-nest/src/modules/Branches/integrations/Sales/SaleInvoiceBranchesActivate.ts new file mode 100644 index 000000000..c609a3e06 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/Sales/SaleInvoiceBranchesActivate.ts @@ -0,0 +1,26 @@ +// import { Service, Inject } from 'typedi'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; +// import { Knex } from 'knex'; + +// @Service() +// export class SaleInvoiceActivateBranches { +// @Inject() +// private tenancy: HasTenancyService; + +// /** +// * Updates all sale invoices transactions with the primary branch. +// * @param {number} tenantId +// * @param {number} primaryBranchId +// * @returns {Promise} +// */ +// public updateInvoicesWithBranch = async ( +// tenantId: number, +// primaryBranchId: number, +// trx?: Knex.Transaction +// ) => { +// const { SaleInvoice } = this.tenancy.models(tenantId); + +// // Updates the sale invoice with primary branch. +// await SaleInvoice.query(trx).update({ branchId: primaryBranchId }); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/Sales/SaleReceiptBranchesActivate.ts b/packages/server-nest/src/modules/Branches/integrations/Sales/SaleReceiptBranchesActivate.ts new file mode 100644 index 000000000..40f486865 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/Sales/SaleReceiptBranchesActivate.ts @@ -0,0 +1,26 @@ +// import { Service, Inject } from 'typedi'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; +// import { Knex } from 'knex'; + +// @Service() +// export class SaleReceiptActivateBranches { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all sale receipts transactions with the primary branch. +// * @param {number} tenantId +// * @param {number} primaryBranchId +// * @returns {Promise} +// */ +// public updateReceiptsWithBranch = async ( +// tenantId: number, +// primaryBranchId: number, +// trx?: Knex.Transaction +// ) => { +// const { SaleReceipt } = this.tenancy.models(tenantId); + +// // Updates the sale receipt with primary branch. +// await SaleReceipt.query(trx).update({ branchId: primaryBranchId }); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/ValidateBranchExistance.ts b/packages/server-nest/src/modules/Branches/integrations/ValidateBranchExistance.ts new file mode 100644 index 000000000..85c931213 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/ValidateBranchExistance.ts @@ -0,0 +1,75 @@ +// import { ServiceError } from '@/exceptions'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; +// import { Service, Inject } from 'typedi'; +// import { BranchesSettings } from '../BranchesSettings'; +// import { ERRORS } from './constants'; + +// @Service() +// export class ValidateBranchExistance { +// @Inject() +// tenancy: HasTenancyService; + +// @Inject() +// branchesSettings: BranchesSettings; + +// /** +// * Validate transaction branch id when the feature is active. +// * @param {number} tenantId +// * @param {number} branchId +// * @returns {Promise} +// */ +// public validateTransactionBranchWhenActive = async ( +// tenantId: number, +// branchId: number | null +// ) => { +// const isActive = this.branchesSettings.isMultiBranchesActive(tenantId); + +// // Can't continue if the multi-warehouses feature is inactive. +// if (!isActive) return; + +// return this.validateTransactionBranch(tenantId, branchId); +// }; + +// /** +// * Validate transaction branch id existance. +// * @param {number} tenantId +// * @param {number} branchId +// * @return {Promise} +// */ +// public validateTransactionBranch = async ( +// tenantId: number, +// branchId: number | null +// ) => { +// this.validateBranchIdExistance(branchId); + +// await this.validateBranchExistance(tenantId, branchId); +// }; + +// /** +// * +// * @param branchId +// */ +// public validateBranchIdExistance = (branchId: number | null) => { +// if (!branchId) { +// throw new ServiceError(ERRORS.BRANCH_ID_REQUIRED); +// } +// }; + +// /** +// * +// * @param tenantId +// * @param branchId +// */ +// public validateBranchExistance = async ( +// tenantId: number, +// branchId: number +// ) => { +// const { Branch } = this.tenancy.models(tenantId); + +// const branch = await Branch.query().findById(branchId); + +// if (!branch) { +// throw new ServiceError(ERRORS.BRANCH_ID_NOT_FOUND); +// } +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/integrations/constants.ts b/packages/server-nest/src/modules/Branches/integrations/constants.ts new file mode 100644 index 000000000..af66f6dae --- /dev/null +++ b/packages/server-nest/src/modules/Branches/integrations/constants.ts @@ -0,0 +1,6 @@ + + +export const ERRORS = { + BRANCH_ID_REQUIRED: 'BRANCH_ID_REQUIRED', + BRANCH_ID_NOT_FOUND: 'BRANCH_ID_NOT_FOUND' +} \ No newline at end of file diff --git a/packages/server-nest/src/modules/Branches/models/Branch.model.ts b/packages/server-nest/src/modules/Branches/models/Branch.model.ts new file mode 100644 index 000000000..a85dc7104 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/models/Branch.model.ts @@ -0,0 +1,192 @@ +import { Model, mixin } from 'objection'; +import TenantModel from 'models/TenantModel'; +import BranchMetadata from './Branch.settings'; +import ModelSetting from './ModelSetting'; +import { BaseModel } from '@/models/Model'; + +export class Branch extends BaseModel{ + name!: string; + code!: string; + address!: string; + city!: string; + country!: string; + phoneNumber!: string; + email!: string; + website!: string; + primary!: boolean; + + /** + * Table name. + */ + static get tableName() { + return 'branches'; + } + + /** + * Timestamps columns. + */ + get timestamps() { + return ['created_at', 'updated_at']; + } + + /** + * Model modifiers. + */ + static get modifiers() { + return { + /** + * Filters accounts by the given ids. + * @param {Query} query + * @param {number[]} accountsIds + */ + isPrimary(query) { + query.where('primary', true); + }, + }; + } + + /** + * Relationship mapping. + */ + // static get relationMappings() { + // const SaleInvoice = require('models/SaleInvoice'); + // const SaleEstimate = require('models/SaleEstimate'); + // const SaleReceipt = require('models/SaleReceipt'); + // const Bill = require('models/Bill'); + // const PaymentReceive = require('models/PaymentReceive'); + // const PaymentMade = require('models/BillPayment'); + // const VendorCredit = require('models/VendorCredit'); + // const CreditNote = require('models/CreditNote'); + // const AccountTransaction = require('models/AccountTransaction'); + // const InventoryTransaction = require('models/InventoryTransaction'); + + // return { + // /** + // * Branch may belongs to associated sale invoices. + // */ + // invoices: { + // relation: Model.HasManyRelation, + // modelClass: SaleInvoice.default, + // join: { + // from: 'branches.id', + // to: 'sales_invoices.branchId', + // }, + // }, + + // /** + // * Branch may belongs to associated sale estimates. + // */ + // estimates: { + // relation: Model.HasManyRelation, + // modelClass: SaleEstimate.default, + // join: { + // from: 'branches.id', + // to: 'sales_estimates.branchId', + // }, + // }, + + // /** + // * Branch may belongs to associated sale receipts. + // */ + // receipts: { + // relation: Model.HasManyRelation, + // modelClass: SaleReceipt.default, + // join: { + // from: 'branches.id', + // to: 'sales_receipts.branchId', + // }, + // }, + + // /** + // * Branch may belongs to associated payment receives. + // */ + // paymentReceives: { + // relation: Model.HasManyRelation, + // modelClass: PaymentReceive.default, + // join: { + // from: 'branches.id', + // to: 'payment_receives.branchId', + // }, + // }, + + // /** + // * Branch may belongs to associated bills. + // */ + // bills: { + // relation: Model.HasManyRelation, + // modelClass: Bill.default, + // join: { + // from: 'branches.id', + // to: 'bills.branchId', + // }, + // }, + + // /** + // * Branch may belongs to associated payment mades. + // */ + // paymentMades: { + // relation: Model.HasManyRelation, + // modelClass: PaymentMade.default, + // join: { + // from: 'branches.id', + // to: 'bills_payments.branchId', + // }, + // }, + + // /** + // * Branch may belongs to associated credit notes. + // */ + // creditNotes: { + // relation: Model.HasManyRelation, + // modelClass: CreditNote.default, + // join: { + // from: 'branches.id', + // to: 'credit_notes.branchId', + // }, + // }, + + // /** + // * Branch may belongs to associated to vendor credits. + // */ + // vendorCredit: { + // relation: Model.HasManyRelation, + // modelClass: VendorCredit.default, + // join: { + // from: 'branches.id', + // to: 'vendor_credits.branchId', + // }, + // }, + + // /** + // * Branch may belongs to associated to accounts transactions. + // */ + // accountsTransactions: { + // relation: Model.HasManyRelation, + // modelClass: AccountTransaction.default, + // join: { + // from: 'branches.id', + // to: 'accounts_transactions.branchId', + // }, + // }, + + // /** + // * Branch may belongs to associated to inventory transactions. + // */ + // inventoryTransactions: { + // relation: Model.HasManyRelation, + // modelClass: InventoryTransaction.default, + // join: { + // from: 'branches.id', + // to: 'inventory_transactions.branchId', + // }, + // }, + // }; + // } + + /** + * Model settings. + */ + static get meta() { + return BranchMetadata; + } +} diff --git a/packages/server-nest/src/modules/Branches/queries/GetBranch.service.ts b/packages/server-nest/src/modules/Branches/queries/GetBranch.service.ts new file mode 100644 index 000000000..7e123a4be --- /dev/null +++ b/packages/server-nest/src/modules/Branches/queries/GetBranch.service.ts @@ -0,0 +1,25 @@ +import { Inject } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; +import { Branch } from '../models/Branch.model'; + +@Injectable() +export class GetBranchService { + constructor( + @Inject(Branch.name) + private readonly branch: typeof Branch, + ) {} + + /** + * Retrieves the given branch details. + * @param {number} branchId + * @returns {Promise} + */ + public getBranch = async (branchId: number): Promise => { + const branch = await this.branch + .query() + .findById(branchId) + .throwIfNotFound(); + + return branch; + }; +} diff --git a/packages/server-nest/src/modules/Branches/queries/GetBranches.service.ts b/packages/server-nest/src/modules/Branches/queries/GetBranches.service.ts new file mode 100644 index 000000000..d70ed4d0a --- /dev/null +++ b/packages/server-nest/src/modules/Branches/queries/GetBranches.service.ts @@ -0,0 +1,20 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Branch } from '../models/Branch.model'; + +@Injectable() +export class GetBranchesService { + constructor( + @Inject(Branch.name) + private readonly branch: typeof Branch, + ) {} + + /** + * Retrieves branches list. + * @returns + */ + public getBranches = async () => { + const branches = await this.branch.query().orderBy('name', 'DESC'); + + return branches; + }; +} diff --git a/packages/server-nest/src/modules/Branches/subscribers/Activate/CashflowBranchesActivateSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Activate/CashflowBranchesActivateSubscriber.ts new file mode 100644 index 000000000..f2c8d818f --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Activate/CashflowBranchesActivateSubscriber.ts @@ -0,0 +1,38 @@ +// import { IBranchesActivatedPayload } from '@/interfaces'; +// import { Service, Inject } from 'typedi'; +// import events from '@/subscribers/events'; +// import { CashflowTransactionsActivateBranches } from '../../Integrations/Cashflow/CashflowActivateBranches'; + +// @Service() +// export class CreditNoteActivateBranchesSubscriber { +// @Inject() +// private cashflowActivateBranches: CashflowTransactionsActivateBranches; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.branch.onActivated, +// this.updateCashflowWithBranchOnActivated +// ); +// return bus; +// } + +// /** +// * Updates accounts transactions with the primary branch once +// * the multi-branches is activated. +// * @param {IBranchesActivatedPayload} +// */ +// private updateCashflowWithBranchOnActivated = async ({ +// tenantId, +// primaryBranch, +// trx, +// }: IBranchesActivatedPayload) => { +// await this.cashflowActivateBranches.updateCashflowTransactionsWithBranch( +// tenantId, +// primaryBranch.id, +// trx +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Activate/CreditNoteBranchesActivateSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Activate/CreditNoteBranchesActivateSubscriber.ts new file mode 100644 index 000000000..05d93b1d5 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Activate/CreditNoteBranchesActivateSubscriber.ts @@ -0,0 +1,38 @@ +// import { IBranchesActivatedPayload } from '@/interfaces'; +// import { Service, Inject } from 'typedi'; +// import { CreditNoteActivateBranches } from '../../Integrations/Sales/CreditNoteBranchesActivate'; +// import events from '@/subscribers/events'; + +// @Service() +// export class CreditNoteActivateBranchesSubscriber { +// @Inject() +// private creditNotesActivateBranches: CreditNoteActivateBranches; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.branch.onActivated, +// this.updateCreditNoteWithBranchOnActivated +// ); +// return bus; +// } + +// /** +// * Updates accounts transactions with the primary branch once +// * the multi-branches is activated. +// * @param {IBranchesActivatedPayload} +// */ +// private updateCreditNoteWithBranchOnActivated = async ({ +// tenantId, +// primaryBranch, +// trx, +// }: IBranchesActivatedPayload) => { +// await this.creditNotesActivateBranches.updateCreditsWithBranch( +// tenantId, +// primaryBranch.id, +// trx +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Activate/ExpenseBranchesActivateSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Activate/ExpenseBranchesActivateSubscriber.ts new file mode 100644 index 000000000..15f7b030d --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Activate/ExpenseBranchesActivateSubscriber.ts @@ -0,0 +1,38 @@ +// import { IBranchesActivatedPayload } from '@/interfaces'; +// import { Service, Inject } from 'typedi'; +// import events from '@/subscribers/events'; +// import { ExpensesActivateBranches } from '../../Integrations/Expense/ExpensesActivateBranches'; + +// @Service() +// export class ExpenseActivateBranchesSubscriber { +// @Inject() +// private expensesActivateBranches: ExpensesActivateBranches; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.branch.onActivated, +// this.updateExpensesWithBranchOnActivated +// ); +// return bus; +// } + +// /** +// * Updates accounts transactions with the primary branch once +// * the multi-branches is activated. +// * @param {IBranchesActivatedPayload} +// */ +// private updateExpensesWithBranchOnActivated = async ({ +// tenantId, +// primaryBranch, +// trx, +// }: IBranchesActivatedPayload) => { +// await this.expensesActivateBranches.updateExpensesWithBranch( +// tenantId, +// primaryBranch.id, +// trx +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Activate/PaymentMadeBranchesActivateSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Activate/PaymentMadeBranchesActivateSubscriber.ts new file mode 100644 index 000000000..1030b48a5 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Activate/PaymentMadeBranchesActivateSubscriber.ts @@ -0,0 +1,38 @@ +// import { IBranchesActivatedPayload } from '@/interfaces'; +// import { Service, Inject } from 'typedi'; +// import events from '@/subscribers/events'; +// import { BillPaymentsActivateBranches } from '../../Integrations/Purchases/PaymentMadeBranchesActivate'; + +// @Service() +// export class PaymentMadeActivateBranchesSubscriber { +// @Inject() +// private paymentsActivateBranches: BillPaymentsActivateBranches; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.branch.onActivated, +// this.updatePaymentsWithBranchOnActivated +// ); +// return bus; +// } + +// /** +// * Updates accounts transactions with the primary branch once +// * the multi-branches is activated. +// * @param {IBranchesActivatedPayload} +// */ +// private updatePaymentsWithBranchOnActivated = async ({ +// tenantId, +// primaryBranch, +// trx, +// }: IBranchesActivatedPayload) => { +// await this.paymentsActivateBranches.updateBillPaymentsWithBranch( +// tenantId, +// primaryBranch.id, +// trx +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Activate/PaymentReceiveBranchesActivateSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Activate/PaymentReceiveBranchesActivateSubscriber.ts new file mode 100644 index 000000000..f77d62086 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Activate/PaymentReceiveBranchesActivateSubscriber.ts @@ -0,0 +1,38 @@ +// import { IBranchesActivatedPayload } from '@/interfaces'; +// import { Service, Inject } from 'typedi'; +// import events from '@/subscribers/events'; +// import { PaymentReceiveActivateBranches } from '../../Integrations/Sales/PaymentReceiveBranchesActivate'; + +// @Service() +// export class PaymentReceiveActivateBranchesSubscriber { +// @Inject() +// private paymentsActivateBranches: PaymentReceiveActivateBranches; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.branch.onActivated, +// this.updateCreditNoteWithBranchOnActivated +// ); +// return bus; +// } + +// /** +// * Updates accounts transactions with the primary branch once +// * the multi-branches is activated. +// * @param {IBranchesActivatedPayload} +// */ +// private updateCreditNoteWithBranchOnActivated = async ({ +// tenantId, +// primaryBranch, +// trx, +// }: IBranchesActivatedPayload) => { +// await this.paymentsActivateBranches.updatePaymentsWithBranch( +// tenantId, +// primaryBranch.id, +// trx +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Activate/SaleEstiamtesBranchesActivateSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Activate/SaleEstiamtesBranchesActivateSubscriber.ts new file mode 100644 index 000000000..fe295f47a --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Activate/SaleEstiamtesBranchesActivateSubscriber.ts @@ -0,0 +1,38 @@ +// import { IBranchesActivatedPayload } from '@/interfaces'; +// import { Service, Inject } from 'typedi'; +// import events from '@/subscribers/events'; +// import { SaleEstimateActivateBranches } from '../../Integrations/Sales/SaleEstimatesBranchesActivate'; + +// @Service() +// export class SaleEstimatesActivateBranchesSubscriber { +// @Inject() +// private estimatesActivateBranches: SaleEstimateActivateBranches; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.branch.onActivated, +// this.updateEstimatesWithBranchOnActivated +// ); +// return bus; +// } + +// /** +// * Updates accounts transactions with the primary branch once +// * the multi-branches is activated. +// * @param {IBranchesActivatedPayload} +// */ +// private updateEstimatesWithBranchOnActivated = async ({ +// tenantId, +// primaryBranch, +// trx, +// }: IBranchesActivatedPayload) => { +// await this.estimatesActivateBranches.updateEstimatesWithBranch( +// tenantId, +// primaryBranch.id, +// trx +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Activate/SaleInvoiceBranchesActivateSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Activate/SaleInvoiceBranchesActivateSubscriber.ts new file mode 100644 index 000000000..545c5ea5c --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Activate/SaleInvoiceBranchesActivateSubscriber.ts @@ -0,0 +1,38 @@ +// import { IBranchesActivatedPayload } from '@/interfaces'; +// import { Service, Inject } from 'typedi'; +// import events from '@/subscribers/events'; +// import { SaleInvoiceActivateBranches } from '../../Integrations/Sales/SaleInvoiceBranchesActivate'; + +// @Service() +// export class SaleInvoicesActivateBranchesSubscriber { +// @Inject() +// private invoicesActivateBranches: SaleInvoiceActivateBranches; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.branch.onActivated, +// this.updateInvoicesWithBranchOnActivated +// ); +// return bus; +// } + +// /** +// * Updates accounts transactions with the primary branch once +// * the multi-branches is activated. +// * @param {IBranchesActivatedPayload} +// */ +// private updateInvoicesWithBranchOnActivated = async ({ +// tenantId, +// primaryBranch, +// trx, +// }: IBranchesActivatedPayload) => { +// await this.invoicesActivateBranches.updateInvoicesWithBranch( +// tenantId, +// primaryBranch.id, +// trx +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Activate/SaleReceiptsBranchesActivateSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Activate/SaleReceiptsBranchesActivateSubscriber.ts new file mode 100644 index 000000000..5ed908936 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Activate/SaleReceiptsBranchesActivateSubscriber.ts @@ -0,0 +1,38 @@ +// import { IBranchesActivatedPayload } from '@/interfaces'; +// import { Service, Inject } from 'typedi'; +// import events from '@/subscribers/events'; +// import { SaleReceiptActivateBranches } from '../../Integrations/Sales/SaleReceiptBranchesActivate'; + +// @Service() +// export class SaleReceiptsActivateBranchesSubscriber { +// @Inject() +// private receiptsActivateBranches: SaleReceiptActivateBranches; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.branch.onActivated, +// this.updateReceiptsWithBranchOnActivated +// ); +// return bus; +// } + +// /** +// * Updates accounts transactions with the primary branch once +// * the multi-branches is activated. +// * @param {IBranchesActivatedPayload} +// */ +// private updateReceiptsWithBranchOnActivated = async ({ +// tenantId, +// primaryBranch, +// trx, +// }: IBranchesActivatedPayload) => { +// await this.receiptsActivateBranches.updateReceiptsWithBranch( +// tenantId, +// primaryBranch.id, +// trx +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Activate/index.ts b/packages/server-nest/src/modules/Branches/subscribers/Activate/index.ts new file mode 100644 index 000000000..64e966e10 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Activate/index.ts @@ -0,0 +1,8 @@ +// export * from './CashflowBranchesActivateSubscriber'; +// export * from './CreditNoteBranchesActivateSubscriber'; +// export * from './PaymentMadeBranchesActivateSubscriber'; +// export * from './PaymentReceiveBranchesActivateSubscriber'; +// export * from './SaleReceiptsBranchesActivateSubscriber'; +// export * from './SaleEstiamtesBranchesActivateSubscriber'; +// export * from './SaleInvoiceBranchesActivateSubscriber'; +// export * from './ExpenseBranchesActivateSubscriber'; \ No newline at end of file diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/BillBranchSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/BillBranchSubscriber.ts new file mode 100644 index 000000000..0783a60f6 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/BillBranchSubscriber.ts @@ -0,0 +1,53 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { IBillCreatingPayload, IBillEditingPayload } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class BillBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.bill.onCreating, +// this.validateBranchExistanceOnBillCreating +// ); +// bus.subscribe( +// events.bill.onEditing, +// this.validateBranchExistanceOnBillEditing +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on estimate creating. +// * @param {ISaleEstimateCreatedPayload} payload +// */ +// private validateBranchExistanceOnBillCreating = async ({ +// tenantId, +// billDTO, +// }: IBillCreatingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// billDTO.branchId +// ); +// }; + +// /** +// * Validate branch existance once estimate editing. +// * @param {ISaleEstimateEditingPayload} payload +// */ +// private validateBranchExistanceOnBillEditing = async ({ +// billDTO, +// tenantId, +// }: IBillEditingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// billDTO.branchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/CashflowBranchDTOValidatorSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/CashflowBranchDTOValidatorSubscriber.ts new file mode 100644 index 000000000..0667d09a7 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/CashflowBranchDTOValidatorSubscriber.ts @@ -0,0 +1,35 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { ICommandCashflowCreatingPayload } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class CashflowBranchDTOValidatorSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.cashflow.onTransactionCreating, +// this.validateBranchExistanceOnCashflowTransactionCreating +// ); +// return bus; +// }; + +// /** +// * Validate branch existance once cashflow transaction creating. +// * @param {ICommandCashflowCreatingPayload} payload +// */ +// private validateBranchExistanceOnCashflowTransactionCreating = async ({ +// tenantId, +// newTransactionDTO, +// }: ICommandCashflowCreatingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// newTransactionDTO.branchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/ContactOpeningBalanceBranchSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/ContactOpeningBalanceBranchSubscriber.ts new file mode 100644 index 000000000..a37ed9d1d --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/ContactOpeningBalanceBranchSubscriber.ts @@ -0,0 +1,104 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { +// ICustomerEventCreatingPayload, +// ICustomerOpeningBalanceEditingPayload, +// IVendorEventCreatingPayload, +// IVendorOpeningBalanceEditingPayload, +// } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class ContactBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.customers.onCreating, +// this.validateBranchExistanceOnCustomerCreating +// ); +// bus.subscribe( +// events.customers.onOpeningBalanceChanging, +// this.validateBranchExistanceOnCustomerOpeningBalanceEditing +// ); +// bus.subscribe( +// events.vendors.onCreating, +// this.validateBranchExistanceonVendorCreating +// ); +// bus.subscribe( +// events.vendors.onOpeningBalanceChanging, +// this.validateBranchExistanceOnVendorOpeningBalanceEditing +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on customer creating. +// * @param {ICustomerEventCreatingPayload} payload +// */ +// private validateBranchExistanceOnCustomerCreating = async ({ +// tenantId, +// customerDTO, +// }: ICustomerEventCreatingPayload) => { +// // Can't continue if the customer opening balance is zero. +// if (!customerDTO.openingBalance) return; + +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// customerDTO.openingBalanceBranchId +// ); +// }; + +// /** +// * Validate branch existance once customer opening balance editing. +// * @param {ICustomerOpeningBalanceEditingPayload} payload +// */ +// private validateBranchExistanceOnCustomerOpeningBalanceEditing = async ({ +// openingBalanceEditDTO, +// tenantId, +// }: ICustomerOpeningBalanceEditingPayload) => { +// if (!openingBalanceEditDTO.openingBalance) return; + +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// openingBalanceEditDTO.openingBalanceBranchId +// ); +// }; + +// /** +// * Validates the branch existance on vendor creating. +// * @param {IVendorEventCreatingPayload} payload - +// */ +// private validateBranchExistanceonVendorCreating = async ({ +// vendorDTO, +// tenantId, +// }: IVendorEventCreatingPayload) => { +// // Can't continue if the customer opening balance is zero. +// if (!vendorDTO.openingBalance) return; + +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// vendorDTO.openingBalanceBranchId +// ); +// }; + +// /** +// * Validate branch existance once the vendor opening balance editing. +// * @param {IVendorOpeningBalanceEditingPayload} +// */ +// private validateBranchExistanceOnVendorOpeningBalanceEditing = async ({ +// tenantId, +// openingBalanceEditDTO, +// }: IVendorOpeningBalanceEditingPayload) => { +// if (!openingBalanceEditDTO.openingBalance) return; + +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// openingBalanceEditDTO.openingBalanceBranchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/CreditNoteBranchesSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/CreditNoteBranchesSubscriber.ts new file mode 100644 index 000000000..8a90ca281 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/CreditNoteBranchesSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { +// ICreditNoteCreatingPayload, +// ICreditNoteEditingPayload, +// } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class CreditNoteBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.creditNote.onCreating, +// this.validateBranchExistanceOnCreditCreating +// ); +// bus.subscribe( +// events.creditNote.onEditing, +// this.validateBranchExistanceOnCreditEditing +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on estimate creating. +// * @param {ICreditNoteCreatingPayload} payload +// */ +// private validateBranchExistanceOnCreditCreating = async ({ +// tenantId, +// creditNoteDTO, +// }: ICreditNoteCreatingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// creditNoteDTO.branchId +// ); +// }; + +// /** +// * Validate branch existance once estimate editing. +// * @param {ISaleEstimateEditingPayload} payload +// */ +// private validateBranchExistanceOnCreditEditing = async ({ +// creditNoteEditDTO, +// tenantId, +// }: ICreditNoteEditingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// creditNoteEditDTO.branchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/CreditNoteRefundBranchSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/CreditNoteRefundBranchSubscriber.ts new file mode 100644 index 000000000..c61539634 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/CreditNoteRefundBranchSubscriber.ts @@ -0,0 +1,35 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { IRefundCreditNoteCreatingPayload } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class CreditNoteRefundBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.creditNote.onRefundCreating, +// this.validateBranchExistanceOnCreditRefundCreating +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on refund credit note creating. +// * @param {ICreditNoteCreatingPayload} payload +// */ +// private validateBranchExistanceOnCreditRefundCreating = async ({ +// tenantId, +// newCreditNoteDTO, +// }: IRefundCreditNoteCreatingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// newCreditNoteDTO.branchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/ExpenseBranchSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/ExpenseBranchSubscriber.ts new file mode 100644 index 000000000..44199876b --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/ExpenseBranchSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { +// IExpenseCreatingPayload, +// IExpenseEventEditingPayload, +// } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class ExpenseBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.expenses.onCreating, +// this.validateBranchExistanceOnExpenseCreating +// ); +// bus.subscribe( +// events.expenses.onEditing, +// this.validateBranchExistanceOnExpenseEditing +// ); +// return bus; +// }; + +// /** +// * Validate branch existance once expense transaction creating. +// * @param {ISaleEstimateCreatedPayload} payload +// */ +// private validateBranchExistanceOnExpenseCreating = async ({ +// tenantId, +// expenseDTO, +// }: IExpenseCreatingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// expenseDTO.branchId +// ); +// }; + +// /** +// * Validate branch existance once expense transaction editing. +// * @param {ISaleEstimateEditingPayload} payload +// */ +// private validateBranchExistanceOnExpenseEditing = async ({ +// expenseDTO, +// tenantId, +// }: IExpenseEventEditingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// expenseDTO.branchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/InventoryAdjustmentBranchValidatorSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/InventoryAdjustmentBranchValidatorSubscriber.ts new file mode 100644 index 000000000..c3a6ae88b --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/InventoryAdjustmentBranchValidatorSubscriber.ts @@ -0,0 +1,35 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { IInventoryAdjustmentCreatingPayload } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class InventoryAdjustmentBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.inventoryAdjustment.onQuickCreating, +// this.validateBranchExistanceOnInventoryCreating +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on invoice creating. +// * @param {ISaleInvoiceCreatingPaylaod} payload +// */ +// private validateBranchExistanceOnInventoryCreating = async ({ +// tenantId, +// quickAdjustmentDTO, +// }: IInventoryAdjustmentCreatingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// quickAdjustmentDTO.branchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/InvoiceBranchValidatorSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/InvoiceBranchValidatorSubscriber.ts new file mode 100644 index 000000000..4f4f8d6da --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/InvoiceBranchValidatorSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { +// ISaleInvoiceCreatingPaylaod, +// ISaleInvoiceEditingPayload, +// } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class InvoiceBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.saleInvoice.onCreating, +// this.validateBranchExistanceOnInvoiceCreating +// ); +// bus.subscribe( +// events.saleInvoice.onEditing, +// this.validateBranchExistanceOnInvoiceEditing +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on invoice creating. +// * @param {ISaleInvoiceCreatingPaylaod} payload +// */ +// private validateBranchExistanceOnInvoiceCreating = async ({ +// tenantId, +// saleInvoiceDTO, +// }: ISaleInvoiceCreatingPaylaod) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// saleInvoiceDTO.branchId +// ); +// }; + +// /** +// * Validate branch existance once invoice editing. +// * @param {ISaleInvoiceEditingPayload} payload +// */ +// private validateBranchExistanceOnInvoiceEditing = async ({ +// saleInvoiceDTO, +// tenantId, +// }: ISaleInvoiceEditingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// saleInvoiceDTO.branchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/ManualJournalBranchSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/ManualJournalBranchSubscriber.ts new file mode 100644 index 000000000..b26e7caf8 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/ManualJournalBranchSubscriber.ts @@ -0,0 +1,76 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { +// Features, +// IManualJournalCreatingPayload, +// IManualJournalEditingPayload, +// } from '@/interfaces'; +// import { ManualJournalBranchesValidator } from '../../Integrations/ManualJournals/ManualJournalsBranchesValidator'; +// import { FeaturesManager } from '@/services/Features/FeaturesManager'; + +// @Service() +// export class ManualJournalBranchValidateSubscriber { +// @Inject() +// private validateManualJournalBranch: ManualJournalBranchesValidator; + +// @Inject() +// private featuresManager: FeaturesManager; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.manualJournals.onCreating, +// this.validateBranchExistanceOnBillCreating +// ); +// bus.subscribe( +// events.manualJournals.onEditing, +// this.validateBranchExistanceOnBillEditing +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on estimate creating. +// * @param {IManualJournalCreatingPayload} payload +// */ +// private validateBranchExistanceOnBillCreating = async ({ +// manualJournalDTO, +// tenantId, +// }: IManualJournalCreatingPayload) => { +// // Detarmines whether the multi-branches is accessible by tenant. +// const isAccessible = await this.featuresManager.accessible( +// tenantId, +// Features.BRANCHES +// ); +// // Can't continue if the multi-branches feature is inactive. +// if (!isAccessible) return; + +// // Validates the entries whether have branch id. +// await this.validateManualJournalBranch.validateEntriesHasBranchId( +// manualJournalDTO +// ); +// }; + +// /** +// * Validate branch existance once estimate editing. +// * @param {ISaleEstimateEditingPayload} payload +// */ +// private validateBranchExistanceOnBillEditing = async ({ +// tenantId, +// manualJournalDTO, +// }: IManualJournalEditingPayload) => { +// // Detarmines whether the multi-branches is accessible by tenant. +// const isAccessible = await this.featuresManager.accessible( +// tenantId, +// Features.BRANCHES +// ); +// // Can't continue if the multi-branches feature is inactive. +// if (!isAccessible) return; + +// await this.validateManualJournalBranch.validateEntriesHasBranchId( +// manualJournalDTO +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/PaymentMadeBranchSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/PaymentMadeBranchSubscriber.ts new file mode 100644 index 000000000..309ebfe3c --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/PaymentMadeBranchSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { +// IBillPaymentCreatingPayload, +// IBillPaymentEditingPayload, +// } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class PaymentMadeBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.billPayment.onCreating, +// this.validateBranchExistanceOnPaymentCreating +// ); +// bus.subscribe( +// events.billPayment.onEditing, +// this.validateBranchExistanceOnPaymentEditing +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on estimate creating. +// * @param {ISaleEstimateCreatedPayload} payload +// */ +// private validateBranchExistanceOnPaymentCreating = async ({ +// tenantId, +// billPaymentDTO, +// }: IBillPaymentCreatingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// billPaymentDTO.branchId +// ); +// }; + +// /** +// * Validate branch existance once estimate editing. +// * @param {ISaleEstimateEditingPayload} payload +// */ +// private validateBranchExistanceOnPaymentEditing = async ({ +// billPaymentDTO, +// tenantId, +// }: IBillPaymentEditingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// billPaymentDTO.branchId +// ); +// }; +// } \ No newline at end of file diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/PaymentReceiveBranchSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/PaymentReceiveBranchSubscriber.ts new file mode 100644 index 000000000..89627ad26 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/PaymentReceiveBranchSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { +// IPaymentReceivedCreatingPayload, +// IPaymentReceivedEditingPayload, +// } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class PaymentReceiveBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.paymentReceive.onCreating, +// this.validateBranchExistanceOnPaymentCreating +// ); +// bus.subscribe( +// events.paymentReceive.onEditing, +// this.validateBranchExistanceOnPaymentEditing +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on estimate creating. +// * @param {IPaymentReceivedCreatingPayload} payload +// */ +// private validateBranchExistanceOnPaymentCreating = async ({ +// tenantId, +// paymentReceiveDTO, +// }: IPaymentReceivedCreatingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// paymentReceiveDTO.branchId +// ); +// }; + +// /** +// * Validate branch existance once estimate editing. +// * @param {IPaymentReceivedEditingPayload} payload +// */ +// private validateBranchExistanceOnPaymentEditing = async ({ +// paymentReceiveDTO, +// tenantId, +// }: IPaymentReceivedEditingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// paymentReceiveDTO.branchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/SaleEstimateMultiBranchesSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/SaleEstimateMultiBranchesSubscriber.ts new file mode 100644 index 000000000..57768b738 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/SaleEstimateMultiBranchesSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { +// ISaleEstimateCreatingPayload, +// ISaleEstimateEditingPayload, +// } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class SaleEstimateBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.saleEstimate.onCreating, +// this.validateBranchExistanceOnEstimateCreating +// ); +// bus.subscribe( +// events.saleEstimate.onEditing, +// this.validateBranchExistanceOnEstimateEditing +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on estimate creating. +// * @param {ISaleEstimateCreatedPayload} payload +// */ +// private validateBranchExistanceOnEstimateCreating = async ({ +// tenantId, +// estimateDTO, +// }: ISaleEstimateCreatingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// estimateDTO.branchId +// ); +// }; + +// /** +// * Validate branch existance once estimate editing. +// * @param {ISaleEstimateEditingPayload} payload +// */ +// private validateBranchExistanceOnEstimateEditing = async ({ +// estimateDTO, +// tenantId, +// }: ISaleEstimateEditingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// estimateDTO.branchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/SaleReceiptBranchesSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/SaleReceiptBranchesSubscriber.ts new file mode 100644 index 000000000..5218da733 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/SaleReceiptBranchesSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { +// ISaleReceiptCreatingPayload, +// ISaleReceiptEditingPayload, +// } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class SaleReceiptBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.saleReceipt.onCreating, +// this.validateBranchExistanceOnInvoiceCreating +// ); +// bus.subscribe( +// events.saleReceipt.onEditing, +// this.validateBranchExistanceOnInvoiceEditing +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on estimate creating. +// * @param {ISaleReceiptCreatingPayload} payload +// */ +// private validateBranchExistanceOnInvoiceCreating = async ({ +// tenantId, +// saleReceiptDTO, +// }: ISaleReceiptCreatingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// saleReceiptDTO.branchId +// ); +// }; + +// /** +// * Validate branch existance once estimate editing. +// * @param {ISaleReceiptEditingPayload} payload +// */ +// private validateBranchExistanceOnInvoiceEditing = async ({ +// saleReceiptDTO, +// tenantId, +// }: ISaleReceiptEditingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// saleReceiptDTO.branchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/VendorCreditBranchSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/VendorCreditBranchSubscriber.ts new file mode 100644 index 000000000..ad74a6654 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/VendorCreditBranchSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { +// IVendorCreditCreatingPayload, +// IVendorCreditEditingPayload, +// } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class VendorCreditBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.vendorCredit.onCreating, +// this.validateBranchExistanceOnCreditCreating +// ); +// bus.subscribe( +// events.vendorCredit.onEditing, +// this.validateBranchExistanceOnCreditEditing +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on estimate creating. +// * @param {ISaleEstimateCreatedPayload} payload +// */ +// private validateBranchExistanceOnCreditCreating = async ({ +// tenantId, +// vendorCreditCreateDTO, +// }: IVendorCreditCreatingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// vendorCreditCreateDTO.branchId +// ); +// }; + +// /** +// * Validate branch existance once estimate editing. +// * @param {ISaleEstimateEditingPayload} payload +// */ +// private validateBranchExistanceOnCreditEditing = async ({ +// vendorCreditDTO, +// tenantId, +// }: IVendorCreditEditingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// vendorCreditDTO.branchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/VendorCreditRefundBranchSubscriber.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/VendorCreditRefundBranchSubscriber.ts new file mode 100644 index 000000000..3e09c81c1 --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/VendorCreditRefundBranchSubscriber.ts @@ -0,0 +1,35 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { IRefundVendorCreditCreatingPayload } from '@/interfaces'; +// import { ValidateBranchExistance } from '../../Integrations/ValidateBranchExistance'; + +// @Service() +// export class VendorCreditRefundBranchValidateSubscriber { +// @Inject() +// private validateBranchExistance: ValidateBranchExistance; + +// /** +// * Attaches events with handlers. +// */ +// public attach = (bus) => { +// bus.subscribe( +// events.vendorCredit.onRefundCreating, +// this.validateBranchExistanceOnCreditRefundCreating +// ); +// return bus; +// }; + +// /** +// * Validate branch existance on refund credit note creating. +// * @param {IRefundVendorCreditCreatingPayload} payload +// */ +// private validateBranchExistanceOnCreditRefundCreating = async ({ +// tenantId, +// refundVendorCreditDTO, +// }: IRefundVendorCreditCreatingPayload) => { +// await this.validateBranchExistance.validateTransactionBranchWhenActive( +// tenantId, +// refundVendorCreditDTO.branchId +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Branches/subscribers/Validators/index.ts b/packages/server-nest/src/modules/Branches/subscribers/Validators/index.ts new file mode 100644 index 000000000..8865dbfcb --- /dev/null +++ b/packages/server-nest/src/modules/Branches/subscribers/Validators/index.ts @@ -0,0 +1,15 @@ +export * from './BillBranchSubscriber'; +export * from './CashflowBranchDTOValidatorSubscriber'; +export * from './CreditNoteBranchesSubscriber'; +export * from './CreditNoteRefundBranchSubscriber'; +export * from './ExpenseBranchSubscriber'; +export * from './ManualJournalBranchSubscriber'; +export * from './PaymentMadeBranchSubscriber'; +export * from './PaymentReceiveBranchSubscriber'; +export * from './SaleEstimateMultiBranchesSubscriber'; +export * from './SaleReceiptBranchesSubscriber'; +export * from './VendorCreditBranchSubscriber'; +export * from './VendorCreditRefundBranchSubscriber'; +export * from './InvoiceBranchValidatorSubscriber'; +export * from './ContactOpeningBalanceBranchSubscriber'; +export * from './InventoryAdjustmentBranchValidatorSubscriber'; \ No newline at end of file diff --git a/packages/server-nest/src/modules/Expenses/commands/CreateExpense.service.ts b/packages/server-nest/src/modules/Expenses/commands/CreateExpense.service.ts index 8283e9387..cb7d5c03d 100644 --- a/packages/server-nest/src/modules/Expenses/commands/CreateExpense.service.ts +++ b/packages/server-nest/src/modules/Expenses/commands/CreateExpense.service.ts @@ -15,6 +15,14 @@ import { events } from '@/common/events/events'; @Injectable() export class CreateExpense { + /** + * @param {EventEmitter2} eventEmitter - Event emitter. + * @param {UnitOfWork} uow - Unit of work. + * @param {CommandExpenseValidator} validator - Command expense validator. + * @param {ExpenseDTOTransformer} transformDTO - Expense DTO transformer. + * @param {typeof Account} accountModel - Account model. + * @param {typeof Expense} expenseModel - Expense model. + */ constructor( private readonly eventEmitter: EventEmitter2, private readonly uow: UnitOfWork, diff --git a/packages/server-nest/src/modules/Expenses/commands/DeleteExpense.service.ts b/packages/server-nest/src/modules/Expenses/commands/DeleteExpense.service.ts index bf113db8e..72edd12e9 100644 --- a/packages/server-nest/src/modules/Expenses/commands/DeleteExpense.service.ts +++ b/packages/server-nest/src/modules/Expenses/commands/DeleteExpense.service.ts @@ -13,6 +13,13 @@ import { @Injectable() export class DeleteExpense { + /** + * @param {EventEmitter2} eventEmitter - Event emitter. + * @param {UnitOfWork} uow - Unit of work. + * @param {CommandExpenseValidator} validator - Command expense validator. + * @param {typeof Expense} expenseModel - Expense model. + * @param {typeof ExpenseCategory} expenseCategoryModel - Expense category model. + */ constructor( private readonly eventEmitter: EventEmitter2, private readonly uow: UnitOfWork, diff --git a/packages/server-nest/src/modules/Expenses/commands/EditExpense.service.ts b/packages/server-nest/src/modules/Expenses/commands/EditExpense.service.ts index 5232b8ace..94411db8c 100644 --- a/packages/server-nest/src/modules/Expenses/commands/EditExpense.service.ts +++ b/packages/server-nest/src/modules/Expenses/commands/EditExpense.service.ts @@ -16,6 +16,14 @@ import { events } from '@/common/events/events'; @Injectable() export class EditExpense { + /** + * @param {EventEmitter2} eventEmitter - Event emitter. + * @param {UnitOfWork} uow - Unit of work. + * @param {CommandExpenseValidator} validator - Command expense validator. + * @param {ExpenseDTOTransformer} transformDTO - Expense DTO transformer. + * @param {typeof Expense} expenseModel - Expense model. + * @param {typeof Account} accountModel - Account model. + */ constructor( private eventEmitter: EventEmitter2, private uow: UnitOfWork, diff --git a/packages/server-nest/src/modules/Expenses/commands/PublishExpense.service.ts b/packages/server-nest/src/modules/Expenses/commands/PublishExpense.service.ts index f93f38e64..898f8f613 100644 --- a/packages/server-nest/src/modules/Expenses/commands/PublishExpense.service.ts +++ b/packages/server-nest/src/modules/Expenses/commands/PublishExpense.service.ts @@ -12,6 +12,12 @@ import { EventEmitter2 } from '@nestjs/event-emitter'; @Injectable() export class PublishExpense { + /** + * @param {EventEmitter2} eventPublisher - Event emitter. + * @param {UnitOfWork} uow - Unit of work. + * @param {CommandExpenseValidator} validator - Command expense validator. + * @param {typeof Expense} expenseModel - Expense model. + */ constructor( private readonly eventPublisher: EventEmitter2, private readonly uow: UnitOfWork, diff --git a/packages/server-nest/src/modules/ItemCategories/ItemCategory.application.ts b/packages/server-nest/src/modules/ItemCategories/ItemCategory.application.ts index 3b8a26e17..d6ce6fec3 100644 --- a/packages/server-nest/src/modules/ItemCategories/ItemCategory.application.ts +++ b/packages/server-nest/src/modules/ItemCategories/ItemCategory.application.ts @@ -7,6 +7,12 @@ import { GetItemCategoryService } from './queries/GetItemCategory.service'; @Injectable() export class ItemCategoryApplication { + /** + * @param {CreateItemCategoryService} createItemCategoryService - Create item category service. + * @param {EditItemCategoryService} editItemCategoryService - Edit item category service. + * @param {GetItemCategoryService} getItemCategoryService - Get item category service. + * @param {DeleteItemCategoryService} deleteItemCategoryService - Delete item category service. + */ constructor( private readonly createItemCategoryService: CreateItemCategoryService, private readonly editItemCategoryService: EditItemCategoryService, diff --git a/packages/server-nest/src/modules/ItemCategories/commands/CommandItemCategoryValidator.service.ts b/packages/server-nest/src/modules/ItemCategories/commands/CommandItemCategoryValidator.service.ts index 5b827e122..9d1e853a6 100644 --- a/packages/server-nest/src/modules/ItemCategories/commands/CommandItemCategoryValidator.service.ts +++ b/packages/server-nest/src/modules/ItemCategories/commands/CommandItemCategoryValidator.service.ts @@ -7,6 +7,10 @@ import { ACCOUNT_ROOT_TYPE, ACCOUNT_TYPE } from '@/constants/accounts'; @Injectable() export class CommandItemCategoryValidatorService { + /** + * @param {typeof ItemCategory} itemCategoryModel - Item category model. + * @param {typeof Account} accountModel - Account model. + */ constructor( @Inject(ItemCategory.name) private readonly itemCategoryModel: typeof ItemCategory, diff --git a/packages/server-nest/src/modules/ItemCategories/commands/CreateItemCategory.service.ts b/packages/server-nest/src/modules/ItemCategories/commands/CreateItemCategory.service.ts index 16bfa5147..125f828b2 100644 --- a/packages/server-nest/src/modules/ItemCategories/commands/CreateItemCategory.service.ts +++ b/packages/server-nest/src/modules/ItemCategories/commands/CreateItemCategory.service.ts @@ -13,6 +13,12 @@ import { SystemUser } from '@/modules/System/models/SystemUser'; @Injectable() export class CreateItemCategoryService { + /** + * @param {UnitOfWork} uow - Unit of work. + * @param {CommandItemCategoryValidatorService} validator - Command item category validator service. + * @param {EventEmitter2} eventEmitter - Event emitter. + * @param {typeof ItemCategory} itemCategoryModel - Item category model. + */ constructor( private readonly uow: UnitOfWork, private readonly validator: CommandItemCategoryValidatorService, diff --git a/packages/server-nest/src/modules/ItemCategories/commands/DeleteItemCategory.service.ts b/packages/server-nest/src/modules/ItemCategories/commands/DeleteItemCategory.service.ts index 64f3b848b..7cbf59dcf 100644 --- a/packages/server-nest/src/modules/ItemCategories/commands/DeleteItemCategory.service.ts +++ b/packages/server-nest/src/modules/ItemCategories/commands/DeleteItemCategory.service.ts @@ -10,6 +10,12 @@ import { Item } from '@/modules/Items/models/Item'; @Injectable() export class DeleteItemCategoryService { + /** + * @param {UnitOfWork} uow - Unit of work. + * @param {CommandItemCategoryValidatorService} validator - Command item category validator service. + * @param {EventEmitter2} eventEmitter - Event emitter. + * @param {typeof ItemCategory} itemCategoryModel - Item category model. + */ constructor( private readonly uow: UnitOfWork, private readonly validator: CommandItemCategoryValidatorService, diff --git a/packages/server-nest/src/modules/ItemCategories/commands/EditItemCategory.service.ts b/packages/server-nest/src/modules/ItemCategories/commands/EditItemCategory.service.ts index 6e78d5b70..ad2e276f9 100644 --- a/packages/server-nest/src/modules/ItemCategories/commands/EditItemCategory.service.ts +++ b/packages/server-nest/src/modules/ItemCategories/commands/EditItemCategory.service.ts @@ -13,6 +13,13 @@ import { Inject } from '@nestjs/common'; import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service'; export class EditItemCategoryService { + /** + * @param {UnitOfWork} uow - Unit of work. + * @param {CommandItemCategoryValidatorService} validator - Command item category validator service. + * @param {EventEmitter2} eventEmitter - Event emitter. + * @param {TenancyContext} tenancyContext - Tenancy context. + * @param {typeof ItemCategory} itemCategoryModel - Item category model. + */ constructor( private readonly uow: UnitOfWork, private readonly validator: CommandItemCategoryValidatorService, @@ -21,6 +28,7 @@ export class EditItemCategoryService { @Inject(ItemCategory.name) private readonly itemCategoryModel: typeof ItemCategory, ) {} + /** * Edits item category. * @param {number} tenantId diff --git a/packages/server-nest/src/modules/ItemCategories/queries/GetItemCategory.service.ts b/packages/server-nest/src/modules/ItemCategories/queries/GetItemCategory.service.ts index 1882883b2..0304bf0f4 100644 --- a/packages/server-nest/src/modules/ItemCategories/queries/GetItemCategory.service.ts +++ b/packages/server-nest/src/modules/ItemCategories/queries/GetItemCategory.service.ts @@ -3,6 +3,9 @@ import { ItemCategory } from '../models/ItemCategory.model'; @Injectable() export class GetItemCategoryService { + /** + * @param {typeof ItemCategory} itemCategoryModel - Item category model. + */ constructor( @Inject(ItemCategory.name) private readonly itemCategoryModel: typeof ItemCategory, diff --git a/packages/server-nest/src/modules/Transformer/TransformerInjectable.service.ts b/packages/server-nest/src/modules/Transformer/TransformerInjectable.service.ts index 3975818f5..125e659e4 100644 --- a/packages/server-nest/src/modules/Transformer/TransformerInjectable.service.ts +++ b/packages/server-nest/src/modules/Transformer/TransformerInjectable.service.ts @@ -6,6 +6,10 @@ import { TransformerContext } from './Transformer.types'; @Injectable() export class TransformerInjectable { + /** + * @param {TenancyContext} tenancyContext - Tenancy context. + * @param {I18nService} i18n - I18n service. + */ constructor( private readonly tenancyContext: TenancyContext, private readonly i18n: I18nService, diff --git a/packages/server-nest/src/modules/Warehouses/Activate/BillWarehousesActivate.ts b/packages/server-nest/src/modules/Warehouses/Activate/BillWarehousesActivate.ts new file mode 100644 index 000000000..677879866 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Activate/BillWarehousesActivate.ts @@ -0,0 +1,30 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehouse } from '@/interfaces'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// @Service() +// export class BillActivateWarehouses { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all credit note transactions with the primary warehouse. +// * @param {number} tenantId +// * @param {number} primaryWarehouse +// * @returns {Promise} +// */ +// public updateBillsWithWarehouse = async ( +// tenantId: number, +// primaryWarehouse: IWarehouse +// ): Promise => { +// const { Bill, ItemEntry } = this.tenancy.models(tenantId); + +// // Updates the sale estimates with primary warehouse. +// await Bill.query().update({ warehouseId: primaryWarehouse.id }); + +// // Update the sale estimates entries with primary warehouse. +// await ItemEntry.query().where('referenceType', 'Bill').update({ +// warehouseId: primaryWarehouse.id, +// }); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Activate/CreditNoteWarehousesActivate.ts b/packages/server-nest/src/modules/Warehouses/Activate/CreditNoteWarehousesActivate.ts new file mode 100644 index 000000000..23e884c4a --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Activate/CreditNoteWarehousesActivate.ts @@ -0,0 +1,30 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehouse } from '@/interfaces'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// @Service() +// export class CreditNotesActivateWarehouses { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all credit note transactions with the primary warehouse. +// * @param {number} tenantId +// * @param {number} primaryWarehouse +// * @returns {Promise} +// */ +// public updateCreditsWithWarehouse = async ( +// tenantId: number, +// primaryWarehouse: IWarehouse +// ): Promise => { +// const { CreditNote, ItemEntry } = this.tenancy.models(tenantId); + +// // Updates the sale estimates with primary warehouse. +// await CreditNote.query().update({ warehouseId: primaryWarehouse.id }); + +// // Update the sale estimates entries with primary warehouse. +// await ItemEntry.query().where('referenceType', 'CreditNote').update({ +// warehouseId: primaryWarehouse.id, +// }); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Activate/EstimateWarehousesActivate.ts b/packages/server-nest/src/modules/Warehouses/Activate/EstimateWarehousesActivate.ts new file mode 100644 index 000000000..eb0d5a4f6 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Activate/EstimateWarehousesActivate.ts @@ -0,0 +1,30 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehouse } from '@/interfaces'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// @Service() +// export class EstimatesActivateWarehouses { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all inventory transactions with the primary warehouse. +// * @param {number} tenantId +// * @param {number} primaryWarehouse +// * @returns {Promise} +// */ +// public updateEstimatesWithWarehouse = async ( +// tenantId: number, +// primaryWarehouse: IWarehouse +// ): Promise => { +// const { SaleEstimate, ItemEntry } = this.tenancy.models(tenantId); + +// // Updates the sale estimates with primary warehouse. +// await SaleEstimate.query().update({ warehouseId: primaryWarehouse.id }); + +// // Update the sale estimates entries with primary warehouse. +// await ItemEntry.query().where('referenceType', 'SaleEstimate').update({ +// warehouseId: primaryWarehouse.id, +// }); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Activate/InventoryTransactionsWarehousesActivate.ts b/packages/server-nest/src/modules/Warehouses/Activate/InventoryTransactionsWarehousesActivate.ts new file mode 100644 index 000000000..cb1349a8f --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Activate/InventoryTransactionsWarehousesActivate.ts @@ -0,0 +1,31 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehouse } from '@/interfaces'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// @Service() +// export class InventoryActivateWarehouses { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all inventory transactions with the primary warehouse. +// * @param {number} tenantId +// * @param {number} primaryWarehouse +// * @returns {Promise} +// */ +// public updateInventoryTransactionsWithWarehouse = async ( +// tenantId: number, +// primaryWarehouse: IWarehouse +// ): Promise => { +// const { InventoryTransaction, InventoryCostLotTracker } = +// this.tenancy.models(tenantId); + +// // Updates the inventory transactions with primary warehouse. +// await InventoryTransaction.query().update({ +// warehouseId: primaryWarehouse.id, +// }); +// await InventoryCostLotTracker.query().update({ +// warehouseId: primaryWarehouse.id, +// }); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Activate/InvoiceWarehousesActivate.ts b/packages/server-nest/src/modules/Warehouses/Activate/InvoiceWarehousesActivate.ts new file mode 100644 index 000000000..19633bdf3 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Activate/InvoiceWarehousesActivate.ts @@ -0,0 +1,30 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehouse } from '@/interfaces'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// @Service() +// export class InvoicesActivateWarehouses { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all inventory transactions with the primary warehouse. +// * @param {number} tenantId +// * @param {number} primaryWarehouse +// * @returns {Promise} +// */ +// public updateInvoicesWithWarehouse = async ( +// tenantId: number, +// primaryWarehouse: IWarehouse +// ): Promise => { +// const { SaleInvoice, ItemEntry } = this.tenancy.models(tenantId); + +// // Updates the sale invoices with primary warehouse. +// await SaleInvoice.query().update({ warehouseId: primaryWarehouse.id }); + +// // Update the sale invoices entries with primary warehouse. +// await ItemEntry.query().where('referenceType', 'SaleInvoice').update({ +// warehouseId: primaryWarehouse.id, +// }); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Activate/ReceiptWarehousesActivate.ts b/packages/server-nest/src/modules/Warehouses/Activate/ReceiptWarehousesActivate.ts new file mode 100644 index 000000000..5dc0e5dc3 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Activate/ReceiptWarehousesActivate.ts @@ -0,0 +1,30 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehouse } from '@/interfaces'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// @Service() +// export class ReceiptActivateWarehouses { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all sale receipts transactions with the primary warehouse. +// * @param {number} tenantId +// * @param {number} primaryWarehouse +// * @returns {Promise} +// */ +// public updateReceiptsWithWarehouse = async ( +// tenantId: number, +// primaryWarehouse: IWarehouse +// ): Promise => { +// const { SaleReceipt, ItemEntry } = this.tenancy.models(tenantId); + +// // Updates the vendor credits transactions with primary warehouse. +// await SaleReceipt.query().update({ warehouseId: primaryWarehouse.id }); + +// // Update the sale invoices entries with primary warehouse. +// await ItemEntry.query().where('referenceType', 'SaleReceipt').update({ +// warehouseId: primaryWarehouse.id, +// }); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Activate/VendorCreditWarehousesActivate.ts b/packages/server-nest/src/modules/Warehouses/Activate/VendorCreditWarehousesActivate.ts new file mode 100644 index 000000000..c1bad4874 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Activate/VendorCreditWarehousesActivate.ts @@ -0,0 +1,30 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehouse } from '@/interfaces'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// @Service() +// export class VendorCreditActivateWarehouses { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all vendor credits transactions with the primary warehouse. +// * @param {number} tenantId +// * @param {number} primaryWarehouse +// * @returns {Promise} +// */ +// public updateCreditsWithWarehouse = async ( +// tenantId: number, +// primaryWarehouse: IWarehouse +// ): Promise => { +// const { VendorCredit, ItemEntry } = this.tenancy.models(tenantId); + +// // Updates the vendor credits transactions with primary warehouse. +// await VendorCredit.query().update({ warehouseId: primaryWarehouse.id }); + +// // Update the sale invoices entries with primary warehouse. +// await ItemEntry.query().where('referenceType', 'VendorCredit').update({ +// warehouseId: primaryWarehouse.id, +// }); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/ActivateWarehousesSubscriber.ts b/packages/server-nest/src/modules/Warehouses/ActivateWarehousesSubscriber.ts new file mode 100644 index 000000000..4e51baf1c --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/ActivateWarehousesSubscriber.ts @@ -0,0 +1,58 @@ +// import { Service, Inject } from 'typedi'; +// import events from '@/subscribers/events'; +// import { IWarehousesActivatedPayload } from '@/interfaces'; +// import { UpdateInventoryTransactionsWithWarehouse } from './UpdateInventoryTransactionsWithWarehouse'; +// import { CreateInitialWarehousesItemsQuantity } from './CreateInitialWarehousesitemsQuantity'; + +// @Service() +// export class ActivateWarehousesSubscriber { +// @Inject() +// private updateInventoryTransactionsWithWarehouse: UpdateInventoryTransactionsWithWarehouse; + +// @Inject() +// private createInitialWarehousesItemsQuantity: CreateInitialWarehousesItemsQuantity; + +// /** +// * Attaches events with handlers. +// */ +// attach(bus) { +// bus.subscribe( +// events.warehouse.onActivated, +// this.updateInventoryTransactionsWithWarehouseOnActivating +// ); +// bus.subscribe( +// events.warehouse.onActivated, +// this.createInitialWarehousesItemsQuantityOnActivating +// ); +// return bus; +// } + +// /** +// * Updates inventory transactiont to primary warehouse once +// * multi-warehouses activated. +// * @param {IWarehousesActivatedPayload} +// */ +// private updateInventoryTransactionsWithWarehouseOnActivating = async ({ +// tenantId, +// primaryWarehouse, +// }: IWarehousesActivatedPayload) => { +// await this.updateInventoryTransactionsWithWarehouse.run( +// tenantId, +// primaryWarehouse.id +// ); +// }; + +// /** +// * Creates initial warehouses items quantity once the multi-warehouses activated. +// * @param {IWarehousesActivatedPayload} +// */ +// private createInitialWarehousesItemsQuantityOnActivating = async ({ +// tenantId, +// primaryWarehouse, +// }: IWarehousesActivatedPayload) => { +// await this.createInitialWarehousesItemsQuantity.run( +// tenantId, +// primaryWarehouse.id +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/CRUDWarehouse.ts b/packages/server-nest/src/modules/Warehouses/CRUDWarehouse.ts new file mode 100644 index 000000000..ff8e86080 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/CRUDWarehouse.ts @@ -0,0 +1,26 @@ +// import { Inject, Service } from 'typedi'; +// import { ServiceError } from '@/exceptions'; +// import { ERRORS } from './contants'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// export class CRUDWarehouse { +// @Inject() +// tenancy: HasTenancyService; + +// getWarehouseOrThrowNotFound = async (tenantId: number, warehouseId: number) => { +// const { Warehouse } = this.tenancy.models(tenantId); + +// const foundWarehouse = await Warehouse.query().findById(warehouseId); + +// if (!foundWarehouse) { +// throw new ServiceError(ERRORS.WAREHOUSE_NOT_FOUND); +// } +// return foundWarehouse; +// }; + +// throwIfWarehouseNotFound = (warehouse) => { +// if (!warehouse) { +// throw new ServiceError(ERRORS.WAREHOUSE_NOT_FOUND); +// } +// } +// } diff --git a/packages/server-nest/src/modules/Warehouses/CreateInitialWarehousesitemsQuantity.ts b/packages/server-nest/src/modules/Warehouses/CreateInitialWarehousesitemsQuantity.ts new file mode 100644 index 000000000..a033924a9 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/CreateInitialWarehousesitemsQuantity.ts @@ -0,0 +1,57 @@ +// import { Service, Inject } from 'typedi'; +// import { Knex } from 'knex'; +// import { IItem, IItemWarehouseQuantityChange } from '@/interfaces'; +// import { WarehousesItemsQuantitySync } from './Integrations/WarehousesItemsQuantitySync'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// @Service() +// export class CreateInitialWarehousesItemsQuantity { +// @Inject() +// private warehousesItemsQuantitySync: WarehousesItemsQuantitySync; + +// @Inject() +// private tenancy: HasTenancyService; + +// /** +// * Retrieves items warehouses quantity changes of the given inventory items. +// * @param {IItem[]} items +// * @param {IWarehouse} primaryWarehouse +// * @returns {IItemWarehouseQuantityChange[]} +// */ +// private getWarehousesItemsChanges = ( +// items: IItem[], +// primaryWarehouseId: number +// ): IItemWarehouseQuantityChange[] => { +// return items +// .filter((item: IItem) => item.quantityOnHand) +// .map((item: IItem) => ({ +// itemId: item.id, +// warehouseId: primaryWarehouseId, +// amount: item.quantityOnHand, +// })); +// }; + +// /** +// * Creates initial warehouses items quantity. +// * @param {number} tenantId +// */ +// public run = async ( +// tenantId: number, +// primaryWarehouseId: number, +// trx?: Knex.Transaction +// ): Promise => { +// const { Item } = this.tenancy.models(tenantId); + +// const items = await Item.query(trx).where('type', 'Inventory'); + +// const warehousesChanges = this.getWarehousesItemsChanges( +// items, +// primaryWarehouseId +// ); +// await this.warehousesItemsQuantitySync.mutateWarehousesItemsQuantity( +// tenantId, +// warehousesChanges, +// trx +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/EventsProvider.ts b/packages/server-nest/src/modules/Warehouses/EventsProvider.ts new file mode 100644 index 000000000..421e9297b --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/EventsProvider.ts @@ -0,0 +1,39 @@ +// import { +// BillsActivateWarehousesSubscriber, +// CreditsActivateWarehousesSubscriber, +// InvoicesActivateWarehousesSubscriber, +// ReceiptsActivateWarehousesSubscriber, +// EstimatesActivateWarehousesSubscriber, +// InventoryActivateWarehousesSubscriber, +// VendorCreditsActivateWarehousesSubscriber, +// } from './Subscribers/Activate'; +// import { +// BillWarehousesValidateSubscriber, +// CreditNoteWarehousesValidateSubscriber, +// SaleReceiptWarehousesValidateSubscriber, +// SaleEstimateWarehousesValidateSubscriber, +// SaleInvoicesWarehousesValidateSubscriber, +// VendorCreditWarehousesValidateSubscriber, +// InventoryAdjustmentWarehouseValidatorSubscriber, +// } from './Subscribers/Validators'; +// import { DeleteItemWarehousesQuantitySubscriber } from './Subscribers/DeleteItemWarehousesQuantitySubscriber'; + +// export default () => [ +// BillsActivateWarehousesSubscriber, +// CreditsActivateWarehousesSubscriber, +// InvoicesActivateWarehousesSubscriber, +// ReceiptsActivateWarehousesSubscriber,, +// EstimatesActivateWarehousesSubscriber, +// InventoryActivateWarehousesSubscriber, +// VendorCreditsActivateWarehousesSubscriber, + +// BillWarehousesValidateSubscriber, +// CreditNoteWarehousesValidateSubscriber, +// SaleReceiptWarehousesValidateSubscriber, +// SaleEstimateWarehousesValidateSubscriber, +// SaleInvoicesWarehousesValidateSubscriber, +// VendorCreditWarehousesValidateSubscriber, +// InventoryAdjustmentWarehouseValidatorSubscriber, + +// DeleteItemWarehousesQuantitySubscriber, +// ]; diff --git a/packages/server-nest/src/modules/Warehouses/Integrations/ValidateWarehouseExistance.ts b/packages/server-nest/src/modules/Warehouses/Integrations/ValidateWarehouseExistance.ts new file mode 100644 index 000000000..f54e6d0eb --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Integrations/ValidateWarehouseExistance.ts @@ -0,0 +1,79 @@ +// import { Inject, Service } from 'typedi'; +// import { chain, difference } from 'lodash'; +// import { ServiceError } from '@/exceptions'; +// import { ERRORS } from './constants'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// @Service() +// export class ValidateWarehouseExistance { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Validate transaction warehouse id existance. +// * @param transDTO +// * @param entries +// */ +// public validateWarehouseIdExistance = ( +// transDTO: { warehouseId?: number }, +// entries: { warehouseId?: number }[] = [] +// ) => { +// const notAssignedWarehouseEntries = entries.filter((e) => !e.warehouseId); + +// if (notAssignedWarehouseEntries.length > 0 && !transDTO.warehouseId) { +// throw new ServiceError(ERRORS.WAREHOUSE_ID_NOT_FOUND); +// } +// if (entries.length === 0 && !transDTO.warehouseId) { +// throw new ServiceError(ERRORS.WAREHOUSE_ID_NOT_FOUND); +// } +// }; + +// /** +// * Validate warehouse existance. +// * @param {number} tenantId +// * @param {number} warehouseId +// */ +// public validateWarehouseExistance = ( +// tenantId: number, +// warehouseId: number +// ) => { +// const { Warehouse } = this.tenancy.models(tenantId); + +// const warehouse = Warehouse.query().findById(warehouseId); + +// if (!warehouse) { +// throw new ServiceError(ERRORS.WAREHOUSE_ID_NOT_FOUND); +// } +// }; + +// /** +// * +// * @param {number} tenantId +// * @param {{ warehouseId?: number }[]} entries +// */ +// public validateItemEntriesWarehousesExistance = async ( +// tenantId: number, +// entries: { warehouseId?: number }[] +// ) => { +// const { Warehouse } = this.tenancy.models(tenantId); + +// const entriesWarehousesIds = chain(entries) +// .filter((e) => !!e.warehouseId) +// .map((e) => e.warehouseId) +// .uniq() +// .value(); + +// const warehouses = await Warehouse.query().whereIn( +// 'id', +// entriesWarehousesIds +// ); +// const warehousesIds = warehouses.map((e) => e.id); +// const notFoundWarehousesIds = difference( +// entriesWarehousesIds, +// warehousesIds +// ); +// if (notFoundWarehousesIds.length > 0) { +// throw new ServiceError(ERRORS.WAREHOUSE_ID_NOT_FOUND); +// } +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Integrations/WarehouseTransactionDTOTransform.ts b/packages/server-nest/src/modules/Warehouses/Integrations/WarehouseTransactionDTOTransform.ts new file mode 100644 index 000000000..b73f69d32 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Integrations/WarehouseTransactionDTOTransform.ts @@ -0,0 +1,38 @@ +// import { Service, Inject } from 'typedi'; +// import { omit } from 'lodash'; +// import * as R from 'ramda'; +// import { WarehousesSettings } from '../WarehousesSettings'; + +// @Service() +// export class WarehouseTransactionDTOTransform { +// @Inject() +// private warehousesSettings: WarehousesSettings; + +// /** +// * Excludes DTO warehouse id when mutli-warehouses feature is inactive. +// * @param {number} tenantId +// * @returns {Promise | T>} +// */ +// private excludeDTOWarehouseIdWhenInactive = < +// T extends { warehouseId?: number } +// >( +// tenantId: number, +// DTO: T +// ): Omit | T => { +// const isActive = this.warehousesSettings.isMultiWarehousesActive(tenantId); + +// return !isActive ? omit(DTO, ['warehouseId']) : DTO; +// }; + +// /** +// * +// * @param {number} tenantId +// * @param {T} DTO - +// * @returns {Omit | T} +// */ +// public transformDTO = +// (tenantId: number) => +// (DTO: T): Omit | T => { +// return this.excludeDTOWarehouseIdWhenInactive(tenantId, DTO); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Integrations/WarehousesDTOValidators.ts b/packages/server-nest/src/modules/Warehouses/Integrations/WarehousesDTOValidators.ts new file mode 100644 index 000000000..1977ffc84 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Integrations/WarehousesDTOValidators.ts @@ -0,0 +1,66 @@ +// import { Service, Inject } from 'typedi'; +// import { isEmpty } from 'lodash'; +// import { ValidateWarehouseExistance } from './ValidateWarehouseExistance'; +// import { WarehousesSettings } from '../WarehousesSettings'; + +// interface IWarehouseTransactionDTO { +// warehouseId?: number|null; +// entries?: { warehouseId?: number|null }[]; +// } + +// @Service() +// export class WarehousesDTOValidators { +// @Inject() +// private validateWarehouseExistanceService: ValidateWarehouseExistance; + +// @Inject() +// private warehousesSettings: WarehousesSettings; + +// /** +// * Validates the warehouse existance of sale invoice transaction. +// * @param {number} tenantId +// * @param {ISaleInvoiceCreateDTO | ISaleInvoiceEditDTO} saleInvoiceDTO +// */ +// public validateDTOWarehouseExistance = async ( +// tenantId: number, +// DTO: IWarehouseTransactionDTO +// ) => { +// // Validates the sale invoice warehouse id existance. +// this.validateWarehouseExistanceService.validateWarehouseIdExistance( +// DTO, +// DTO.entries +// ); +// // Validate the sale invoice warehouse existance on the storage. +// if (DTO.warehouseId) { +// this.validateWarehouseExistanceService.validateWarehouseExistance( +// tenantId, +// DTO.warehouseId +// ); +// } +// // Validate the sale invoice entries warehouses existance on the storage. +// if (!isEmpty(DTO.entries)) { +// await this.validateWarehouseExistanceService.validateItemEntriesWarehousesExistance( +// tenantId, +// DTO.entries +// ); +// } +// }; + +// /** +// * Validate the warehouse existance of +// * @param {number} tenantId +// * @param {IWarehouseTransactionDTO} saleInvoiceDTO +// * @returns +// */ +// public validateDTOWarehouseWhenActive = async ( +// tenantId: number, +// DTO: IWarehouseTransactionDTO +// ): Promise => { +// const isActive = this.warehousesSettings.isMultiWarehousesActive(tenantId); + +// // Can't continue if the multi-warehouses feature is inactive. +// if (!isActive) return; + +// return this.validateDTOWarehouseExistance(tenantId, DTO); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Integrations/WarehousesItemsQuantity.ts b/packages/server-nest/src/modules/Warehouses/Integrations/WarehousesItemsQuantity.ts new file mode 100644 index 000000000..c9e0acc7f --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Integrations/WarehousesItemsQuantity.ts @@ -0,0 +1,117 @@ +// import { +// IInventoryTransaction, +// IItemWarehouseQuantityChange, +// } from '@/interfaces'; +// import { set, get, chain, toPairs } from 'lodash'; + +// export class WarehousesItemsQuantity { +// balanceMap: { [warehouseId: number]: { [itemId: number]: number } } = {}; +// /** +// * +// * @param {number} warehouseId +// * @param {number} itemId +// * @returns {number} +// */ +// public get = (warehouseId: number, itemId: number): number => { +// return get(this.balanceMap, `${warehouseId}.${itemId}`, 0); +// }; + +// /** +// * +// * @param {number} warehouseId +// * @param {number} itemId +// * @param {number} amount +// * @returns {WarehousesItemsQuantity} +// */ +// public set = (warehouseId: number, itemId: number, amount: number) => { +// if (!get(this.balanceMap, warehouseId)) { +// set(this.balanceMap, warehouseId, {}); +// } +// set(this.balanceMap, `${warehouseId}.${itemId}`, amount); + +// return this; +// }; + +// /** +// * +// * @param {number} warehouseId +// * @param {number} itemId +// * @param {number} amount +// * @returns {WarehousesItemsQuantity} +// */ +// public increment = (warehouseId: number, itemId: number, amount: number) => { +// const oldAmount = this.get(warehouseId, itemId); + +// return this.set(warehouseId, itemId, oldAmount + amount); +// }; + +// /** +// * +// * @param {number} warehouseId +// * @param {number} itemId +// * @param {number} amount +// * @returns {WarehousesItemsQuantity} +// */ +// public decrement = (warehouseId: number, itemId: number, amount: number) => { +// const oldAmount = this.get(warehouseId, itemId); + +// return this.set(warehouseId, itemId, oldAmount - amount); +// }; + +// /** +// * +// * @returns {WarehousesItemsQuantity} +// */ +// public reverse = () => { +// const collection = this.toArray(); + +// collection.forEach((change) => { +// this.set(change.warehouseId, change.itemId, change.amount * -1); +// }); +// return this; +// }; + +// /** +// * +// * @returns {IItemWarehouseQuantityChange[]} +// */ +// public toArray = (): IItemWarehouseQuantityChange[] => { +// return chain(this.balanceMap) +// .toPairs() +// .map(([warehouseId, item]) => { +// const pairs = toPairs(item); + +// return pairs.map(([itemId, amount]) => ({ +// itemId: parseInt(itemId), +// warehouseId: parseInt(warehouseId), +// amount, +// })); +// }) +// .flatten() +// .value(); +// }; + +// /** +// * +// * @param {IInventoryTransaction[]} inventoryTransactions +// * @returns {WarehousesItemsQuantity} +// */ +// static fromInventoryTransaction = ( +// inventoryTransactions: IInventoryTransaction[] +// ): WarehousesItemsQuantity => { +// const warehouseTransactions = inventoryTransactions.filter( +// (transaction) => transaction.warehouseId +// ); +// const warehouseItemsQuantity = new WarehousesItemsQuantity(); + +// warehouseTransactions.forEach((transaction: IInventoryTransaction) => { +// const change = +// transaction.direction === 'IN' +// ? warehouseItemsQuantity.increment +// : warehouseItemsQuantity.decrement; + +// change(transaction.warehouseId, transaction.itemId, transaction.quantity); +// }); +// return warehouseItemsQuantity; +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Integrations/WarehousesItemsQuantitySynSubscriber.ts b/packages/server-nest/src/modules/Warehouses/Integrations/WarehousesItemsQuantitySynSubscriber.ts new file mode 100644 index 000000000..f9c026139 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Integrations/WarehousesItemsQuantitySynSubscriber.ts @@ -0,0 +1,74 @@ +// import events from '@/subscribers/events'; +// import { Service, Inject } from 'typedi'; +// import { WarehousesItemsQuantitySync } from './WarehousesItemsQuantitySync'; +// import { +// IInventoryTransactionsCreatedPayload, +// IInventoryTransactionsDeletedPayload, +// } from '@/interfaces'; +// import { WarehousesSettings } from '../WarehousesSettings'; + +// @Service() +// export class WarehousesItemsQuantitySyncSubscriber { +// @Inject() +// private warehousesItemsQuantitySync: WarehousesItemsQuantitySync; + +// @Inject() +// private warehousesSettings: WarehousesSettings; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.inventory.onInventoryTransactionsCreated, +// this.syncWarehousesItemsQuantityOnInventoryTransCreated +// ); +// bus.subscribe( +// events.inventory.onInventoryTransactionsDeleted, +// this.syncWarehousesItemsQuantityOnInventoryTransDeleted +// ); +// return bus; +// } + +// /** +// * Syncs warehouses items quantity once inventory transactions created. +// * @param {IInventoryTransactionsCreatedPayload} +// */ +// private syncWarehousesItemsQuantityOnInventoryTransCreated = async ({ +// tenantId, +// inventoryTransactions, +// trx, +// }: IInventoryTransactionsCreatedPayload) => { +// const isActive = this.warehousesSettings.isMultiWarehousesActive(tenantId); + +// // Can't continue if the warehouses features is not active. +// if (!isActive) return; + +// await this.warehousesItemsQuantitySync.mutateWarehousesItemsQuantityFromTransactions( +// tenantId, +// inventoryTransactions, +// trx +// ); +// }; + +// /** +// * Syncs warehouses items quantity once inventory transactions deleted. +// * @param {IInventoryTransactionsDeletedPayload} +// */ +// private syncWarehousesItemsQuantityOnInventoryTransDeleted = async ({ +// tenantId, +// oldInventoryTransactions, +// trx, +// }: IInventoryTransactionsDeletedPayload) => { +// const isActive = this.warehousesSettings.isMultiWarehousesActive(tenantId); + +// // Can't continue if the warehouses feature is not active yet. +// if (!isActive) return; + +// await this.warehousesItemsQuantitySync.reverseWarehousesItemsQuantityFromTransactions( +// tenantId, +// oldInventoryTransactions, +// trx +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Integrations/WarehousesItemsQuantitySync.ts b/packages/server-nest/src/modules/Warehouses/Integrations/WarehousesItemsQuantitySync.ts new file mode 100644 index 000000000..9c4ccf84e --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Integrations/WarehousesItemsQuantitySync.ts @@ -0,0 +1,131 @@ +// import { Knex } from 'knex'; +// import { Service, Inject } from 'typedi'; +// import { omit } from 'lodash'; +// import { +// IInventoryTransaction, +// IItemWarehouseQuantityChange, +// } from '@/interfaces'; +// import { WarehousesItemsQuantity } from './WarehousesItemsQuantity'; +// import HasTenancyService from '@/services/Tenancy/TenancyService'; + +// @Service() +// export class WarehousesItemsQuantitySync { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Retrieves the reversed warehouses items quantity changes. +// * @param {IInventoryTransaction[]} inventoryTransactions +// * @returns {IItemWarehouseQuantityChange[]} +// */ +// public getReverseWarehousesItemsQuantityChanges = ( +// inventoryTransactions: IInventoryTransaction[] +// ): IItemWarehouseQuantityChange[] => { +// const warehouseItemsQuantity = +// WarehousesItemsQuantity.fromInventoryTransaction(inventoryTransactions); + +// return warehouseItemsQuantity.reverse().toArray(); +// }; + +// /** +// * Retrieves the warehouses items changes from the given inventory tranasctions. +// * @param {IInventoryTransaction[]} inventoryTransactions +// * @returns {IItemWarehouseQuantityChange[]} +// */ +// public getWarehousesItemsQuantityChange = ( +// inventoryTransactions: IInventoryTransaction[] +// ): IItemWarehouseQuantityChange[] => { +// const warehouseItemsQuantity = +// WarehousesItemsQuantity.fromInventoryTransaction(inventoryTransactions); + +// return warehouseItemsQuantity.toArray(); +// }; + +// /** +// * Mutates warehouses items quantity on hand on the storage. +// * @param {number} tenantId +// * @param {IItemWarehouseQuantityChange[]} warehousesItemsQuantity +// * @param {Knex.Transaction} trx +// */ +// public mutateWarehousesItemsQuantity = async ( +// tenantId: number, +// warehousesItemsQuantity: IItemWarehouseQuantityChange[], +// trx?: Knex.Transaction +// ): Promise => { +// const mutationsOpers = warehousesItemsQuantity.map( +// (change: IItemWarehouseQuantityChange) => +// this.mutateWarehouseItemQuantity(tenantId, change, trx) +// ); +// await Promise.all(mutationsOpers); +// }; + +// /** +// * Mutates the warehouse item quantity. +// * @param {number} tenantId +// * @param {number} warehouseItemQuantity +// * @param {Knex.Transaction} trx +// */ +// public mutateWarehouseItemQuantity = async ( +// tenantId: number, +// warehouseItemQuantity: IItemWarehouseQuantityChange, +// trx: Knex.Transaction +// ): Promise => { +// const { ItemWarehouseQuantity } = this.tenancy.models(tenantId); + +// const itemWarehouseQuantity = await ItemWarehouseQuantity.query(trx) +// .where('itemId', warehouseItemQuantity.itemId) +// .where('warehouseId', warehouseItemQuantity.warehouseId) +// .first(); + +// if (itemWarehouseQuantity) { +// await ItemWarehouseQuantity.changeAmount( +// { +// itemId: warehouseItemQuantity.itemId, +// warehouseId: warehouseItemQuantity.warehouseId, +// }, +// 'quantityOnHand', +// warehouseItemQuantity.amount, +// trx +// ); +// } else { +// await ItemWarehouseQuantity.query(trx).insert({ +// ...omit(warehouseItemQuantity, ['amount']), +// quantityOnHand: warehouseItemQuantity.amount, +// }); +// } +// }; + +// /** +// * Mutates warehouses items quantity from inventory transactions. +// * @param {number} tenantId - +// * @param {IInventoryTransaction[]} inventoryTransactions - +// * @param {Knex.Transaction} +// */ +// public mutateWarehousesItemsQuantityFromTransactions = async ( +// tenantId: number, +// inventoryTransactions: IInventoryTransaction[], +// trx?: Knex.Transaction +// ) => { +// const changes = this.getWarehousesItemsQuantityChange( +// inventoryTransactions +// ); +// await this.mutateWarehousesItemsQuantity(tenantId, changes, trx); +// }; + +// /** +// * Reverses warehouses items quantity from inventory transactions. +// * @param {number} tenantId +// * @param {IInventoryTransaction[]} inventoryTransactions +// * @param {Knex.Transaction} trx +// */ +// public reverseWarehousesItemsQuantityFromTransactions = async ( +// tenantId: number, +// inventoryTransactions: IInventoryTransaction[], +// trx?: Knex.Transaction +// ) => { +// const changes = this.getReverseWarehousesItemsQuantityChanges( +// inventoryTransactions +// ); +// await this.mutateWarehousesItemsQuantity(tenantId, changes, trx); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Integrations/constants.ts b/packages/server-nest/src/modules/Warehouses/Integrations/constants.ts new file mode 100644 index 000000000..f1799f58d --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Integrations/constants.ts @@ -0,0 +1,4 @@ +export const ERRORS = { + WAREHOUSE_ID_NOT_FOUND: 'WAREHOUSE_ID_NOT_FOUND', + ITEM_ENTRY_WAREHOUSE_ID_NOT_FOUND: 'ITEM_ENTRY_WAREHOUSE_ID_NOT_FOUND', +}; diff --git a/packages/server-nest/src/modules/Warehouses/Items/GetItemWarehouses.ts b/packages/server-nest/src/modules/Warehouses/Items/GetItemWarehouses.ts new file mode 100644 index 000000000..0dde7c901 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Items/GetItemWarehouses.ts @@ -0,0 +1,41 @@ +import { GetItemWarehouseTransformer } from './GettItemWarehouseTransformer'; +import { Inject, Injectable } from '@nestjs/common'; +import { ItemWarehouseQuantity } from '../models/ItemWarehouseQuantity'; +import { Item } from '@/modules/Items/models/Item'; +import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; + +@Injectable() +export class GetItemWarehouses { + constructor( + @Inject(ItemWarehouseQuantity.name) + private readonly itemWarehouseQuantityModel: typeof ItemWarehouseQuantity, + + @Inject(Item.name) + private readonly itemModel: typeof Item, + private readonly transformer: TransformerInjectable, + ) {} + + /** + * Retrieves the item warehouses. + * @param {number} itemId + * @returns + */ + public getItemWarehouses = async (itemId: number) => { + // Retrieves specific item or throw not found service error. + const item = await this.itemModel + .query() + .findById(itemId) + .throwIfNotFound(); + + const itemWarehouses = await this.itemWarehouseQuantityModel + .query() + .where('itemId', itemId) + .withGraphFetched('warehouse'); + + // Retrieves the transformed items warehouses. + return this.transformer.transform( + itemWarehouses, + new GetItemWarehouseTransformer(), + ); + }; +} diff --git a/packages/server-nest/src/modules/Warehouses/Items/GettItemWarehouseTransformer.ts b/packages/server-nest/src/modules/Warehouses/Items/GettItemWarehouseTransformer.ts new file mode 100644 index 000000000..2daab9206 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Items/GettItemWarehouseTransformer.ts @@ -0,0 +1,46 @@ +import { Transformer } from '@/modules/Transformer/Transformer'; +import { Item } from '@/modules/Items/models/Item'; + +export class GetItemWarehouseTransformer extends Transformer { + /** + * Include these attributes to sale invoice object. + * @returns {Array} + */ + public includeAttributes = (): string[] => { + return [ + 'warehouseId', + 'warehouseName', + 'warehouseCode', + 'quantityOnHandFormatted', + ]; + }; + + /** + * Exclude the warehouse attribute. + * @returns {Array} + */ + public excludeAttributes = (): string[] => { + return ['warehouse']; + }; + + /** + * Formatted sell price. + * @param item + * @returns {string} + */ + public quantityOnHandFormatted(item: Item): string { + return this.formatNumber(item.quantityOnHand, { money: false }); + } + + public warehouseCode(item: Item): string { + return item.warehouse.code; + } + + public warehouseName(item: Item): string { + return item.warehouse.name; + } + + public warehouseId(item: Item): number { + return item.warehouse.id; + } +} diff --git a/packages/server-nest/src/modules/Warehouses/UpdateInventoryTransactionsWithWarehouse.ts b/packages/server-nest/src/modules/Warehouses/UpdateInventoryTransactionsWithWarehouse.ts new file mode 100644 index 000000000..f59c49c4d --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/UpdateInventoryTransactionsWithWarehouse.ts @@ -0,0 +1,21 @@ +// import HasTenancyService from '@/services/Tenancy/TenancyService'; +// import { Service, Inject } from 'typedi'; + +// @Service() +// export class UpdateInventoryTransactionsWithWarehouse { +// @Inject() +// tenancy: HasTenancyService; + +// /** +// * Updates all inventory transactions with primary warehouse. +// * @param {number} tenantId - +// * @param {number} warehouseId - +// */ +// public run = async (tenantId: number, primaryWarehouseId: number) => { +// const { InventoryTransaction } = this.tenancy.models(tenantId); + +// await InventoryTransaction.query().update({ +// warehouseId: primaryWarehouseId, +// }); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/Warehouse.types.ts b/packages/server-nest/src/modules/Warehouses/Warehouse.types.ts new file mode 100644 index 000000000..ca55aef8c --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/Warehouse.types.ts @@ -0,0 +1,212 @@ +import { Knex } from 'knex'; + +export interface IWarehouse { + id?: number; +} +export interface IWarehouseTransfer { + id?: number; + date: Date; + fromWarehouseId: number; + toWarehouseId: number; + reason?: string; + transactionNumber: string; + entries: IWarehouseTransferEntry[]; + transferInitiatedAt?: Date; + transferDeliveredAt?: Date; + + isInitiated?: boolean; + isTransferred?: boolean; +} +export interface IWarehouseTransferEntry { + id?: number; + index?: number; + itemId: number; + description: string; + quantity: number; + cost: number; +} +export interface ICreateWarehouseDTO { + name: string; + code: string; + + city?: string; + country?: string; + address?: string; + + primary?: boolean; +} +export interface IEditWarehouseDTO { + name: string; + code: string; + + city: string; + country: string; + address: string; +} + +export interface IWarehouseTransferEntryDTO { + index?: number; + itemId: number; + description: string; + quantity: number; + cost?: number; +} + +export interface ICreateWarehouseTransferDTO { + fromWarehouseId: number; + toWarehouseId: number; + transactionNumber: string; + date: Date; + transferInitiated: boolean; + transferDelivered: boolean; + entries: IWarehouseTransferEntryDTO[]; +} +export interface IEditWarehouseTransferDTO { + fromWarehouseId: number; + toWarehouseId: number; + transactionNumber: string; + date: Date; + entries: { + id?: number; + itemId: number; + description: string; + quantity: number; + }[]; +} + +export interface IWarehouseEditPayload { + tenantId: number; + warehouseId: number; + warehouseDTO: IEditWarehouseDTO; + trx: Knex.Transaction; +} + +export interface IWarehouseEditedPayload { + tenantId: number; + warehouse: IWarehouse; + warehouseDTO: IEditWarehouseDTO; + trx: Knex.Transaction; +} + +export interface IWarehouseDeletePayload { + // tenantId: number; + warehouseId: number; + trx: Knex.Transaction; +} +export interface IWarehouseDeletedPayload { + tenantId: number; + warehouseId: number; + trx: Knex.Transaction; +} +export interface IWarehouseCreatePayload { + // tenantId: number; + warehouseDTO: ICreateWarehouseDTO; + trx: Knex.Transaction; +} + +export interface IWarehouseCreatedPayload { + // tenantId: number; + warehouse: IWarehouse; + warehouseDTO: ICreateWarehouseDTO; + trx: Knex.Transaction; +} + +export interface IWarehouseTransferCreate { + trx: Knex.Transaction; + warehouseTransferDTO: ICreateWarehouseTransferDTO; + tenantId: number; +} + +export interface IWarehouseTransferCreated { + trx: Knex.Transaction; + warehouseTransfer: IWarehouseTransfer; + warehouseTransferDTO: ICreateWarehouseTransferDTO; + // tenantId: number; +} + +export interface IWarehouseTransferEditPayload { + // tenantId: number; + editWarehouseDTO: IEditWarehouseTransferDTO; + oldWarehouseTransfer: IWarehouseTransfer; + trx: Knex.Transaction; +} + +export interface IWarehouseTransferEditedPayload { + // tenantId: number; + editWarehouseDTO: IEditWarehouseTransferDTO; + oldWarehouseTransfer: IWarehouseTransfer; + warehouseTransfer: IWarehouseTransfer; + trx: Knex.Transaction; +} + +export interface IWarehouseTransferDeletePayload { + // tenantId: number; + oldWarehouseTransfer: IWarehouseTransfer; + trx: Knex.Transaction; +} + +export interface IWarehouseTransferDeletedPayload { + // tenantId: number; + warehouseTransfer: IWarehouseTransfer; + oldWarehouseTransfer: IWarehouseTransfer; + trx: Knex.Transaction; +} + +export interface IGetWarehousesTransfersFilterDTO { + page: number; + pageSize: number; + searchKeyword: string; +} + +export interface IItemWarehouseQuantityChange { + itemId: number; + warehouseId: number; + amount: number; +} + +export interface IWarehousesActivatePayload { + // tenantId: number; +} +export interface IWarehousesActivatedPayload { + // tenantId: number; + primaryWarehouse: IWarehouse; +} + +export interface IWarehouseMarkAsPrimaryPayload { + // tenantId: number; + oldWarehouse: IWarehouse; + trx: Knex.Transaction; +} +export interface IWarehouseMarkedAsPrimaryPayload { + // tenantId: number; + oldWarehouse: IWarehouse; + markedWarehouse: IWarehouse; + trx: Knex.Transaction; +} + +export interface IWarehouseTransferInitiatePayload { + // tenantId: number; + oldWarehouseTransfer: IWarehouseTransfer; + trx: Knex.Transaction; +} + + +export interface IWarehouseTransferInitiatedPayload { + // tenantId: number; + warehouseTransfer: IWarehouseTransfer; + oldWarehouseTransfer: IWarehouseTransfer; + trx: Knex.Transaction; +} + +export interface IWarehouseTransferTransferingPayload { + // tenantId: number; + oldWarehouseTransfer: IWarehouseTransfer; + trx: Knex.Transaction; +} + +export interface IWarehouseTransferTransferredPayload { + // tenantId: number; + warehouseTransfer: IWarehouseTransfer; + oldWarehouseTransfer: IWarehouseTransfer; + trx: Knex.Transaction; +} diff --git a/packages/server-nest/src/modules/Warehouses/WarehousesApplication.service.ts b/packages/server-nest/src/modules/Warehouses/WarehousesApplication.service.ts new file mode 100644 index 000000000..22a410f8c --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/WarehousesApplication.service.ts @@ -0,0 +1,111 @@ +import { + ICreateWarehouseDTO, + IEditWarehouseDTO, + IWarehouse, +} from './Warehouse.types'; +import { ActivateWarehousesService } from './commands/ActivateWarehouses'; +import { CreateWarehouse } from './commands/CreateWarehouse.service'; +import { DeleteWarehouseService } from './commands/DeleteWarehouse.service'; +import { EditWarehouse } from './commands/EditWarehouse.service'; +import { GetWarehouse } from './queries/GetWarehouse'; +import { GetWarehouses } from './queries/GetWarehouses'; +import { GetItemWarehouses } from './Items/GetItemWarehouses'; +import { WarehouseMarkPrimary } from './commands/WarehouseMarkPrimary.service'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class WarehousesApplication { + constructor( + private createWarehouseService: CreateWarehouse, + private editWarehouseService: EditWarehouse, + private deleteWarehouseService: DeleteWarehouseService, + private getWarehouseService: GetWarehouse, + private getWarehousesService: GetWarehouses, + private activateWarehousesService: ActivateWarehousesService, + private markWarehousePrimaryService: WarehouseMarkPrimary, + private getItemWarehousesService: GetItemWarehouses, + ) {} + + /** + * Creates a new warehouse. + * @param {ICreateWarehouseDTO} createWarehouseDTO + * @returns {Promise} + */ + public createWarehouse = (createWarehouseDTO: ICreateWarehouseDTO) => { + return this.createWarehouseService.createWarehouse(createWarehouseDTO); + }; + + /** + * Edits the given warehouse. + * @param {number} tenantId + * @param {number} warehouseId + * @param {IEditWarehouseDTO} editWarehouseDTO + * @returns {Promise} + */ + public editWarehouse = ( + warehouseId: number, + editWarehouseDTO: IEditWarehouseDTO, + ) => { + return this.editWarehouseService.editWarehouse( + warehouseId, + editWarehouseDTO, + ); + }; + + /** + * Deletes the given warehouse. + * @param {number} tenantId + * @param {number} warehouseId + */ + public deleteWarehouse = (warehouseId: number) => { + return this.deleteWarehouseService.deleteWarehouse(warehouseId); + }; + + /** + * Retrieves the specific warehouse. + * @param {number} warehouseId + * @returns + */ + public getWarehouse = (warehouseId: number) => { + return this.getWarehouseService.getWarehouse(warehouseId); + }; + + /** + * + * @param {number} tenantId + * @returns + */ + public getWarehouses = () => { + return this.getWarehousesService.getWarehouses(); + }; + + /** + * Activates the warehouses feature. + * @returns {Promise} + */ + public activateWarehouses = () => { + return this.activateWarehousesService.activateWarehouses(); + }; + + /** + * Mark the given warehouse as primary. + * @param {number} tenantId - + * @returns {Promise} + */ + public markWarehousePrimary = ( + tenantId: number, + warehouseId: number, + ): Promise => { + return this.markWarehousePrimaryService.markAsPrimary(warehouseId); + }; + + /** + * Retrieves the specific item warehouses quantity. + * @param {number} tenantId + * @param {number} itemId + * @returns + */ + public getItemWarehouses = (itemId: number): Promise => { + return this.getItemWarehousesService.getItemWarehouses(itemId); + }; +} diff --git a/packages/server-nest/src/modules/Warehouses/WarehousesSettings.ts b/packages/server-nest/src/modules/Warehouses/WarehousesSettings.ts new file mode 100644 index 000000000..05b640e11 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/WarehousesSettings.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class WarehousesSettings { + /** + * Marks multi-warehouses as activated. + */ + public markMutliwarehoussAsActivated = () => { + // const settings = this.tenancy.settings(tenantId); + + // settings.set({ group: 'features', key: Features.WAREHOUSES, value: 1 }); + }; + + /** + * Detarmines multi-warehouses is active. + * @param {number} tenantId + * @returns {boolean} + */ + public isMultiWarehousesActive = () => { + // const settings = this.tenancy.settings(tenantId); + + // return settings.get({ group: 'features', key: Features.WAREHOUSES }); + return true; + }; +} diff --git a/packages/server-nest/src/modules/Warehouses/commands/ActivateWarehouses.ts b/packages/server-nest/src/modules/Warehouses/commands/ActivateWarehouses.ts new file mode 100644 index 000000000..9d8ce7bae --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/commands/ActivateWarehouses.ts @@ -0,0 +1,60 @@ +import { Knex } from 'knex'; +import { Injectable } from '@nestjs/common'; +import { CreateInitialWarehouse } from './CreateInitialWarehouse.service'; +import { WarehousesSettings } from '../WarehousesSettings'; +import { ERRORS } from '../contants'; +import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { ServiceError } from '@/modules/Items/ServiceError'; +import { events } from '@/common/events/events'; + +@Injectable() +export class ActivateWarehousesService { + /** + * @param {UnitOfWork} uow - Unit of work. + * @param {EventEmitter2} eventEmitter - Event emitter. + * @param {CreateInitialWarehouse} createInitialWarehouse - Create initial warehouse service. + * @param {WarehousesSettings} settings - Warehouses settings. + */ + constructor( + private readonly uow: UnitOfWork, + private readonly eventEmitter: EventEmitter2, + private readonly createInitialWarehouse: CreateInitialWarehouse, + private readonly settings: WarehousesSettings, + ) {} + + /** + * Throws error if the multi-warehouses is already activated. + */ + private throwIfWarehousesActivated(isActivated: boolean): void { + if (isActivated) { + throw new ServiceError(ERRORS.MUTLI_WAREHOUSES_ALREADY_ACTIVATED); + } + } + + /** + * Activates the multi-warehouses. + * + * - Creates a new warehouses and mark it as primary. + * - Seed warehouses items quantity. + * - Mutate inventory transactions with the primary warehouse. + */ + public async activateWarehouses(): Promise { + const isActivated = this.settings.isMultiWarehousesActive(); + this.throwIfWarehousesActivated(isActivated); + + return this.uow.withTransaction(async (trx: Knex.Transaction) => { + await this.eventEmitter.emitAsync(events.warehouse.onActivate, { trx }); + + const primaryWarehouse = + await this.createInitialWarehouse.createInitialWarehouse(); + + this.settings.markMutliwarehoussAsActivated(); + + await this.eventEmitter.emitAsync(events.warehouse.onActivated, { + primaryWarehouse, + trx, + }); + }); + } +} diff --git a/packages/server-nest/src/modules/Warehouses/commands/CreateInitialWarehouse.service.ts b/packages/server-nest/src/modules/Warehouses/commands/CreateInitialWarehouse.service.ts new file mode 100644 index 000000000..1761c34c1 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/commands/CreateInitialWarehouse.service.ts @@ -0,0 +1,27 @@ +import { CreateWarehouse } from './CreateWarehouse.service'; +import { Injectable } from '@nestjs/common'; +import { I18nContext } from 'nestjs-i18n'; + +@Injectable() +export class CreateInitialWarehouse { + /** + * @param {CreateWarehouse} createWarehouse - Create warehouse service. + * @param {I18nContext} i18n - I18n context. + */ + constructor( + private readonly createWarehouse: CreateWarehouse, + private readonly i18n: I18nContext, + ) {} + + /** + * Creates a initial warehouse. + * @param {number} tenantId + */ + public createInitialWarehouse = async () => { + return this.createWarehouse.createWarehouse({ + name: this.i18n.t('warehouses.primary_warehouse'), + code: '10001', + primary: true, + }); + }; +} diff --git a/packages/server-nest/src/modules/Warehouses/commands/CreateWarehouse.service.ts b/packages/server-nest/src/modules/Warehouses/commands/CreateWarehouse.service.ts new file mode 100644 index 000000000..d057062eb --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/commands/CreateWarehouse.service.ts @@ -0,0 +1,73 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Knex } from 'knex'; +import { + ICreateWarehouseDTO, + IWarehouseCreatedPayload, + IWarehouseCreatePayload, +} from '../Warehouse.types'; +import { WarehouseValidator } from './WarehouseValidator.service'; +import { Warehouse } from '../models/Warehouse.model'; +import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { events } from '@/common/events/events'; + +@Injectable() +export class CreateWarehouse { + /** + * @param {UnitOfWork} uow - Unit of work. + * @param {EventEmitter2} eventEmitter - Event emitter. + * @param {WarehouseValidator} validator - Warehouse command validator. + * @param {typeof Warehouse} warehouseModel - Warehouse model. + */ + constructor( + private readonly uow: UnitOfWork, + private readonly eventEmitter: EventEmitter2, + private readonly validator: WarehouseValidator, + + @Inject(Warehouse.name) + private readonly warehouseModel: typeof Warehouse, + ) {} + + /** + * Authorize the warehouse before creating. + * @param {ICreateWarehouseDTO} warehouseDTO - + */ + public authorize = async (warehouseDTO: ICreateWarehouseDTO) => { + if (warehouseDTO.code) { + await this.validator.validateWarehouseCodeUnique(warehouseDTO.code); + } + }; + + /** + * Creates a new warehouse on the system. + * @param {ICreateWarehouseDTO} warehouseDTO + */ + public createWarehouse = async ( + warehouseDTO: ICreateWarehouseDTO + ): Promise => { + // Authorize warehouse before creating. + await this.authorize(warehouseDTO); + + return this.uow.withTransaction(async (trx: Knex.Transaction) => { + // Triggers `onWarehouseCreate` event. + await this.eventEmitter.emitAsync(events.warehouse.onEdit, { + warehouseDTO, + trx, + } as IWarehouseCreatePayload); + + // Creates a new warehouse on the storage. + const warehouse = await this.warehouseModel.query(trx).insertAndFetch({ + ...warehouseDTO, + }); + + // Triggers `onWarehouseCreated` event. + await this.eventEmitter.emitAsync(events.warehouse.onCreated, { + warehouseDTO, + warehouse, + trx, + } as IWarehouseCreatedPayload); + + return warehouse; + }); + }; +} diff --git a/packages/server-nest/src/modules/Warehouses/commands/DeleteItemWarehousesQuantity.ts b/packages/server-nest/src/modules/Warehouses/commands/DeleteItemWarehousesQuantity.ts new file mode 100644 index 000000000..89f2611dc --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/commands/DeleteItemWarehousesQuantity.ts @@ -0,0 +1,29 @@ +import { Knex } from 'knex'; +import { Inject, Injectable } from '@nestjs/common'; +import { ItemWarehouseQuantity } from '../models/ItemWarehouseQuantity'; + +@Injectable() +export class DeleteItemWarehousesQuantity { + /** + * @param {typeof ItemWarehouseQuantity} itemWarehouseQuantityModel - Item warehouse quantity model. + */ + constructor( + @Inject(ItemWarehouseQuantity.name) + private readonly itemWarehouseQuantityModel: typeof ItemWarehouseQuantity, + ) {} + + /** + * Deletes the given item warehouses quantities. + * @param {number} itemId + * @param {Knex.Transaction} trx - + */ + public deleteItemWarehousesQuantity = async ( + itemId: number, + trx?: Knex.Transaction, + ): Promise => { + await this.itemWarehouseQuantityModel + .query(trx) + .where('itemId', itemId) + .delete(); + }; +} diff --git a/packages/server-nest/src/modules/Warehouses/commands/DeleteWarehouse.service.ts b/packages/server-nest/src/modules/Warehouses/commands/DeleteWarehouse.service.ts new file mode 100644 index 000000000..558e2ef9b --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/commands/DeleteWarehouse.service.ts @@ -0,0 +1,81 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Knex } from 'knex'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { + IWarehouseDeletedPayload, + IWarehouseDeletePayload, +} from '../Warehouse.types'; +import { WarehouseValidator } from './WarehouseValidator.service'; +import { ERRORS } from '../contants'; +import { Warehouse } from '../models/Warehouse.model'; +import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; +import { events } from '@/common/events/events'; + +@Injectable() +export class DeleteWarehouseService { + /** + * @param {UnitOfWork} uow - Unit of work. + * @param {EventEmitter2} eventPublisher - Event emitter. + * @param {WarehouseValidator} validator - Warehouse command validator. + * @param {typeof Warehouse} warehouseModel - Warehouse model. + */ + constructor( + private readonly uow: UnitOfWork, + private readonly eventPublisher: EventEmitter2, + private readonly validator: WarehouseValidator, + + @Inject(Warehouse.name) + private readonly warehouseModel: typeof Warehouse, + ) {} + + /** + * Validates the given warehouse before deleting. + * @param {number} warehouseId + * @returns {Promise} + */ + public authorize = async (warehouseId: number): Promise => { + await this.validator.validateWarehouseNotOnlyWarehouse(warehouseId); + }; + + /** + * Deletes specific warehouse. + * @param {number} warehouseId + * @returns {Promise} + */ + public deleteWarehouse = async (warehouseId: number): Promise => { + // Retrieves the old warehouse or throw not found service error. + const oldWarehouse = await this.warehouseModel + .query() + .findById(warehouseId) + .throwIfNotFound() + .queryAndThrowIfHasRelations({ + type: ERRORS.WAREHOUSE_HAS_ASSOCIATED_TRANSACTIONS, + }); + + // Validates the given warehouse before deleting. + await this.authorize(warehouseId); + + // Creates a new warehouse under unit-of-work. + return this.uow.withTransaction(async (trx: Knex.Transaction) => { + const eventPayload = { + warehouseId, + oldWarehouse, + trx, + } as IWarehouseDeletePayload | IWarehouseDeletedPayload; + + // Triggers `onWarehouseCreate`. + await this.eventPublisher.emitAsync( + events.warehouse.onDelete, + eventPayload, + ); + // Deletes the given warehouse from the storage. + await this.warehouseModel.query().findById(warehouseId).delete(); + + // Triggers `onWarehouseCreated`. + await this.eventPublisher.emitAsync( + events.warehouse.onDeleted, + eventPayload as IWarehouseDeletedPayload, + ); + }); + }; +} diff --git a/packages/server-nest/src/modules/Warehouses/commands/EditWarehouse.service.ts b/packages/server-nest/src/modules/Warehouses/commands/EditWarehouse.service.ts new file mode 100644 index 000000000..b9153a045 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/commands/EditWarehouse.service.ts @@ -0,0 +1,79 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Knex } from 'knex'; +import { IEditWarehouseDTO, IWarehouse } from '../Warehouse.types'; +import { WarehouseValidator } from './WarehouseValidator.service'; +import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { Warehouse } from '../models/Warehouse.model'; +import { events } from '@/common/events/events'; + +@Injectable() +export class EditWarehouse { + /** + * @param {UnitOfWork} uow - Unit of work. + * @param {EventEmitter2} eventPublisher - Event emitter. + * @param {WarehouseValidator} validator - Warehouse command validator. + * @param {typeof Warehouse} warehouseModel - Warehouse model. + */ + constructor( + private readonly uow: UnitOfWork, + private readonly eventPublisher: EventEmitter2, + private readonly validator: WarehouseValidator, + + @Inject(Warehouse.name) + private readonly warehouseModel: typeof Warehouse, + ) {} + + /** + * Authorize the warehouse before deleting. + */ + public authorize = async ( + warehouseDTO: IEditWarehouseDTO, + warehouseId: number, + ) => { + if (warehouseDTO.code) { + await this.validator.validateWarehouseCodeUnique( + warehouseDTO.code, + warehouseId, + ); + } + }; + + /** + * Edits a new warehouse on the system. + * @param {ICreateWarehouseDTO} warehouseDTO + * @returns {Promise} + */ + public editWarehouse = async ( + warehouseId: number, + warehouseDTO: IEditWarehouseDTO, + ): Promise => { + // Authorize the warehouse DTO before editing. + await this.authorize(warehouseDTO, warehouseId); + + // Edits warehouse under unit-of-work. + return this.uow.withTransaction(async (trx: Knex.Transaction) => { + // Triggers `onWarehouseEdit` event. + await this.eventPublisher.emitAsync(events.warehouse.onEdit, { + warehouseId, + warehouseDTO, + trx, + }); + // Updates the given branch on the storage. + const warehouse = await this.warehouseModel + .query() + .patchAndFetchById(warehouseId, { + ...warehouseDTO, + }); + + // Triggers `onWarehouseEdited` event. + await this.eventPublisher.emitAsync(events.warehouse.onEdited, { + warehouse, + warehouseDTO, + trx, + }); + + return warehouse; + }); + }; +} diff --git a/packages/server-nest/src/modules/Warehouses/commands/WarehouseMarkPrimary.service.ts b/packages/server-nest/src/modules/Warehouses/commands/WarehouseMarkPrimary.service.ts new file mode 100644 index 000000000..b73aaca52 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/commands/WarehouseMarkPrimary.service.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@nestjs/common'; +import { Knex } from 'knex'; +import { + IWarehouseMarkAsPrimaryPayload, + IWarehouseMarkedAsPrimaryPayload, +} from '../Warehouse.types'; +import { Warehouse } from '../models/Warehouse.model'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; +import { events } from '@/common/events/events'; + +@Injectable() +export class WarehouseMarkPrimary { + constructor( + private readonly warehouseModel: typeof Warehouse, + private readonly uow: UnitOfWork, + private readonly eventPublisher: EventEmitter2, + ) { + } + + /** + * Marks the given warehouse as primary. + * @param {number} warehouseId + * @returns {Promise} + */ + public async markAsPrimary(warehouseId: number) { + const oldWarehouse = await this.warehouseModel + .query() + .findById(warehouseId) + .throwIfNotFound(); + + return this.uow.withTransaction(async (trx: Knex.Transaction) => { + await this.eventPublisher.emitAsync(events.warehouse.onMarkPrimary, { + oldWarehouse, + trx, + } as IWarehouseMarkAsPrimaryPayload); + + await this.warehouseModel.query(trx).update({ primary: false }); + + const markedWarehouse = await this.warehouseModel + .query(trx) + .patchAndFetchById(warehouseId, { primary: true }); + + await this.eventPublisher.emitAsync(events.warehouse.onMarkedPrimary, { + oldWarehouse, + markedWarehouse, + trx, + } as IWarehouseMarkedAsPrimaryPayload); + + return markedWarehouse; + }); + } +} diff --git a/packages/server-nest/src/modules/Warehouses/commands/WarehouseValidator.service.ts b/packages/server-nest/src/modules/Warehouses/commands/WarehouseValidator.service.ts new file mode 100644 index 000000000..b209162bc --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/commands/WarehouseValidator.service.ts @@ -0,0 +1,51 @@ + +import { ServiceError } from '@/modules/Items/ServiceError'; +import { Inject } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; +import { ERRORS } from '../contants'; +import { Warehouse } from '../models/Warehouse.model'; + +@Injectable() +export class WarehouseValidator { + constructor( + @Inject(Warehouse.name) + private readonly warehouseModel: typeof Warehouse, + ) {} + + /** + * Validates the warehouse not only warehouse. + * @param {number} warehouseId + */ + public validateWarehouseNotOnlyWarehouse = async (warehouseId: number) => { + const warehouses = await this.warehouseModel.query().whereNot('id', warehouseId); + + if (warehouses.length === 0) { + throw new ServiceError(ERRORS.COULD_NOT_DELETE_ONLY_WAERHOUSE); + } + }; + + /** + * Validates the warehouse code uniqueness. + * @param {string} code + * @param {number} exceptWarehouseId + */ + public validateWarehouseCodeUnique = async ( + code: string, + exceptWarehouseId?: number, + ) => { + const warehouse = await this.warehouseModel.query() + .onBuild((query) => { + query.select(['id']); + query.where('code', code); + + if (exceptWarehouseId) { + query.whereNot('id', exceptWarehouseId); + } + }) + .first(); + + if (warehouse) { + throw new ServiceError(ERRORS.WAREHOUSE_CODE_NOT_UNIQUE); + } + }; +} diff --git a/packages/server-nest/src/modules/Warehouses/contants.ts b/packages/server-nest/src/modules/Warehouses/contants.ts new file mode 100644 index 000000000..e41d9b3ff --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/contants.ts @@ -0,0 +1,7 @@ +export const ERRORS = { + WAREHOUSE_NOT_FOUND: 'WAREHOUSE_NOT_FOUND', + MUTLI_WAREHOUSES_ALREADY_ACTIVATED: 'MUTLI_WAREHOUSES_ALREADY_ACTIVATED', + COULD_NOT_DELETE_ONLY_WAERHOUSE: 'COULD_NOT_DELETE_ONLY_WAERHOUSE', + WAREHOUSE_CODE_NOT_UNIQUE: 'WAREHOUSE_CODE_NOT_UNIQUE', + WAREHOUSE_HAS_ASSOCIATED_TRANSACTIONS: 'WAREHOUSE_HAS_ASSOCIATED_TRANSACTIONS' +}; \ No newline at end of file diff --git a/packages/server-nest/src/modules/Warehouses/models/ItemWarehouseQuantity.ts b/packages/server-nest/src/modules/Warehouses/models/ItemWarehouseQuantity.ts new file mode 100644 index 000000000..5ff763dd3 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/models/ItemWarehouseQuantity.ts @@ -0,0 +1,38 @@ +import { BaseModel } from '@/models/Model'; +import { Model } from 'objection'; + +export class ItemWarehouseQuantity extends BaseModel{ + /** + * Table name. + */ + static get tableName() { + return 'items_warehouses_quantity'; + } + + /** + * Relation mappings. + */ + static get relationMappings() { + const { Item } = require('../../Items/models/Item'); + const { Warehouse } = require('./Warehouse.model'); + + return { + item: { + relation: Model.BelongsToOneRelation, + modelClass: Item, + join: { + from: 'items_warehouses_quantity.itemId', + to: 'items.id', + }, + }, + warehouse: { + relation: Model.BelongsToOneRelation, + modelClass: Warehouse, + join: { + from: 'items_warehouses_quantity.warehouseId', + to: 'warehouses.id', + }, + }, + }; + } +} diff --git a/packages/server-nest/src/modules/Warehouses/models/Warehouse.model.ts b/packages/server-nest/src/modules/Warehouses/models/Warehouse.model.ts new file mode 100644 index 000000000..f484b30f0 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/models/Warehouse.model.ts @@ -0,0 +1,178 @@ +// import { Model } from 'objection'; +import { BaseModel } from '@/models/Model'; + +export class Warehouse extends BaseModel { + date!: Date; + + fromWarehouseId!: number; + toWarehouseId!: number; + + reason!: string; + transactionNumber!: string; + + transferInitiatedAt!: Date; + transferDeliveredAt!: Date; + + isInitiated!: boolean; + isTransferred!: boolean; + + primary!: boolean; + + /** + * Table name. + */ + static get tableName() { + return 'warehouses'; + } + + /** + * Timestamps columns. + */ + get timestamps() { + return ['created_at', 'updated_at']; + } + + /** + * Model modifiers. + */ + static get modifiers() { + return { + /** + * Filters accounts by the given ids. + * @param {Query} query + * @param {number[]} accountsIds + */ + isPrimary(query) { + query.where('primary', true); + }, + }; + } + + /** + * Relationship mapping. + */ + // static get relationMappings() { + // const SaleInvoice = require('models/SaleInvoice'); + // const SaleEstimate = require('models/SaleEstimate'); + // const SaleReceipt = require('models/SaleReceipt'); + // const Bill = require('models/Bill'); + // const VendorCredit = require('models/VendorCredit'); + // const CreditNote = require('models/CreditNote'); + // const InventoryTransaction = require('models/InventoryTransaction'); + // const WarehouseTransfer = require('models/WarehouseTransfer'); + // const InventoryAdjustment = require('models/InventoryAdjustment'); + + // return { + // /** + // * Warehouse may belongs to associated sale invoices. + // */ + // invoices: { + // relation: Model.HasManyRelation, + // modelClass: SaleInvoice.default, + // join: { + // from: 'warehouses.id', + // to: 'sales_invoices.warehouseId', + // }, + // }, + + // /** + // * Warehouse may belongs to associated sale estimates. + // */ + // estimates: { + // relation: Model.HasManyRelation, + // modelClass: SaleEstimate.default, + // join: { + // from: 'warehouses.id', + // to: 'sales_estimates.warehouseId', + // }, + // }, + + // /** + // * Warehouse may belongs to associated sale receipts. + // */ + // receipts: { + // relation: Model.HasManyRelation, + // modelClass: SaleReceipt.default, + // join: { + // from: 'warehouses.id', + // to: 'sales_receipts.warehouseId', + // }, + // }, + + // /** + // * Warehouse may belongs to associated bills. + // */ + // bills: { + // relation: Model.HasManyRelation, + // modelClass: Bill.default, + // join: { + // from: 'warehouses.id', + // to: 'bills.warehouseId', + // }, + // }, + + // /** + // * Warehouse may belongs to associated credit notes. + // */ + // creditNotes: { + // relation: Model.HasManyRelation, + // modelClass: CreditNote.default, + // join: { + // from: 'warehouses.id', + // to: 'credit_notes.warehouseId', + // }, + // }, + + // /** + // * Warehouse may belongs to associated to vendor credits. + // */ + // vendorCredit: { + // relation: Model.HasManyRelation, + // modelClass: VendorCredit.default, + // join: { + // from: 'warehouses.id', + // to: 'vendor_credits.warehouseId', + // }, + // }, + + // /** + // * Warehouse may belongs to associated to inventory transactions. + // */ + // inventoryTransactions: { + // relation: Model.HasManyRelation, + // modelClass: InventoryTransaction.default, + // join: { + // from: 'warehouses.id', + // to: 'inventory_transactions.warehouseId', + // }, + // }, + + // warehouseTransferTo: { + // relation: Model.HasManyRelation, + // modelClass: WarehouseTransfer.default, + // join: { + // from: 'warehouses.id', + // to: 'warehouses_transfers.toWarehouseId', + // }, + // }, + + // warehouseTransferFrom: { + // relation: Model.HasManyRelation, + // modelClass: WarehouseTransfer.default, + // join: { + // from: 'warehouses.id', + // to: 'warehouses_transfers.fromWarehouseId', + // }, + // }, + + // inventoryAdjustment: { + // relation: Model.HasManyRelation, + // modelClass: InventoryAdjustment.default, + // join: { + // from: 'warehouses.id', + // to: 'inventory_adjustments.warehouseId', + // }, + // }, + // }; + // } +} diff --git a/packages/server-nest/src/modules/Warehouses/queries/GetWarehouse.ts b/packages/server-nest/src/modules/Warehouses/queries/GetWarehouse.ts new file mode 100644 index 000000000..5b44910d1 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/queries/GetWarehouse.ts @@ -0,0 +1,23 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Warehouse } from '../models/Warehouse.model'; + +@Injectable() +export class GetWarehouse { + constructor( + @Inject(Warehouse.name) + private readonly warehouseModel: typeof Warehouse, + ) {} + /** + * Retrieves warehouse details. + * @param {number} warehouseId + * @returns {Promise} + */ + public getWarehouse = async (warehouseId: number) => { + const warehouse = await this.warehouseModel + .query() + .findById(warehouseId) + .throwIfNotFound(); + + return warehouse; + }; +} diff --git a/packages/server-nest/src/modules/Warehouses/queries/GetWarehouses.ts b/packages/server-nest/src/modules/Warehouses/queries/GetWarehouses.ts new file mode 100644 index 000000000..651b29d2c --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/queries/GetWarehouses.ts @@ -0,0 +1,22 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Warehouse } from '../models/Warehouse.model'; + +@Injectable() +export class GetWarehouses { + constructor( + @Inject(Warehouse.name) + private readonly warehouseModel: typeof Warehouse, + ) {} + + /** + * Retrieves warehouses list. + * @returns + */ + public getWarehouses = async () => { + const warehouses = await this.warehouseModel + .query() + .orderBy('name', 'DESC'); + + return warehouses; + }; +} diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Activate/BillWarehousesActivateSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/BillWarehousesActivateSubscriber.ts new file mode 100644 index 000000000..f1ce0bb8b --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/BillWarehousesActivateSubscriber.ts @@ -0,0 +1,36 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehousesActivatedPayload } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { BillActivateWarehouses } from '../../Activate/BillWarehousesActivate'; + +// @Service() +// export class BillsActivateWarehousesSubscriber { +// @Inject() +// private billsActivateWarehouses: BillActivateWarehouses; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.warehouse.onActivated, +// this.updateBillsWithWarehouseOnActivated +// ); +// return bus; +// } + +// /** +// * Updates all inventory transactions with the primary warehouse once +// * multi-warehouses feature is activated. +// * @param {IWarehousesActivatedPayload} +// */ +// private updateBillsWithWarehouseOnActivated = async ({ +// tenantId, +// primaryWarehouse, +// }: IWarehousesActivatedPayload) => { +// await this.billsActivateWarehouses.updateBillsWithWarehouse( +// tenantId, +// primaryWarehouse +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Activate/CreditNoteWarehousesActivateSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/CreditNoteWarehousesActivateSubscriber.ts new file mode 100644 index 000000000..f67800577 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/CreditNoteWarehousesActivateSubscriber.ts @@ -0,0 +1,36 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehousesActivatedPayload } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { CreditNotesActivateWarehouses } from '../../Activate/CreditNoteWarehousesActivate'; + +// @Service() +// export class CreditsActivateWarehousesSubscriber { +// @Inject() +// private creditsActivateWarehouses: CreditNotesActivateWarehouses; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.warehouse.onActivated, +// this.updateInvoicesWithWarehouseOnActivated +// ); +// return bus; +// } + +// /** +// * Updates all inventory transactions with the primary warehouse once +// * multi-warehouses feature is activated. +// * @param {IWarehousesActivatedPayload} +// */ +// private updateInvoicesWithWarehouseOnActivated = async ({ +// tenantId, +// primaryWarehouse, +// }: IWarehousesActivatedPayload) => { +// await this.creditsActivateWarehouses.updateCreditsWithWarehouse( +// tenantId, +// primaryWarehouse +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Activate/EstimateWarehousesActivateSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/EstimateWarehousesActivateSubscriber.ts new file mode 100644 index 000000000..f4a207201 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/EstimateWarehousesActivateSubscriber.ts @@ -0,0 +1,36 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehousesActivatedPayload } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { EstimatesActivateWarehouses } from '../../Activate/EstimateWarehousesActivate'; + +// @Service() +// export class EstimatesActivateWarehousesSubscriber { +// @Inject() +// private estimatesActivateWarehouses: EstimatesActivateWarehouses; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.warehouse.onActivated, +// this.updateEstimatessWithWarehouseOnActivated +// ); +// return bus; +// } + +// /** +// * Updates all inventory transactions with the primary warehouse once +// * multi-warehouses feature is activated. +// * @param {IWarehousesActivatedPayload} +// */ +// private updateEstimatessWithWarehouseOnActivated = async ({ +// tenantId, +// primaryWarehouse, +// }: IWarehousesActivatedPayload) => { +// await this.estimatesActivateWarehouses.updateEstimatesWithWarehouse( +// tenantId, +// primaryWarehouse +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Activate/InventoryTransactionsWarehousesActivateSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/InventoryTransactionsWarehousesActivateSubscriber.ts new file mode 100644 index 000000000..2ac29f3f0 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/InventoryTransactionsWarehousesActivateSubscriber.ts @@ -0,0 +1,36 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehousesActivatedPayload } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { InventoryActivateWarehouses } from '../../Activate/InventoryTransactionsWarehousesActivate'; + +// @Service() +// export class InventoryActivateWarehousesSubscriber { +// @Inject() +// private inventoryActivateWarehouses: InventoryActivateWarehouses; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.warehouse.onActivated, +// this.updateInventoryTransactionsWithWarehouseOnActivated +// ); +// return bus; +// } + +// /** +// * Updates all inventory transactions with the primary warehouse once +// * multi-warehouses feature is activated. +// * @param {IWarehousesActivatedPayload} +// */ +// private updateInventoryTransactionsWithWarehouseOnActivated = async ({ +// tenantId, +// primaryWarehouse, +// }: IWarehousesActivatedPayload) => { +// await this.inventoryActivateWarehouses.updateInventoryTransactionsWithWarehouse( +// tenantId, +// primaryWarehouse +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Activate/InvoiceWarehousesActivateSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/InvoiceWarehousesActivateSubscriber.ts new file mode 100644 index 000000000..364593377 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/InvoiceWarehousesActivateSubscriber.ts @@ -0,0 +1,36 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehousesActivatedPayload } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { InvoicesActivateWarehouses } from '../../Activate/InvoiceWarehousesActivate'; + +// @Service() +// export class InvoicesActivateWarehousesSubscriber { +// @Inject() +// private invoicesActivateWarehouses: InvoicesActivateWarehouses; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.warehouse.onActivated, +// this.updateInvoicesWithWarehouseOnActivated +// ); +// return bus; +// } + +// /** +// * Updates all inventory transactions with the primary warehouse once +// * multi-warehouses feature is activated. +// * @param {IWarehousesActivatedPayload} +// */ +// private updateInvoicesWithWarehouseOnActivated = async ({ +// tenantId, +// primaryWarehouse, +// }: IWarehousesActivatedPayload) => { +// await this.invoicesActivateWarehouses.updateInvoicesWithWarehouse( +// tenantId, +// primaryWarehouse +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Activate/ReceiptWarehousesActivateSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/ReceiptWarehousesActivateSubscriber.ts new file mode 100644 index 000000000..5328e7e1c --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/ReceiptWarehousesActivateSubscriber.ts @@ -0,0 +1,36 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehousesActivatedPayload } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { ReceiptActivateWarehouses } from '../../Activate/ReceiptWarehousesActivate'; + +// @Service() +// export class ReceiptsActivateWarehousesSubscriber { +// @Inject() +// private receiptsActivateWarehouses: ReceiptActivateWarehouses; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.warehouse.onActivated, +// this.updateInventoryTransactionsWithWarehouseOnActivated +// ); +// return bus; +// } + +// /** +// * Updates all receipts transactions with the primary warehouse once +// * multi-warehouses feature is activated. +// * @param {IWarehousesActivatedPayload} +// */ +// private updateInventoryTransactionsWithWarehouseOnActivated = async ({ +// tenantId, +// primaryWarehouse, +// }: IWarehousesActivatedPayload) => { +// await this.receiptsActivateWarehouses.updateReceiptsWithWarehouse( +// tenantId, +// primaryWarehouse +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Activate/VendorCreditWarehousesActivateSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/VendorCreditWarehousesActivateSubscriber.ts new file mode 100644 index 000000000..67b59f82f --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/VendorCreditWarehousesActivateSubscriber.ts @@ -0,0 +1,36 @@ +// import { Service, Inject } from 'typedi'; +// import { IWarehousesActivatedPayload } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { VendorCreditActivateWarehouses } from '../../Activate/VendorCreditWarehousesActivate'; + +// @Service() +// export class VendorCreditsActivateWarehousesSubscriber { +// @Inject() +// private creditsActivateWarehouses: VendorCreditActivateWarehouses; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.warehouse.onActivated, +// this.updateCreditsWithWarehouseOnActivated +// ); +// return bus; +// } + +// /** +// * Updates all inventory transactions with the primary warehouse once +// * multi-warehouses feature is activated. +// * @param {IWarehousesActivatedPayload} +// */ +// private updateCreditsWithWarehouseOnActivated = async ({ +// tenantId, +// primaryWarehouse, +// }: IWarehousesActivatedPayload) => { +// await this.creditsActivateWarehouses.updateCreditsWithWarehouse( +// tenantId, +// primaryWarehouse +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Activate/index.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/index.ts new file mode 100644 index 000000000..d92d3d5b6 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Activate/index.ts @@ -0,0 +1,8 @@ +// /* eslint-disable import/extensions */ +// export * from './BillWarehousesActivateSubscriber'; +// export * from './CreditNoteWarehousesActivateSubscriber'; +// export * from './EstimateWarehousesActivateSubscriber'; +// export * from './InventoryTransactionsWarehousesActivateSubscriber'; +// export * from './VendorCreditWarehousesActivateSubscriber'; +// export * from './ReceiptWarehousesActivateSubscriber'; +// export * from './InvoiceWarehousesActivateSubscriber'; diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/DeleteItemWarehousesQuantitySubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/DeleteItemWarehousesQuantitySubscriber.ts new file mode 100644 index 000000000..860f78284 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/DeleteItemWarehousesQuantitySubscriber.ts @@ -0,0 +1,36 @@ +// import { Inject, Service } from 'typedi'; +// import events from '@/subscribers/events'; +// import { DeleteItemWarehousesQuantity } from '../commands/DeleteItemWarehousesQuantity'; +// import { IItemEventDeletingPayload } from '@/interfaces'; + +// @Service() +// export class DeleteItemWarehousesQuantitySubscriber { +// @Inject() +// private deleteItemWarehousesQuantity: DeleteItemWarehousesQuantity; + +// /** +// * Attaches events. +// */ +// public attach(bus) { +// bus.subscribe( +// events.item.onDeleting, +// this.deleteItemWarehouseQuantitiesOnItemDelete +// ); +// } + +// /** +// * Deletes the given item warehouses quantities once the item deleting. +// * @param {IItemEventDeletingPayload} payload - +// */ +// private deleteItemWarehouseQuantitiesOnItemDelete = async ({ +// tenantId, +// oldItem, +// trx, +// }: IItemEventDeletingPayload) => { +// await this.deleteItemWarehousesQuantity.deleteItemWarehousesQuantity( +// tenantId, +// oldItem.id, +// trx +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Validators/InventoryAdjustment/InventoryAdjustmentWarehouseValidatorSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/InventoryAdjustment/InventoryAdjustmentWarehouseValidatorSubscriber.ts new file mode 100644 index 000000000..ef49e37bd --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/InventoryAdjustment/InventoryAdjustmentWarehouseValidatorSubscriber.ts @@ -0,0 +1,35 @@ +// import { Inject, Service } from 'typedi'; +// import { IInventoryAdjustmentCreatingPayload } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { WarehousesDTOValidators } from '../../../Integrations/WarehousesDTOValidators'; + +// @Service() +// export class InventoryAdjustmentWarehouseValidatorSubscriber { +// @Inject() +// private warehouseDTOValidator: WarehousesDTOValidators; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.inventoryAdjustment.onQuickCreating, +// this.validateAdjustmentWarehouseExistanceOnCreating +// ); +// return bus; +// } + +// /** +// * Validate warehouse existance of sale invoice once creating. +// * @param {IBillCreatingPayload} +// */ +// private validateAdjustmentWarehouseExistanceOnCreating = async ({ +// quickAdjustmentDTO, +// tenantId, +// }: IInventoryAdjustmentCreatingPayload) => { +// await this.warehouseDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// quickAdjustmentDTO +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Purchases/BillWarehousesSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Purchases/BillWarehousesSubscriber.ts new file mode 100644 index 000000000..e1c5781a9 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Purchases/BillWarehousesSubscriber.ts @@ -0,0 +1,53 @@ +// import { Inject, Service } from 'typedi'; +// import { IBillCreatingPayload, IBillEditingPayload } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { WarehousesDTOValidators } from '../../../Integrations/WarehousesDTOValidators'; + +// @Service() +// export class BillWarehousesValidateSubscriber { +// @Inject() +// private warehouseDTOValidator: WarehousesDTOValidators; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.bill.onCreating, +// this.validateBillWarehouseExistanceOnCreating +// ); +// bus.subscribe( +// events.bill.onEditing, +// this.validateSaleEstimateWarehouseExistanceOnEditing +// ); +// return bus; +// } + +// /** +// * Validate warehouse existance of sale invoice once creating. +// * @param {IBillCreatingPayload} +// */ +// private validateBillWarehouseExistanceOnCreating = async ({ +// billDTO, +// tenantId, +// }: IBillCreatingPayload) => { +// await this.warehouseDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// billDTO +// ); +// }; + +// /** +// * Validate warehouse existance of sale invoice once editing. +// * @param {IBillEditingPayload} +// */ +// private validateSaleEstimateWarehouseExistanceOnEditing = async ({ +// tenantId, +// billDTO, +// }: IBillEditingPayload) => { +// await this.warehouseDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// billDTO +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Purchases/VendorCreditWarehousesSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Purchases/VendorCreditWarehousesSubscriber.ts new file mode 100644 index 000000000..851015e82 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Purchases/VendorCreditWarehousesSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import { +// IVendorCreditCreatingPayload, +// IVendorCreditEditingPayload, +// } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { WarehousesDTOValidators } from '../../../Integrations/WarehousesDTOValidators'; + +// @Service() +// export class VendorCreditWarehousesValidateSubscriber { +// @Inject() +// warehouseDTOValidator: WarehousesDTOValidators; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.vendorCredit.onCreating, +// this.validateVendorCreditWarehouseExistanceOnCreating +// ); +// bus.subscribe( +// events.vendorCredit.onEditing, +// this.validateSaleEstimateWarehouseExistanceOnEditing +// ); +// return bus; +// } + +// /** +// * Validate warehouse existance of sale invoice once creating. +// * @param {IVendorCreditCreatingPayload} +// */ +// private validateVendorCreditWarehouseExistanceOnCreating = async ({ +// vendorCreditCreateDTO, +// tenantId, +// }: IVendorCreditCreatingPayload) => { +// await this.warehouseDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// vendorCreditCreateDTO +// ); +// }; + +// /** +// * Validate warehouse existance of sale invoice once editing. +// * @param {IVendorCreditEditingPayload} +// */ +// private validateSaleEstimateWarehouseExistanceOnEditing = async ({ +// tenantId, +// vendorCreditDTO, +// }: IVendorCreditEditingPayload) => { +// await this.warehouseDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// vendorCreditDTO +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/CreditNoteWarehousesSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/CreditNoteWarehousesSubscriber.ts new file mode 100644 index 000000000..d00f1ef3c --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/CreditNoteWarehousesSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import { +// ICreditNoteCreatingPayload, +// ICreditNoteEditingPayload, +// } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { WarehousesDTOValidators } from '../../../Integrations/WarehousesDTOValidators'; + +// @Service() +// export class CreditNoteWarehousesValidateSubscriber { +// @Inject() +// warehouseDTOValidator: WarehousesDTOValidators; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.creditNote.onCreating, +// this.validateCreditNoteWarehouseExistanceOnCreating +// ); +// bus.subscribe( +// events.creditNote.onEditing, +// this.validateCreditNoteWarehouseExistanceOnEditing +// ); +// return bus; +// } + +// /** +// * Validate warehouse existance of sale invoice once creating. +// * @param {ICreditNoteCreatingPayload} +// */ +// private validateCreditNoteWarehouseExistanceOnCreating = async ({ +// creditNoteDTO, +// tenantId, +// }: ICreditNoteCreatingPayload) => { +// await this.warehouseDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// creditNoteDTO +// ); +// }; + +// /** +// * Validate warehouse existance of sale invoice once editing. +// * @param {ICreditNoteEditingPayload} +// */ +// private validateCreditNoteWarehouseExistanceOnEditing = async ({ +// tenantId, +// creditNoteEditDTO, +// }: ICreditNoteEditingPayload) => { +// await this.warehouseDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// creditNoteEditDTO +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/SaleEstimateWarehousesSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/SaleEstimateWarehousesSubscriber.ts new file mode 100644 index 000000000..c81b5bf65 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/SaleEstimateWarehousesSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import { +// ISaleEstimateCreatingPayload, +// ISaleEstimateEditingPayload, +// } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { WarehousesDTOValidators } from '../../../Integrations/WarehousesDTOValidators'; + +// @Service() +// export class SaleEstimateWarehousesValidateSubscriber { +// @Inject() +// warehouseDTOValidator: WarehousesDTOValidators; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.saleEstimate.onCreating, +// this.validateSaleEstimateWarehouseExistanceOnCreating +// ); +// bus.subscribe( +// events.saleEstimate.onEditing, +// this.validateSaleEstimateWarehouseExistanceOnEditing +// ); +// return bus; +// } + +// /** +// * Validate warehouse existance of sale invoice once creating. +// * @param {ISaleEstimateCreatingPayload} +// */ +// private validateSaleEstimateWarehouseExistanceOnCreating = async ({ +// estimateDTO, +// tenantId, +// }: ISaleEstimateCreatingPayload) => { +// await this.warehouseDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// estimateDTO +// ); +// }; + +// /** +// * Validate warehouse existance of sale invoice once editing. +// * @param {ISaleEstimateEditingPayload} +// */ +// private validateSaleEstimateWarehouseExistanceOnEditing = async ({ +// tenantId, +// estimateDTO, +// }: ISaleEstimateEditingPayload) => { +// await this.warehouseDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// estimateDTO +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/SaleInvoicesWarehousesSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/SaleInvoicesWarehousesSubscriber.ts new file mode 100644 index 000000000..f778a2524 --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/SaleInvoicesWarehousesSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import { +// ISaleInvoiceCreatingPaylaod, +// ISaleInvoiceEditingPayload, +// } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { WarehousesDTOValidators } from '../../../Integrations/WarehousesDTOValidators'; + +// @Service() +// export class SaleInvoicesWarehousesValidateSubscriber { +// @Inject() +// warehousesDTOValidator: WarehousesDTOValidators; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.saleInvoice.onCreating, +// this.validateSaleInvoiceWarehouseExistanceOnCreating +// ); +// bus.subscribe( +// events.saleInvoice.onEditing, +// this.validateSaleInvoiceWarehouseExistanceOnEditing +// ); +// return bus; +// } + +// /** +// * Validate warehouse existance of sale invoice once creating. +// * @param {ISaleInvoiceCreatingPaylaod} +// */ +// private validateSaleInvoiceWarehouseExistanceOnCreating = async ({ +// saleInvoiceDTO, +// tenantId, +// }: ISaleInvoiceCreatingPaylaod) => { +// await this.warehousesDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// saleInvoiceDTO +// ); +// }; + +// /** +// * Validate warehouse existance of sale invoice once editing. +// * @param {ISaleInvoiceEditingPayload} +// */ +// private validateSaleInvoiceWarehouseExistanceOnEditing = async ({ +// tenantId, +// saleInvoiceDTO, +// }: ISaleInvoiceEditingPayload) => { +// await this.warehousesDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// saleInvoiceDTO +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/SaleReceiptWarehousesSubscriber.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/SaleReceiptWarehousesSubscriber.ts new file mode 100644 index 000000000..1c71adb2b --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/Sales/SaleReceiptWarehousesSubscriber.ts @@ -0,0 +1,56 @@ +// import { Inject, Service } from 'typedi'; +// import { +// ISaleReceiptCreatingPayload, +// ISaleReceiptEditingPayload, +// } from '@/interfaces'; +// import events from '@/subscribers/events'; +// import { WarehousesDTOValidators } from '../../../Integrations/WarehousesDTOValidators'; + +// @Service() +// export class SaleReceiptWarehousesValidateSubscriber { +// @Inject() +// private warehousesDTOValidator: WarehousesDTOValidators; + +// /** +// * Attaches events with handlers. +// */ +// public attach(bus) { +// bus.subscribe( +// events.saleReceipt.onCreating, +// this.validateSaleReceiptWarehouseExistanceOnCreating +// ); +// bus.subscribe( +// events.saleReceipt.onEditing, +// this.validateSaleReceiptWarehouseExistanceOnEditing +// ); +// return bus; +// } + +// /** +// * Validate warehouse existance of sale invoice once creating. +// * @param {ISaleReceiptCreatingPayload} +// */ +// private validateSaleReceiptWarehouseExistanceOnCreating = async ({ +// saleReceiptDTO, +// tenantId, +// }: ISaleReceiptCreatingPayload) => { +// await this.warehousesDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// saleReceiptDTO +// ); +// }; + +// /** +// * Validate warehouse existance of sale invoice once editing. +// * @param {ISaleReceiptEditingPayload} +// */ +// private validateSaleReceiptWarehouseExistanceOnEditing = async ({ +// tenantId, +// saleReceiptDTO, +// }: ISaleReceiptEditingPayload) => { +// await this.warehousesDTOValidator.validateDTOWarehouseWhenActive( +// tenantId, +// saleReceiptDTO +// ); +// }; +// } diff --git a/packages/server-nest/src/modules/Warehouses/subscribers/Validators/index.ts b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/index.ts new file mode 100644 index 000000000..b4346b03f --- /dev/null +++ b/packages/server-nest/src/modules/Warehouses/subscribers/Validators/index.ts @@ -0,0 +1,9 @@ +// export * from './Purchases/BillWarehousesSubscriber'; +// export * from './Purchases/VendorCreditWarehousesSubscriber'; + +// export * from './Sales/SaleEstimateWarehousesSubscriber'; +// export * from './Sales/CreditNoteWarehousesSubscriber'; +// export * from './Sales/SaleInvoicesWarehousesSubscriber'; +// export * from './Sales/SaleReceiptWarehousesSubscriber'; + +// export * from './InventoryAdjustment/InventoryAdjustmentWarehouseValidatorSubscriber'; \ No newline at end of file