From ee284196eb68eb5851b1957a99be098e27c00214 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Wed, 8 Jan 2025 15:43:43 +0200 Subject: [PATCH] refactor: inventory adjustments e2e test cases --- packages/server-nest/package.json | 20 ++-- .../server-nest/src/modules/App/App.module.ts | 4 +- .../EventsTracker/EventTracker.service.ts | 10 +- .../TransactionsLockingEventsTracker.ts | 1 - .../modules/EventsTracker/postHog.module.ts | 12 +- .../InventoryAdjustments.controller.ts | 23 +++- .../InventoryAdjustments.module.ts | 2 + .../CreateQuickInventoryAdjustment.service.ts | 5 +- .../PublishInventoryAdjustment.service.ts | 14 ++- .../InventoryAdjustments.constants.ts | 2 +- .../models/InventoryAdjustment.ts | 2 +- .../queries/GetInventoryAdjustment.service.ts | 17 +-- .../src/modules/Items/Item.controller.ts | 4 +- .../src/modules/Metable/MetableStore.ts | 25 ++-- .../src/modules/Metable/MetableStoreDB.ts | 7 +- .../src/modules/Settings/Settings.module.ts | 1 + .../src/modules/Settings/SettingsStore.ts | 2 +- .../TransactionsLocking.module.ts | 2 + .../TransactionsLockingRepository.ts | 5 +- .../modules/TransactionsLocking/constants.ts | 6 +- .../PurchasesTransactionLockingGuard.ts | 3 +- .../guards/SalesTransactionLockingGuard.ts | 3 +- .../guards/TransactionsLockingGuard.ts | 8 +- .../models/RefundVendorCredit.ts | 1 + packages/server-nest/src/utils/is-blank.ts | 5 + .../server-nest/src/utils/items-start-with.ts | 3 + .../server-nest/src/utils/parse-boolean.ts | 23 ++++ .../test/inventory-adjustment.e2e-spec.ts | 113 ++++++++++++++++++ packages/server/package.json | 2 +- 29 files changed, 257 insertions(+), 68 deletions(-) create mode 100644 packages/server-nest/src/utils/is-blank.ts create mode 100644 packages/server-nest/src/utils/items-start-with.ts create mode 100644 packages/server-nest/src/utils/parse-boolean.ts create mode 100644 packages/server-nest/test/inventory-adjustment.e2e-spec.ts diff --git a/packages/server-nest/package.json b/packages/server-nest/package.json index b0b528c12..5eb7c80ea 100644 --- a/packages/server-nest/package.json +++ b/packages/server-nest/package.json @@ -20,9 +20,9 @@ "test:e2e": "jest --config ./test/jest-e2e.json --watchAll" }, "dependencies": { - "@bigcapital/utils": "*", "@bigcapital/email-components": "*", "@bigcapital/pdf-templates": "*", + "@bigcapital/utils": "*", "@nestjs/bull": "^10.2.1", "@nestjs/bullmq": "^10.2.1", "@nestjs/cache-manager": "^2.2.2", @@ -35,13 +35,13 @@ "@nestjs/platform-express": "^10.0.0", "@nestjs/swagger": "^7.4.2", "@nestjs/throttler": "^6.2.1", + "@supercharge/promise-pool": "^3.2.0", "@types/passport-local": "^1.0.38", "@types/ramda": "^0.30.2", "accounting": "^0.4.1", - "bluebird": "^3.7.2", "async": "^3.2.0", "axios": "^1.6.0", - "form-data": "^4.0.0", + "bluebird": "^3.7.2", "bull": "^4.16.3", "bullmq": "^5.21.1", "cache-manager": "^6.1.1", @@ -49,6 +49,7 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "express-validator": "^7.2.0", + "form-data": "^4.0.0", "fp-ts": "^2.16.9", "js-money": "^0.6.3", "knex": "^3.1.0", @@ -59,25 +60,24 @@ "mysql2": "^3.11.3", "nestjs-cls": "^4.4.1", "nestjs-i18n": "^10.4.9", - "uuid": "^10.0.0", - "pug": "^3.0.2", "object-hash": "^2.0.3", "objection": "^3.1.5", "passport": "^0.7.0", "passport-jwt": "^4.0.1", "passport-local": "^1.0.0", + "plaid": "^10.3.0", + "posthog-node": "^4.3.2", + "pug": "^3.0.2", "ramda": "^0.30.1", "redis": "^4.7.0", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", "serialize-interceptor": "^1.1.7", "strategy": "^1.1.1", - "zod": "^3.23.8", - "plaid": "^10.3.0", - "@supercharge/promise-pool": "^3.2.0", - "yup": "^0.28.1", "uniqid": "^5.2.0", - "posthog-node": "^4.2.0" + "uuid": "^10.0.0", + "yup": "^0.28.1", + "zod": "^3.23.8" }, "devDependencies": { "@nestjs/cli": "^10.0.0", diff --git a/packages/server-nest/src/modules/App/App.module.ts b/packages/server-nest/src/modules/App/App.module.ts index 3c4e03242..7d282c9ac 100644 --- a/packages/server-nest/src/modules/App/App.module.ts +++ b/packages/server-nest/src/modules/App/App.module.ts @@ -152,8 +152,8 @@ import { PostHogModule } from '../EventsTracker/postHog.module'; TransactionsLockingModule, SettingsModule, InventoryAdjustmentsModule, - PostHogModule, - EventTrackerModule, + // PostHogModule, + // EventTrackerModule, ], controllers: [AppController], providers: [ diff --git a/packages/server-nest/src/modules/EventsTracker/EventTracker.service.ts b/packages/server-nest/src/modules/EventsTracker/EventTracker.service.ts index 8eaba1654..8014430d6 100644 --- a/packages/server-nest/src/modules/EventsTracker/EventTracker.service.ts +++ b/packages/server-nest/src/modules/EventsTracker/EventTracker.service.ts @@ -1,13 +1,15 @@ import { Inject, Injectable } from '@nestjs/common'; -import { PostHog } from 'posthog-node'; -import { EventMessage } from 'posthog-node/src/types'; +// import { PostHog, EventMessage } from 'posthog-node'; import { POSTHOG } from './postHog.module'; import { TenancyContext } from '../Tenancy/TenancyContext.service'; +interface EventMessage { + distinctId +} @Injectable() export class EventTrackerService { constructor( - @Inject(POSTHOG) private readonly posthog: PostHog, + @Inject(POSTHOG) private readonly posthog: any, private readonly tenancyContext: TenancyContext, ) {} @@ -15,7 +17,7 @@ export class EventTrackerService { * Track tenant an event. * @param event - The event to track. */ - public async trackEvent(event: Omit) { + public async trackEvent(event: any) { // Cannot continue if the Posthog not configured. if (!this.posthog) return; diff --git a/packages/server-nest/src/modules/EventsTracker/events/TransactionsLockingEventsTracker.ts b/packages/server-nest/src/modules/EventsTracker/events/TransactionsLockingEventsTracker.ts index e5666c378..25630bf47 100644 --- a/packages/server-nest/src/modules/EventsTracker/events/TransactionsLockingEventsTracker.ts +++ b/packages/server-nest/src/modules/EventsTracker/events/TransactionsLockingEventsTracker.ts @@ -1,4 +1,3 @@ -import { ITransactionsLockingPartialUnlocked } from '@/interfaces'; import { SUBSCRIPTION_CANCELLED, SUBSCRIPTION_PAYMENT_FAILED, diff --git a/packages/server-nest/src/modules/EventsTracker/postHog.module.ts b/packages/server-nest/src/modules/EventsTracker/postHog.module.ts index 35bbfea73..6dba3444b 100644 --- a/packages/server-nest/src/modules/EventsTracker/postHog.module.ts +++ b/packages/server-nest/src/modules/EventsTracker/postHog.module.ts @@ -1,5 +1,5 @@ import { Module } from '@nestjs/common'; -import { PostHog } from 'posthog-node'; +// import { PostHog } from 'posthog-node'; import { EventTrackerService } from './EventTracker.service'; import { ConfigService } from '@nestjs/config'; @@ -10,10 +10,12 @@ export const POSTHOG = 'PostHog'; EventTrackerService, { provide: POSTHOG, - useFactory: (configService: ConfigService) => - new PostHog(configService.get('posthog.apiKey'), { - host: configService.get('posthog.host'), - }), + useFactory: (configService: ConfigService) => { + + }, + // new PostHog(configService.get('posthog.apiKey'), { + // host: configService.get('posthog.host'), + // }), inject: [ConfigService], }, ], diff --git a/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustments.controller.ts b/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustments.controller.ts index 617b25ad0..2333ccf42 100644 --- a/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustments.controller.ts +++ b/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustments.controller.ts @@ -1,9 +1,19 @@ -import { Body, Controller, Delete, Param, Post } from '@nestjs/common'; +import { + Body, + Controller, + Delete, + Get, + Param, + Post, + Put, +} from '@nestjs/common'; import { InventoryAdjustmentsApplicationService } from './InventoryAdjustmentsApplication.service'; import { IQuickInventoryAdjustmentDTO } from './types/InventoryAdjustments.types'; import { InventoryAdjustment } from './models/InventoryAdjustment'; +import { PublicRoute } from '../Auth/Jwt.guard'; @Controller('inventory-adjustments') +@PublicRoute() export class InventoryAdjustmentsController { constructor( private readonly inventoryAdjustmentsApplicationService: InventoryAdjustmentsApplicationService, @@ -27,7 +37,16 @@ export class InventoryAdjustmentsController { ); } - @Post(':id/publish') + @Get(':id') + public async getInventoryAdjustment( + @Param('id') inventoryAdjustmentId: number, + ): Promise { + return this.inventoryAdjustmentsApplicationService.getInventoryAdjustment( + inventoryAdjustmentId, + ); + } + + @Put(':id/publish') public async publishInventoryAdjustment( @Param('id') inventoryAdjustmentId: number, ): Promise { diff --git a/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustments.module.ts b/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustments.module.ts index e4fbd6925..9c9dd1003 100644 --- a/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustments.module.ts +++ b/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustments.module.ts @@ -14,6 +14,7 @@ import { WarehousesModule } from '../Warehouses/Warehouses.module'; import { InventoryAdjustmentsGLSubscriber } from './subscribers/InventoryAdjustmentGL.subscriber'; import { InventoryAdjustmentsGLEntries } from './commands/ledger/InventoryAdjustmentsGLEntries'; import { LedgerModule } from '../Ledger/Ledger.module'; +import { TenancyContext } from '../Tenancy/TenancyContext.service'; const models = [ RegisterTenancyModel(InventoryAdjustment), @@ -32,6 +33,7 @@ const models = [ InventoryAdjustmentsApplicationService, InventoryAdjustmentsGLSubscriber, InventoryAdjustmentsGLEntries, + TenancyContext, ], exports: [...models], }) diff --git a/packages/server-nest/src/modules/InventoryAdjutments/commands/CreateQuickInventoryAdjustment.service.ts b/packages/server-nest/src/modules/InventoryAdjutments/commands/CreateQuickInventoryAdjustment.service.ts index 56d74c26f..6710c20bf 100644 --- a/packages/server-nest/src/modules/InventoryAdjutments/commands/CreateQuickInventoryAdjustment.service.ts +++ b/packages/server-nest/src/modules/InventoryAdjutments/commands/CreateQuickInventoryAdjustment.service.ts @@ -1,6 +1,7 @@ import { Knex } from 'knex'; import { Inject } from '@nestjs/common'; import * as R from 'ramda'; +import * as moment from 'moment'; import { omit } from 'lodash'; import { events } from '@/common/events/events'; import { InventoryAdjustment } from '../models/InventoryAdjustment'; @@ -17,6 +18,7 @@ import { Account } from '@/modules/Accounts/models/Account.model'; import { BranchTransactionDTOTransformer } from '@/modules/Branches/integrations/BranchTransactionDTOTransform'; import { WarehouseTransactionDTOTransform } from '@/modules/Warehouses/Integrations/WarehouseTransactionDTOTransform'; import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service'; +import { ERRORS } from '../constants/InventoryAdjustments.constants'; export class CreateQuickInventoryAdjustmentService { constructor( @@ -80,7 +82,6 @@ export class CreateQuickInventoryAdjustmentService { /** * Creates a quick inventory adjustment for specific item. - * @param {number} tenantId - Tenant id. * @param {IQuickInventoryAdjustmentDTO} quickAdjustmentDTO - qucik adjustment DTO. */ public async createQuickAdjustment( @@ -119,7 +120,7 @@ export class CreateQuickInventoryAdjustmentService { // Saves the inventory adjustment with associated entries to the storage. const inventoryAdjustment = await this.inventoryAdjustmentModel .query(trx) - .upsertGraph({ + .upsertGraphAndFetch({ ...invAdjustmentObject, }); // Triggers `onInventoryAdjustmentQuickCreated` event. diff --git a/packages/server-nest/src/modules/InventoryAdjutments/commands/PublishInventoryAdjustment.service.ts b/packages/server-nest/src/modules/InventoryAdjutments/commands/PublishInventoryAdjustment.service.ts index 4d1586d12..7949cfae6 100644 --- a/packages/server-nest/src/modules/InventoryAdjutments/commands/PublishInventoryAdjustment.service.ts +++ b/packages/server-nest/src/modules/InventoryAdjutments/commands/PublishInventoryAdjustment.service.ts @@ -1,6 +1,7 @@ import { Knex } from 'knex'; import { Inject } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; +import * as moment from 'moment'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { InventoryAdjustment } from '../models/InventoryAdjustment'; import { @@ -9,6 +10,7 @@ import { } from '../types/InventoryAdjustments.types'; import { events } from '@/common/events/events'; import { ServiceError } from '@/modules/Items/ServiceError'; +import { ERRORS } from '../constants/InventoryAdjustments.constants'; export class PublishInventoryAdjustmentService { constructor( @@ -47,11 +49,15 @@ export class PublishInventoryAdjustmentService { ); // Publish the inventory adjustment transaction. - await InventoryAdjustment.query().findById(inventoryAdjustmentId).patch({ - publishedAt: moment().toMySqlDateTime(), - }); + await this.inventoryAdjustmentModel + .query() + .findById(inventoryAdjustmentId) + .patch({ + publishedAt: moment().toMySqlDateTime(), + }); // Retrieve the inventory adjustment after the modification. - const inventoryAdjustment = await InventoryAdjustment.query() + const inventoryAdjustment = await this.inventoryAdjustmentModel + .query() .findById(inventoryAdjustmentId) .withGraphFetched('entries'); diff --git a/packages/server-nest/src/modules/InventoryAdjutments/constants/InventoryAdjustments.constants.ts b/packages/server-nest/src/modules/InventoryAdjutments/constants/InventoryAdjustments.constants.ts index a3f59e428..de18ba41c 100644 --- a/packages/server-nest/src/modules/InventoryAdjutments/constants/InventoryAdjustments.constants.ts +++ b/packages/server-nest/src/modules/InventoryAdjutments/constants/InventoryAdjustments.constants.ts @@ -1,4 +1,4 @@ -const ERRORS = { +export const ERRORS = { INVENTORY_ADJUSTMENT_NOT_FOUND: 'INVENTORY_ADJUSTMENT_NOT_FOUND', ITEM_SHOULD_BE_INVENTORY_TYPE: 'ITEM_SHOULD_BE_INVENTORY_TYPE', INVENTORY_ADJUSTMENT_ALREADY_PUBLISHED: diff --git a/packages/server-nest/src/modules/InventoryAdjutments/models/InventoryAdjustment.ts b/packages/server-nest/src/modules/InventoryAdjutments/models/InventoryAdjustment.ts index fdba465c4..e18ee0c59 100644 --- a/packages/server-nest/src/modules/InventoryAdjutments/models/InventoryAdjustment.ts +++ b/packages/server-nest/src/modules/InventoryAdjutments/models/InventoryAdjustment.ts @@ -1,4 +1,4 @@ -import { Model, mixin } from 'objection'; +import { Model } from 'objection'; // import TenantModel from 'models/TenantModel'; // import InventoryAdjustmentSettings from './InventoryAdjustment.Settings'; // import ModelSetting from './ModelSetting'; diff --git a/packages/server-nest/src/modules/InventoryAdjutments/queries/GetInventoryAdjustment.service.ts b/packages/server-nest/src/modules/InventoryAdjutments/queries/GetInventoryAdjustment.service.ts index d4e4d7da9..267137a64 100644 --- a/packages/server-nest/src/modules/InventoryAdjutments/queries/GetInventoryAdjustment.service.ts +++ b/packages/server-nest/src/modules/InventoryAdjutments/queries/GetInventoryAdjustment.service.ts @@ -1,21 +1,24 @@ -import { TransformerInjectable } from "@/modules/Transformer/TransformerInjectable.service"; -import { InventoryAdjustment } from "../models/InventoryAdjustment"; -import { InventoryAdjustmentTransformer } from "../InventoryAdjustmentTransformer"; +import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; +import { InventoryAdjustment } from '../models/InventoryAdjustment'; +import { InventoryAdjustmentTransformer } from '../InventoryAdjustmentTransformer'; +import { Inject } from '@nestjs/common'; export class GetInventoryAdjustmentService { constructor( private readonly transformer: TransformerInjectable, + + @Inject(InventoryAdjustment.name) + private readonly inventoryAdjustmentModel: typeof InventoryAdjustment, ) {} /** * Retrieve specific inventory adjustment transaction details. * @param {number} inventoryAdjustmentId - Inventory adjustment id. */ - async getInventoryAdjustment( - inventoryAdjustmentId: number, - ) { + async getInventoryAdjustment(inventoryAdjustmentId: number) { // Retrieve inventory adjustment transation with associated models. - const inventoryAdjustment = await InventoryAdjustment.query() + const inventoryAdjustment = await this.inventoryAdjustmentModel + .query() .findById(inventoryAdjustmentId) .withGraphFetched('entries.item') .withGraphFetched('adjustmentAccount') diff --git a/packages/server-nest/src/modules/Items/Item.controller.ts b/packages/server-nest/src/modules/Items/Item.controller.ts index f8b876850..54fbd358d 100644 --- a/packages/server-nest/src/modules/Items/Item.controller.ts +++ b/packages/server-nest/src/modules/Items/Item.controller.ts @@ -40,7 +40,7 @@ export class ItemsController extends TenantController { * @returns The updated item id. */ @Put(':id') - @UsePipes(new ZodValidationPipe(createItemSchema)) + // @UsePipes(new ZodValidationPipe(createItemSchema)) async editItem( @Param('id') id: string, @Body() editItemDto: any, @@ -55,7 +55,7 @@ export class ItemsController extends TenantController { * @returns The created item id. */ @Post() - @UsePipes(new ZodValidationPipe(createItemSchema)) + // @UsePipes(new ZodValidationPipe(createItemSchema)) async createItem(@Body() createItemDto: any): Promise { return this.createItemService.createItem(createItemDto); } diff --git a/packages/server-nest/src/modules/Metable/MetableStore.ts b/packages/server-nest/src/modules/Metable/MetableStore.ts index 6b5aee04c..87f79ed15 100644 --- a/packages/server-nest/src/modules/Metable/MetableStore.ts +++ b/packages/server-nest/src/modules/Metable/MetableStore.ts @@ -1,7 +1,7 @@ import { Model } from 'objection'; import { omit, isEmpty } from 'lodash'; import { IMetadata, IMetaQuery, IMetableStore } from './types'; -import { itemsStartWith } from 'utils'; +import { itemsStartWith } from '@/utils/items-start-with'; export class MetableStore implements IMetableStore { metadata: IMetadata[]; @@ -23,7 +23,7 @@ export class MetableStore implements IMetableStore { */ setExtraColumns(columns: string[]): void { this.extraColumns = columns; - } +} /** * Find the given metadata key. @@ -120,6 +120,7 @@ export class MetableStore implements IMetableStore { key, ...extraColumns, _markAsInserted: true, + group: 'default', }); } } @@ -166,11 +167,11 @@ export class MetableStore implements IMetableStore { * Parse the metadata to the collection. * @param {Array} collection - */ - mapMetadataToCollection(metadata: IMetadata[], parseType: string = 'parse') { - return metadata.map((model) => - this.mapMetadataToCollection(model, parseType) - ); - } + // mapMetadataToCollection(metadata: IMetadata[], parseType: string = 'parse') { + // return metadata.map((model) => + // this.mapMetadataToCollection(model, parseType) + // ); + // } /** * Load metadata to the metable collection. @@ -198,12 +199,12 @@ export class MetableStore implements IMetableStore { * Static method to load metadata to the collection. * @param {Array} meta */ - static from(meta) { - const collection = new MetableCollection(); - collection.from(meta); + // static from(meta) { + // const collection = new MetableCollection(); + // collection.from(meta); - return collection; - } + // return collection; + // } /** * Reset the momerized metadata. diff --git a/packages/server-nest/src/modules/Metable/MetableStoreDB.ts b/packages/server-nest/src/modules/Metable/MetableStoreDB.ts index c2dbff9dc..136d7c289 100644 --- a/packages/server-nest/src/modules/Metable/MetableStoreDB.ts +++ b/packages/server-nest/src/modules/Metable/MetableStoreDB.ts @@ -1,8 +1,9 @@ import { IMetadata, IMetableStoreStorage } from './types'; import { MetableStore } from './MetableStore'; -import { isBlank, parseBoolean } from 'utils'; import { MetableConfig } from './MetableConfig'; import { EntityRepository } from '@/common/repository/EntityRepository'; +import { isBlank } from '@/utils/is-blank'; +import { parseBoolean } from '@/utils/parse-boolean'; export class MetableDBStore extends MetableStore @@ -72,10 +73,10 @@ export class MetableDBStore /** * Saves the modified, deleted and insert metadata. */ - save() { + async save() { this.validateStoreIsLoaded(); - return Promise.all([ + await Promise.all([ this.saveUpdated(this.metadata), this.saveDeleted(this.metadata), this.saveInserted(this.metadata), diff --git a/packages/server-nest/src/modules/Settings/Settings.module.ts b/packages/server-nest/src/modules/Settings/Settings.module.ts index 14b059ac9..9bf9c86b2 100644 --- a/packages/server-nest/src/modules/Settings/Settings.module.ts +++ b/packages/server-nest/src/modules/Settings/Settings.module.ts @@ -15,5 +15,6 @@ export const SETTINGS = 'SETTINGS'; inject: [SettingRepository], }, ], + exports: [SETTINGS] }) export class SettingsModule {} diff --git a/packages/server-nest/src/modules/Settings/SettingsStore.ts b/packages/server-nest/src/modules/Settings/SettingsStore.ts index 3ff11f85e..d798a5bab 100644 --- a/packages/server-nest/src/modules/Settings/SettingsStore.ts +++ b/packages/server-nest/src/modules/Settings/SettingsStore.ts @@ -10,7 +10,7 @@ export class SettingsStore extends MetableDBStore { constructor(repository: EntityRepository, config: any = SettingsOptions) { super(config); - // this.setExtraColumns(['group']); + this.setExtraColumns(['group']); this.setRepository(repository); } } diff --git a/packages/server-nest/src/modules/TransactionsLocking/TransactionsLocking.module.ts b/packages/server-nest/src/modules/TransactionsLocking/TransactionsLocking.module.ts index 41c755406..787f7ee17 100644 --- a/packages/server-nest/src/modules/TransactionsLocking/TransactionsLocking.module.ts +++ b/packages/server-nest/src/modules/TransactionsLocking/TransactionsLocking.module.ts @@ -10,8 +10,10 @@ import { PurchasesTransactionLockingGuardSubscriber } from './subscribers/Purcha import { SalesTransactionLockingGuardSubscriber } from './subscribers/SalesTransactionLockingGuardSubscriber'; import { QueryTransactionsLocking } from './queries/QueryTransactionsLocking'; import { TransactionsLockingController } from './TransactionsLocking.controller'; +import { SettingsModule } from '../Settings/Settings.module'; @Module({ + imports: [SettingsModule], providers: [ TransactionsLockingService, FinancialTransactionLocking, diff --git a/packages/server-nest/src/modules/TransactionsLocking/TransactionsLockingRepository.ts b/packages/server-nest/src/modules/TransactionsLocking/TransactionsLockingRepository.ts index 8ff1b212e..af91a2b2c 100644 --- a/packages/server-nest/src/modules/TransactionsLocking/TransactionsLockingRepository.ts +++ b/packages/server-nest/src/modules/TransactionsLocking/TransactionsLockingRepository.ts @@ -4,7 +4,6 @@ import { TransactionsLockingGroup, TransactionsLockingType, } from './types/TransactionsLocking.types'; -import { parseDate } from 'utils'; import { Inject, Injectable } from '@nestjs/common'; import { SettingsStore } from '../Settings/SettingsStore'; import { SETTINGS } from '../Settings/Settings.module'; @@ -159,3 +158,7 @@ export class TransactionsLockingRepository { }); } } + +export const parseDate = (date: string) => { + return date ? moment(date).utcOffset(0).format('YYYY-MM-DD') : ''; +}; diff --git a/packages/server-nest/src/modules/TransactionsLocking/constants.ts b/packages/server-nest/src/modules/TransactionsLocking/constants.ts index 01a2bd35e..ace088de4 100644 --- a/packages/server-nest/src/modules/TransactionsLocking/constants.ts +++ b/packages/server-nest/src/modules/TransactionsLocking/constants.ts @@ -1,7 +1,7 @@ import { - ITransactionsLockingSchema, TransactionsLockingGroup, -} from '@/interfaces'; + ITransactionsLockingSchema, +} from './types/TransactionsLocking.types'; export const ERRORS = { TRANSACTIONS_DATE_LOCKED: 'TRANSACTIONS_DATE_LOCKED', @@ -30,7 +30,7 @@ export const TRANSACTIONS_LOCKING_SCHEMA = [ ] as ITransactionsLockingSchema[]; export function getTransactionsLockingSchemaMeta( - module: TransactionsLockingGroup + module: TransactionsLockingGroup, ): ITransactionsLockingSchema { return TRANSACTIONS_LOCKING_SCHEMA.find((schema) => schema.module === module); } diff --git a/packages/server-nest/src/modules/TransactionsLocking/guards/PurchasesTransactionLockingGuard.ts b/packages/server-nest/src/modules/TransactionsLocking/guards/PurchasesTransactionLockingGuard.ts index efecaf04c..863da3d8d 100644 --- a/packages/server-nest/src/modules/TransactionsLocking/guards/PurchasesTransactionLockingGuard.ts +++ b/packages/server-nest/src/modules/TransactionsLocking/guards/PurchasesTransactionLockingGuard.ts @@ -1,6 +1,7 @@ import { TransactionsLockingGroup } from '../types/TransactionsLocking.types'; import { Injectable } from '@nestjs/common'; import { TransactionsLockingGuard } from './TransactionsLockingGuard'; +import { MomentInput } from 'moment'; @Injectable() export class PurchasesTransactionLockingGuard { @@ -13,7 +14,7 @@ export class PurchasesTransactionLockingGuard { * @param {Date} transactionDate - The transaction date. */ public transactionLockingGuard = async ( - transactionDate: Date + transactionDate: MomentInput ) => { this.transactionLockingGuardService.transactionsLockingGuard( transactionDate, diff --git a/packages/server-nest/src/modules/TransactionsLocking/guards/SalesTransactionLockingGuard.ts b/packages/server-nest/src/modules/TransactionsLocking/guards/SalesTransactionLockingGuard.ts index 318f7f777..ef87f9775 100644 --- a/packages/server-nest/src/modules/TransactionsLocking/guards/SalesTransactionLockingGuard.ts +++ b/packages/server-nest/src/modules/TransactionsLocking/guards/SalesTransactionLockingGuard.ts @@ -1,6 +1,7 @@ import { TransactionsLockingGroup } from '../types/TransactionsLocking.types'; import { Injectable } from '@nestjs/common'; import { TransactionsLockingGuard } from './TransactionsLockingGuard'; +import { MomentInput } from 'moment'; @Injectable() export class SalesTransactionLockingGuard { @@ -13,7 +14,7 @@ export class SalesTransactionLockingGuard { * @param {Date} transactionDate - The transaction date. */ public transactionLockingGuard = async ( - transactionDate: Date + transactionDate: MomentInput ) => { await this.transactionLockingGuardService.transactionsLockingGuard( transactionDate, diff --git a/packages/server-nest/src/modules/TransactionsLocking/guards/TransactionsLockingGuard.ts b/packages/server-nest/src/modules/TransactionsLocking/guards/TransactionsLockingGuard.ts index b7fd8fe42..e8aa2de20 100644 --- a/packages/server-nest/src/modules/TransactionsLocking/guards/TransactionsLockingGuard.ts +++ b/packages/server-nest/src/modules/TransactionsLocking/guards/TransactionsLockingGuard.ts @@ -1,4 +1,4 @@ -import moment from 'moment'; +import moment, { MomentInput } from 'moment'; import { Injectable } from '@nestjs/common'; import { TransactionsLockingGroup } from '../types/TransactionsLocking.types'; import { TransactionsLockingRepository } from '../TransactionsLockingRepository'; @@ -18,7 +18,7 @@ export class TransactionsLockingGuard { * @returns {boolean} */ public isTransactionsLocking = ( - transactionDate: Date, + transactionDate: MomentInput, lockingGroup: string = TransactionsLockingGroup.All ): boolean => { const { isEnabled, unlockFromDate, unlockToDate, lockToDate } = @@ -49,7 +49,7 @@ export class TransactionsLockingGuard { * @throws {ServiceError} */ public validateTransactionsLocking = ( - transactionDate: Date, + transactionDate: MomentInput, lockingGroup: TransactionsLockingGroup ) => { const isLocked = this.isTransactionsLocking( @@ -83,7 +83,7 @@ export class TransactionsLockingGuard { * @param {Date} transactionDate - The transaction date. */ public transactionsLockingGuard = ( - transactionDate: Date, + transactionDate: MomentInput, moduleType: TransactionsLockingGroup ) => { const lockingType = diff --git a/packages/server-nest/src/modules/VendorCreditsRefund/models/RefundVendorCredit.ts b/packages/server-nest/src/modules/VendorCreditsRefund/models/RefundVendorCredit.ts index 18b1dbf1b..aabc2e48e 100644 --- a/packages/server-nest/src/modules/VendorCreditsRefund/models/RefundVendorCredit.ts +++ b/packages/server-nest/src/modules/VendorCreditsRefund/models/RefundVendorCredit.ts @@ -16,6 +16,7 @@ export class RefundVendorCredit extends BaseModel { public depositAccountId!: number; public description!: string; public branchId!: number; + public date!: Date; public vendorCredit!: VendorCredit; public depositAccount!: Account; diff --git a/packages/server-nest/src/utils/is-blank.ts b/packages/server-nest/src/utils/is-blank.ts new file mode 100644 index 000000000..aa285e990 --- /dev/null +++ b/packages/server-nest/src/utils/is-blank.ts @@ -0,0 +1,5 @@ +import _ from 'lodash'; + +export const isBlank = (value) => { + return (_.isEmpty(value) && !_.isNumber(value)) || _.isNaN(value); +}; diff --git a/packages/server-nest/src/utils/items-start-with.ts b/packages/server-nest/src/utils/items-start-with.ts new file mode 100644 index 000000000..b29ab26b3 --- /dev/null +++ b/packages/server-nest/src/utils/items-start-with.ts @@ -0,0 +1,3 @@ +export const itemsStartWith = (items: string[], char: string) => { + return items.filter((item) => item.indexOf(char) === 0); +}; diff --git a/packages/server-nest/src/utils/parse-boolean.ts b/packages/server-nest/src/utils/parse-boolean.ts new file mode 100644 index 000000000..d714b0b4a --- /dev/null +++ b/packages/server-nest/src/utils/parse-boolean.ts @@ -0,0 +1,23 @@ +import { isEmpty } from 'lodash'; + +const booleanValuesRepresentingTrue: string[] = ['true', '1']; +const booleanValuesRepresentingFalse: string[] = ['false', '0']; + +const normalizeValue = (value: any): string => + value?.toString().trim().toLowerCase(); + +const booleanValues: string[] = [ + ...booleanValuesRepresentingTrue, + ...booleanValuesRepresentingFalse, +].map((value) => normalizeValue(value)); + +export const parseBoolean = (value: any, defaultValue: T): T | boolean => { + if (typeof value === 'boolean') { + return value; // Retrun early we have nothing to parse. + } + const normalizedValue = normalizeValue(value); + if (isEmpty(value) || booleanValues.indexOf(normalizedValue) === -1) { + return defaultValue; + } + return booleanValuesRepresentingTrue.indexOf(normalizedValue) !== -1; +}; diff --git a/packages/server-nest/test/inventory-adjustment.e2e-spec.ts b/packages/server-nest/test/inventory-adjustment.e2e-spec.ts new file mode 100644 index 000000000..22dde01b3 --- /dev/null +++ b/packages/server-nest/test/inventory-adjustment.e2e-spec.ts @@ -0,0 +1,113 @@ +import * as request from 'supertest'; +import { faker } from '@faker-js/faker'; +import { app } from './init-app-test'; + +export const createInventoryAdjustment = ({ itemId }) => ({ + date: '2020-01-01', + type: 'increment', + adjustmentAccountId: 1001, + reason: faker.lorem.sentence(), + description: faker.lorem.paragraph(), + referenceNo: faker.string.alphanumeric(10), + itemId, + quantity: faker.number.int({ min: 1, max: 100 }), + cost: faker.number.float({ min: 1, max: 1000 }), + publish: true, + + warehouseId: 1, + branchId: 1, +}); + +const makeItemRequest = () => ({ + name: faker.commerce.productName(), + type: 'inventory', + inventory_account_id: 1007, +}); + +describe('Inventory Adjustments (e2e)', () => { + it('/inventory-adjustments/quick (POST)', async () => { + const itemResponse = await request(app.getHttpServer()) + .post('/items') + .set('organization-id', '4064541lv40nhca') + .send(makeItemRequest()) + .expect(201); + + const itemId = itemResponse.text; + + return request(app.getHttpServer()) + .post('/inventory-adjustments/quick') + .set('organization-id', '4064541lv40nhca') + .send(createInventoryAdjustment({ itemId })) + .expect(201); + }); + + it('/inventory-adjustments/:id (DELETE)', async () => { + const itemResponse = await request(app.getHttpServer()) + .post('/items') + .set('organization-id', '4064541lv40nhca') + .send(makeItemRequest()) + .expect(201); + + const itemId = itemResponse.text; + + const inventoryAdjustmentResponse = await request(app.getHttpServer()) + .post('/inventory-adjustments/quick') + .set('organization-id', '4064541lv40nhca') + .send(createInventoryAdjustment({ itemId })) + .expect(201); + + const inventoryAdjustmentId = inventoryAdjustmentResponse.body.id; + + return request(app.getHttpServer()) + .delete(`/inventory-adjustments/${inventoryAdjustmentId}`) + .set('organization-id', '4064541lv40nhca') + .expect(200); + }); + + it('/inventory-adjustments/:id (GET)', async () => { + const itemResponse = await request(app.getHttpServer()) + .post('/items') + .set('organization-id', '4064541lv40nhca') + .send(makeItemRequest()) + .expect(201); + + const itemId = itemResponse.text; + const inventoryAdjustmentResponse = await request(app.getHttpServer()) + .post('/inventory-adjustments/quick') + .set('organization-id', '4064541lv40nhca') + .send(createInventoryAdjustment({ itemId })) + .expect(201); + + const inventoryAdjustmentId = inventoryAdjustmentResponse.body.id; + + return request(app.getHttpServer()) + .get(`/inventory-adjustments/${inventoryAdjustmentId}`) + .set('organization-id', '4064541lv40nhca') + .expect(200); + }); + + it('/inventory-adjustments/:id/publish (POST)', async () => { + const itemResponse = await request(app.getHttpServer()) + .post('/items') + .set('organization-id', '4064541lv40nhca') + .send(makeItemRequest()) + .expect(201); + + const itemId = itemResponse.text; + const inventoryAdjustmentResponse = await request(app.getHttpServer()) + .post('/inventory-adjustments/quick') + .set('organization-id', '4064541lv40nhca') + .send({ + ...createInventoryAdjustment({ itemId }), + publish: false, + }) + .expect(201); + + const inventoryAdjustmentId = inventoryAdjustmentResponse.body.id; + + return request(app.getHttpServer()) + .put(`/inventory-adjustments/${inventoryAdjustmentId}/publish`) + .set('organization-id', '4064541lv40nhca') + .expect(200); + }); +}); diff --git a/packages/server/package.json b/packages/server/package.json index 050bbba3b..1f5a1f293 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -102,7 +102,7 @@ "objection-unique": "^1.2.2", "plaid": "^10.3.0", "pluralize": "^8.0.0", - "posthog-node": "^4.2.0", + "posthog-node": "^4.3.2", "pug": "^3.0.2", "puppeteer": "^10.2.0", "qim": "0.0.52",