mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 22:00:31 +00:00
refactor: inventory adjustments e2e test cases
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -152,8 +152,8 @@ import { PostHogModule } from '../EventsTracker/postHog.module';
|
||||
TransactionsLockingModule,
|
||||
SettingsModule,
|
||||
InventoryAdjustmentsModule,
|
||||
PostHogModule,
|
||||
EventTrackerModule,
|
||||
// PostHogModule,
|
||||
// EventTrackerModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [
|
||||
|
||||
@@ -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<EventMessage, 'distinctId'>) {
|
||||
public async trackEvent(event: any) {
|
||||
// Cannot continue if the Posthog not configured.
|
||||
if (!this.posthog) return;
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { ITransactionsLockingPartialUnlocked } from '@/interfaces';
|
||||
import {
|
||||
SUBSCRIPTION_CANCELLED,
|
||||
SUBSCRIPTION_PAYMENT_FAILED,
|
||||
|
||||
@@ -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],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -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<InventoryAdjustment> {
|
||||
return this.inventoryAdjustmentsApplicationService.getInventoryAdjustment(
|
||||
inventoryAdjustmentId,
|
||||
);
|
||||
}
|
||||
|
||||
@Put(':id/publish')
|
||||
public async publishInventoryAdjustment(
|
||||
@Param('id') inventoryAdjustmentId: number,
|
||||
): Promise<void> {
|
||||
|
||||
@@ -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],
|
||||
})
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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<number> {
|
||||
return this.createItemService.createItem(createItemDto);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -15,5 +15,6 @@ export const SETTINGS = 'SETTINGS';
|
||||
inject: [SettingRepository],
|
||||
},
|
||||
],
|
||||
exports: [SETTINGS]
|
||||
})
|
||||
export class SettingsModule {}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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') : '';
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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;
|
||||
|
||||
5
packages/server-nest/src/utils/is-blank.ts
Normal file
5
packages/server-nest/src/utils/is-blank.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
export const isBlank = (value) => {
|
||||
return (_.isEmpty(value) && !_.isNumber(value)) || _.isNaN(value);
|
||||
};
|
||||
3
packages/server-nest/src/utils/items-start-with.ts
Normal file
3
packages/server-nest/src/utils/items-start-with.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const itemsStartWith = (items: string[], char: string) => {
|
||||
return items.filter((item) => item.indexOf(char) === 0);
|
||||
};
|
||||
23
packages/server-nest/src/utils/parse-boolean.ts
Normal file
23
packages/server-nest/src/utils/parse-boolean.ts
Normal file
@@ -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 = <T>(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;
|
||||
};
|
||||
113
packages/server-nest/test/inventory-adjustment.e2e-spec.ts
Normal file
113
packages/server-nest/test/inventory-adjustment.e2e-spec.ts
Normal file
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user