mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
feat(nestjs): migrate to NestJS
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Param,
|
||||
Post,
|
||||
Put,
|
||||
Query,
|
||||
} from '@nestjs/common';
|
||||
import { VendorCreditsApplicationService } from './VendorCreditsApplication.service';
|
||||
import { IVendorCreditsQueryDTO } from './types/VendorCredit.types';
|
||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import {
|
||||
CreateVendorCreditDto,
|
||||
EditVendorCreditDto,
|
||||
} from './dtos/VendorCredit.dto';
|
||||
|
||||
@Controller('vendor-credits')
|
||||
@ApiTags('vendor-credits')
|
||||
export class VendorCreditsController {
|
||||
constructor(
|
||||
private readonly vendorCreditsApplication: VendorCreditsApplicationService,
|
||||
) {}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Create a new vendor credit.' })
|
||||
async createVendorCredit(@Body() dto: CreateVendorCreditDto) {
|
||||
return this.vendorCreditsApplication.createVendorCredit(dto);
|
||||
}
|
||||
|
||||
@Put(':id/open')
|
||||
@ApiOperation({ summary: 'Open the given vendor credit.' })
|
||||
async openVendorCredit(@Param('id') vendorCreditId: number) {
|
||||
return this.vendorCreditsApplication.openVendorCredit(vendorCreditId);
|
||||
}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Retrieves the vendor credits.' })
|
||||
async getVendorCredits(@Query() filterDTO: IVendorCreditsQueryDTO) {
|
||||
return this.vendorCreditsApplication.getVendorCredits(filterDTO);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@ApiOperation({ summary: 'Edit the given vendor credit.' })
|
||||
async editVendorCredit(
|
||||
@Param('id') vendorCreditId: number,
|
||||
@Body() dto: EditVendorCreditDto,
|
||||
) {
|
||||
return this.vendorCreditsApplication.editVendorCredit(vendorCreditId, dto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: 'Delete the given vendor credit.' })
|
||||
async deleteVendorCredit(@Param('id') vendorCreditId: number) {
|
||||
return this.vendorCreditsApplication.deleteVendorCredit(vendorCreditId);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Retrieves the vendor credit details.' })
|
||||
async getVendorCredit(@Param('id') vendorCreditId: number) {
|
||||
return this.vendorCreditsApplication.getVendorCredit(vendorCreditId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { CreateVendorCreditService } from './commands/CreateVendorCredit.service';
|
||||
import { DeleteVendorCreditService } from './commands/DeleteVendorCredit.service';
|
||||
import { EditVendorCreditService } from './commands/EditVendorCredit.service';
|
||||
import { VendorCreditDTOTransformService } from './commands/VendorCreditDTOTransform.service';
|
||||
import { VendorCreditAutoIncrementService } from './commands/VendorCreditAutoIncrement.service';
|
||||
import { GetRefundVendorCreditService } from '../VendorCreditsRefund/queries/GetRefundVendorCredit.service';
|
||||
import { GetVendorCreditService } from './queries/GetVendorCredit.service';
|
||||
import { VendorCreditsController } from './VendorCredits.controller';
|
||||
import { ItemsModule } from '../Items/items.module';
|
||||
import { TemplateInjectableModule } from '../TemplateInjectable/TemplateInjectable.module';
|
||||
import { AutoIncrementOrdersModule } from '../AutoIncrementOrders/AutoIncrementOrders.module';
|
||||
import { ChromiumlyTenancyModule } from '../ChromiumlyTenancy/ChromiumlyTenancy.module';
|
||||
import { PdfTemplatesModule } from '../PdfTemplate/PdfTemplates.module';
|
||||
import { BranchesModule } from '../Branches/Branches.module';
|
||||
import { WarehousesModule } from '../Warehouses/Warehouses.module';
|
||||
import { VendorCreditsApplicationService } from './VendorCreditsApplication.service';
|
||||
import { OpenVendorCreditService } from './commands/OpenVendorCredit.service';
|
||||
import { VendorCreditGlEntriesSubscriber } from './subscribers/VendorCreditGLEntriesSubscriber';
|
||||
import { VendorCreditGLEntries } from './commands/VendorCreditGLEntries';
|
||||
import { LedgerModule } from '../Ledger/Ledger.module';
|
||||
import { AccountsModule } from '../Accounts/Accounts.module';
|
||||
import VendorCreditInventoryTransactionsSubscriber from './subscribers/VendorCreditInventoryTransactionsSusbcriber';
|
||||
import { VendorCreditInventoryTransactions } from './commands/VendorCreditInventoryTransactions';
|
||||
import { GetVendorCreditsService } from './queries/GetVendorCredits.service';
|
||||
import { DynamicListModule } from '../DynamicListing/DynamicList.module';
|
||||
import { InventoryCostModule } from '../InventoryCost/InventoryCost.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ItemsModule,
|
||||
PdfTemplatesModule,
|
||||
ChromiumlyTenancyModule,
|
||||
TemplateInjectableModule,
|
||||
AutoIncrementOrdersModule,
|
||||
BranchesModule,
|
||||
WarehousesModule,
|
||||
LedgerModule,
|
||||
AccountsModule,
|
||||
DynamicListModule,
|
||||
InventoryCostModule
|
||||
],
|
||||
providers: [
|
||||
CreateVendorCreditService,
|
||||
DeleteVendorCreditService,
|
||||
EditVendorCreditService,
|
||||
VendorCreditDTOTransformService,
|
||||
VendorCreditAutoIncrementService,
|
||||
GetRefundVendorCreditService,
|
||||
GetVendorCreditService,
|
||||
GetVendorCreditsService,
|
||||
VendorCreditsApplicationService,
|
||||
OpenVendorCreditService,
|
||||
VendorCreditGLEntries,
|
||||
VendorCreditGlEntriesSubscriber,
|
||||
VendorCreditInventoryTransactions,
|
||||
VendorCreditInventoryTransactionsSubscriber
|
||||
],
|
||||
exports: [
|
||||
CreateVendorCreditService,
|
||||
DeleteVendorCreditService,
|
||||
EditVendorCreditService,
|
||||
VendorCreditDTOTransformService,
|
||||
VendorCreditAutoIncrementService,
|
||||
GetRefundVendorCreditService,
|
||||
GetVendorCreditService,
|
||||
VendorCreditsApplicationService,
|
||||
OpenVendorCreditService
|
||||
],
|
||||
controllers: [VendorCreditsController],
|
||||
})
|
||||
export class VendorCreditsModule {}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { Knex } from 'knex';
|
||||
import { CreateVendorCreditService } from './commands/CreateVendorCredit.service';
|
||||
import { DeleteVendorCreditService } from './commands/DeleteVendorCredit.service';
|
||||
import { EditVendorCreditService } from './commands/EditVendorCredit.service';
|
||||
import { GetVendorCreditService } from './queries/GetVendorCredit.service';
|
||||
import { IVendorCreditEditDTO, IVendorCreditsQueryDTO } from './types/VendorCredit.types';
|
||||
import { IVendorCreditCreateDTO } from './types/VendorCredit.types';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { OpenVendorCreditService } from './commands/OpenVendorCredit.service';
|
||||
import { GetVendorCreditsService } from './queries/GetVendorCredits.service';
|
||||
import { CreateVendorCreditDto, EditVendorCreditDto } from './dtos/VendorCredit.dto';
|
||||
|
||||
@Injectable()
|
||||
export class VendorCreditsApplicationService {
|
||||
/**
|
||||
* @param {CreateVendorCreditService} createVendorCreditService - Create vendor credit service.
|
||||
* @param {EditVendorCreditService} editVendorCreditService - Edit vendor credit service.
|
||||
* @param {DeleteVendorCreditService} deleteVendorCreditService - Delete vendor credit service.
|
||||
* @param {GetVendorCreditService} getVendorCreditService - Get vendor credit service.
|
||||
*/
|
||||
constructor(
|
||||
private readonly createVendorCreditService: CreateVendorCreditService,
|
||||
private readonly editVendorCreditService: EditVendorCreditService,
|
||||
private readonly deleteVendorCreditService: DeleteVendorCreditService,
|
||||
private readonly getVendorCreditService: GetVendorCreditService,
|
||||
private readonly openVendorCreditService: OpenVendorCreditService,
|
||||
private readonly getVendorCreditsService: GetVendorCreditsService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates a new vendor credit.
|
||||
* @param {CreateVendorCreditDto} dto - The vendor credit create DTO.
|
||||
* @param {Knex.Transaction} trx - The transaction.
|
||||
* @returns {Promise<VendorCredit>} The created vendor credit.
|
||||
*/
|
||||
createVendorCredit(dto: CreateVendorCreditDto, trx?: Knex.Transaction) {
|
||||
return this.createVendorCreditService.newVendorCredit(dto, trx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the given vendor credit.
|
||||
* @param {number} vendorCreditId - The vendor credit id.
|
||||
* @returns {Promise<VendorCredit>} The opened vendor credit.
|
||||
*/
|
||||
openVendorCredit(vendorCreditId: number) {
|
||||
return this.openVendorCreditService.openVendorCredit(vendorCreditId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the given vendor credit.
|
||||
* @param {number} vendorCreditId - The vendor credit id.
|
||||
* @param {EditVendorCreditDto} dto - The vendor credit edit DTO.
|
||||
* @param {Knex.Transaction} trx - The transaction.
|
||||
* @returns {Promise<VendorCredit>} The edited vendor credit.
|
||||
*/
|
||||
editVendorCredit(
|
||||
vendorCreditId: number,
|
||||
dto: EditVendorCreditDto,
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
return this.editVendorCreditService.editVendorCredit(
|
||||
vendorCreditId,
|
||||
dto,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given vendor credit.
|
||||
* @param {number} vendorCreditId - The vendor credit id.
|
||||
* @param {Knex.Transaction} trx - The transaction.
|
||||
* @returns {Promise<VendorCredit>} The deleted vendor credit.
|
||||
*/
|
||||
deleteVendorCredit(vendorCreditId: number, trx?: Knex.Transaction) {
|
||||
return this.deleteVendorCreditService.deleteVendorCredit(
|
||||
vendorCreditId,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
getVendorCredit(vendorCreditId: number, trx?: Knex.Transaction) {
|
||||
return this.getVendorCreditService.getVendorCredit(vendorCreditId, trx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the paginated filterable vendor credits list.
|
||||
* @param {IVendorCreditsQueryDTO} query
|
||||
* @returns {}
|
||||
*/
|
||||
getVendorCredits(query: IVendorCreditsQueryDTO) {
|
||||
return this.getVendorCreditsService.getVendorCredits(query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import {
|
||||
IVendorCreditCreatedPayload,
|
||||
IVendorCreditCreatingPayload,
|
||||
} from '@/modules/VendorCredit/types/VendorCredit.types';
|
||||
import { VendorCredit } from '../models/VendorCredit';
|
||||
import { Vendor } from '@/modules/Vendors/models/Vendor';
|
||||
import { events } from '@/common/events/events';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { VendorCreditDTOTransformService } from './VendorCreditDTOTransform.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { CreateVendorCreditDto } from '../dtos/VendorCredit.dto';
|
||||
|
||||
@Injectable()
|
||||
export class CreateVendorCreditService {
|
||||
/**
|
||||
* @param {UnitOfWork} uow - The unit of work service.
|
||||
* @param {ItemsEntriesService} itemsEntriesService - The items entries service.
|
||||
* @param {EventEmitter2} eventPublisher - The event emitter service.
|
||||
* @param {typeof VendorCredit} vendorCreditModel - The vendor credit model.
|
||||
* @param {typeof Vendor} vendorModel - The vendor model.
|
||||
*/
|
||||
constructor(
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly itemsEntriesService: ItemsEntriesService,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
private readonly vendorCreditDTOTransformService: VendorCreditDTOTransformService,
|
||||
|
||||
@Inject(VendorCredit.name)
|
||||
private readonly vendorCreditModel: TenantModelProxy<typeof VendorCredit>,
|
||||
|
||||
@Inject(Vendor.name)
|
||||
private readonly vendorModel: TenantModelProxy<typeof Vendor>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates a new vendor credit.
|
||||
* @param {IVendorCreditCreateDTO} vendorCreditCreateDTO -
|
||||
* @param {Knex.Transaction} trx -
|
||||
*/
|
||||
public newVendorCredit = async (
|
||||
vendorCreditCreateDTO: CreateVendorCreditDto,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
// Triggers `onVendorCreditCreate` event.
|
||||
await this.eventPublisher.emitAsync(events.vendorCredit.onCreate, {
|
||||
vendorCreditCreateDTO,
|
||||
});
|
||||
// Retrieve the given vendor or throw not found service error.
|
||||
const vendor = await this.vendorModel()
|
||||
.query()
|
||||
.findById(vendorCreditCreateDTO.vendorId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Validate items should be sellable items.
|
||||
await this.itemsEntriesService.validateNonSellableEntriesItems(
|
||||
vendorCreditCreateDTO.entries,
|
||||
);
|
||||
// Transforms the credit DTO to storage layer.
|
||||
const vendorCreditModel =
|
||||
await this.vendorCreditDTOTransformService.transformCreateEditDTOToModel(
|
||||
vendorCreditCreateDTO,
|
||||
vendor.currencyCode,
|
||||
);
|
||||
// Saves the vendor credit transactions under UOW environment.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onVendorCreditCreating` event.
|
||||
await this.eventPublisher.emitAsync(events.vendorCredit.onCreating, {
|
||||
vendorCreditCreateDTO,
|
||||
trx,
|
||||
} as IVendorCreditCreatingPayload);
|
||||
|
||||
// Saves the vendor credit graph.
|
||||
const vendorCredit = await this.vendorCreditModel()
|
||||
.query(trx)
|
||||
.upsertGraphAndFetch({
|
||||
...vendorCreditModel,
|
||||
});
|
||||
|
||||
// Triggers `onVendorCreditCreated` event.
|
||||
await this.eventPublisher.emitAsync(events.vendorCredit.onCreated, {
|
||||
vendorCredit,
|
||||
vendorCreditCreateDTO,
|
||||
trx,
|
||||
} as IVendorCreditCreatedPayload);
|
||||
|
||||
return vendorCredit;
|
||||
}, trx);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import {
|
||||
IVendorCreditDeletedPayload,
|
||||
IVendorCreditDeletingPayload,
|
||||
} from '@/modules/VendorCredit/types/VendorCredit.types';
|
||||
import { ERRORS } from '../constants';
|
||||
import { VendorCredit } from '../models/VendorCredit';
|
||||
import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
|
||||
import { VendorCreditAppliedBill } from '../../VendorCreditsApplyBills/models/VendorCreditAppliedBill';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { RefundVendorCredit } from '../../VendorCreditsRefund/models/RefundVendorCredit';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteVendorCreditService {
|
||||
/**
|
||||
* @param {typeof VendorCredit} vendorCreditModel - The vendor credit model.
|
||||
* @param {typeof ItemEntry} itemEntryModel - The item entry model.
|
||||
* @param {EventEmitter2} eventPublisher - The event emitter service.
|
||||
* @param {UnitOfWork} uow - The unit of work service.
|
||||
* @param {typeof RefundVendorCredit} refundVendorCreditModel - The refund vendor credit model.
|
||||
* @param {typeof VendorCreditAppliedBill} vendorCreditAppliedBillModel - The vendor credit applied bill model.
|
||||
*/
|
||||
constructor(
|
||||
private eventPublisher: EventEmitter2,
|
||||
private uow: UnitOfWork,
|
||||
|
||||
@Inject(ItemEntry.name)
|
||||
private itemEntryModel: TenantModelProxy<typeof ItemEntry>,
|
||||
|
||||
@Inject(VendorCredit.name)
|
||||
private vendorCreditModel: TenantModelProxy<typeof VendorCredit>,
|
||||
|
||||
@Inject(RefundVendorCredit.name)
|
||||
private refundVendorCreditModel: TenantModelProxy<
|
||||
typeof RefundVendorCredit
|
||||
>,
|
||||
|
||||
@Inject(VendorCreditAppliedBill.name)
|
||||
private vendorCreditAppliedBillModel: TenantModelProxy<
|
||||
typeof VendorCreditAppliedBill
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Deletes the given vendor credit.
|
||||
* @param {number} vendorCreditId - Vendor credit id.
|
||||
*/
|
||||
public deleteVendorCredit = async (
|
||||
vendorCreditId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
// Retrieve the old vendor credit.
|
||||
const oldVendorCredit = await this.vendorCreditModel()
|
||||
.query()
|
||||
.findById(vendorCreditId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Validates vendor credit has no associate refund transactions.
|
||||
await this.validateVendorCreditHasNoRefundTransactions(vendorCreditId);
|
||||
|
||||
// Validates vendor credit has no associated applied to bills transactions.
|
||||
await this.validateVendorCreditHasNoApplyBillsTransactions(vendorCreditId);
|
||||
|
||||
// Deletes the vendor credit transactions under UOW environment.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onVendorCreditEditing` event.
|
||||
await this.eventPublisher.emitAsync(events.vendorCredit.onDeleting, {
|
||||
oldVendorCredit,
|
||||
trx,
|
||||
} as IVendorCreditDeletingPayload);
|
||||
|
||||
// Deletes the associated credit note entries.
|
||||
await this.itemEntryModel()
|
||||
.query(trx)
|
||||
.where('reference_id', vendorCreditId)
|
||||
.where('reference_type', 'VendorCredit')
|
||||
.delete();
|
||||
|
||||
// Deletes the credit note transaction.
|
||||
await this.vendorCreditModel()
|
||||
.query(trx)
|
||||
.findById(vendorCreditId)
|
||||
.delete();
|
||||
|
||||
// Triggers `onVendorCreditDeleted` event.
|
||||
await this.eventPublisher.emitAsync(events.vendorCredit.onDeleted, {
|
||||
vendorCreditId,
|
||||
oldVendorCredit,
|
||||
trx,
|
||||
} as IVendorCreditDeletedPayload);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates vendor credit has no refund transactions.
|
||||
* @param {number} vendorCreditId
|
||||
*/
|
||||
private validateVendorCreditHasNoRefundTransactions = async (
|
||||
vendorCreditId: number,
|
||||
): Promise<void> => {
|
||||
const refundCredits = await this.refundVendorCreditModel()
|
||||
.query()
|
||||
.where('vendorCreditId', vendorCreditId);
|
||||
if (refundCredits.length > 0) {
|
||||
throw new ServiceError(ERRORS.VENDOR_CREDIT_HAS_REFUND_TRANSACTIONS);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate vendor credit has no applied transactions to bills.
|
||||
* @param {number} vendorCreditId
|
||||
*/
|
||||
private validateVendorCreditHasNoApplyBillsTransactions = async (
|
||||
vendorCreditId: number,
|
||||
): Promise<void> => {
|
||||
const appliedTransactions = await this.vendorCreditAppliedBillModel()
|
||||
.query()
|
||||
.where('vendorCreditId', vendorCreditId);
|
||||
if (appliedTransactions.length > 0) {
|
||||
throw new ServiceError(ERRORS.VENDOR_CREDIT_HAS_APPLIED_BILLS);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
IVendorCreditEditedPayload,
|
||||
IVendorCreditEditingPayload,
|
||||
} from '../types/VendorCredit.types';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
import { VendorCredit } from '../models/VendorCredit';
|
||||
import { Contact } from '@/modules/Contacts/models/Contact';
|
||||
import { events } from '@/common/events/events';
|
||||
import { VendorCreditDTOTransformService } from './VendorCreditDTOTransform.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { EditVendorCreditDto } from '../dtos/VendorCredit.dto';
|
||||
|
||||
@Injectable()
|
||||
export class EditVendorCreditService {
|
||||
/**
|
||||
* @param {EventEmitter2} eventPublisher - The event emitter service.
|
||||
* @param {UnitOfWork} uow - The unit of work service.
|
||||
* @param {ItemsEntriesService} itemsEntriesService - The items entries service.
|
||||
* @param {typeof VendorCredit} vendorCreditModel - The vendor credit model.
|
||||
* @param {typeof Contact} contactModel - The contact model.
|
||||
*/
|
||||
constructor(
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly itemsEntriesService: ItemsEntriesService,
|
||||
private readonly vendorCreditDTOTransform: VendorCreditDTOTransformService,
|
||||
|
||||
@Inject(VendorCredit.name)
|
||||
private readonly vendorCreditModel: TenantModelProxy<typeof VendorCredit>,
|
||||
|
||||
@Inject(Contact.name)
|
||||
private readonly contactModel: TenantModelProxy<typeof Contact>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Deletes the given vendor credit.
|
||||
* @param {number} vendorCreditId - Vendor credit id.
|
||||
* @param {EditVendorCreditDto} vendorCreditDto -
|
||||
*/
|
||||
public editVendorCredit = async (
|
||||
vendorCreditId: number,
|
||||
vendorCreditDTO: EditVendorCreditDto,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
// Retrieve the vendor credit or throw not found service error.
|
||||
const oldVendorCredit = await this.vendorCreditModel()
|
||||
.query()
|
||||
.findById(vendorCreditId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Validate customer existance.
|
||||
const vendor = await this.contactModel()
|
||||
.query()
|
||||
.modify('vendor')
|
||||
.findById(vendorCreditDTO.vendorId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Validate items ids existance.
|
||||
await this.itemsEntriesService.validateItemsIdsExistance(
|
||||
vendorCreditDTO.entries,
|
||||
);
|
||||
// Validate non-sellable entries items.
|
||||
await this.itemsEntriesService.validateNonSellableEntriesItems(
|
||||
vendorCreditDTO.entries,
|
||||
);
|
||||
// Validate the items entries existance.
|
||||
await this.itemsEntriesService.validateEntriesIdsExistance(
|
||||
vendorCreditId,
|
||||
'VendorCredit',
|
||||
vendorCreditDTO.entries,
|
||||
);
|
||||
// Transformes edit DTO to model storage layer.
|
||||
const vendorCreditModel =
|
||||
await this.vendorCreditDTOTransform.transformCreateEditDTOToModel(
|
||||
vendorCreditDTO,
|
||||
vendor.currencyCode,
|
||||
oldVendorCredit,
|
||||
);
|
||||
// Edits the vendor credit graph under unit-of-work envirement.
|
||||
return this.uow.withTransaction(async (trx) => {
|
||||
// Triggers `onVendorCreditEditing` event.
|
||||
await this.eventPublisher.emitAsync(events.vendorCredit.onEditing, {
|
||||
oldVendorCredit,
|
||||
vendorCreditDTO,
|
||||
trx,
|
||||
} as IVendorCreditEditingPayload);
|
||||
|
||||
// Saves the vendor credit graph to the storage.
|
||||
const vendorCredit = await this.vendorCreditModel()
|
||||
.query(trx)
|
||||
.upsertGraphAndFetch({
|
||||
id: vendorCreditId,
|
||||
...vendorCreditModel,
|
||||
});
|
||||
// Triggers `onVendorCreditEdited event.
|
||||
await this.eventPublisher.emitAsync(events.vendorCredit.onEdited, {
|
||||
oldVendorCredit,
|
||||
vendorCredit,
|
||||
vendorCreditDTO,
|
||||
trx,
|
||||
} as IVendorCreditEditedPayload);
|
||||
|
||||
return vendorCredit;
|
||||
}, trx);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
IVendorCreditOpenedPayload,
|
||||
IVendorCreditOpeningPayload,
|
||||
IVendorCreditOpenPayload,
|
||||
} from '../types/VendorCredit.types';
|
||||
import { ERRORS } from '../constants';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { VendorCredit } from '../models/VendorCredit';
|
||||
import { events } from '@/common/events/events';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { Knex } from 'knex';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class OpenVendorCreditService {
|
||||
/**
|
||||
* @param {EventEmitter2} eventPublisher - The event emitter service.
|
||||
* @param {UnitOfWork} uow - The unit of work service.
|
||||
* @param {typeof VendorCredit} vendorCreditModel - The vendor credit model.
|
||||
*/
|
||||
constructor(
|
||||
private eventPublisher: EventEmitter2,
|
||||
private uow: UnitOfWork,
|
||||
|
||||
@Inject(VendorCredit.name)
|
||||
private vendorCreditModel: TenantModelProxy<typeof VendorCredit>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Opens the given credit note.
|
||||
* @param {number} vendorCreditId -
|
||||
* @returns {Promise<IVendorCredit>}
|
||||
*/
|
||||
public openVendorCredit = async (
|
||||
vendorCreditId: number,
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<VendorCredit> => {
|
||||
// Retrieve the vendor credit or throw not found service error.
|
||||
const oldVendorCredit = await this.vendorCreditModel()
|
||||
.query()
|
||||
.findById(vendorCreditId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Throw service error if the credit note is already open.
|
||||
this.throwErrorIfAlreadyOpen(oldVendorCredit);
|
||||
|
||||
// Triggers `onVendorCreditOpen` event.
|
||||
await this.eventPublisher.emitAsync(events.vendorCredit.onOpen, {
|
||||
vendorCreditId,
|
||||
oldVendorCredit,
|
||||
} as IVendorCreditOpenPayload);
|
||||
|
||||
// Sales the credit note transactions with associated entries.
|
||||
return this.uow.withTransaction(async (trx) => {
|
||||
const eventPayload = {
|
||||
vendorCreditId,
|
||||
oldVendorCredit,
|
||||
trx,
|
||||
} as IVendorCreditOpeningPayload;
|
||||
|
||||
// Triggers `onCreditNoteOpening` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.creditNote.onOpening,
|
||||
eventPayload as IVendorCreditOpeningPayload,
|
||||
);
|
||||
// Saves the vendor credit graph to the storage.
|
||||
const vendorCredit = await this.vendorCreditModel()
|
||||
.query(trx)
|
||||
.findById(vendorCreditId)
|
||||
.updateAndFetchById(vendorCreditId, {
|
||||
openedAt: new Date(),
|
||||
});
|
||||
// Triggers `onVendorCreditOpened` event.
|
||||
await this.eventPublisher.emitAsync(events.vendorCredit.onOpened, {
|
||||
...eventPayload,
|
||||
vendorCredit,
|
||||
} as IVendorCreditOpenedPayload);
|
||||
|
||||
return vendorCredit;
|
||||
}, trx);
|
||||
};
|
||||
|
||||
/**
|
||||
* Throw error if the vendor credit is already open.
|
||||
* @param {IVendorCredit} vendorCredit
|
||||
*/
|
||||
public throwErrorIfAlreadyOpen = (vendorCredit: VendorCredit) => {
|
||||
if (vendorCredit.openedAt) {
|
||||
throw new ServiceError(ERRORS.VENDOR_CREDIT_ALREADY_OPENED);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { AutoIncrementOrdersService } from '@/modules/AutoIncrementOrders/AutoIncrementOrders.service';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class VendorCreditAutoIncrementService {
|
||||
/**
|
||||
* @param {AutoIncrementOrdersService} autoIncrementOrdersService - Auto increment orders service.
|
||||
*/
|
||||
constructor(private autoIncrementOrdersService: AutoIncrementOrdersService) {}
|
||||
|
||||
/**
|
||||
* Retrieve the next unique credit number.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @return {string}
|
||||
*/
|
||||
public getNextCreditNumber = (): Promise<string> => {
|
||||
return this.autoIncrementOrdersService.getNextTransactionNumber(
|
||||
'vendor_credit',
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Increment the vendor credit serial next number.
|
||||
*/
|
||||
public incrementSerialNumber = () => {
|
||||
return this.autoIncrementOrdersService.incrementSettingsNextNumber(
|
||||
'vendor_credit',
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import * as moment from 'moment';
|
||||
import { omit } from 'lodash';
|
||||
import * as R from 'ramda';
|
||||
import * as composeAsync from 'async/compose';
|
||||
import { ERRORS } from '../constants';
|
||||
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
import { BranchTransactionDTOTransformer } from '@/modules/Branches/integrations/BranchTransactionDTOTransform';
|
||||
import { WarehouseTransactionDTOTransform } from '@/modules/Warehouses/Integrations/WarehouseTransactionDTOTransform';
|
||||
import { VendorCredit } from '../models/VendorCredit';
|
||||
import { assocItemEntriesDefaultIndex } from '@/utils/associate-item-entries-index';
|
||||
import { VendorCreditAutoIncrementService } from './VendorCreditAutoIncrement.service';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import {
|
||||
CreateVendorCreditDto,
|
||||
EditVendorCreditDto,
|
||||
VendorCreditEntryDto,
|
||||
} from '../dtos/VendorCredit.dto';
|
||||
|
||||
@Injectable()
|
||||
export class VendorCreditDTOTransformService {
|
||||
/**
|
||||
* @param {ItemsEntriesService} itemsEntriesService - The items entries service.
|
||||
* @param {BranchTransactionDTOTransformer} branchDTOTransform - The branch transaction DTO transformer.
|
||||
* @param {WarehouseTransactionDTOTransform} warehouseDTOTransform - The warehouse transaction DTO transformer.
|
||||
* @param {VendorCreditAutoIncrementService} vendorCreditAutoIncrement - The vendor credit auto increment service.
|
||||
*/
|
||||
constructor(
|
||||
private itemsEntriesService: ItemsEntriesService,
|
||||
private branchDTOTransform: BranchTransactionDTOTransformer,
|
||||
private warehouseDTOTransform: WarehouseTransactionDTOTransform,
|
||||
private vendorCreditAutoIncrement: VendorCreditAutoIncrementService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Transforms the credit/edit vendor credit DTO to model.
|
||||
* @param {IVendorCreditCreateDTO | IVendorCreditEditDTO} vendorCreditDTO
|
||||
* @param {string} vendorCurrencyCode -
|
||||
* @param {IVendorCredit} oldVendorCredit -
|
||||
* @returns {VendorCredit}
|
||||
*/
|
||||
public transformCreateEditDTOToModel = async (
|
||||
vendorCreditDTO: CreateVendorCreditDto | EditVendorCreditDto,
|
||||
vendorCurrencyCode: string,
|
||||
oldVendorCredit?: VendorCredit,
|
||||
): Promise<VendorCredit> => {
|
||||
// Calculates the total amount of items entries.
|
||||
const amount = this.itemsEntriesService.getTotalItemsEntries(
|
||||
vendorCreditDTO.entries,
|
||||
);
|
||||
const entries = R.compose(
|
||||
// Associate the default index to each item entry.
|
||||
assocItemEntriesDefaultIndex,
|
||||
|
||||
// Associate the reference type to item entries.
|
||||
R.map((entry: VendorCreditEntryDto) => ({
|
||||
referenceType: 'VendorCredit',
|
||||
...entry,
|
||||
})),
|
||||
)(vendorCreditDTO.entries);
|
||||
|
||||
// Retreive the next vendor credit number.
|
||||
const autoNextNumber =
|
||||
await this.vendorCreditAutoIncrement.getNextCreditNumber();
|
||||
|
||||
// Detarmines the credit note number.
|
||||
const vendorCreditNumber =
|
||||
vendorCreditDTO.vendorCreditNumber ||
|
||||
oldVendorCredit?.vendorCreditNumber ||
|
||||
autoNextNumber;
|
||||
|
||||
const initialDTO = {
|
||||
...omit(vendorCreditDTO, ['open', 'attachments']),
|
||||
amount,
|
||||
currencyCode: vendorCurrencyCode,
|
||||
exchangeRate: vendorCreditDTO.exchangeRate || 1,
|
||||
vendorCreditNumber,
|
||||
entries,
|
||||
...(vendorCreditDTO.open &&
|
||||
!oldVendorCredit?.openedAt && {
|
||||
openedAt: moment().toMySqlDateTime(),
|
||||
}),
|
||||
};
|
||||
return composeAsync(
|
||||
this.branchDTOTransform.transformDTO<VendorCredit>,
|
||||
this.warehouseDTOTransform.transformDTO<VendorCredit>,
|
||||
)(initialDTO) as VendorCredit;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate the credit note remaining amount.
|
||||
* @param {ICreditNote} creditNote
|
||||
* @param {number} amount
|
||||
*/
|
||||
public validateCreditRemainingAmount = (
|
||||
vendorCredit: VendorCredit,
|
||||
amount: number,
|
||||
) => {
|
||||
if (vendorCredit.creditsRemaining < amount) {
|
||||
throw new ServiceError(ERRORS.VENDOR_CREDIT_HAS_NO_REMAINING_AMOUNT);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
|
||||
import { VendorCredit } from '../models/VendorCredit';
|
||||
import { ILedgerEntry } from '@/modules/Ledger/types/Ledger.types';
|
||||
import { AccountNormal } from '@/interfaces/Account';
|
||||
import { Ledger } from '@/modules/Ledger/Ledger';
|
||||
|
||||
export class VendorCreditGL {
|
||||
private APAccountId: number;
|
||||
private purchaseDiscountAccountId: number;
|
||||
private otherExpensesAccountId: number;
|
||||
|
||||
constructor(private vendorCredit: VendorCredit) {}
|
||||
|
||||
/**
|
||||
* Sets the payable account (A/P) ID.
|
||||
* @param {number} APAccountId
|
||||
* @returns {VendorCreditGL}
|
||||
*/
|
||||
public setAPAccountId(APAccountId: number) {
|
||||
this.APAccountId = APAccountId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the purchase discount account ID.
|
||||
* @param {number} purchaseDiscountAccountId
|
||||
* @returns {VendorCreditGL}
|
||||
*/
|
||||
public setPurchaseDiscountAccountId(purchaseDiscountAccountId: number) {
|
||||
this.purchaseDiscountAccountId = purchaseDiscountAccountId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the other expenses account ID.
|
||||
* @param {number} otherExpensesAccountId
|
||||
* @returns {VendorCreditGL}
|
||||
*/
|
||||
public setOtherExpensesAccountId(otherExpensesAccountId: number) {
|
||||
this.otherExpensesAccountId = otherExpensesAccountId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the vendor credit GL common entry.
|
||||
* @param {IVendorCredit} vendorCredit
|
||||
*/
|
||||
public get vendorCreditGLCommonEntry() {
|
||||
return {
|
||||
date: this.vendorCredit.vendorCreditDate,
|
||||
currencyCode: this.vendorCredit.currencyCode,
|
||||
exchangeRate: this.vendorCredit.exchangeRate,
|
||||
|
||||
transactionId: this.vendorCredit.id,
|
||||
transactionType: 'VendorCredit',
|
||||
transactionNumber: this.vendorCredit.vendorCreditNumber,
|
||||
referenceNumber: this.vendorCredit.referenceNo,
|
||||
|
||||
credit: 0,
|
||||
debit: 0,
|
||||
|
||||
branchId: this.vendorCredit.branchId,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the vendor credit payable GL entry.
|
||||
* @returns {ILedgerEntry}
|
||||
*/
|
||||
public get vendorCreditPayableGLEntry(): ILedgerEntry {
|
||||
const commonEntity = this.vendorCreditGLCommonEntry;
|
||||
|
||||
return {
|
||||
...commonEntity,
|
||||
debit: this.vendorCredit.totalLocal,
|
||||
accountId: this.APAccountId,
|
||||
contactId: this.vendorCredit.vendorId,
|
||||
accountNormal: AccountNormal.CREDIT,
|
||||
index: 1,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the vendor credit item GL entry.
|
||||
* @returns {ILedgerEntry}
|
||||
*/
|
||||
public getVendorCreditGLItemEntry(
|
||||
entry: ItemEntry,
|
||||
index: number,
|
||||
): ILedgerEntry {
|
||||
const commonEntity = this.vendorCreditGLCommonEntry;
|
||||
const totalLocal = entry.totalExcludingTax * this.vendorCredit.exchangeRate;
|
||||
|
||||
return {
|
||||
...commonEntity,
|
||||
credit: totalLocal,
|
||||
index: index + 2,
|
||||
itemId: entry.itemId,
|
||||
// itemQuantity: entry.quantity,
|
||||
accountId:
|
||||
'inventory' === entry.item.type
|
||||
? entry.item.inventoryAccountId
|
||||
: entry.costAccountId || entry.item.costAccountId,
|
||||
accountNormal: AccountNormal.DEBIT,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the vendor credit discount GL entry.
|
||||
* @returns {ILedgerEntry}
|
||||
*/
|
||||
public get discountEntry(): ILedgerEntry {
|
||||
const commonEntry = this.vendorCreditGLCommonEntry;
|
||||
|
||||
return {
|
||||
...commonEntry,
|
||||
debit: this.vendorCredit.discountAmountLocal,
|
||||
accountId: this.purchaseDiscountAccountId,
|
||||
accountNormal: AccountNormal.DEBIT,
|
||||
index: 1,
|
||||
indexGroup: 40,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the vendor credit adjustment GL entry.
|
||||
* @returns {ILedgerEntry}
|
||||
*/
|
||||
public get adjustmentEntry(): ILedgerEntry {
|
||||
const commonEntry = this.vendorCreditGLCommonEntry;
|
||||
const adjustmentAmount = Math.abs(this.vendorCredit.adjustmentLocal);
|
||||
|
||||
return {
|
||||
...commonEntry,
|
||||
credit: this.vendorCredit.adjustmentLocal > 0 ? adjustmentAmount : 0,
|
||||
debit: this.vendorCredit.adjustmentLocal < 0 ? adjustmentAmount : 0,
|
||||
accountId: this.otherExpensesAccountId,
|
||||
accountNormal: AccountNormal.DEBIT,
|
||||
index: 1,
|
||||
indexGroup: 40,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the vendor credit GL entries.
|
||||
* @return {ILedgerEntry[]}
|
||||
*/
|
||||
public getVendorCreditGLEntries(): ILedgerEntry[] {
|
||||
const payableEntry = this.vendorCreditPayableGLEntry;
|
||||
const itemsEntries = this.vendorCredit.entries.map((entry, index) =>
|
||||
this.getVendorCreditGLItemEntry(entry, index),
|
||||
);
|
||||
const discountEntry = this.discountEntry;
|
||||
const adjustmentEntry = this.adjustmentEntry;
|
||||
|
||||
return [payableEntry, discountEntry, adjustmentEntry, ...itemsEntries];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the vendor credit ledger.
|
||||
* @returns {Ledger}
|
||||
*/
|
||||
public getVendorCreditLedger(): Ledger {
|
||||
const entries = this.getVendorCreditGLEntries();
|
||||
return new Ledger(entries);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import { Knex } from 'knex';
|
||||
import { VendorCreditGL } from './VendorCreditGL';
|
||||
import { LedgerStorageService } from '@/modules/Ledger/LedgerStorage.service';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { AccountRepository } from '@/modules/Accounts/repositories/Account.repository';
|
||||
import { VendorCredit } from '../models/VendorCredit';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class VendorCreditGLEntries {
|
||||
constructor(
|
||||
private readonly ledgerStorage: LedgerStorageService,
|
||||
private readonly accountRepository: AccountRepository,
|
||||
|
||||
@Inject(VendorCredit.name)
|
||||
private readonly vendorCreditModel: TenantModelProxy<typeof VendorCredit>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates vendor credit associated GL entries.
|
||||
* @param {number} vendorCreditId
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
public writeVendorCreditGLEntries = async (
|
||||
vendorCreditId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
// Vendor credit with entries items.
|
||||
const vendorCredit = await this.vendorCreditModel()
|
||||
.query(trx)
|
||||
.findById(vendorCreditId)
|
||||
.withGraphFetched('entries.item');
|
||||
|
||||
// Retrieve the payable account (A/P) account.
|
||||
const APAccount = await this.accountRepository.findOrCreateAccountsPayable(
|
||||
vendorCredit.currencyCode,
|
||||
{},
|
||||
trx,
|
||||
);
|
||||
// Retrieve the purchase discount account.
|
||||
const purchaseDiscountAccount =
|
||||
await this.accountRepository.findOrCreatePurchaseDiscountAccount({}, trx);
|
||||
|
||||
// Retrieve the other expenses account.
|
||||
const otherExpensesAccount =
|
||||
await this.accountRepository.findOrCreateOtherExpensesAccount({}, trx);
|
||||
|
||||
const vendorCreditLedger = new VendorCreditGL(vendorCredit)
|
||||
.setAPAccountId(APAccount.id)
|
||||
.setPurchaseDiscountAccountId(purchaseDiscountAccount.id)
|
||||
.setOtherExpensesAccountId(otherExpensesAccount.id)
|
||||
.getVendorCreditLedger();
|
||||
|
||||
// Commits the ledger entries to the storage.
|
||||
await this.ledgerStorage.commit(vendorCreditLedger, trx);
|
||||
};
|
||||
|
||||
/**
|
||||
* Edits vendor credit associated GL entries.
|
||||
* @param {number} vendorCreditId
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
public rewriteVendorCreditGLEntries = async (
|
||||
vendorCreditId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
// Reverts the GL entries.
|
||||
await this.revertVendorCreditGLEntries(vendorCreditId, trx);
|
||||
|
||||
// Re-write the GL entries.
|
||||
await this.writeVendorCreditGLEntries(vendorCreditId, trx);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reverts the vendor credit associated GL entries.
|
||||
* @param {number} vendorCreditId - Vendor credit identifier.
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
public async revertVendorCreditGLEntries(
|
||||
vendorCreditId: number,
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> {
|
||||
await this.ledgerStorage.deleteByReference(
|
||||
vendorCreditId,
|
||||
'VendorCredit',
|
||||
trx,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// @ts-nocheck
|
||||
import { Knex } from 'knex';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { VendorCredit } from '../models/VendorCredit';
|
||||
import { InventoryTransactionsService } from '@/modules/InventoryCost/commands/InventoryTransactions.service';
|
||||
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
|
||||
@Injectable()
|
||||
export class VendorCreditInventoryTransactions {
|
||||
constructor(
|
||||
private readonly inventoryService: InventoryTransactionsService,
|
||||
private readonly itemsEntriesService: ItemsEntriesService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates vendor credit associated inventory transactions.
|
||||
* @param {IVnedorCredit} vendorCredit
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
public createInventoryTransactions = async (
|
||||
vendorCredit: VendorCredit,
|
||||
trx: Knex.Transaction
|
||||
): Promise<void> => {
|
||||
// Loads the inventory items entries of the given sale invoice.
|
||||
const inventoryEntries =
|
||||
await this.itemsEntriesService.filterInventoryEntries(
|
||||
vendorCredit.entries
|
||||
);
|
||||
|
||||
const transaction = {
|
||||
transactionId: vendorCredit.id,
|
||||
transactionType: 'VendorCredit',
|
||||
transactionNumber: vendorCredit.vendorCreditNumber,
|
||||
exchangeRate: vendorCredit.exchangeRate,
|
||||
date: vendorCredit.vendorCreditDate,
|
||||
direction: 'OUT',
|
||||
entries: inventoryEntries,
|
||||
warehouseId: vendorCredit.warehouseId,
|
||||
createdAt: vendorCredit.createdAt,
|
||||
};
|
||||
// Writes inventory tranactions.
|
||||
await this.inventoryService.recordInventoryTransactionsFromItemsEntries(
|
||||
transaction,
|
||||
false,
|
||||
trx
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Edits vendor credit associated inventory transactions.
|
||||
* @param {number} vendorCreditId - Vendor credit id.
|
||||
* @param {IVendorCredit} vendorCredit - Vendor credit.
|
||||
* @param {Knex.Transactions} trx - Knex transaction.
|
||||
*/
|
||||
public async editInventoryTransactions(
|
||||
vendorCreditId: number,
|
||||
vendorCredit: VendorCredit,
|
||||
trx?: Knex.Transaction
|
||||
): Promise<void> {
|
||||
// Deletes inventory transactions.
|
||||
await this.deleteInventoryTransactions(vendorCreditId, trx);
|
||||
|
||||
// Re-write inventory transactions.
|
||||
await this.createInventoryTransactions(vendorCredit, trx);
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes credit note associated inventory transactions.
|
||||
* @param {number} vendorCreditId - Vendor credit id.
|
||||
* @param {Knex.Transaction} trx - Knex transaction.
|
||||
*/
|
||||
public async deleteInventoryTransactions(
|
||||
vendorCreditId: number,
|
||||
trx?: Knex.Transaction
|
||||
): Promise<void> {
|
||||
// Deletes the inventory transactions by the given reference id and type.
|
||||
await this.inventoryService.deleteInventoryTransactions(
|
||||
vendorCreditId,
|
||||
'VendorCredit',
|
||||
trx
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { IVendorCreditsQueryDTO } from '@/interfaces';
|
||||
// import ListVendorCredits from '../queries/ListVendorCredits';
|
||||
// import { Exportable } from '@/services/Export/Exportable';
|
||||
// import { QueryBuilder } from 'knex';
|
||||
|
||||
// @Service()
|
||||
// export class VendorCreditsExportable extends Exportable {
|
||||
// @Inject()
|
||||
// private getVendorCredits: ListVendorCredits;
|
||||
|
||||
// /**
|
||||
// * Retrieves the vendor credits data to exportable sheet.
|
||||
// * @param {number} tenantId -
|
||||
// * @param {IVendorCreditsQueryDTO} query -
|
||||
// * @returns {}
|
||||
// */
|
||||
// public exportable(tenantId: number, query: IVendorCreditsQueryDTO) {
|
||||
// const filterQuery = (query) => {
|
||||
// query.withGraphFetched('branch');
|
||||
// query.withGraphFetched('warehouse');
|
||||
// };
|
||||
// const parsedQuery = {
|
||||
// sortOrder: 'desc',
|
||||
// columnSortBy: 'created_at',
|
||||
// ...query,
|
||||
// page: 1,
|
||||
// pageSize: 12000,
|
||||
// filterQuery,
|
||||
// } as IVendorCreditsQueryDTO;
|
||||
|
||||
// return this.getVendorCredits
|
||||
// .getVendorCredits(tenantId, parsedQuery)
|
||||
// .then((output) => output.vendorCredits);
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,45 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { Knex } from 'knex';
|
||||
// import { Importable } from '@/services/Import/Importable';
|
||||
// import CreateVendorCredit from './CreateVendorCredit.service';
|
||||
// import { IVendorCreditCreateDTO } from '@/interfaces';
|
||||
// import { VendorCreditsSampleData } from '../constants';
|
||||
|
||||
// @Service()
|
||||
// export class VendorCreditsImportable extends Importable {
|
||||
// @Inject()
|
||||
// private createVendorCreditService: CreateVendorCredit;
|
||||
|
||||
// /**
|
||||
// * Importing to account service.
|
||||
// * @param {number} tenantId
|
||||
// * @param {IAccountCreateDTO} createAccountDTO
|
||||
// * @returns
|
||||
// */
|
||||
// public importable(
|
||||
// tenantId: number,
|
||||
// createPaymentDTO: IVendorCreditCreateDTO,
|
||||
// trx?: Knex.Transaction
|
||||
// ) {
|
||||
// return this.createVendorCreditService.newVendorCredit(
|
||||
// tenantId,
|
||||
// createPaymentDTO,
|
||||
// trx
|
||||
// );
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Concurrrency controlling of the importing process.
|
||||
// * @returns {number}
|
||||
// */
|
||||
// public get concurrency() {
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Retrieves the sample data that used to download accounts sample sheet.
|
||||
// */
|
||||
// public sampleData(): any[] {
|
||||
// return VendorCreditsSampleData;
|
||||
// }
|
||||
// }
|
||||
82
packages/server/src/modules/VendorCredit/constants.ts
Normal file
82
packages/server/src/modules/VendorCredit/constants.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
export const ERRORS = {
|
||||
VENDOR_CREDIT_NOT_FOUND: 'VENDOR_CREDIT_NOT_FOUND',
|
||||
VENDOR_CREDIT_ALREADY_OPENED: 'VENDOR_CREDIT_ALREADY_OPENED',
|
||||
VENDOR_CREDIT_HAS_NO_REMAINING_AMOUNT:
|
||||
'VENDOR_CREDIT_HAS_NO_REMAINING_AMOUNT',
|
||||
VENDOR_CREDIT_APPLY_TO_BILLS_NOT_FOUND:
|
||||
'VENDOR_CREDIT_APPLY_TO_BILLS_NOT_FOUND',
|
||||
BILLS_HAS_NO_REMAINING_AMOUNT: 'BILLS_HAS_NO_REMAINING_AMOUNT',
|
||||
VENDOR_CREDIT_HAS_REFUND_TRANSACTIONS:
|
||||
'VENDOR_CREDIT_HAS_REFUND_TRANSACTIONS',
|
||||
VENDOR_CREDIT_HAS_APPLIED_BILLS: 'VENDOR_CREDIT_HAS_APPLIED_BILLS',
|
||||
};
|
||||
|
||||
export const DEFAULT_VIEW_COLUMNS = [];
|
||||
export const DEFAULT_VIEWS = [
|
||||
{
|
||||
name: 'vendor_credit.view.draft',
|
||||
slug: 'draft',
|
||||
rolesLogicExpression: '1',
|
||||
roles: [
|
||||
{ index: 1, fieldKey: 'status', comparator: 'equals', value: 'draft' },
|
||||
],
|
||||
columns: DEFAULT_VIEW_COLUMNS,
|
||||
},
|
||||
{
|
||||
name: 'vendor_credit.view.published',
|
||||
slug: 'published',
|
||||
rolesLogicExpression: '1',
|
||||
roles: [
|
||||
{
|
||||
index: 1,
|
||||
fieldKey: 'status',
|
||||
comparator: 'equals',
|
||||
value: 'published',
|
||||
},
|
||||
],
|
||||
columns: DEFAULT_VIEW_COLUMNS,
|
||||
},
|
||||
{
|
||||
name: 'vendor_credit.view.open',
|
||||
slug: 'open',
|
||||
rolesLogicExpression: '1',
|
||||
roles: [
|
||||
{
|
||||
index: 1,
|
||||
fieldKey: 'status',
|
||||
comparator: 'equals',
|
||||
value: 'open',
|
||||
},
|
||||
],
|
||||
columns: DEFAULT_VIEW_COLUMNS,
|
||||
},
|
||||
{
|
||||
name: 'vendor_credit.view.closed',
|
||||
slug: 'closed',
|
||||
rolesLogicExpression: '1',
|
||||
roles: [
|
||||
{
|
||||
index: 1,
|
||||
fieldKey: 'status',
|
||||
comparator: 'equals',
|
||||
value: 'closed',
|
||||
},
|
||||
],
|
||||
columns: DEFAULT_VIEW_COLUMNS,
|
||||
},
|
||||
];
|
||||
|
||||
export const VendorCreditsSampleData = [
|
||||
{
|
||||
Vendor: 'Randall Kohler VENDOR',
|
||||
'Vendor Credit Date': '2024-01-01',
|
||||
'Vendor Credit No.': 'VC-0001',
|
||||
'Reference No.': 'REF-00001',
|
||||
'Exchange Rate': '',
|
||||
Note: 'Note',
|
||||
Open: 'T',
|
||||
'Item Name': 'Hettinger, Schumm and Bartoletti',
|
||||
Quantity: 100,
|
||||
Rate: 100,
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,157 @@
|
||||
import { ItemEntryDto } from '@/modules/TransactionItemEntry/dto/ItemEntry.dto';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsArray,
|
||||
IsEnum,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
|
||||
enum DiscountType {
|
||||
Percentage = 'percentage',
|
||||
Amount = 'amount',
|
||||
}
|
||||
|
||||
export class VendorCreditEntryDto extends ItemEntryDto {}
|
||||
|
||||
class AttachmentDto {
|
||||
@IsString()
|
||||
key: string;
|
||||
}
|
||||
|
||||
export class CommandVendorCreditDto {
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({
|
||||
description: 'The id of the vendor',
|
||||
example: 1,
|
||||
})
|
||||
vendorId: number;
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
description: 'The exchange rate of the vendor credit',
|
||||
example: 1,
|
||||
})
|
||||
exchangeRate?: number;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
description: 'The vendor credit number',
|
||||
example: '123456',
|
||||
})
|
||||
vendorCreditNumber?: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
description: 'The reference number of the vendor credit',
|
||||
example: '123456',
|
||||
})
|
||||
referenceNo?: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({
|
||||
description: 'The date of the vendor credit',
|
||||
example: '2021-01-01',
|
||||
})
|
||||
vendorCreditDate: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
description: 'The note of the vendor credit',
|
||||
example: '123456',
|
||||
})
|
||||
note?: string;
|
||||
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
description: 'The open status of the vendor credit',
|
||||
example: true,
|
||||
})
|
||||
open: boolean = false;
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
description: 'The warehouse id of the vendor credit',
|
||||
example: 1,
|
||||
})
|
||||
warehouseId?: number;
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
description: 'The branch id of the vendor credit',
|
||||
example: 1,
|
||||
})
|
||||
branchId?: number;
|
||||
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => VendorCreditEntryDto)
|
||||
@ApiProperty({
|
||||
description: 'The entries of the vendor credit',
|
||||
example: [
|
||||
{
|
||||
itemId: 1,
|
||||
quantity: 1,
|
||||
unitPrice: 1,
|
||||
discount: 1,
|
||||
discountType: DiscountType.Percentage,
|
||||
accountId: 1,
|
||||
amount: 1,
|
||||
},
|
||||
],
|
||||
})
|
||||
entries: VendorCreditEntryDto[];
|
||||
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => AttachmentDto)
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
description: 'The attachments of the vendor credit',
|
||||
example: [
|
||||
{
|
||||
key: '123456',
|
||||
},
|
||||
],
|
||||
})
|
||||
attachments?: AttachmentDto[];
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
description: 'The discount of the vendor credit',
|
||||
example: 1,
|
||||
})
|
||||
discount?: number;
|
||||
|
||||
@IsEnum(DiscountType)
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
description: 'The discount type of the vendor credit',
|
||||
example: DiscountType.Percentage,
|
||||
})
|
||||
discountType?: DiscountType;
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
description: 'The adjustment of the vendor credit',
|
||||
example: 1,
|
||||
})
|
||||
adjustment?: number;
|
||||
}
|
||||
|
||||
export class CreateVendorCreditDto extends CommandVendorCreditDto {}
|
||||
export class EditVendorCreditDto extends CommandVendorCreditDto {}
|
||||
395
packages/server/src/modules/VendorCredit/models/VendorCredit.ts
Normal file
395
packages/server/src/modules/VendorCredit/models/VendorCredit.ts
Normal file
@@ -0,0 +1,395 @@
|
||||
import { Model, raw } from 'objection';
|
||||
import { Vendor } from '@/modules/Vendors/models/Vendor';
|
||||
import { Warehouse } from '@/modules/Warehouses/models/Warehouse.model';
|
||||
import { Branch } from '@/modules/Branches/models/Branch.model';
|
||||
import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
|
||||
import { DiscountType } from '@/common/types/Discount';
|
||||
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
export class VendorCredit extends TenantBaseModel {
|
||||
vendorId: number;
|
||||
amount: number;
|
||||
currencyCode: string;
|
||||
|
||||
vendorCreditDate: Date;
|
||||
vendorCreditNumber: string;
|
||||
|
||||
referenceNo: string;
|
||||
refundedAmount: number;
|
||||
invoicedAmount: number;
|
||||
adjustment: number;
|
||||
exchangeRate: number;
|
||||
note: string;
|
||||
openedAt: Date;
|
||||
userId: number;
|
||||
|
||||
discount: number;
|
||||
discountType: DiscountType;
|
||||
|
||||
branchId: number;
|
||||
warehouseId: number;
|
||||
|
||||
vendor?: Vendor;
|
||||
warehouse?: Warehouse;
|
||||
branch?: Branch;
|
||||
entries?: ItemEntry[];
|
||||
attachments?: Document[];
|
||||
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
/**
|
||||
* Table name
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'vendor_credits';
|
||||
}
|
||||
/**
|
||||
* Vendor credit amount in local currency.
|
||||
* @returns {number}
|
||||
*/
|
||||
get localAmount() {
|
||||
return this.amount * this.exchangeRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vendor credit subtotal.
|
||||
* @returns {number}
|
||||
*/
|
||||
get subtotal() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vendor credit subtotal in local currency.
|
||||
* @returns {number}
|
||||
*/
|
||||
get subtotalLocal() {
|
||||
return this.subtotal * this.exchangeRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discount amount.
|
||||
* @returns {number}
|
||||
*/
|
||||
get discountAmount() {
|
||||
return this.discountType === DiscountType.Amount
|
||||
? this.discount
|
||||
: this.subtotal * (this.discount / 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discount amount in local currency.
|
||||
* @returns {number | null}
|
||||
*/
|
||||
get discountAmountLocal() {
|
||||
return this.discountAmount ? this.discountAmount * this.exchangeRate : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discount percentage.
|
||||
* @returns {number | null}
|
||||
*/
|
||||
get discountPercentage(): number | null {
|
||||
return this.discountType === DiscountType.Percentage ? this.discount : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjustment amount in local currency.
|
||||
* @returns {number | null}
|
||||
*/
|
||||
get adjustmentLocal() {
|
||||
return this.adjustment ? this.adjustment * this.exchangeRate : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vendor credit total.
|
||||
* @returns {number}
|
||||
*/
|
||||
get total() {
|
||||
return this.subtotal - this.discountAmount + this.adjustment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vendor credit total in local currency.
|
||||
* @returns {number}
|
||||
*/
|
||||
get totalLocal() {
|
||||
return this.total * this.exchangeRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Model modifiers.
|
||||
*/
|
||||
static get modifiers() {
|
||||
return {
|
||||
/**
|
||||
* Filters the credit notes in draft status.
|
||||
*/
|
||||
draft(query) {
|
||||
query.where('opened_at', null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Filters the published vendor credits.
|
||||
*/
|
||||
published(query) {
|
||||
query.whereNot('opened_at', null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Filters the open vendor credits.
|
||||
*/
|
||||
open(query) {
|
||||
query
|
||||
.where(
|
||||
raw(`COALESCE(REFUNDED_AMOUNT) + COALESCE(INVOICED_AMOUNT) <
|
||||
COALESCE(AMOUNT)`),
|
||||
)
|
||||
.modify('published');
|
||||
},
|
||||
|
||||
/**
|
||||
* Filters the closed vendor credits.
|
||||
*/
|
||||
closed(query) {
|
||||
query
|
||||
.where(
|
||||
raw(`COALESCE(REFUNDED_AMOUNT) + COALESCE(INVOICED_AMOUNT) =
|
||||
COALESCE(AMOUNT)`),
|
||||
)
|
||||
.modify('published');
|
||||
},
|
||||
|
||||
/**
|
||||
* Status filter.
|
||||
*/
|
||||
filterByStatus(query, filterType) {
|
||||
switch (filterType) {
|
||||
case 'draft':
|
||||
query.modify('draft');
|
||||
break;
|
||||
case 'published':
|
||||
query.modify('published');
|
||||
break;
|
||||
case 'open':
|
||||
default:
|
||||
query.modify('open');
|
||||
break;
|
||||
case 'closed':
|
||||
query.modify('closed');
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
sortByStatus(query, order) {
|
||||
query.orderByRaw(
|
||||
`COALESCE(REFUNDED_AMOUNT) + COALESCE(INVOICED_AMOUNT) = COALESCE(AMOUNT) ${order}`,
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamps columns.
|
||||
*/
|
||||
get timestamps() {
|
||||
return ['createdAt', 'updatedAt'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual attributes.
|
||||
*/
|
||||
static get virtualAttributes() {
|
||||
return [
|
||||
'isDraft',
|
||||
'isPublished',
|
||||
'isOpen',
|
||||
'isClosed',
|
||||
|
||||
'creditsRemaining',
|
||||
'localAmount',
|
||||
|
||||
'discountAmount',
|
||||
'discountAmountLocal',
|
||||
'discountPercentage',
|
||||
|
||||
'adjustmentLocal',
|
||||
|
||||
'total',
|
||||
'totalLocal',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detarmines whether the vendor credit is draft.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get isDraft() {
|
||||
return !this.openedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detarmines whether vendor credit is published.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get isPublished() {
|
||||
return !!this.openedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detarmines whether the credit note is open.
|
||||
* @return {boolean}
|
||||
*/
|
||||
get isOpen() {
|
||||
return !!this.openedAt && this.creditsRemaining > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detarmines whether the credit note is closed.
|
||||
* @return {boolean}
|
||||
*/
|
||||
get isClosed() {
|
||||
return this.openedAt && this.creditsRemaining === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the credits remaining.
|
||||
* @returns {number}
|
||||
*/
|
||||
get creditsRemaining() {
|
||||
return Math.max(this.amount - this.refundedAmount - this.invoicedAmount, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bill model settings.
|
||||
*/
|
||||
// static get meta() {
|
||||
// return BillSettings;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Relationship mapping.
|
||||
*/
|
||||
static get relationMappings() {
|
||||
const { Vendor } = require('../../Vendors/models/Vendor');
|
||||
const {
|
||||
ItemEntry,
|
||||
} = require('../../TransactionItemEntry/models/ItemEntry');
|
||||
const { Branch } = require('../../Branches/models/Branch.model');
|
||||
const { Document } = require('../../ChromiumlyTenancy/models/Document');
|
||||
const { Warehouse } = require('../../Warehouses/models/Warehouse.model');
|
||||
|
||||
return {
|
||||
/**
|
||||
* Vendor credit may belongs to vendor.
|
||||
*/
|
||||
vendor: {
|
||||
relation: Model.BelongsToOneRelation,
|
||||
modelClass: Vendor,
|
||||
join: {
|
||||
from: 'vendor_credits.vendorId',
|
||||
to: 'contacts.id',
|
||||
},
|
||||
filter(query) {
|
||||
query.where('contact_service', 'vendor');
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Vendor credit may has many item entries.
|
||||
*/
|
||||
entries: {
|
||||
relation: Model.HasManyRelation,
|
||||
modelClass: ItemEntry,
|
||||
join: {
|
||||
from: 'vendor_credits.id',
|
||||
to: 'items_entries.referenceId',
|
||||
},
|
||||
filter(builder) {
|
||||
builder.where('reference_type', 'VendorCredit');
|
||||
builder.orderBy('index', 'ASC');
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Vendor credit may belongs to branch.
|
||||
*/
|
||||
branch: {
|
||||
relation: Model.BelongsToOneRelation,
|
||||
modelClass: Branch,
|
||||
join: {
|
||||
from: 'vendor_credits.branchId',
|
||||
to: 'branches.id',
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Vendor credit may has associated warehouse.
|
||||
*/
|
||||
warehouse: {
|
||||
relation: Model.BelongsToOneRelation,
|
||||
modelClass: Warehouse,
|
||||
join: {
|
||||
from: 'vendor_credits.warehouseId',
|
||||
to: 'warehouses.id',
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Vendor credit may has many attached attachments.
|
||||
*/
|
||||
attachments: {
|
||||
relation: Model.ManyToManyRelation,
|
||||
modelClass: Document,
|
||||
join: {
|
||||
from: 'vendor_credits.id',
|
||||
through: {
|
||||
from: 'document_links.modelId',
|
||||
to: 'document_links.documentId',
|
||||
},
|
||||
to: 'documents.id',
|
||||
},
|
||||
filter(query) {
|
||||
query.where('model_ref', 'VendorCredit');
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
// static get meta() {
|
||||
// return VendorCreditMeta;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Retrieve the default custom views, roles and columns.
|
||||
*/
|
||||
// static get defaultViews() {
|
||||
// return DEFAULT_VIEWS;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Model search attributes.
|
||||
*/
|
||||
static get searchRoles() {
|
||||
return [
|
||||
{ fieldKey: 'credit_number', comparator: 'contains' },
|
||||
{ condition: 'or', fieldKey: 'reference_no', comparator: 'contains' },
|
||||
{ condition: 'or', fieldKey: 'amount', comparator: 'equals' },
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents mutate base currency since the model is not empty.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static get preventMutateBaseCurrency() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { VendorCreditTransformer } from './VendorCreditTransformer';
|
||||
import { ERRORS } from '../constants';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { VendorCredit } from '../models/VendorCredit';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetVendorCreditService {
|
||||
/**
|
||||
* @param {typeof VendorCredit} vendorCreditModel - Vendor credit model.
|
||||
* @param {TransformerInjectable} transformer - Transformer service.
|
||||
*/
|
||||
constructor(
|
||||
@Inject(VendorCredit.name)
|
||||
private readonly vendorCreditModel: TenantModelProxy<typeof VendorCredit>,
|
||||
private readonly transformer: TransformerInjectable,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Retrieves the given vendor credit.
|
||||
* @param {number} vendorCreditId - Vendor credit id.
|
||||
* @param {Knex.Transaction} trx - Knex transaction.
|
||||
*/
|
||||
public async getVendorCredit(vendorCreditId: number, trx?: Knex.Transaction) {
|
||||
// Retrieve the vendor credit model graph.
|
||||
const vendorCredit = await this.vendorCreditModel()
|
||||
.query(trx)
|
||||
.findById(vendorCreditId)
|
||||
.withGraphFetched('entries.item')
|
||||
.withGraphFetched('vendor')
|
||||
.withGraphFetched('branch')
|
||||
.withGraphFetched('attachments');
|
||||
|
||||
if (!vendorCredit) {
|
||||
throw new ServiceError(ERRORS.VENDOR_CREDIT_NOT_FOUND);
|
||||
}
|
||||
return this.transformer.transform(
|
||||
vendorCredit,
|
||||
new VendorCreditTransformer(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import * as R from 'ramda';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { VendorCreditTransformer } from './VendorCreditTransformer';
|
||||
import { DynamicListService } from '@/modules/DynamicListing/DynamicList.service';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { VendorCredit } from '../models/VendorCredit';
|
||||
import { IVendorCreditsQueryDTO } from '../types/VendorCredit.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetVendorCreditsService {
|
||||
constructor(
|
||||
private readonly dynamicListService: DynamicListService,
|
||||
private readonly transformer: TransformerInjectable,
|
||||
|
||||
@Inject(VendorCredit.name)
|
||||
private readonly vendorCreditModel: TenantModelProxy<typeof VendorCredit>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Parses the sale invoice list filter DTO.
|
||||
* @param {IVendorCreditsQueryDTO} filterDTO
|
||||
* @returns
|
||||
*/
|
||||
private parseListFilterDTO = (filterDTO: IVendorCreditsQueryDTO) => {
|
||||
return R.compose(this.dynamicListService.parseStringifiedFilter)(filterDTO);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the vendor credits list.
|
||||
* @param {IVendorCreditsQueryDTO} vendorCreditQuery -
|
||||
*/
|
||||
public getVendorCredits = async (
|
||||
vendorCreditQuery: IVendorCreditsQueryDTO,
|
||||
) => {
|
||||
// Parses stringified filter roles.
|
||||
const filter = this.parseListFilterDTO(vendorCreditQuery);
|
||||
|
||||
// Dynamic list service.
|
||||
const dynamicFilter = await this.dynamicListService.dynamicList(
|
||||
VendorCredit,
|
||||
filter,
|
||||
);
|
||||
const { results, pagination } = await this.vendorCreditModel()
|
||||
.query()
|
||||
.onBuild((builder) => {
|
||||
builder.withGraphFetched('entries');
|
||||
builder.withGraphFetched('vendor');
|
||||
dynamicFilter.buildQuery()(builder);
|
||||
|
||||
// Gives ability to inject custom query to filter results.
|
||||
vendorCreditQuery?.filterQuery &&
|
||||
vendorCreditQuery?.filterQuery(builder);
|
||||
})
|
||||
.pagination(filter.page - 1, filter.pageSize);
|
||||
|
||||
// Transformes the vendor credits models to POJO.
|
||||
const vendorCredits = await this.transformer.transform(
|
||||
results,
|
||||
new VendorCreditTransformer(),
|
||||
);
|
||||
return {
|
||||
vendorCredits,
|
||||
pagination,
|
||||
filterMeta: dynamicFilter.getResponseMeta(),
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
import { AttachmentTransformer } from "@/modules/Attachments/Attachment.transformer";
|
||||
import { ItemEntryTransformer } from "@/modules/TransactionItemEntry/ItemEntry.transformer";
|
||||
import { Transformer } from "@/modules/Transformer/Transformer";
|
||||
import { VendorCredit } from "../models/VendorCredit";
|
||||
|
||||
export class VendorCreditTransformer extends Transformer {
|
||||
/**
|
||||
* Include these attributes to vendor credit object.
|
||||
* @returns {Array}
|
||||
*/
|
||||
public includeAttributes = (): string[] => {
|
||||
return [
|
||||
'formattedAmount',
|
||||
'formattedSubtotal',
|
||||
'formattedVendorCreditDate',
|
||||
'formattedCreatedAt',
|
||||
'formattedCreditsRemaining',
|
||||
'formattedInvoicedAmount',
|
||||
|
||||
'discountAmountFormatted',
|
||||
'discountPercentageFormatted',
|
||||
'discountAmountLocalFormatted',
|
||||
|
||||
'adjustmentFormatted',
|
||||
'adjustmentLocalFormatted',
|
||||
|
||||
'totalFormatted',
|
||||
'entries',
|
||||
'attachments',
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve formatted vendor credit date.
|
||||
* @param {VendorCredit} credit
|
||||
* @returns {String}
|
||||
*/
|
||||
protected formattedVendorCreditDate = (vendorCredit: VendorCredit): string => {
|
||||
return this.formatDate(vendorCredit.vendorCreditDate);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retireve formatted created at date.
|
||||
* @param {VendorCredit} vendorCredit
|
||||
* @returns {string}
|
||||
*/
|
||||
protected formattedCreatedAt = (vendorCredit: VendorCredit): string => {
|
||||
return this.formatDate(vendorCredit.createdAt);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve formatted vendor credit amount.
|
||||
* @param {VendorCredit} credit
|
||||
* @returns {string}
|
||||
*/
|
||||
protected formattedAmount = (vendorCredit: VendorCredit): string => {
|
||||
return this.formatNumber(vendorCredit.amount, {
|
||||
currencyCode: vendorCredit.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the vendor credit formatted subtotal.
|
||||
* @param {VendorCredit} vendorCredit
|
||||
* @returns {string}
|
||||
*/
|
||||
protected formattedSubtotal = (vendorCredit: VendorCredit): string => {
|
||||
return this.formatNumber(vendorCredit.amount, { money: false });
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve formatted credits remaining.
|
||||
* @param {VendorCredit} credit
|
||||
* @returns {string}
|
||||
*/
|
||||
protected formattedCreditsRemaining = (credit: VendorCredit): string => {
|
||||
return this.formatNumber(credit.creditsRemaining, {
|
||||
currencyCode: credit.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the formatted discount amount.
|
||||
* @param {IVendorCredit} credit
|
||||
* @returns {string}
|
||||
*/
|
||||
protected discountAmountFormatted = (credit): string => {
|
||||
return this.formatNumber(credit.discountAmount, {
|
||||
currencyCode: credit.currencyCode,
|
||||
excerptZero: true,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the formatted discount amount in local currency.
|
||||
* @param {VendorCredit} credit
|
||||
* @returns {string}
|
||||
*/
|
||||
protected discountAmountLocalFormatted = (credit): string => {
|
||||
return this.formatNumber(credit.discountAmountLocal, {
|
||||
currencyCode: this.context.organization.baseCurrency,
|
||||
excerptZero: true,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the formatted discount percentage.
|
||||
* @param {VendorCredit} credit
|
||||
* @returns {string}
|
||||
*/
|
||||
protected discountPercentageFormatted = (credit): string => {
|
||||
return credit.discountPercentage ? `${credit.discountPercentage}%` : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the formatted adjustment amount.
|
||||
* @param {VendorCredit} credit
|
||||
* @returns {string}
|
||||
*/
|
||||
protected adjustmentFormatted = (credit): string => {
|
||||
return this.formatNumber(credit.adjustment, {
|
||||
currencyCode: credit.currencyCode,
|
||||
excerptZero: true,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the formatted adjustment amount in local currency.
|
||||
* @param {VendorCredit} credit
|
||||
* @returns {string}
|
||||
*/
|
||||
protected adjustmentLocalFormatted = (credit: VendorCredit): string => {
|
||||
return this.formatNumber(credit.adjustmentLocal, {
|
||||
currencyCode: this.context.organization.baseCurrency,
|
||||
excerptZero: true,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the formatted invoiced amount.
|
||||
* @param credit
|
||||
* @returns {string}
|
||||
*/
|
||||
protected formattedInvoicedAmount = (credit: VendorCredit): string => {
|
||||
return this.formatNumber(credit.invoicedAmount, {
|
||||
currencyCode: credit.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the formatted total.
|
||||
* @param {VendorCredit} credit
|
||||
* @returns {string}
|
||||
*/
|
||||
protected totalFormatted = (credit: VendorCredit): string => {
|
||||
return this.formatNumber(credit.total, {
|
||||
currencyCode: credit.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the entries of the bill.
|
||||
* @param {VendorCredit} vendorCredit
|
||||
* @returns {}
|
||||
*/
|
||||
protected entries = (vendorCredit: VendorCredit) => {
|
||||
return this.item(vendorCredit.entries, new ItemEntryTransformer(), {
|
||||
currencyCode: vendorCredit.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the vendor credit attachments.
|
||||
* @param {VendorCredit} invoice
|
||||
* @returns
|
||||
*/
|
||||
protected attachments = (vendorCredit: VendorCredit) => {
|
||||
return this.item(vendorCredit.attachments, new AttachmentTransformer());
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// import { Inject, Injectable } from '@nestjs/common';
|
||||
// import { OnEvent } from '@nestjs/event-emitter';
|
||||
// import { VendorCredit } from '../models/VendorCredit';
|
||||
// import { IVendorEventDeletingPayload } from '@/modules/Vendors/types/Vendors.types';
|
||||
// import { events } from '@/common/events/events';
|
||||
// import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
|
||||
// const ERRORS = {
|
||||
// VENDOR_HAS_TRANSACTIONS: 'VENDOR_HAS_TRANSACTIONS',
|
||||
// };
|
||||
|
||||
// @Injectable()
|
||||
// export class DeleteVendorAssociatedVendorCredit {
|
||||
// /**
|
||||
// * @param {typeof VendorCredit} vendorCreditModel - Vendor credit model.
|
||||
// */
|
||||
// constructor(
|
||||
// @Inject(VendorCredit.name)
|
||||
// private readonly vendorCreditModel: typeof VendorCredit,
|
||||
// ) {}
|
||||
|
||||
// /**
|
||||
// * Validate vendor has no associated credit transaction once the vendor deleting.
|
||||
// * @param {IVendorEventDeletingPayload} payload -
|
||||
// */
|
||||
// @OnEvent(events.vendors.onDeleting)
|
||||
// public async validateVendorHasNoCreditsTransactionsOnceDeleting({
|
||||
// vendorId,
|
||||
// }: IVendorEventDeletingPayload) {
|
||||
// await this.validateVendorHasNoCreditsTransactions(vendorId);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Validate the given vendor has no associated vendor credit transactions.
|
||||
// * @param {number} vendorId
|
||||
// */
|
||||
// public async validateVendorHasNoCreditsTransactions(
|
||||
// vendorId: number,
|
||||
// ): Promise<void> {
|
||||
// const associatedVendors = await this.vendorCreditModel
|
||||
// .query()
|
||||
// .where('vendorId', vendorId);
|
||||
|
||||
// if (associatedVendors.length > 0) {
|
||||
// throw new ServiceError(ERRORS.VENDOR_HAS_TRANSACTIONS);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,62 @@
|
||||
// import { Service, Inject } from 'typedi';
|
||||
// import {
|
||||
// IRefundVendorCreditCreatedPayload,
|
||||
// IRefundVendorCreditDeletedPayload,
|
||||
// } from '@/interfaces';
|
||||
// import events from '@/subscribers/events';
|
||||
// import RefundSyncCreditRefundedAmount from './RefundSyncCreditRefundedAmount';
|
||||
|
||||
// @Service()
|
||||
// export default class RefundSyncVendorCreditBalanceSubscriber {
|
||||
// @Inject()
|
||||
// refundSyncCreditRefunded: RefundSyncCreditRefundedAmount;
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// public attach = (bus) => {
|
||||
// bus.subscribe(
|
||||
// events.vendorCredit.onRefundCreated,
|
||||
// this.incrementRefundedAmountOnceRefundCreated
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.vendorCredit.onRefundDeleted,
|
||||
// this.decrementRefundedAmountOnceRefundDeleted
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Increment refunded vendor credit amount once refund transaction created.
|
||||
// * @param {IRefundVendorCreditCreatedPayload} payload -
|
||||
// */
|
||||
// private incrementRefundedAmountOnceRefundCreated = async ({
|
||||
// refundVendorCredit,
|
||||
// vendorCredit,
|
||||
// tenantId,
|
||||
// trx,
|
||||
// }: IRefundVendorCreditCreatedPayload) => {
|
||||
// await this.refundSyncCreditRefunded.incrementCreditRefundedAmount(
|
||||
// tenantId,
|
||||
// refundVendorCredit.vendorCreditId,
|
||||
// refundVendorCredit.amount,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Decrement refunded vendor credit amount once refund transaction deleted.
|
||||
// * @param {IRefundVendorCreditDeletedPayload} payload -
|
||||
// */
|
||||
// private decrementRefundedAmountOnceRefundDeleted = async ({
|
||||
// trx,
|
||||
// oldRefundCredit,
|
||||
// tenantId,
|
||||
// }: IRefundVendorCreditDeletedPayload) => {
|
||||
// await this.refundSyncCreditRefunded.decrementCreditNoteRefundAmount(
|
||||
// tenantId,
|
||||
// oldRefundCredit.vendorCreditId,
|
||||
// oldRefundCredit.amount,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,59 @@
|
||||
// import { Service, Inject } from 'typedi';
|
||||
// import events from '@/subscribers/events';
|
||||
// import RefundVendorCreditGLEntries from '../RefundVendorCredits/commands/RefundVendorCreditGLEntries';
|
||||
// import {
|
||||
// IRefundCreditNoteDeletedPayload,
|
||||
// IRefundVendorCreditCreatedPayload,
|
||||
// } from '@/interfaces';
|
||||
|
||||
// @Service()
|
||||
// export default class RefundVendorCreditGLEntriesSubscriber {
|
||||
// @Inject()
|
||||
// refundVendorGLEntries: RefundVendorCreditGLEntries;
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.vendorCredit.onRefundCreated,
|
||||
// this.writeRefundVendorCreditGLEntriesOnceCreated
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.vendorCredit.onRefundDeleted,
|
||||
// this.revertRefundVendorCreditOnceDeleted
|
||||
// );
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Writes refund vendor credit GL entries once the transaction created.
|
||||
// * @param {IRefundCreditNoteCreatedPayload} payload -
|
||||
// */
|
||||
// private writeRefundVendorCreditGLEntriesOnceCreated = async ({
|
||||
// tenantId,
|
||||
// trx,
|
||||
// refundVendorCredit,
|
||||
// }: IRefundVendorCreditCreatedPayload) => {
|
||||
// await this.refundVendorGLEntries.saveRefundCreditGLEntries(
|
||||
// tenantId,
|
||||
// refundVendorCredit.id,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Reverts refund vendor credit GL entries once the transaction deleted.
|
||||
// * @param {IRefundCreditNoteDeletedPayload} payload -
|
||||
// */
|
||||
// private revertRefundVendorCreditOnceDeleted = async ({
|
||||
// tenantId,
|
||||
// trx,
|
||||
// refundCreditId,
|
||||
// }: IRefundCreditNoteDeletedPayload) => {
|
||||
// await this.refundVendorGLEntries.revertRefundCreditGLEntries(
|
||||
// tenantId,
|
||||
// refundCreditId,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,27 @@
|
||||
// import { Service, Inject } from 'typedi';
|
||||
// import events from '@/subscribers/events';
|
||||
// import BaseVendorCredit from '../commands/VendorCreditDTOTransform.service';
|
||||
// import { IVendorCreditCreatedPayload } from '@/interfaces';
|
||||
|
||||
// @Service()
|
||||
// export default class VendorCreditAutoSerialSubscriber {
|
||||
// @Inject()
|
||||
// vendorCreditService: BaseVendorCredit;
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(events.vendorCredit.onCreated, this.autoIncrementOnceCreated);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Auto serial increment once the vendor credit created.
|
||||
// * @param {IVendorCreditCreatedPayload} payload
|
||||
// */
|
||||
// private autoIncrementOnceCreated = ({
|
||||
// tenantId,
|
||||
// }: IVendorCreditCreatedPayload) => {
|
||||
// this.vendorCreditService.incrementSerialNumber(tenantId);
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,83 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import {
|
||||
IVendorCreditCreatedPayload,
|
||||
IVendorCreditDeletedPayload,
|
||||
IVendorCreditEditedPayload,
|
||||
IVendorCreditOpenedPayload,
|
||||
} from '../types/VendorCredit.types';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { VendorCreditGLEntries } from '../commands/VendorCreditGLEntries';
|
||||
import { events } from '@/common/events/events';
|
||||
|
||||
@Injectable()
|
||||
export class VendorCreditGlEntriesSubscriber {
|
||||
constructor(public readonly vendorCreditGLEntries: VendorCreditGLEntries) {}
|
||||
|
||||
/**
|
||||
* Writes GL entries of vendor credit once the transaction created.
|
||||
* @param {IVendorCreditCreatedPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onCreated)
|
||||
public async writeGLEntriesOnceVendorCreditCreated({
|
||||
vendorCredit,
|
||||
trx,
|
||||
}: IVendorCreditCreatedPayload): Promise<void> {
|
||||
// Can't continue if the vendor credit is not open yet.
|
||||
if (!vendorCredit.isPublished) return;
|
||||
|
||||
await this.vendorCreditGLEntries.writeVendorCreditGLEntries(
|
||||
vendorCredit.id,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Gl entries of vendor credit once the transaction opened.
|
||||
* @param {IVendorCreditOpenedPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onOpened)
|
||||
public async writeGLEntgriesOnceVendorCreditOpened({
|
||||
vendorCreditId,
|
||||
trx,
|
||||
}: IVendorCreditOpenedPayload): Promise<void> {
|
||||
await this.vendorCreditGLEntries.writeVendorCreditGLEntries(
|
||||
vendorCreditId,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits associated GL entries once vendor credit edited.
|
||||
* @param {IVendorCreditEditedPayload} payload
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onEdited)
|
||||
public async editGLEntriesOnceVendorCreditEdited({
|
||||
vendorCredit,
|
||||
trx,
|
||||
}: IVendorCreditEditedPayload): Promise<void> {
|
||||
// Can't continue if the vendor credit is not open yet.
|
||||
if (!vendorCredit.isPublished) return;
|
||||
|
||||
await this.vendorCreditGLEntries.rewriteVendorCreditGLEntries(
|
||||
vendorCredit.id,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts the GL entries once vendor credit deleted.
|
||||
* @param {IVendorCreditDeletedPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onDeleted)
|
||||
public async revertGLEntriesOnceDeleted({
|
||||
vendorCreditId,
|
||||
oldVendorCredit,
|
||||
}: IVendorCreditDeletedPayload): Promise<void> {
|
||||
// Can't continue of the vendor credit is not open yet.
|
||||
if (!oldVendorCredit.isPublished) return;
|
||||
|
||||
await this.vendorCreditGLEntries.revertVendorCreditGLEntries(
|
||||
vendorCreditId,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import {
|
||||
IVendorCreditCreatedPayload,
|
||||
IVendorCreditDeletedPayload,
|
||||
IVendorCreditEditedPayload,
|
||||
} from '../types/VendorCredit.types';
|
||||
import { VendorCreditInventoryTransactions } from '../commands/VendorCreditInventoryTransactions';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { events } from '@/common/events/events';
|
||||
|
||||
@Injectable()
|
||||
export default class VendorCreditInventoryTransactionsSubscriber {
|
||||
constructor(
|
||||
private readonly inventoryTransactions: VendorCreditInventoryTransactions,
|
||||
) {}
|
||||
/**
|
||||
* Writes inventory transactions once vendor created created.
|
||||
* @param {IVendorCreditCreatedPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onCreated)
|
||||
@OnEvent(events.vendorCredit.onOpened)
|
||||
public async writeInventoryTransactionsOnceCreated({
|
||||
vendorCredit,
|
||||
trx,
|
||||
}: IVendorCreditCreatedPayload) {
|
||||
// Can't continue if vendor credit is not opened.
|
||||
if (!vendorCredit.openedAt) return null;
|
||||
|
||||
await this.inventoryTransactions.createInventoryTransactions(
|
||||
vendorCredit,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites inventory transactions once vendor credit edited.
|
||||
* @param {IVendorCreditEditedPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onEdited)
|
||||
public async rewriteInventroyTransactionsOnceEdited({
|
||||
oldVendorCredit,
|
||||
vendorCredit,
|
||||
trx,
|
||||
}: IVendorCreditEditedPayload) {
|
||||
// Can't continue if vendor credit is not opened.
|
||||
if (!vendorCredit.openedAt) return null;
|
||||
|
||||
await this.inventoryTransactions.editInventoryTransactions(
|
||||
oldVendorCredit.id,
|
||||
vendorCredit,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts inventory transactions once vendor credit deleted.
|
||||
* @param {IVendorCreditDeletedPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.vendorCredit.onDeleted)
|
||||
public async revertInventoryTransactionsOnceDeleted({
|
||||
vendorCreditId,
|
||||
trx,
|
||||
}: IVendorCreditDeletedPayload) {
|
||||
await this.inventoryTransactions.deleteInventoryTransactions(
|
||||
vendorCreditId,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
import { Knex } from 'knex';
|
||||
import { VendorCredit } from '../models/VendorCredit';
|
||||
import { AttachmentLinkDTO } from '@/modules/Attachments/Attachments.types';
|
||||
import { IRefundVendorCreditDTO } from '@/modules/VendorCreditsRefund/types/VendorCreditRefund.types';
|
||||
import { IItemEntryDTO } from '@/modules/TransactionItemEntry/ItemEntry.types';
|
||||
import { DiscountType } from '@/common/types/Discount';
|
||||
import { IDynamicListFilter } from '@/modules/DynamicListing/DynamicFilter/DynamicFilter.types';
|
||||
import {
|
||||
CreateVendorCreditDto,
|
||||
EditVendorCreditDto,
|
||||
} from '../dtos/VendorCredit.dto';
|
||||
|
||||
export enum VendorCreditAction {
|
||||
Create = 'Create',
|
||||
Edit = 'Edit',
|
||||
Delete = 'Delete',
|
||||
View = 'View',
|
||||
Refund = 'Refund',
|
||||
}
|
||||
|
||||
export interface IVendorCreditEntryDTO extends IItemEntryDTO {}
|
||||
|
||||
export interface IVendorCreditsQueryDTO extends IDynamicListFilter {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
searchKeyword?: string;
|
||||
filterQuery?: (q: any) => void;
|
||||
}
|
||||
|
||||
export interface IVendorCreditDTO {
|
||||
vendorId: number;
|
||||
exchangeRate?: number;
|
||||
vendorCreditNumber: string;
|
||||
referenceNo: string;
|
||||
vendorCreditDate: Date;
|
||||
note: string;
|
||||
open: boolean;
|
||||
entries: IVendorCreditEntryDTO[];
|
||||
|
||||
branchId?: number;
|
||||
warehouseId?: number;
|
||||
attachments?: AttachmentLinkDTO[];
|
||||
|
||||
discount?: number;
|
||||
discountType?: DiscountType;
|
||||
|
||||
adjustment?: number;
|
||||
}
|
||||
|
||||
export interface IVendorCreditCreateDTO extends IVendorCreditDTO {}
|
||||
export interface IVendorCreditEditDTO extends IVendorCreditDTO {}
|
||||
export interface IVendorCreditCreatePayload {
|
||||
refundVendorCreditDTO: IRefundVendorCreditDTO;
|
||||
}
|
||||
|
||||
// Create Vendor Credit Events
|
||||
// ------------------------
|
||||
export interface IVendorCreditCreatingPayload {
|
||||
vendorCredit: VendorCredit;
|
||||
vendorCreditId: number;
|
||||
vendorCreditCreateDTO: CreateVendorCreditDto;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface IVendorCreditCreatedPayload {
|
||||
vendorCredit: VendorCredit;
|
||||
vendorCreditCreateDTO: CreateVendorCreditDto;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface IVendorCreditCreatedPayload {}
|
||||
|
||||
// Delete Vendor Credit Events
|
||||
// ------------------------
|
||||
export interface IVendorCreditDeletedPayload {
|
||||
trx: Knex.Transaction;
|
||||
vendorCreditId: number;
|
||||
oldVendorCredit: VendorCredit;
|
||||
}
|
||||
|
||||
export interface IVendorCreditDeletingPayload {
|
||||
trx: Knex.Transaction;
|
||||
oldVendorCredit: VendorCredit;
|
||||
}
|
||||
|
||||
// Edit Vendor Credit Events
|
||||
// ------------------------
|
||||
export interface IVendorCreditEditingPayload {
|
||||
oldVendorCredit: VendorCredit;
|
||||
vendorCreditDTO: EditVendorCreditDto;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface IVendorCreditEditedPayload {
|
||||
oldVendorCredit: VendorCredit;
|
||||
vendorCredit: VendorCredit;
|
||||
vendorCreditDTO: EditVendorCreditDto;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface IApplyCreditToBillEntryDTO {
|
||||
amount: number;
|
||||
billId: number;
|
||||
}
|
||||
|
||||
// Open Vendor Credit Events
|
||||
// ------------------------
|
||||
export interface IVendorCreditOpenedPayload {
|
||||
// tenantId: number;
|
||||
vendorCreditId: number;
|
||||
vendorCredit: VendorCredit;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface IVendorCreditOpenPayload {
|
||||
// tenantId: number;
|
||||
vendorCreditId: number;
|
||||
oldVendorCredit: VendorCredit;
|
||||
}
|
||||
|
||||
export interface IVendorCreditOpeningPayload {
|
||||
// tenantId: number;
|
||||
vendorCreditId: number;
|
||||
oldVendorCredit: VendorCredit;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
Reference in New Issue
Block a user