Compare commits

...

6 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
421f0c26a7 fix(server): mark compute inventory cost flag 2026-01-25 21:59:44 +02:00
Ahmed Bouhuolia
f461cc221b Merge pull request #911 from bigcapitalhq/feature/20260125001703
fix(server): landed cost gl transactions
2026-01-25 00:19:07 +02:00
Ahmed Bouhuolia
acae75a912 fix(server): landed cost gl transactions 2026-01-25 00:17:14 +02:00
Ahmed Bouhuolia
b5a69971a9 Merge pull request #910 from bigcapitalhq/feature/20260123174320
fix(server): customer/vendor opening balance
2026-01-24 14:02:17 +02:00
Ahmed Bouhuolia
04d065b969 wip 2026-01-24 13:59:43 +02:00
Ahmed Bouhuolia
ca910ee489 fix(server): customer/vendor opening balance: 2026-01-23 17:43:22 +02:00
45 changed files with 903 additions and 899 deletions

View File

@@ -2,9 +2,11 @@ import { forwardRef, Module } from '@nestjs/common';
import { TransactionLandedCostEntriesService } from './TransactionLandedCostEntries.service'; import { TransactionLandedCostEntriesService } from './TransactionLandedCostEntries.service';
import { AllocateLandedCostService } from './commands/AllocateLandedCost.service'; import { AllocateLandedCostService } from './commands/AllocateLandedCost.service';
import { LandedCostGLEntriesSubscriber } from './commands/LandedCostGLEntries.subscriber'; import { LandedCostGLEntriesSubscriber } from './commands/LandedCostGLEntries.subscriber';
// import { LandedCostGLEntries } from './commands/LandedCostGLEntries.service'; import { LandedCostGLEntriesService } from './commands/LandedCostGLEntries.service';
import { LandedCostSyncCostTransactions } from './commands/LandedCostSyncCostTransactions.service'; import { LandedCostSyncCostTransactions } from './commands/LandedCostSyncCostTransactions.service';
import { LedgerModule } from '../Ledger/Ledger.module';
import { LandedCostSyncCostTransactionsSubscriber } from './commands/LandedCostSyncCostTransactions.subscriber'; import { LandedCostSyncCostTransactionsSubscriber } from './commands/LandedCostSyncCostTransactions.subscriber';
import { LandedCostInventoryTransactionsSubscriber } from './commands/LandedCostInventoryTransactions.subscriber';
import { BillAllocatedLandedCostTransactions } from './commands/BillAllocatedLandedCostTransactions.service'; import { BillAllocatedLandedCostTransactions } from './commands/BillAllocatedLandedCostTransactions.service';
import { BillAllocateLandedCostController } from './LandedCost.controller'; import { BillAllocateLandedCostController } from './LandedCost.controller';
import { RevertAllocatedLandedCost } from './commands/RevertAllocatedLandedCost.service'; import { RevertAllocatedLandedCost } from './commands/RevertAllocatedLandedCost.service';
@@ -16,12 +18,12 @@ import { ExpenseLandedCost } from './commands/ExpenseLandedCost.service';
import { BillLandedCost } from './commands/BillLandedCost.service'; import { BillLandedCost } from './commands/BillLandedCost.service';
@Module({ @Module({
imports: [forwardRef(() => InventoryCostModule)], imports: [forwardRef(() => InventoryCostModule), LedgerModule],
providers: [ providers: [
AllocateLandedCostService, AllocateLandedCostService,
TransactionLandedCostEntriesService, TransactionLandedCostEntriesService,
BillAllocatedLandedCostTransactions, BillAllocatedLandedCostTransactions,
LandedCostGLEntriesSubscriber, LandedCostGLEntriesService,
TransactionLandedCost, TransactionLandedCost,
BillLandedCost, BillLandedCost,
ExpenseLandedCost, ExpenseLandedCost,
@@ -29,6 +31,8 @@ import { BillLandedCost } from './commands/BillLandedCost.service';
RevertAllocatedLandedCost, RevertAllocatedLandedCost,
LandedCostInventoryTransactions, LandedCostInventoryTransactions,
LandedCostTranasctions, LandedCostTranasctions,
LandedCostGLEntriesSubscriber,
LandedCostInventoryTransactionsSubscriber,
LandedCostSyncCostTransactionsSubscriber, LandedCostSyncCostTransactionsSubscriber,
], ],
exports: [TransactionLandedCostEntriesService], exports: [TransactionLandedCostEntriesService],

View File

@@ -23,7 +23,9 @@ export class AllocateLandedCostService extends BaseLandedCostService {
private readonly billModel: TenantModelProxy<typeof Bill>, private readonly billModel: TenantModelProxy<typeof Bill>,
@Inject(BillLandedCost.name) @Inject(BillLandedCost.name)
protected readonly billLandedCostModel: TenantModelProxy<typeof BillLandedCost> protected readonly billLandedCostModel: TenantModelProxy<
typeof BillLandedCost
>,
) { ) {
super(); super();
} }
@@ -54,7 +56,8 @@ export class AllocateLandedCostService extends BaseLandedCostService {
const amount = this.getAllocateItemsCostTotal(allocateCostDTO); const amount = this.getAllocateItemsCostTotal(allocateCostDTO);
// Retrieve the purchase invoice or throw not found error. // Retrieve the purchase invoice or throw not found error.
const bill = await this.billModel().query() const bill = await this.billModel()
.query()
.findById(billId) .findById(billId)
.withGraphFetched('entries') .withGraphFetched('entries')
.throwIfNotFound(); .throwIfNotFound();
@@ -89,8 +92,9 @@ export class AllocateLandedCostService extends BaseLandedCostService {
// unit-of-work eniverment. // unit-of-work eniverment.
return this.uow.withTransaction(async (trx: Knex.Transaction) => { return this.uow.withTransaction(async (trx: Knex.Transaction) => {
// Save the bill landed cost model. // Save the bill landed cost model.
const billLandedCost = const billLandedCost = await this.billLandedCostModel()
await BillLandedCost.query(trx).insertGraph(billLandedCostObj); .query(trx)
.insertGraph(billLandedCostObj);
// Triggers `onBillLandedCostCreated` event. // Triggers `onBillLandedCostCreated` event.
await this.eventPublisher.emitAsync(events.billLandedCost.onCreated, { await this.eventPublisher.emitAsync(events.billLandedCost.onCreated, {
bill, bill,
@@ -103,5 +107,5 @@ export class AllocateLandedCostService extends BaseLandedCostService {
return billLandedCost; return billLandedCost;
}); });
}; }
} }

View File

@@ -1,236 +1,188 @@
// import * as R from 'ramda'; import { Knex } from 'knex';
// import { Knex } from 'knex'; import { Inject, Injectable } from '@nestjs/common';
// import { Inject, Injectable } from '@nestjs/common'; import * as moment from 'moment';
// import { BaseLandedCostService } from '../BaseLandedCost.service'; import { BaseLandedCostService } from '../BaseLandedCost.service';
// import { BillLandedCost } from '../models/BillLandedCost'; import { BillLandedCost } from '../models/BillLandedCost';
// import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; import { Bill } from '@/modules/Bills/models/Bill';
// import { Bill } from '@/modules/Bills/models/Bill'; import { BillLandedCostEntry } from '../models/BillLandedCostEntry';
// import { BillLandedCostEntry } from '../models/BillLandedCostEntry'; import { ILedgerEntry } from '@/modules/Ledger/types/Ledger.types';
// import { ILedger, ILedgerEntry } from '@/modules/Ledger/types/Ledger.types'; import { Ledger } from '@/modules/Ledger/Ledger';
// import { Ledger } from '@/modules/Ledger/Ledger'; import { LedgerStorageService } from '@/modules/Ledger/LedgerStorage.service';
// import { AccountNormal } from '@/interfaces/Account'; import { AccountNormal } from '@/modules/Accounts/Accounts.types';
// import { ILandedCostTransactionEntry } from '../types/BillLandedCosts.types'; import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
// @Injectable() @Injectable()
// export class LandedCostGLEntries extends BaseLandedCostService { export class LandedCostGLEntriesService extends BaseLandedCostService {
// constructor( constructor(
// private readonly journalService: JournalPosterService, private readonly ledgerStorage: LedgerStorageService,
// private readonly ledgerRepository: LedgerRepository,
// @Inject(BillLandedCost.name) @Inject(BillLandedCost.name)
// private readonly billLandedCostModel: TenantModelProxy<typeof BillLandedCost>, protected readonly billLandedCostModel: TenantModelProxy<
// ) { typeof BillLandedCost
// super(); >,
// } ) {
super();
}
// /** /**
// * Retrieves the landed cost GL common entry. * Retrieves the landed cost GL common entry.
// * @param {IBill} bill */
// * @param {IBillLandedCost} allocatedLandedCost private getLandedCostGLCommonEntry(
// * @returns bill: Bill,
// */ allocatedLandedCost: BillLandedCost,
// private getLandedCostGLCommonEntry = ( ) {
// bill: Bill, return {
// allocatedLandedCost: BillLandedCost date: moment(bill.billDate).format('YYYY-MM-DD'),
// ) => { currencyCode: allocatedLandedCost.currencyCode,
// return { exchangeRate: allocatedLandedCost.exchangeRate,
// date: bill.billDate,
// currencyCode: allocatedLandedCost.currencyCode,
// exchangeRate: allocatedLandedCost.exchangeRate,
// transactionType: 'LandedCost', transactionType: 'LandedCost',
// transactionId: allocatedLandedCost.id, transactionId: allocatedLandedCost.id,
// transactionNumber: bill.billNumber, transactionNumber: bill.billNumber,
// referenceNumber: bill.referenceNo, referenceNumber: bill.referenceNo,
// credit: 0, branchId: bill.branchId,
// debit: 0, projectId: bill.projectId,
// };
// };
// /** credit: 0,
// * Retrieves the landed cost GL inventory entry. debit: 0,
// * @param {IBill} bill };
// * @param {IBillLandedCost} allocatedLandedCost }
// * @param {IBillLandedCostEntry} allocatedEntry
// * @returns {ILedgerEntry}
// */
// private getLandedCostGLInventoryEntry = (
// bill: Bill,
// allocatedLandedCost: BillLandedCost,
// allocatedEntry: BillLandedCostEntry
// ): ILedgerEntry => {
// const commonEntry = this.getLandedCostGLCommonEntry(
// bill,
// allocatedLandedCost
// );
// return {
// ...commonEntry,
// debit: allocatedLandedCost.localAmount,
// accountId: allocatedEntry.itemEntry.item.inventoryAccountId,
// index: 1,
// accountNormal: AccountNormal.DEBIT,
// };
// };
// /** /**
// * Retrieves the landed cost GL cost entry. * Retrieves the landed cost GL inventory entry for an allocated item.
// * @param {IBill} bill */
// * @param {IBillLandedCost} allocatedLandedCost private getLandedCostGLInventoryEntry(
// * @param {ILandedCostTransactionEntry} fromTransactionEntry bill: Bill,
// * @returns {ILedgerEntry} allocatedLandedCost: BillLandedCost,
// */ allocatedEntry: BillLandedCostEntry,
// private getLandedCostGLCostEntry = ( index: number,
// bill: Bill, ): ILedgerEntry {
// allocatedLandedCost: BillLandedCost, const commonEntry = this.getLandedCostGLCommonEntry(
// fromTransactionEntry: ILandedCostTransactionEntry bill,
// ): ILedgerEntry => { allocatedLandedCost,
// const commonEntry = this.getLandedCostGLCommonEntry( );
// bill, const itemEntry = (
// allocatedLandedCost allocatedEntry as BillLandedCostEntry & {
// ); itemEntry?: {
// return { item?: { type?: string; inventoryAccountId?: number };
// ...commonEntry, costAccountId?: number;
// credit: allocatedLandedCost.localAmount, itemId?: number;
// accountId: fromTransactionEntry.costAccountId, };
// index: 2, }
// accountNormal: AccountNormal.CREDIT, ).itemEntry;
// }; const item = itemEntry?.item;
// }; const isInventory = item && ['inventory'].indexOf(item.type) !== -1;
const accountId = isInventory
? item?.inventoryAccountId
: itemEntry?.costAccountId;
// /** if (!accountId) {
// * Retrieve allocated landed cost entry GL entries. throw new Error(
// * @param {IBill} bill `Cannot determine GL account for landed cost allocate entry (entryId: ${allocatedEntry.entryId})`,
// * @param {IBillLandedCost} allocatedLandedCost );
// * @param {ILandedCostTransactionEntry} fromTransactionEntry }
// * @param {IBillLandedCostEntry} allocatedEntry
// * @returns {ILedgerEntry}
// */
// private getLandedCostGLAllocateEntry = R.curry(
// (
// bill: Bill,
// allocatedLandedCost: BillLandedCost,
// fromTransactionEntry: ILandedCostTransactionEntry,
// allocatedEntry: BillLandedCostEntry
// ): ILedgerEntry[] => {
// const inventoryEntry = this.getLandedCostGLInventoryEntry(
// bill,
// allocatedLandedCost,
// allocatedEntry
// );
// const costEntry = this.getLandedCostGLCostEntry(
// bill,
// allocatedLandedCost,
// fromTransactionEntry
// );
// return [inventoryEntry, costEntry];
// }
// );
// /** const localAmount =
// * Compose the landed cost GL entries. allocatedEntry.cost * (allocatedLandedCost.exchangeRate || 1);
// * @param {BillLandedCost} allocatedLandedCost
// * @param {Bill} bill
// * @param {ILandedCostTransactionEntry} fromTransactionEntry
// * @returns {ILedgerEntry[]}
// */
// public getLandedCostGLEntries = (
// allocatedLandedCost: BillLandedCost,
// bill: Bill,
// fromTransactionEntry: ILandedCostTransactionEntry
// ): ILedgerEntry[] => {
// const getEntry = this.getLandedCostGLAllocateEntry(
// bill,
// allocatedLandedCost,
// fromTransactionEntry
// );
// return allocatedLandedCost.allocateEntries.map(getEntry).flat();
// };
// /** return {
// * Retrieves the landed cost GL ledger. ...commonEntry,
// * @param {BillLandedCost} allocatedLandedCost debit: localAmount,
// * @param {Bill} bill accountId,
// * @param {ILandedCostTransactionEntry} fromTransactionEntry index: index + 1,
// * @returns {ILedger} indexGroup: 10,
// */ itemId: itemEntry?.itemId,
// public getLandedCostLedger = ( accountNormal: AccountNormal.DEBIT,
// allocatedLandedCost: BillLandedCost, };
// bill: Bill, }
// fromTransactionEntry: ILandedCostTransactionEntry
// ): ILedger => {
// const entries = this.getLandedCostGLEntries(
// allocatedLandedCost,
// bill,
// fromTransactionEntry
// );
// return new Ledger(entries);
// };
// /** /**
// * Writes landed cost GL entries to the storage layer. * Retrieves the landed cost GL cost entry (credit to cost account).
// * @param {number} tenantId - */
// */ private getLandedCostGLCostEntry(
// public writeLandedCostGLEntries = async ( bill: Bill,
// allocatedLandedCost: BillLandedCost, allocatedLandedCost: BillLandedCost,
// bill: Bill, ): ILedgerEntry {
// fromTransactionEntry: ILandedCostTransactionEntry, const commonEntry = this.getLandedCostGLCommonEntry(
// trx?: Knex.Transaction bill,
// ) => { allocatedLandedCost,
// const ledgerEntries = this.getLandedCostGLEntries( );
// allocatedLandedCost,
// bill,
// fromTransactionEntry
// );
// await this.ledgerRepository.saveLedgerEntries(ledgerEntries, trx);
// };
// /** return {
// * Generates and writes GL entries of the given landed cost. ...commonEntry,
// * @param {number} billLandedCostId credit: allocatedLandedCost.localAmount,
// * @param {Knex.Transaction} trx accountId: allocatedLandedCost.costAccountId,
// */ index: 1,
// public createLandedCostGLEntries = async ( indexGroup: 20,
// billLandedCostId: number, accountNormal: AccountNormal.CREDIT,
// trx?: Knex.Transaction };
// ) => { }
// // Retrieve the bill landed cost transacion with associated
// // allocated entries and items.
// const allocatedLandedCost = await this.billLandedCostModel().query(trx)
// .findById(billLandedCostId)
// .withGraphFetched('bill')
// .withGraphFetched('allocateEntries.itemEntry.item');
// // Retrieve the allocated from transactione entry. /**
// const transactionEntry = await this.getLandedCostEntry( * Composes the landed cost GL entries.
// allocatedLandedCost.fromTransactionType, */
// allocatedLandedCost.fromTransactionId, public getLandedCostGLEntries(
// allocatedLandedCost.fromTransactionEntryId allocatedLandedCost: BillLandedCost,
// ); bill: Bill,
// // Writes the given landed cost GL entries to the storage layer. ): ILedgerEntry[] {
// await this.writeLandedCostGLEntries( const inventoryEntries = allocatedLandedCost.allocateEntries.map(
// allocatedLandedCost, (allocatedEntry, index) =>
// allocatedLandedCost.bill, this.getLandedCostGLInventoryEntry(
// transactionEntry, bill,
// trx allocatedLandedCost,
// ); allocatedEntry,
// }; index,
),
);
const costEntry = this.getLandedCostGLCostEntry(bill, allocatedLandedCost);
// /** return [...inventoryEntries, costEntry];
// * Reverts GL entries of the given allocated landed cost transaction. }
// * @param {number} tenantId
// * @param {number} landedCostId /**
// * @param {Knex.Transaction} trx * Retrieves the landed cost GL ledger.
// */ */
// public revertLandedCostGLEntries = async ( public getLandedCostLedger(
// landedCostId: number, allocatedLandedCost: BillLandedCost,
// trx: Knex.Transaction bill: Bill,
// ) => { ): Ledger {
// await this.journalService.revertJournalTransactions( const entries = this.getLandedCostGLEntries(allocatedLandedCost, bill);
// landedCostId, return new Ledger(entries);
// 'LandedCost', }
// trx
// ); /**
// }; * Generates and writes GL entries of the given landed cost.
// } */
public createLandedCostGLEntries = async (
billLandedCostId: number,
trx?: Knex.Transaction,
) => {
const allocatedLandedCost = await this.billLandedCostModel()
.query(trx)
.findById(billLandedCostId)
.withGraphFetched('bill')
.withGraphFetched('allocateEntries.itemEntry.item');
if (!allocatedLandedCost?.bill) {
throw new Error('BillLandedCost or associated Bill not found');
}
const ledger = this.getLandedCostLedger(
allocatedLandedCost,
allocatedLandedCost.bill,
);
await this.ledgerStorage.commit(ledger, trx);
};
/**
* Reverts GL entries of the given allocated landed cost transaction.
*/
public revertLandedCostGLEntries = async (
landedCostId: number,
trx?: Knex.Transaction,
) => {
await this.ledgerStorage.deleteByReference(landedCostId, 'LandedCost', trx);
};
}

View File

@@ -3,14 +3,15 @@ import {
IAllocatedLandedCostDeletedPayload, IAllocatedLandedCostDeletedPayload,
} from '../types/BillLandedCosts.types'; } from '../types/BillLandedCosts.types';
import { OnEvent } from '@nestjs/event-emitter'; import { OnEvent } from '@nestjs/event-emitter';
// import { LandedCostGLEntries } from './LandedCostGLEntries.service';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
import { LandedCostGLEntriesService } from './LandedCostGLEntries.service';
@Injectable() @Injectable()
export class LandedCostGLEntriesSubscriber { export class LandedCostGLEntriesSubscriber {
constructor() // private readonly billLandedCostGLEntries: LandedCostGLEntries, constructor(
{} private readonly landedCostGLEntries: LandedCostGLEntriesService,
) {}
/** /**
* Writes GL entries once landed cost transaction created. * Writes GL entries once landed cost transaction created.
@@ -21,10 +22,10 @@ export class LandedCostGLEntriesSubscriber {
billLandedCost, billLandedCost,
trx, trx,
}: IAllocatedLandedCostCreatedPayload) { }: IAllocatedLandedCostCreatedPayload) {
// await this.billLandedCostGLEntries.createLandedCostGLEntries( await this.landedCostGLEntries.createLandedCostGLEntries(
// billLandedCost.id, billLandedCost.id,
// trx trx,
// ); );
} }
/** /**
@@ -32,13 +33,13 @@ export class LandedCostGLEntriesSubscriber {
* @param {IAllocatedLandedCostDeletedPayload} payload - * @param {IAllocatedLandedCostDeletedPayload} payload -
*/ */
@OnEvent(events.billLandedCost.onDeleted) @OnEvent(events.billLandedCost.onDeleted)
async revertGLEnteriesOnceLandedCostDeleted({ async revertGLEntriesOnceLandedCostDeleted({
oldBillLandedCost, oldBillLandedCost,
trx, trx,
}: IAllocatedLandedCostDeletedPayload) { }: IAllocatedLandedCostDeletedPayload) {
// await this.billLandedCostGLEntries.revertLandedCostGLEntries( await this.landedCostGLEntries.revertLandedCostGLEntries(
// oldBillLandedCost.id, oldBillLandedCost.id,
// trx trx,
// ); );
} }
} }

View File

@@ -17,7 +17,7 @@ export class BillBranchValidateSubscriber {
* Validate branch existance on bill creating. * Validate branch existance on bill creating.
* @param {IBillCreatingPayload} payload * @param {IBillCreatingPayload} payload
*/ */
@OnEvent(events.bill.onCreating) @OnEvent(events.bill.onCreating, { suppressErrors: false })
async validateBranchExistanceOnBillCreating({ async validateBranchExistanceOnBillCreating({
billDTO, billDTO,
}: IBillCreatingPayload) { }: IBillCreatingPayload) {
@@ -30,7 +30,7 @@ export class BillBranchValidateSubscriber {
* Validate branch existance once bill editing. * Validate branch existance once bill editing.
* @param {IBillEditingPayload} payload * @param {IBillEditingPayload} payload
*/ */
@OnEvent(events.bill.onEditing) @OnEvent(events.bill.onEditing, { suppressErrors: false })
async validateBranchExistanceOnBillEditing({ billDTO }: IBillEditingPayload) { async validateBranchExistanceOnBillEditing({ billDTO }: IBillEditingPayload) {
await this.validateBranchExistance.validateTransactionBranchWhenActive( await this.validateBranchExistance.validateTransactionBranchWhenActive(
billDTO.branchId, billDTO.branchId,

View File

@@ -14,7 +14,7 @@ export class CashflowBranchDTOValidatorSubscriber {
* Validate branch existance once cashflow transaction creating. * Validate branch existance once cashflow transaction creating.
* @param {ICommandCashflowCreatingPayload} payload * @param {ICommandCashflowCreatingPayload} payload
*/ */
@OnEvent(events.cashflow.onTransactionCreating) @OnEvent(events.cashflow.onTransactionCreating, { suppressErrors: false })
async validateBranchExistanceOnCashflowTransactionCreating({ async validateBranchExistanceOnCashflowTransactionCreating({
newTransactionDTO, newTransactionDTO,
}: ICommandCashflowCreatingPayload) { }: ICommandCashflowCreatingPayload) {

View File

@@ -15,13 +15,13 @@ import {
export class ContactBranchValidateSubscriber { export class ContactBranchValidateSubscriber {
constructor( constructor(
private readonly validateBranchExistance: ValidateBranchExistance, private readonly validateBranchExistance: ValidateBranchExistance,
) { } ) {}
/** /**
* Validate branch existance on customer creating. * Validate branch existance on customer creating.
* @param {ICustomerEventCreatingPayload} payload * @param {ICustomerEventCreatingPayload} payload
*/ */
@OnEvent(events.customers.onCreating) @OnEvent(events.customers.onCreating, { suppressErrors: false })
async validateBranchExistanceOnCustomerCreating({ async validateBranchExistanceOnCustomerCreating({
customerDTO, customerDTO,
}: ICustomerEventCreatingPayload) { }: ICustomerEventCreatingPayload) {
@@ -37,7 +37,7 @@ export class ContactBranchValidateSubscriber {
* Validate branch existance once customer opening balance editing. * Validate branch existance once customer opening balance editing.
* @param {ICustomerOpeningBalanceEditingPayload} payload * @param {ICustomerOpeningBalanceEditingPayload} payload
*/ */
@OnEvent(events.customers.onOpeningBalanceChanging) @OnEvent(events.customers.onOpeningBalanceChanging, { suppressErrors: false })
async validateBranchExistanceOnCustomerOpeningBalanceEditing({ async validateBranchExistanceOnCustomerOpeningBalanceEditing({
openingBalanceEditDTO, openingBalanceEditDTO,
}: ICustomerOpeningBalanceEditingPayload) { }: ICustomerOpeningBalanceEditingPayload) {
@@ -52,7 +52,7 @@ export class ContactBranchValidateSubscriber {
* Validates the branch existance on vendor creating. * Validates the branch existance on vendor creating.
* @param {IVendorEventCreatingPayload} payload * @param {IVendorEventCreatingPayload} payload
*/ */
@OnEvent(events.vendors.onCreating) @OnEvent(events.vendors.onCreating, { suppressErrors: false })
async validateBranchExistanceonVendorCreating({ async validateBranchExistanceonVendorCreating({
vendorDTO, vendorDTO,
}: IVendorEventCreatingPayload) { }: IVendorEventCreatingPayload) {
@@ -68,7 +68,7 @@ export class ContactBranchValidateSubscriber {
* Validate branch existance once the vendor opening balance editing. * Validate branch existance once the vendor opening balance editing.
* @param {IVendorOpeningBalanceEditingPayload} payload * @param {IVendorOpeningBalanceEditingPayload} payload
*/ */
@OnEvent(events.vendors.onOpeningBalanceChanging) @OnEvent(events.vendors.onOpeningBalanceChanging, { suppressErrors: false })
async validateBranchExistanceOnVendorOpeningBalanceEditing({ async validateBranchExistanceOnVendorOpeningBalanceEditing({
openingBalanceEditDTO, openingBalanceEditDTO,
}: IVendorOpeningBalanceEditingPayload) { }: IVendorOpeningBalanceEditingPayload) {

View File

@@ -15,7 +15,7 @@ export class CreditNoteBranchValidateSubscriber {
* Validate branch existance on credit note creating. * Validate branch existance on credit note creating.
* @param {ICreditNoteCreatingPayload} payload * @param {ICreditNoteCreatingPayload} payload
*/ */
@OnEvent(events.creditNote.onCreating) @OnEvent(events.creditNote.onCreating, { suppressErrors: false })
async validateBranchExistanceOnCreditCreating({ async validateBranchExistanceOnCreditCreating({
creditNoteDTO, creditNoteDTO,
}: ICreditNoteCreatingPayload) { }: ICreditNoteCreatingPayload) {
@@ -28,7 +28,7 @@ export class CreditNoteBranchValidateSubscriber {
* Validate branch existance once credit note editing. * Validate branch existance once credit note editing.
* @param {ICreditNoteEditingPayload} payload * @param {ICreditNoteEditingPayload} payload
*/ */
@OnEvent(events.creditNote.onEditing) @OnEvent(events.creditNote.onEditing, { suppressErrors: false })
async validateBranchExistanceOnCreditEditing({ async validateBranchExistanceOnCreditEditing({
creditNoteEditDTO, creditNoteEditDTO,
}: ICreditNoteEditingPayload) { }: ICreditNoteEditingPayload) {

View File

@@ -14,7 +14,7 @@ export class CreditNoteRefundBranchValidateSubscriber {
* Validate branch existance on refund credit note creating. * Validate branch existance on refund credit note creating.
* @param {IRefundCreditNoteCreatingPayload} payload * @param {IRefundCreditNoteCreatingPayload} payload
*/ */
@OnEvent(events.creditNote.onRefundCreating) @OnEvent(events.creditNote.onRefundCreating, { suppressErrors: false })
async validateBranchExistanceOnCreditRefundCreating({ async validateBranchExistanceOnCreditRefundCreating({
newCreditNoteDTO, newCreditNoteDTO,
}: IRefundCreditNoteCreatingPayload) { }: IRefundCreditNoteCreatingPayload) {

View File

@@ -16,7 +16,7 @@ export class ExpenseBranchValidateSubscriber {
* Validate branch existance once expense transaction creating. * Validate branch existance once expense transaction creating.
* @param {IExpenseCreatingPayload} payload * @param {IExpenseCreatingPayload} payload
*/ */
@OnEvent(events.expenses.onCreating) @OnEvent(events.expenses.onCreating, { suppressErrors: false })
async validateBranchExistanceOnExpenseCreating({ async validateBranchExistanceOnExpenseCreating({
expenseDTO, expenseDTO,
}: IExpenseCreatingPayload) { }: IExpenseCreatingPayload) {
@@ -29,7 +29,7 @@ export class ExpenseBranchValidateSubscriber {
* Validate branch existance once expense transaction editing. * Validate branch existance once expense transaction editing.
* @param {IExpenseEventEditingPayload} payload * @param {IExpenseEventEditingPayload} payload
*/ */
@OnEvent(events.expenses.onEditing) @OnEvent(events.expenses.onEditing, { suppressErrors: false })
async validateBranchExistanceOnExpenseEditing({ async validateBranchExistanceOnExpenseEditing({
expenseDTO, expenseDTO,
}: IExpenseEventEditingPayload) { }: IExpenseEventEditingPayload) {

View File

@@ -14,7 +14,7 @@ export class InventoryAdjustmentBranchValidateSubscriber {
* Validate branch existance on inventory adjustment creating. * Validate branch existance on inventory adjustment creating.
* @param {IInventoryAdjustmentCreatingPayload} payload * @param {IInventoryAdjustmentCreatingPayload} payload
*/ */
@OnEvent(events.inventoryAdjustment.onQuickCreating) @OnEvent(events.inventoryAdjustment.onQuickCreating, { suppressErrors: false })
async validateBranchExistanceOnInventoryCreating({ async validateBranchExistanceOnInventoryCreating({
quickAdjustmentDTO, quickAdjustmentDTO,
}: IInventoryAdjustmentCreatingPayload) { }: IInventoryAdjustmentCreatingPayload) {

View File

@@ -17,7 +17,7 @@ export class InvoiceBranchValidateSubscriber {
* Validate branch existance on invoice creating. * Validate branch existance on invoice creating.
* @param {ISaleInvoiceCreatingPayload} payload * @param {ISaleInvoiceCreatingPayload} payload
*/ */
@OnEvent(events.saleInvoice.onCreating) @OnEvent(events.saleInvoice.onCreating, { suppressErrors: false })
async validateBranchExistanceOnInvoiceCreating({ async validateBranchExistanceOnInvoiceCreating({
saleInvoiceDTO, saleInvoiceDTO,
}: ISaleInvoiceCreatingPaylaod) { }: ISaleInvoiceCreatingPaylaod) {
@@ -30,7 +30,7 @@ export class InvoiceBranchValidateSubscriber {
* Validate branch existance once invoice editing. * Validate branch existance once invoice editing.
* @param {ISaleInvoiceEditingPayload} payload * @param {ISaleInvoiceEditingPayload} payload
*/ */
@OnEvent(events.saleInvoice.onEditing) @OnEvent(events.saleInvoice.onEditing, { suppressErrors: false })
async validateBranchExistanceOnInvoiceEditing({ async validateBranchExistanceOnInvoiceEditing({
saleInvoiceDTO, saleInvoiceDTO,
}: ISaleInvoiceEditingPayload) { }: ISaleInvoiceEditingPayload) {

View File

@@ -17,7 +17,7 @@ export class PaymentMadeBranchValidateSubscriber {
* Validate branch existance on estimate creating. * Validate branch existance on estimate creating.
* @param {ISaleEstimateCreatedPayload} payload * @param {ISaleEstimateCreatedPayload} payload
*/ */
@OnEvent(events.billPayment.onCreating) @OnEvent(events.billPayment.onCreating, { suppressErrors: false })
async validateBranchExistanceOnPaymentCreating({ async validateBranchExistanceOnPaymentCreating({
billPaymentDTO, billPaymentDTO,
}: IBillPaymentCreatingPayload) { }: IBillPaymentCreatingPayload) {
@@ -30,7 +30,7 @@ export class PaymentMadeBranchValidateSubscriber {
* Validate branch existance once estimate editing. * Validate branch existance once estimate editing.
* @param {ISaleEstimateEditingPayload} payload * @param {ISaleEstimateEditingPayload} payload
*/ */
@OnEvent(events.billPayment.onEditing) @OnEvent(events.billPayment.onEditing, { suppressErrors: false })
async validateBranchExistanceOnPaymentEditing({ async validateBranchExistanceOnPaymentEditing({
billPaymentDTO, billPaymentDTO,
}: IBillPaymentEditingPayload) { }: IBillPaymentEditingPayload) {

View File

@@ -17,7 +17,7 @@ export class PaymentReceiveBranchValidateSubscriber {
* Validate branch existance on estimate creating. * Validate branch existance on estimate creating.
* @param {IPaymentReceivedCreatingPayload} payload * @param {IPaymentReceivedCreatingPayload} payload
*/ */
@OnEvent(events.paymentReceive.onCreating) @OnEvent(events.paymentReceive.onCreating, { suppressErrors: false })
async validateBranchExistanceOnPaymentCreating({ async validateBranchExistanceOnPaymentCreating({
paymentReceiveDTO, paymentReceiveDTO,
}: IPaymentReceivedCreatingPayload) { }: IPaymentReceivedCreatingPayload) {
@@ -30,7 +30,7 @@ export class PaymentReceiveBranchValidateSubscriber {
* Validate branch existance once estimate editing. * Validate branch existance once estimate editing.
* @param {IPaymentReceivedEditingPayload} payload * @param {IPaymentReceivedEditingPayload} payload
*/ */
@OnEvent(events.paymentReceive.onEditing) @OnEvent(events.paymentReceive.onEditing, { suppressErrors: false })
async validateBranchExistanceOnPaymentEditing({ async validateBranchExistanceOnPaymentEditing({
paymentReceiveDTO, paymentReceiveDTO,
}: IPaymentReceivedEditingPayload) { }: IPaymentReceivedEditingPayload) {

View File

@@ -17,7 +17,7 @@ export class SaleEstimateBranchValidateSubscriber {
* Validate branch existance on estimate creating. * Validate branch existance on estimate creating.
* @param {ISaleEstimateCreatedPayload} payload * @param {ISaleEstimateCreatedPayload} payload
*/ */
@OnEvent(events.saleEstimate.onCreating) @OnEvent(events.saleEstimate.onCreating, { suppressErrors: false })
async validateBranchExistanceOnEstimateCreating({ async validateBranchExistanceOnEstimateCreating({
estimateDTO, estimateDTO,
}: ISaleEstimateCreatingPayload) { }: ISaleEstimateCreatingPayload) {
@@ -30,7 +30,7 @@ export class SaleEstimateBranchValidateSubscriber {
* Validate branch existance once estimate editing. * Validate branch existance once estimate editing.
* @param {ISaleEstimateEditingPayload} payload * @param {ISaleEstimateEditingPayload} payload
*/ */
@OnEvent(events.saleEstimate.onEditing) @OnEvent(events.saleEstimate.onEditing, { suppressErrors: false })
async validateBranchExistanceOnEstimateEditing({ async validateBranchExistanceOnEstimateEditing({
estimateDTO, estimateDTO,
}: ISaleEstimateEditingPayload) { }: ISaleEstimateEditingPayload) {

View File

@@ -17,7 +17,7 @@ export class SaleReceiptBranchValidateSubscriber {
* Validate branch existance on estimate creating. * Validate branch existance on estimate creating.
* @param {ISaleReceiptCreatingPayload} payload * @param {ISaleReceiptCreatingPayload} payload
*/ */
@OnEvent(events.saleReceipt.onCreating) @OnEvent(events.saleReceipt.onCreating, { suppressErrors: false })
async validateBranchExistanceOnInvoiceCreating({ async validateBranchExistanceOnInvoiceCreating({
saleReceiptDTO, saleReceiptDTO,
}: ISaleReceiptCreatingPayload) { }: ISaleReceiptCreatingPayload) {
@@ -30,7 +30,7 @@ export class SaleReceiptBranchValidateSubscriber {
* Validate branch existance once estimate editing. * Validate branch existance once estimate editing.
* @param {ISaleReceiptEditingPayload} payload * @param {ISaleReceiptEditingPayload} payload
*/ */
@OnEvent(events.saleReceipt.onEditing) @OnEvent(events.saleReceipt.onEditing, { suppressErrors: false })
async validateBranchExistanceOnInvoiceEditing({ async validateBranchExistanceOnInvoiceEditing({
saleReceiptDTO, saleReceiptDTO,
}: ISaleReceiptEditingPayload) { }: ISaleReceiptEditingPayload) {

View File

@@ -17,7 +17,7 @@ export class VendorCreditBranchValidateSubscriber {
* Validate branch existance on estimate creating. * Validate branch existance on estimate creating.
* @param {ISaleEstimateCreatedPayload} payload * @param {ISaleEstimateCreatedPayload} payload
*/ */
@OnEvent(events.vendorCredit.onCreating) @OnEvent(events.vendorCredit.onCreating, { suppressErrors: false })
async validateBranchExistanceOnCreditCreating({ async validateBranchExistanceOnCreditCreating({
vendorCreditCreateDTO, vendorCreditCreateDTO,
}: IVendorCreditCreatingPayload) { }: IVendorCreditCreatingPayload) {
@@ -30,7 +30,7 @@ export class VendorCreditBranchValidateSubscriber {
* Validate branch existance once estimate editing. * Validate branch existance once estimate editing.
* @param {ISaleEstimateEditingPayload} payload * @param {ISaleEstimateEditingPayload} payload
*/ */
@OnEvent(events.vendorCredit.onEditing) @OnEvent(events.vendorCredit.onEditing, { suppressErrors: false })
async validateBranchExistanceOnCreditEditing({ async validateBranchExistanceOnCreditEditing({
vendorCreditDTO, vendorCreditDTO,
}: IVendorCreditEditingPayload) { }: IVendorCreditEditingPayload) {

View File

@@ -14,7 +14,7 @@ export class VendorCreditRefundBranchValidateSubscriber {
* Validate branch existance on refund credit note creating. * Validate branch existance on refund credit note creating.
* @param {IRefundVendorCreditCreatingPayload} payload * @param {IRefundVendorCreditCreatingPayload} payload
*/ */
@OnEvent(events.vendorCredit.onRefundCreating) @OnEvent(events.vendorCredit.onRefundCreating, { suppressErrors: false })
async validateBranchExistanceOnCreditRefundCreating({ async validateBranchExistanceOnCreditRefundCreating({
refundVendorCreditDTO, refundVendorCreditDTO,
}: IRefundVendorCreditCreatingPayload) { }: IRefundVendorCreditCreatingPayload) {

View File

@@ -1,117 +1,103 @@
// import { Service, Inject } from 'typedi'; import { Injectable } from '@nestjs/common';
// import { AccountNormal, ICustomer, ILedgerEntry } from '@/interfaces'; import { AccountNormal } from '@/interfaces/Account';
// import Ledger from '@/services/Accounting/Ledger'; import { ILedgerEntry } from '@/modules/Ledger/types/Ledger.types';
import { Ledger } from '@/modules/Ledger/Ledger';
import { Customer } from './models/Customer';
// @Service() @Injectable()
// export class CustomerGLEntries { export class CustomerGLEntries {
// /** /**
// * Retrieves the customer opening balance common entry attributes. * Retrieves the customer opening balance common entry attributes.
// * @param {ICustomer} customer */
// */ private getCustomerOpeningGLCommonEntry = (customer: Customer) => {
// private getCustomerOpeningGLCommonEntry = (customer: ICustomer) => { return {
// return { exchangeRate: customer.openingBalanceExchangeRate,
// exchangeRate: customer.openingBalanceExchangeRate, currencyCode: customer.currencyCode,
// currencyCode: customer.currencyCode,
// transactionType: 'CustomerOpeningBalance', transactionType: 'CustomerOpeningBalance',
// transactionId: customer.id, transactionId: customer.id,
// date: customer.openingBalanceAt, date: customer.openingBalanceAt,
// userId: customer.userId, contactId: customer.id,
// contactId: customer.id,
// credit: 0, credit: 0,
// debit: 0, debit: 0,
// branchId: customer.openingBalanceBranchId, branchId: customer.openingBalanceBranchId,
// }; };
// }; };
// /** /**
// * Retrieves the customer opening GL credit entry. * Retrieves the customer opening GL credit entry.
// * @param {number} ARAccountId */
// * @param {ICustomer} customer private getCustomerOpeningGLCreditEntry = (
// * @returns {ILedgerEntry} ARAccountId: number,
// */ customer: Customer
// private getCustomerOpeningGLCreditEntry = ( ): ILedgerEntry => {
// ARAccountId: number, const commonEntry = this.getCustomerOpeningGLCommonEntry(customer);
// customer: ICustomer
// ): ILedgerEntry => {
// const commonEntry = this.getCustomerOpeningGLCommonEntry(customer);
// return { return {
// ...commonEntry, ...commonEntry,
// credit: 0, credit: 0,
// debit: customer.localOpeningBalance, debit: customer.localOpeningBalance,
// accountId: ARAccountId, accountId: ARAccountId,
// accountNormal: AccountNormal.DEBIT, accountNormal: AccountNormal.DEBIT,
// index: 1, index: 1,
// }; };
// }; };
// /** /**
// * Retrieves the customer opening GL debit entry. * Retrieves the customer opening GL debit entry.
// * @param {number} incomeAccountId */
// * @param {ICustomer} customer private getCustomerOpeningGLDebitEntry = (
// * @returns {ILedgerEntry} incomeAccountId: number,
// */ customer: Customer
// private getCustomerOpeningGLDebitEntry = ( ): ILedgerEntry => {
// incomeAccountId: number, const commonEntry = this.getCustomerOpeningGLCommonEntry(customer);
// customer: ICustomer
// ): ILedgerEntry => {
// const commonEntry = this.getCustomerOpeningGLCommonEntry(customer);
// return { return {
// ...commonEntry, ...commonEntry,
// credit: customer.localOpeningBalance, credit: customer.localOpeningBalance,
// debit: 0, debit: 0,
// accountId: incomeAccountId, accountId: incomeAccountId,
// accountNormal: AccountNormal.CREDIT, accountNormal: AccountNormal.CREDIT,
// index: 2, index: 2,
// }; };
// }; };
// /** /**
// * Retrieves the customer opening GL entries. * Retrieves the customer opening GL entries.
// * @param {number} ARAccountId */
// * @param {number} incomeAccountId public getCustomerOpeningGLEntries = (
// * @param {ICustomer} customer ARAccountId: number,
// * @returns {ILedgerEntry[]} incomeAccountId: number,
// */ customer: Customer
// public getCustomerOpeningGLEntries = ( ) => {
// ARAccountId: number, const debitEntry = this.getCustomerOpeningGLDebitEntry(
// incomeAccountId: number, incomeAccountId,
// customer: ICustomer customer
// ) => { );
// const debitEntry = this.getCustomerOpeningGLDebitEntry( const creditEntry = this.getCustomerOpeningGLCreditEntry(
// incomeAccountId, ARAccountId,
// customer customer
// ); );
// const creditEntry = this.getCustomerOpeningGLCreditEntry( return [debitEntry, creditEntry];
// ARAccountId, };
// customer
// );
// return [debitEntry, creditEntry];
// };
// /** /**
// * Retrieves the customer opening balance ledger. * Retrieves the customer opening balance ledger.
// * @param {number} ARAccountId */
// * @param {number} incomeAccountId public getCustomerOpeningLedger = (
// * @param {ICustomer} customer ARAccountId: number,
// * @returns {ILedger} incomeAccountId: number,
// */ customer: Customer
// public getCustomerOpeningLedger = ( ) => {
// ARAccountId: number, const entries = this.getCustomerOpeningGLEntries(
// incomeAccountId: number, ARAccountId,
// customer: ICustomer incomeAccountId,
// ) => { customer
// const entries = this.getCustomerOpeningGLEntries( );
// ARAccountId, return new Ledger(entries);
// incomeAccountId, };
// customer }
// );
// return new Ledger(entries);
// };
// }

View File

@@ -1,90 +1,84 @@
// import { Knex } from 'knex'; import { Knex } from 'knex';
// import LedgerStorageService from '@/services/Accounting/LedgerStorageService'; import { Inject, Injectable } from '@nestjs/common';
// import HasTenancyService from '@/services/Tenancy/TenancyService'; import { LedgerStorageService } from '@/modules/Ledger/LedgerStorage.service';
// import { Service, Inject } from 'typedi'; import { AccountRepository } from '@/modules/Accounts/repositories/Account.repository';
// import { CustomerGLEntries } from './CustomerGLEntries'; import { CustomerGLEntries } from './CustomerGLEntries';
import { Customer } from './models/Customer';
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
import { Account } from '../Accounts/models/Account.model';
// @Service() @Injectable()
// export class CustomerGLEntriesStorage { export class CustomerGLEntriesStorage {
// @Inject() constructor(
// private tenancy: HasTenancyService; private readonly ledgerStorage: LedgerStorageService,
private readonly accountRepository: AccountRepository,
private readonly customerGLEntries: CustomerGLEntries,
// @Inject() @Inject(Account.name)
// private ledegrRepository: LedgerStorageService; private readonly accountModel: TenantModelProxy<typeof Account>,
// @Inject() @Inject(Customer.name)
// private customerGLEntries: CustomerGLEntries; private readonly customerModel: TenantModelProxy<typeof Customer>,
) { }
// /** /**
// * Customer opening balance journals. * Customer opening balance journals.
// * @param {number} tenantId */
// * @param {number} customerId public writeCustomerOpeningBalance = async (
// * @param {Knex.Transaction} trx customerId: number,
// */ trx?: Knex.Transaction,
// public writeCustomerOpeningBalance = async ( ) => {
// tenantId: number, const customer = await this.customerModel()
// customerId: number, .query(trx)
// trx?: Knex.Transaction .findById(customerId);
// ) => {
// const { Customer } = this.tenancy.models(tenantId);
// const { accountRepository } = this.tenancy.repositories(tenantId);
// const customer = await Customer.query(trx).findById(customerId); // Finds the income account.
const incomeAccount = await this.accountModel()
.query(trx)
.findOne({ slug: 'other-income' });
// // Finds the income account. // Find or create the A/R account.
// const incomeAccount = await accountRepository.findOne({ const ARAccount =
// slug: 'other-income', await this.accountRepository.findOrCreateAccountReceivable(
// }); customer.currencyCode,
// // Find or create the A/R account. {},
// const ARAccount = await accountRepository.findOrCreateAccountReceivable( trx,
// customer.currencyCode, );
// {}, // Retrieves the customer opening balance ledger.
// trx const ledger = this.customerGLEntries.getCustomerOpeningLedger(
// ); ARAccount.id,
// // Retrieves the customer opening balance ledger. incomeAccount.id,
// const ledger = this.customerGLEntries.getCustomerOpeningLedger( customer,
// ARAccount.id, );
// incomeAccount.id, // Commits the ledger entries to the storage.
// customer await this.ledgerStorage.commit(ledger, trx);
// ); };
// // Commits the ledger entries to the storage.
// await this.ledegrRepository.commit(tenantId, ledger, trx);
// };
// /** /**
// * Reverts the customer opening balance GL entries. * Reverts the customer opening balance GL entries.
// * @param {number} tenantId */
// * @param {number} customerId public revertCustomerOpeningBalance = async (
// * @param {Knex.Transaction} trx customerId: number,
// */ trx?: Knex.Transaction,
// public revertCustomerOpeningBalance = async ( ) => {
// tenantId: number, await this.ledgerStorage.deleteByReference(
// customerId: number, customerId,
// trx?: Knex.Transaction 'CustomerOpeningBalance',
// ) => { trx,
// await this.ledegrRepository.deleteByReference( );
// tenantId, };
// customerId,
// 'CustomerOpeningBalance',
// trx
// );
// };
// /** /**
// * Writes the customer opening balance GL entries. * Writes the customer opening balance GL entries.
// * @param {number} tenantId */
// * @param {number} customerId public rewriteCustomerOpeningBalance = async (
// * @param {Knex.Transaction} trx customerId: number,
// */ trx?: Knex.Transaction,
// public rewriteCustomerOpeningBalance = async ( ) => {
// tenantId: number, // Reverts the customer opening balance entries.
// customerId: number, await this.revertCustomerOpeningBalance(customerId, trx);
// trx?: Knex.Transaction
// ) => {
// // Reverts the customer opening balance entries.
// await this.revertCustomerOpeningBalance(tenantId, customerId, trx);
// // Write the customer opening balance entries. // Write the customer opening balance entries.
// await this.writeCustomerOpeningBalance(tenantId, customerId, trx); await this.writeCustomerOpeningBalance(customerId, trx);
// }; };
// } }

View File

@@ -9,10 +9,7 @@ import {
Query, Query,
} from '@nestjs/common'; } from '@nestjs/common';
import { CustomersApplication } from './CustomersApplication.service'; import { CustomersApplication } from './CustomersApplication.service';
import { import { CustomerOpeningBalanceEditDto } from './dtos/CustomerOpeningBalanceEdit.dto';
ICustomerOpeningBalanceEditDTO,
ICustomersFilter,
} from './types/Customers.types';
import { import {
ApiOperation, ApiOperation,
ApiResponse, ApiResponse,
@@ -106,7 +103,7 @@ export class CustomersController {
}) })
editOpeningBalance( editOpeningBalance(
@Param('id') customerId: number, @Param('id') customerId: number,
@Body() openingBalanceDTO: ICustomerOpeningBalanceEditDTO, @Body() openingBalanceDTO: CustomerOpeningBalanceEditDto,
) { ) {
return this.customersApplication.editOpeningBalance( return this.customersApplication.editOpeningBalance(
customerId, customerId,

View File

@@ -18,9 +18,19 @@ import { GetCustomers } from './queries/GetCustomers.service';
import { DynamicListModule } from '../DynamicListing/DynamicList.module'; import { DynamicListModule } from '../DynamicListing/DynamicList.module';
import { BulkDeleteCustomersService } from './BulkDeleteCustomers.service'; import { BulkDeleteCustomersService } from './BulkDeleteCustomers.service';
import { ValidateBulkDeleteCustomersService } from './ValidateBulkDeleteCustomers.service'; import { ValidateBulkDeleteCustomersService } from './ValidateBulkDeleteCustomers.service';
import { LedgerModule } from '../Ledger/Ledger.module';
import { AccountsModule } from '../Accounts/Accounts.module';
import { CustomerGLEntries } from './CustomerGLEntries';
import { CustomerGLEntriesStorage } from './CustomerGLEntriesStorage';
import { CustomerWriteGLOpeningBalanceSubscriber } from './subscribers/CustomerGLEntriesSubscriber';
@Module({ @Module({
imports: [TenancyDatabaseModule, DynamicListModule], imports: [
TenancyDatabaseModule,
DynamicListModule,
LedgerModule,
AccountsModule,
],
controllers: [CustomersController], controllers: [CustomersController],
providers: [ providers: [
ActivateCustomer, ActivateCustomer,
@@ -41,6 +51,9 @@ import { ValidateBulkDeleteCustomersService } from './ValidateBulkDeleteCustomer
GetCustomers, GetCustomers,
BulkDeleteCustomersService, BulkDeleteCustomersService,
ValidateBulkDeleteCustomersService, ValidateBulkDeleteCustomersService,
CustomerGLEntries,
CustomerGLEntriesStorage,
CustomerWriteGLOpeningBalanceSubscriber,
], ],
}) })
export class CustomersModule {} export class CustomersModule {}

View File

@@ -4,10 +4,7 @@ import { CreateCustomer } from './commands/CreateCustomer.service';
import { EditCustomer } from './commands/EditCustomer.service'; import { EditCustomer } from './commands/EditCustomer.service';
import { DeleteCustomer } from './commands/DeleteCustomer.service'; import { DeleteCustomer } from './commands/DeleteCustomer.service';
import { EditOpeningBalanceCustomer } from './commands/EditOpeningBalanceCustomer.service'; import { EditOpeningBalanceCustomer } from './commands/EditOpeningBalanceCustomer.service';
import { import { CustomerOpeningBalanceEditDto } from './dtos/CustomerOpeningBalanceEdit.dto';
ICustomerOpeningBalanceEditDTO,
ICustomersFilter,
} from './types/Customers.types';
import { CreateCustomerDto } from './dtos/CreateCustomer.dto'; import { CreateCustomerDto } from './dtos/CreateCustomer.dto';
import { EditCustomerDto } from './dtos/EditCustomer.dto'; import { EditCustomerDto } from './dtos/EditCustomer.dto';
import { GetCustomers } from './queries/GetCustomers.service'; import { GetCustomers } from './queries/GetCustomers.service';
@@ -18,12 +15,12 @@ import { ValidateBulkDeleteCustomersService } from './ValidateBulkDeleteCustomer
@Injectable() @Injectable()
export class CustomersApplication { export class CustomersApplication {
constructor( constructor(
private getCustomerService: GetCustomerService, private readonly getCustomerService: GetCustomerService,
private createCustomerService: CreateCustomer, private readonly createCustomerService: CreateCustomer,
private editCustomerService: EditCustomer, private readonly editCustomerService: EditCustomer,
private deleteCustomerService: DeleteCustomer, private readonly deleteCustomerService: DeleteCustomer,
private editOpeningBalanceService: EditOpeningBalanceCustomer, private readonly editOpeningBalanceService: EditOpeningBalanceCustomer,
private getCustomersService: GetCustomers, private readonly getCustomersService: GetCustomers,
private readonly bulkDeleteCustomersService: BulkDeleteCustomersService, private readonly bulkDeleteCustomersService: BulkDeleteCustomersService,
private readonly validateBulkDeleteCustomersService: ValidateBulkDeleteCustomersService, private readonly validateBulkDeleteCustomersService: ValidateBulkDeleteCustomersService,
) {} ) {}
@@ -72,7 +69,7 @@ export class CustomersApplication {
*/ */
public editOpeningBalance = ( public editOpeningBalance = (
customerId: number, customerId: number,
openingBalanceEditDTO: ICustomerOpeningBalanceEditDTO, openingBalanceEditDTO: CustomerOpeningBalanceEditDto,
) => { ) => {
return this.editOpeningBalanceService.changeOpeningBalance( return this.editOpeningBalanceService.changeOpeningBalance(
customerId, customerId,
@@ -82,7 +79,7 @@ export class CustomersApplication {
/** /**
* Retrieve customers paginated list. * Retrieve customers paginated list.
* @param {ICustomersFilter} filter - Cusotmers filter. * @param {GetCustomersQueryDto} filter - Cusotmers filter.
*/ */
public getCustomers = (filterDTO: GetCustomersQueryDto) => { public getCustomers = (filterDTO: GetCustomersQueryDto) => {
return this.getCustomersService.getCustomersList(filterDTO); return this.getCustomersService.getCustomersList(filterDTO);

View File

@@ -31,7 +31,7 @@ export class CreateCustomer {
/** /**
* Creates a new customer. * Creates a new customer.
* @param {ICustomerNewDTO} customerDTO * @param {CreateCustomerDto} customerDTO
* @return {Promise<ICustomer>} * @return {Promise<ICustomer>}
*/ */
public async createCustomer( public async createCustomer(

View File

@@ -1,10 +1,10 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Knex } from 'knex'; import { Knex } from 'knex';
import { import {
ICustomerOpeningBalanceEditDTO,
ICustomerOpeningBalanceEditedPayload, ICustomerOpeningBalanceEditedPayload,
ICustomerOpeningBalanceEditingPayload, ICustomerOpeningBalanceEditingPayload,
} from '../types/Customers.types'; } from '../types/Customers.types';
import { CustomerOpeningBalanceEditDto } from '../dtos/CustomerOpeningBalanceEdit.dto';
import { EventEmitter2 } from '@nestjs/event-emitter'; import { EventEmitter2 } from '@nestjs/event-emitter';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { Customer } from '../models/Customer'; import { Customer } from '../models/Customer';
@@ -29,11 +29,11 @@ export class EditOpeningBalanceCustomer {
/** /**
* Changes the opening balance of the given customer. * Changes the opening balance of the given customer.
* @param {number} customerId - Customer ID. * @param {number} customerId - Customer ID.
* @param {ICustomerOpeningBalanceEditDTO} openingBalanceEditDTO * @param {CustomerOpeningBalanceEditDto} openingBalanceEditDTO
*/ */
public async changeOpeningBalance( public async changeOpeningBalance(
customerId: number, customerId: number,
openingBalanceEditDTO: ICustomerOpeningBalanceEditDTO, openingBalanceEditDTO: CustomerOpeningBalanceEditDto,
): Promise<Customer> { ): Promise<Customer> {
// Retrieves the old customer or throw not found error. // Retrieves the old customer or throw not found error.
const oldCustomer = await this.customerModel() const oldCustomer = await this.customerModel()

View File

@@ -4,6 +4,7 @@ import {
IsNotEmpty, IsNotEmpty,
IsNumber, IsNumber,
IsString, IsString,
ValidateIf,
} from 'class-validator'; } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { IsOptional, ToNumber } from '@/common/decorators/Validators'; import { IsOptional, ToNumber } from '@/common/decorators/Validators';
@@ -40,10 +41,11 @@ export class CreateCustomerDto extends ContactAddressDto {
@ApiProperty({ @ApiProperty({
required: false, required: false,
description: 'Opening balance date', description: 'Opening balance date (required when openingBalance is provided)',
example: '2024-01-01', example: '2024-01-01',
}) })
@IsOptional() @ValidateIf((o) => o.openingBalance != null)
@IsNotEmpty({ message: 'openingBalanceAt is required when openingBalance is provided' })
@IsString() @IsString()
openingBalanceAt?: string; openingBalanceAt?: string;

View File

@@ -0,0 +1,44 @@
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { IsOptional, ToNumber } from '@/common/decorators/Validators';
export class CustomerOpeningBalanceEditDto {
@ApiProperty({
required: true,
description: 'Opening balance',
example: 5000.0,
})
@IsNumber()
@IsNotEmpty()
@ToNumber()
openingBalance: number;
@ApiProperty({
required: false,
description: 'Opening balance date',
example: '2024-01-01',
})
@IsOptional()
@IsString()
openingBalanceAt?: string;
@ApiProperty({
required: false,
description: 'Opening balance exchange rate',
example: 1.0,
})
@IsOptional()
@IsNumber()
@ToNumber()
openingBalanceExchangeRate?: number;
@ApiProperty({
required: false,
description: 'Opening balance branch ID',
example: 101,
})
@IsOptional()
@IsNumber()
@ToNumber()
openingBalanceBranchId?: number;
}

View File

@@ -1,91 +1,63 @@
// import { Service, Inject } from 'typedi'; import { Injectable } from '@nestjs/common';
// import { import { OnEvent } from '@nestjs/event-emitter';
// ICustomerEventCreatedPayload, import {
// ICustomerEventDeletedPayload, ICustomerEventCreatedPayload,
// ICustomerOpeningBalanceEditedPayload, ICustomerEventDeletedPayload,
// } from '@/interfaces'; ICustomerOpeningBalanceEditedPayload,
// import events from '@/subscribers/events'; } from '../types/Customers.types';
// import { CustomerGLEntriesStorage } from '../CustomerGLEntriesStorage'; import { events } from '@/common/events/events';
import { CustomerGLEntriesStorage } from '../CustomerGLEntriesStorage';
// @Service() @Injectable()
// export class CustomerWriteGLOpeningBalanceSubscriber { export class CustomerWriteGLOpeningBalanceSubscriber {
// @Inject() constructor(private readonly customerGLEntries: CustomerGLEntriesStorage) { }
// private customerGLEntries: CustomerGLEntriesStorage;
// /** /**
// * Attaches events with handlers. * Handles the writing opening balance journal entries once the customer created.
// */ */
// public attach(bus) { @OnEvent(events.customers.onCreated)
// bus.subscribe( public async handleWriteOpenBalanceEntries({
// events.customers.onCreated, customer,
// this.handleWriteOpenBalanceEntries trx,
// ); }: ICustomerEventCreatedPayload) {
// bus.subscribe( // Writes the customer opening balance journal entries.
// events.customers.onDeleted, if (customer.openingBalance) {
// this.handleRevertOpeningBalanceEntries await this.customerGLEntries.writeCustomerOpeningBalance(
// ); customer.id,
// bus.subscribe( trx,
// events.customers.onOpeningBalanceChanged, );
// this.handleRewriteOpeningEntriesOnChanged }
// ); }
// }
// /** /**
// * Handles the writing opening balance journal entries once the customer created. * Handles the deleting opening balance journal entries once the customer deleted.
// * @param {ICustomerEventCreatedPayload} payload - */
// */ @OnEvent(events.customers.onDeleted)
// private handleWriteOpenBalanceEntries = async ({ public async handleRevertOpeningBalanceEntries({
// tenantId, customerId,
// customer, trx,
// trx, }: ICustomerEventDeletedPayload) {
// }: ICustomerEventCreatedPayload) => { await this.customerGLEntries.revertCustomerOpeningBalance(customerId, trx);
// // Writes the customer opening balance journal entries. }
// if (customer.openingBalance) {
// await this.customerGLEntries.writeCustomerOpeningBalance(
// tenantId,
// customer.id,
// trx
// );
// }
// };
// /** /**
// * Handles the deleting opeing balance journal entrise once the customer deleted. * Handles the rewrite opening balance entries once opening balance changed.
// * @param {ICustomerEventDeletedPayload} payload - */
// */ @OnEvent(events.customers.onOpeningBalanceChanged)
// private handleRevertOpeningBalanceEntries = async ({ public async handleRewriteOpeningEntriesOnChanged({
// tenantId, customer,
// customerId, trx,
// trx, }: ICustomerOpeningBalanceEditedPayload) {
// }: ICustomerEventDeletedPayload) => { if (customer.openingBalance) {
// await this.customerGLEntries.revertCustomerOpeningBalance( await this.customerGLEntries.rewriteCustomerOpeningBalance(
// tenantId, customer.id,
// customerId, trx,
// trx );
// ); } else {
// }; await this.customerGLEntries.revertCustomerOpeningBalance(
customer.id,
// /** trx,
// * Handles the rewrite opening balance entries once opening balnace changed. );
// * @param {ICustomerOpeningBalanceEditedPayload} payload - }
// */ }
// private handleRewriteOpeningEntriesOnChanged = async ({ }
// tenantId,
// customer,
// trx,
// }: ICustomerOpeningBalanceEditedPayload) => {
// if (customer.openingBalance) {
// await this.customerGLEntries.rewriteCustomerOpeningBalance(
// tenantId,
// customer.id,
// trx
// );
// } else {
// await this.customerGLEntries.revertCustomerOpeningBalance(
// tenantId,
// customer.id,
// trx
// );
// }
// };
// }

View File

@@ -4,6 +4,7 @@ import { IContactAddressDTO } from '@/modules/Contacts/types/Contacts.types';
import { IDynamicListFilter } from '@/modules/DynamicListing/DynamicFilter/DynamicFilter.types'; import { IDynamicListFilter } from '@/modules/DynamicListing/DynamicFilter/DynamicFilter.types';
import { IFilterMeta, IPaginationMeta } from '@/interfaces/Model'; import { IFilterMeta, IPaginationMeta } from '@/interfaces/Model';
import { CreateCustomerDto } from '../dtos/CreateCustomer.dto'; import { CreateCustomerDto } from '../dtos/CreateCustomer.dto';
import { CustomerOpeningBalanceEditDto } from '../dtos/CustomerOpeningBalanceEdit.dto';
import { EditCustomerDto } from '../dtos/EditCustomer.dto'; import { EditCustomerDto } from '../dtos/EditCustomer.dto';
// Customer Interfaces. // Customer Interfaces.
@@ -113,23 +114,16 @@ export enum VendorAction {
View = 'View', View = 'View',
} }
export interface ICustomerOpeningBalanceEditDTO {
openingBalance: number;
openingBalanceAt: Date | string;
openingBalanceExchangeRate: number;
openingBalanceBranchId?: number;
}
export interface ICustomerOpeningBalanceEditingPayload { export interface ICustomerOpeningBalanceEditingPayload {
oldCustomer: Customer; oldCustomer: Customer;
openingBalanceEditDTO: ICustomerOpeningBalanceEditDTO; openingBalanceEditDTO: CustomerOpeningBalanceEditDto;
trx?: Knex.Transaction; trx?: Knex.Transaction;
} }
export interface ICustomerOpeningBalanceEditedPayload { export interface ICustomerOpeningBalanceEditedPayload {
customer: Customer; customer: Customer;
oldCustomer: Customer; oldCustomer: Customer;
openingBalanceEditDTO: ICustomerOpeningBalanceEditDTO; openingBalanceEditDTO: CustomerOpeningBalanceEditDto;
trx: Knex.Transaction; trx: Knex.Transaction;
} }

View File

@@ -4,14 +4,15 @@ import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
import { TableSheetPdf } from './TableSheetPdf'; import { TableSheetPdf } from './TableSheetPdf';
import { TemplateInjectableModule } from '@/modules/TemplateInjectable/TemplateInjectable.module'; import { TemplateInjectableModule } from '@/modules/TemplateInjectable/TemplateInjectable.module';
import { ChromiumlyTenancyModule } from '@/modules/ChromiumlyTenancy/ChromiumlyTenancy.module'; import { ChromiumlyTenancyModule } from '@/modules/ChromiumlyTenancy/ChromiumlyTenancy.module';
import { InventoryCostModule } from '@/modules/InventoryCost/InventoryCost.module';
@Module({ @Module({
imports: [TemplateInjectableModule, ChromiumlyTenancyModule], imports: [
providers: [ TemplateInjectableModule,
FinancialSheetMeta, ChromiumlyTenancyModule,
TenancyContext, InventoryCostModule,
TableSheetPdf,
], ],
providers: [FinancialSheetMeta, TenancyContext, TableSheetPdf],
exports: [FinancialSheetMeta, TableSheetPdf], exports: [FinancialSheetMeta, TableSheetPdf],
}) })
export class FinancialSheetCommonModule {} export class FinancialSheetCommonModule {}

View File

@@ -1,10 +1,14 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { IFinancialSheetCommonMeta } from '../types/Report.types'; import { IFinancialSheetCommonMeta } from '../types/Report.types';
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service'; import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
import { InventoryComputeCostService } from '@/modules/InventoryCost/commands/InventoryComputeCost.service';
@Injectable() @Injectable()
export class FinancialSheetMeta { export class FinancialSheetMeta {
constructor(private readonly tenancyContext: TenancyContext) {} constructor(
private readonly tenancyContext: TenancyContext,
private readonly inventoryComputeCostService: InventoryComputeCostService,
) {}
/** /**
* Retrieves the common meta data of the financial sheet. * Retrieves the common meta data of the financial sheet.
@@ -17,10 +21,8 @@ export class FinancialSheetMeta {
const baseCurrency = tenantMetadata.baseCurrency; const baseCurrency = tenantMetadata.baseCurrency;
const dateFormat = tenantMetadata.dateFormat; const dateFormat = tenantMetadata.dateFormat;
// const isCostComputeRunning = const isCostComputeRunning =
// this.inventoryService.isItemsCostComputeRunning(); await this.inventoryComputeCostService.isItemsCostComputeRunning();
const isCostComputeRunning = false;
return { return {
organizationName, organizationName,

View File

@@ -68,6 +68,12 @@ export class ComputeItemCostProcessor extends WorkerHost {
} catch (error) { } catch (error) {
console.error(`[error] Error computing item cost for item ${itemId}:`, error); console.error(`[error] Error computing item cost for item ${itemId}:`, error);
console.error('Error stack:', error instanceof Error ? error.stack : 'No stack trace'); console.error('Error stack:', error instanceof Error ? error.stack : 'No stack trace');
// Reset cost_compute_running when job fails so it does not stay true indefinitely
try {
await this.inventoryComputeCostService.markItemsCostComputeRunning(false);
} catch (markError) {
console.error('[error] Failed to mark cost compute as not running:', markError);
}
throw error; throw error;
} }
} }

View File

@@ -114,7 +114,6 @@ export class SaleInvoicesCost {
*/ */
scheduleWriteJournalEntries(startingDate?: Date) { scheduleWriteJournalEntries(startingDate?: Date) {
// const agenda = Container.get('agenda'); // const agenda = Container.get('agenda');
// return agenda.schedule('in 3 seconds', 'rewrite-invoices-journal-entries', { // return agenda.schedule('in 3 seconds', 'rewrite-invoices-journal-entries', {
// startingDate, // startingDate,
// tenantId, // tenantId,
@@ -123,12 +122,11 @@ export class SaleInvoicesCost {
/** /**
* Writes cost GL entries from the inventory cost lots. * Writes cost GL entries from the inventory cost lots.
* @param {number} tenantId - * @param {Date} startingDate - Starting date.
* @param {Date} startingDate -
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
public writeCostLotsGLEntries = (startingDate: Date) => { public writeCostLotsGLEntries = async (startingDate: Date) => {
return this.uow.withTransaction(async (trx: Knex.Transaction) => { await this.uow.withTransaction(async (trx: Knex.Transaction) => {
// Triggers event `onInventoryCostLotsGLEntriesBeforeWrite`. // Triggers event `onInventoryCostLotsGLEntriesBeforeWrite`.
await this.eventPublisher.emitAsync( await this.eventPublisher.emitAsync(
events.inventory.onCostLotsGLEntriesBeforeWrite, events.inventory.onCostLotsGLEntriesBeforeWrite,
@@ -146,5 +144,10 @@ export class SaleInvoicesCost {
} as IInventoryCostLotsGLEntriesWriteEvent, } as IInventoryCostLotsGLEntriesWriteEvent,
); );
}); });
// Signal that cost entries have been written so cost_compute_running can be set to false.
await this.eventPublisher.emitAsync(
events.inventory.onInventoryCostEntriesWritten,
{},
);
}; };
} }

View File

@@ -1,115 +1,116 @@
// import { Service } from 'typedi'; import { Injectable } from '@nestjs/common';
// import { IVendor, AccountNormal, ILedgerEntry } from '@/interfaces'; import { AccountNormal } from '@/interfaces/Account';
// import Ledger from '@/services/Accounting/Ledger'; import { ILedgerEntry } from '@/modules/Ledger/types/Ledger.types';
import { Ledger } from '@/modules/Ledger/Ledger';
import { Vendor } from './models/Vendor';
// @Service() @Injectable()
// export class VendorGLEntries { export class VendorGLEntries {
// /** /**
// * Retrieves the opening balance GL common entry. * Retrieves the opening balance GL common entry.
// * @param {IVendor} vendor - * @param {Vendor} vendor -
// */ */
// private getOpeningBalanceGLCommonEntry = (vendor: IVendor) => { private getOpeningBalanceGLCommonEntry = (vendor: Vendor) => {
// return { return {
// exchangeRate: vendor.openingBalanceExchangeRate, exchangeRate: vendor.openingBalanceExchangeRate,
// currencyCode: vendor.currencyCode, currencyCode: vendor.currencyCode,
// transactionType: 'VendorOpeningBalance', transactionType: 'VendorOpeningBalance',
// transactionId: vendor.id, transactionId: vendor.id,
// date: vendor.openingBalanceAt, date: vendor.openingBalanceAt,
// userId: vendor.userId, contactId: vendor.id,
// contactId: vendor.id,
// credit: 0, credit: 0,
// debit: 0, debit: 0,
// branchId: vendor.openingBalanceBranchId, branchId: vendor.openingBalanceBranchId,
// }; };
// }; };
// /** /**
// * Retrieves the opening balance GL debit entry. * Retrieves the opening balance GL debit entry.
// * @param {number} costAccountId - * @param {number} costAccountId -
// * @param {IVendor} vendor * @param {Vendor} vendor
// * @returns {ILedgerEntry} * @returns {ILedgerEntry}
// */ */
// private getOpeningBalanceGLDebitEntry = ( private getOpeningBalanceGLDebitEntry = (
// costAccountId: number, costAccountId: number,
// vendor: IVendor vendor: Vendor
// ): ILedgerEntry => { ): ILedgerEntry => {
// const commonEntry = this.getOpeningBalanceGLCommonEntry(vendor); const commonEntry = this.getOpeningBalanceGLCommonEntry(vendor);
// return { return {
// ...commonEntry, ...commonEntry,
// accountId: costAccountId, accountId: costAccountId,
// accountNormal: AccountNormal.DEBIT, accountNormal: AccountNormal.DEBIT,
// debit: vendor.localOpeningBalance, debit: vendor.localOpeningBalance,
// credit: 0, credit: 0,
// index: 2, index: 2,
// }; };
// }; };
// /** /**
// * Retrieves the opening balance GL credit entry. * Retrieves the opening balance GL credit entry.
// * @param {number} APAccountId * @param {number} APAccountId
// * @param {IVendor} vendor * @param {Vendor} vendor
// * @returns {ILedgerEntry} * @returns {ILedgerEntry}
// */ */
// private getOpeningBalanceGLCreditEntry = ( private getOpeningBalanceGLCreditEntry = (
// APAccountId: number, APAccountId: number,
// vendor: IVendor vendor: Vendor
// ): ILedgerEntry => { ): ILedgerEntry => {
// const commonEntry = this.getOpeningBalanceGLCommonEntry(vendor); const commonEntry = this.getOpeningBalanceGLCommonEntry(vendor);
// return { return {
// ...commonEntry, ...commonEntry,
// accountId: APAccountId, accountId: APAccountId,
// accountNormal: AccountNormal.CREDIT, accountNormal: AccountNormal.CREDIT,
// credit: vendor.localOpeningBalance, credit: vendor.localOpeningBalance,
// index: 1, index: 1,
// }; };
// }; };
// /** /**
// * Retrieves the opening balance GL entries. * Retrieves the opening balance GL entries.
// * @param {number} APAccountId * @param {number} APAccountId
// * @param {number} costAccountId - * @param {number} costAccountId -
// * @param {IVendor} vendor * @param {Vendor} vendor
// * @returns {ILedgerEntry[]} * @returns {ILedgerEntry[]}
// */ */
// public getOpeningBalanceGLEntries = ( public getOpeningBalanceGLEntries = (
// APAccountId: number, APAccountId: number,
// costAccountId: number, costAccountId: number,
// vendor: IVendor vendor: Vendor
// ): ILedgerEntry[] => { ): ILedgerEntry[] => {
// const debitEntry = this.getOpeningBalanceGLDebitEntry( const debitEntry = this.getOpeningBalanceGLDebitEntry(
// costAccountId, costAccountId,
// vendor vendor
// ); );
// const creditEntry = this.getOpeningBalanceGLCreditEntry( const creditEntry = this.getOpeningBalanceGLCreditEntry(
// APAccountId, APAccountId,
// vendor vendor
// ); );
// return [debitEntry, creditEntry]; return [debitEntry, creditEntry];
// }; };
// /** /**
// * Retrieves the opening balance ledger. * Retrieves the opening balance ledger.
// * @param {number} APAccountId * @param {number} APAccountId
// * @param {number} costAccountId - * @param {number} costAccountId -
// * @param {IVendor} vendor * @param {Vendor} vendor
// * @returns {Ledger} * @returns {Ledger}
// */ */
// public getOpeningBalanceLedger = ( public getOpeningBalanceLedger = (
// APAccountId: number, APAccountId: number,
// costAccountId: number, costAccountId: number,
// vendor: IVendor vendor: Vendor
// ) => { ) => {
// const entries = this.getOpeningBalanceGLEntries( const entries = this.getOpeningBalanceGLEntries(
// APAccountId, APAccountId,
// costAccountId, costAccountId,
// vendor vendor
// ); );
// return new Ledger(entries); return new Ledger(entries);
// }; };
// } }

View File

@@ -1,88 +1,86 @@
// import { Knex } from 'knex'; import { Knex } from 'knex';
// import { Service, Inject } from 'typedi'; import { Inject, Injectable } from '@nestjs/common';
// import LedgerStorageService from '@/services/Accounting/LedgerStorageService'; import { LedgerStorageService } from '@/modules/Ledger/LedgerStorage.service';
// import HasTenancyService from '@/services/Tenancy/TenancyService'; import { AccountRepository } from '@/modules/Accounts/repositories/Account.repository';
// import { VendorGLEntries } from './VendorGLEntries'; import { VendorGLEntries } from './VendorGLEntries';
import { Vendor } from './models/Vendor';
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
// @Service() @Injectable()
// export class VendorGLEntriesStorage { export class VendorGLEntriesStorage {
// @Inject() constructor(
// private tenancy: HasTenancyService; private readonly ledgerStorage: LedgerStorageService,
private readonly accountRepository: AccountRepository,
private readonly vendorGLEntries: VendorGLEntries,
// @Inject() @Inject(Vendor.name)
// private ledegrRepository: LedgerStorageService; private readonly vendorModel: TenantModelProxy<typeof Vendor>,
) { }
// @Inject() /**
// private vendorGLEntries: VendorGLEntries; * Vendor opening balance journals.
* @param {number} vendorId
* @param {Knex.Transaction} trx
*/
public writeVendorOpeningBalance = async (
vendorId: number,
trx?: Knex.Transaction,
) => {
const vendor = await this.vendorModel()
.query(trx)
.findById(vendorId);
// /** // Finds the expense account.
// * Vendor opening balance journals. const expenseAccount = await this.accountRepository.findOrCreateOtherExpensesAccount(
// * @param {number} tenantId {},
// * @param {number} vendorId trx,
// * @param {Knex.Transaction} trx );
// */ // Find or create the A/P account.
// public writeVendorOpeningBalance = async ( const APAccount =
// tenantId: number, await this.accountRepository.findOrCreateAccountsPayable(
// vendorId: number, vendor.currencyCode,
// trx?: Knex.Transaction {},
// ) => { trx,
// const { Vendor } = this.tenancy.models(tenantId); );
// const { accountRepository } = this.tenancy.repositories(tenantId); // Retrieves the vendor opening balance ledger.
const ledger = this.vendorGLEntries.getOpeningBalanceLedger(
APAccount.id,
expenseAccount.id,
vendor,
);
// Commits the ledger entries to the storage.
await this.ledgerStorage.commit(ledger, trx);
};
// const vendor = await Vendor.query(trx).findById(vendorId); /**
* Reverts the vendor opening balance GL entries.
* @param {number} vendorId
* @param {Knex.Transaction} trx
*/
public revertVendorOpeningBalance = async (
vendorId: number,
trx?: Knex.Transaction,
) => {
await this.ledgerStorage.deleteByReference(
vendorId,
'VendorOpeningBalance',
trx,
);
};
// // Finds the expense account. /**
// const expenseAccount = await accountRepository.findOne({ * Writes the vendor opening balance GL entries.
// slug: 'other-expenses', * @param {number} vendorId
// }); * @param {Knex.Transaction} trx
// // Find or create the A/P account. */
// const APAccount = await accountRepository.findOrCreateAccountsPayable( public rewriteVendorOpeningBalance = async (
// vendor.currencyCode, vendorId: number,
// {}, trx?: Knex.Transaction,
// trx ) => {
// ); // Reverts the vendor opening balance entries first.
// // Retrieves the vendor opening balance ledger. await this.revertVendorOpeningBalance(vendorId, trx);
// const ledger = this.vendorGLEntries.getOpeningBalanceLedger(
// APAccount.id,
// expenseAccount.id,
// vendor
// );
// // Commits the ledger entries to the storage.
// await this.ledegrRepository.commit(tenantId, ledger, trx);
// };
// /** // Write the vendor opening balance entries.
// * Reverts the vendor opening balance GL entries. await this.writeVendorOpeningBalance(vendorId, trx);
// * @param {number} tenantId };
// * @param {number} vendorId }
// * @param {Knex.Transaction} trx
// */
// public revertVendorOpeningBalance = async (
// tenantId: number,
// vendorId: number,
// trx?: Knex.Transaction
// ) => {
// await this.ledegrRepository.deleteByReference(
// tenantId,
// vendorId,
// 'VendorOpeningBalance',
// trx
// );
// };
// /**
// * Writes the vendor opening balance GL entries.
// * @param {number} tenantId
// * @param {number} vendorId
// * @param {Knex.Transaction} trx
// */
// public rewriteVendorOpeningBalance = async (
// tenantId: number,
// vendorId: number,
// trx?: Knex.Transaction
// ) => {
// await this.writeVendorOpeningBalance(tenantId, vendorId, trx);
// await this.revertVendorOpeningBalance(tenantId, vendorId, trx);
// };
// }

View File

@@ -9,10 +9,7 @@ import {
Query, Query,
} from '@nestjs/common'; } from '@nestjs/common';
import { VendorsApplication } from './VendorsApplication.service'; import { VendorsApplication } from './VendorsApplication.service';
import { import { VendorOpeningBalanceEditDto } from './dtos/VendorOpeningBalanceEdit.dto';
IVendorOpeningBalanceEditDTO,
IVendorsFilter,
} from './types/Vendors.types';
import { import {
ApiOperation, ApiOperation,
ApiResponse, ApiResponse,
@@ -68,7 +65,7 @@ export class VendorsController {
@ApiOperation({ summary: 'Edit the given vendor opening balance.' }) @ApiOperation({ summary: 'Edit the given vendor opening balance.' })
editOpeningBalance( editOpeningBalance(
@Param('id') vendorId: number, @Param('id') vendorId: number,
@Body() openingBalanceDTO: IVendorOpeningBalanceEditDTO, @Body() openingBalanceDTO: VendorOpeningBalanceEditDto,
) { ) {
return this.vendorsApplication.editOpeningBalance( return this.vendorsApplication.editOpeningBalance(
vendorId, vendorId,

View File

@@ -18,9 +18,14 @@ import { VendorsExportable } from './VendorsExportable';
import { VendorsImportable } from './VendorsImportable'; import { VendorsImportable } from './VendorsImportable';
import { BulkDeleteVendorsService } from './BulkDeleteVendors.service'; import { BulkDeleteVendorsService } from './BulkDeleteVendors.service';
import { ValidateBulkDeleteVendorsService } from './ValidateBulkDeleteVendors.service'; import { ValidateBulkDeleteVendorsService } from './ValidateBulkDeleteVendors.service';
import { LedgerModule } from '../Ledger/Ledger.module';
import { AccountsModule } from '../Accounts/Accounts.module';
import { VendorGLEntries } from './VendorGLEntries';
import { VendorGLEntriesStorage } from './VendorGLEntriesStorage';
import { VendorsWriteGLOpeningSubscriber } from './subscribers/VendorGLEntriesSubscriber';
@Module({ @Module({
imports: [TenancyDatabaseModule, DynamicListModule], imports: [TenancyDatabaseModule, DynamicListModule, LedgerModule, AccountsModule],
controllers: [VendorsController], controllers: [VendorsController],
providers: [ providers: [
ActivateVendorService, ActivateVendorService,
@@ -38,7 +43,10 @@ import { ValidateBulkDeleteVendorsService } from './ValidateBulkDeleteVendors.se
TransformerInjectable, TransformerInjectable,
TenancyContext, TenancyContext,
VendorsExportable, VendorsExportable,
VendorsImportable VendorsImportable,
VendorGLEntries,
VendorGLEntriesStorage,
VendorsWriteGLOpeningSubscriber,
], ],
}) })
export class VendorsModule {} export class VendorsModule { }

View File

@@ -5,10 +5,7 @@ import { EditVendorService } from './commands/EditVendor.service';
import { DeleteVendorService } from './commands/DeleteVendor.service'; import { DeleteVendorService } from './commands/DeleteVendor.service';
import { EditOpeningBalanceVendorService } from './commands/EditOpeningBalanceVendor.service'; import { EditOpeningBalanceVendorService } from './commands/EditOpeningBalanceVendor.service';
import { GetVendorService } from './queries/GetVendor'; import { GetVendorService } from './queries/GetVendor';
import { import { VendorOpeningBalanceEditDto } from './dtos/VendorOpeningBalanceEdit.dto';
IVendorOpeningBalanceEditDTO,
IVendorsFilter,
} from './types/Vendors.types';
import { GetVendorsService } from './queries/GetVendors.service'; import { GetVendorsService } from './queries/GetVendors.service';
import { CreateVendorDto } from './dtos/CreateVendor.dto'; import { CreateVendorDto } from './dtos/CreateVendor.dto';
import { EditVendorDto } from './dtos/EditVendor.dto'; import { EditVendorDto } from './dtos/EditVendor.dto';
@@ -58,14 +55,14 @@ export class VendorsApplication {
} }
/** /**
* Changes the opening balance of the given customer. * Changes the opening balance of the given vendor.
* @param {number} vendorId * @param {number} vendorId
* @param {IVendorOpeningBalanceEditDTO} openingBalanceEditDTO * @param {VendorOpeningBalanceEditDto} openingBalanceEditDTO
* @returns {Promise<IVendor>} * @returns {Promise<IVendor>}
*/ */
public editOpeningBalance( public editOpeningBalance(
vendorId: number, vendorId: number,
openingBalanceEditDTO: IVendorOpeningBalanceEditDTO, openingBalanceEditDTO: VendorOpeningBalanceEditDto,
) { ) {
return this.editOpeningBalanceService.editOpeningBalance( return this.editOpeningBalanceService.editOpeningBalance(
vendorId, vendorId,
@@ -95,10 +92,7 @@ export class VendorsApplication {
vendorIds: number[], vendorIds: number[],
options?: { skipUndeletable?: boolean }, options?: { skipUndeletable?: boolean },
) { ) {
return this.bulkDeleteVendorsService.bulkDeleteVendors( return this.bulkDeleteVendorsService.bulkDeleteVendors(vendorIds, options);
vendorIds,
options,
);
} }
public validateBulkDeleteVendors(vendorIds: number[]) { public validateBulkDeleteVendors(vendorIds: number[]) {

View File

@@ -2,10 +2,10 @@ import { Knex } from 'knex';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter'; import { EventEmitter2 } from '@nestjs/event-emitter';
import { import {
IVendorOpeningBalanceEditDTO,
IVendorOpeningBalanceEditedPayload, IVendorOpeningBalanceEditedPayload,
IVendorOpeningBalanceEditingPayload, IVendorOpeningBalanceEditingPayload,
} from '../types/Vendors.types'; } from '../types/Vendors.types';
import { VendorOpeningBalanceEditDto } from '../dtos/VendorOpeningBalanceEdit.dto';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service'; import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { Vendor } from '../models/Vendor'; import { Vendor } from '../models/Vendor';
import { events } from '@/common/events/events'; import { events } from '@/common/events/events';
@@ -29,12 +29,12 @@ export class EditOpeningBalanceVendorService {
/** /**
* Changes the opening balance of the given customer. * Changes the opening balance of the given customer.
* @param {number} vendorId * @param {number} vendorId
* @param {IVendorOpeningBalanceEditDTO} openingBalanceEditDTO * @param {VendorOpeningBalanceEditDto} openingBalanceEditDTO
* @returns {Promise<IVendor>} * @returns {Promise<IVendor>}
*/ */
public async editOpeningBalance( public async editOpeningBalance(
vendorId: number, vendorId: number,
openingBalanceEditDTO: IVendorOpeningBalanceEditDTO, openingBalanceEditDTO: VendorOpeningBalanceEditDto,
) { ) {
// Retrieves the old vendor or throw not found error. // Retrieves the old vendor or throw not found error.
const oldVendor = await this.vendorModel() const oldVendor = await this.vendorModel()

View File

@@ -2,11 +2,13 @@ import { ApiProperty } from '@nestjs/swagger';
import { import {
IsISO8601, IsISO8601,
IsInt, IsInt,
IsNotEmpty,
IsNumber, IsNumber,
Min, Min,
IsBoolean, IsBoolean,
IsEmail, IsEmail,
IsString, IsString,
ValidateIf,
} from 'class-validator'; } from 'class-validator';
import { ContactAddressDto } from '@/modules/Customers/dtos/ContactAddress.dto'; import { ContactAddressDto } from '@/modules/Customers/dtos/ContactAddress.dto';
import { IsOptional, ToNumber } from '@/common/decorators/Validators'; import { IsOptional, ToNumber } from '@/common/decorators/Validators';
@@ -30,8 +32,12 @@ export class CreateVendorDto extends ContactAddressDto {
@ToNumber() @ToNumber()
openingBalanceExchangeRate?: number; openingBalanceExchangeRate?: number;
@ApiProperty({ required: false, description: 'Date of the opening balance' }) @ApiProperty({
@IsOptional() required: false,
description: 'Date of the opening balance (required when openingBalance is provided)',
})
@ValidateIf((o) => o.openingBalance != null)
@IsNotEmpty({ message: 'openingBalanceAt is required when openingBalance is provided' })
@IsISO8601() @IsISO8601()
openingBalanceAt?: Date; openingBalanceAt?: Date;

View File

@@ -0,0 +1,44 @@
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { IsOptional, ToNumber } from '@/common/decorators/Validators';
export class VendorOpeningBalanceEditDto {
@ApiProperty({
required: true,
description: 'Opening balance',
example: 5000.0,
})
@IsNumber()
@IsNotEmpty()
@ToNumber()
openingBalance: number;
@ApiProperty({
required: false,
description: 'Opening balance date',
example: '2024-01-01',
})
@IsOptional()
@IsString()
openingBalanceAt?: string;
@ApiProperty({
required: false,
description: 'Opening balance exchange rate',
example: 1.0,
})
@IsOptional()
@IsNumber()
@ToNumber()
openingBalanceExchangeRate?: number;
@ApiProperty({
required: false,
description: 'Opening balance branch ID',
example: 101,
})
@IsOptional()
@IsNumber()
@ToNumber()
openingBalanceBranchId?: number;
}

View File

@@ -36,6 +36,7 @@ export class Vendor extends TenantBaseModel {
openingBalance: number; openingBalance: number;
openingBalanceExchangeRate: number; openingBalanceExchangeRate: number;
openingBalanceAt: Date | string; openingBalanceAt: Date | string;
openingBalanceBranchId?: number;
salutation: string; salutation: string;
firstName: string; firstName: string;

View File

@@ -1,91 +1,71 @@
// import { Inject, Service } from 'typedi'; import { Injectable } from '@nestjs/common';
// import events from '@/subscribers/events'; import { OnEvent } from '@nestjs/event-emitter';
// import { VendorGLEntriesStorage } from '../VendorGLEntriesStorage'; import { events } from '@/common/events/events';
// import { import { VendorGLEntriesStorage } from '../VendorGLEntriesStorage';
// IVendorEventCreatedPayload, import {
// IVendorEventDeletedPayload, IVendorEventCreatedPayload,
// IVendorOpeningBalanceEditedPayload, IVendorEventDeletedPayload,
// } from '@/interfaces'; IVendorOpeningBalanceEditedPayload,
} from '../types/Vendors.types';
// @Service() @Injectable()
// export class VendorsWriteGLOpeningSubscriber { export class VendorsWriteGLOpeningSubscriber {
// @Inject() constructor(
// private vendorGLEntriesStorage: VendorGLEntriesStorage; private readonly vendorGLEntriesStorage: VendorGLEntriesStorage,
) {}
// /** /**
// * Constructor method. * Writes the open balance journal entries once the vendor created.
// */ * @param {IVendorEventCreatedPayload} payload -
// public attach(bus) { */
// bus.subscribe( @OnEvent(events.vendors.onCreated)
// events.vendors.onCreated, public async handleWriteOpeningBalanceEntries({
// this.handleWriteOpeningBalanceEntries vendor,
// ); trx,
// bus.subscribe( }: IVendorEventCreatedPayload) {
// events.vendors.onDeleted, // Writes the vendor opening balance journal entries.
// this.handleRevertOpeningBalanceEntries if (vendor.openingBalance) {
// ); await this.vendorGLEntriesStorage.writeVendorOpeningBalance(
// bus.subscribe( vendor.id,
// events.vendors.onOpeningBalanceChanged, trx,
// this.handleRewriteOpeningEntriesOnChanged );
// ); }
// } }
// /** /**
// * Writes the open balance journal entries once the vendor created. * Revert the opening balance journal entries once the vendor deleted.
// * @param {IVendorEventCreatedPayload} payload - * @param {IVendorEventDeletedPayload} payload -
// */ */
// private handleWriteOpeningBalanceEntries = async ({ @OnEvent(events.vendors.onDeleted)
// tenantId, public async handleRevertOpeningBalanceEntries({
// vendor, vendorId,
// trx, trx,
// }: IVendorEventCreatedPayload) => { }: IVendorEventDeletedPayload) {
// // Writes the vendor opening balance journal entries. await this.vendorGLEntriesStorage.revertVendorOpeningBalance(
// if (vendor.openingBalance) { vendorId,
// await this.vendorGLEntriesStorage.writeVendorOpeningBalance( trx,
// tenantId, );
// vendor.id, }
// trx
// );
// }
// };
// /** /**
// * Revert the opening balance journal entries once the vendor deleted. * Handles the rewrite opening balance entries once opening balance changed.
// * @param {IVendorEventDeletedPayload} payload - * @param {IVendorOpeningBalanceEditedPayload} payload -
// */ */
// private handleRevertOpeningBalanceEntries = async ({ @OnEvent(events.vendors.onOpeningBalanceChanged)
// tenantId, public async handleRewriteOpeningEntriesOnChanged({
// vendorId, vendor,
// trx, trx,
// }: IVendorEventDeletedPayload) => { }: IVendorOpeningBalanceEditedPayload) {
// await this.vendorGLEntriesStorage.revertVendorOpeningBalance( if (vendor.openingBalance) {
// tenantId, await this.vendorGLEntriesStorage.rewriteVendorOpeningBalance(
// vendorId, vendor.id,
// trx trx,
// ); );
// }; } else {
await this.vendorGLEntriesStorage.revertVendorOpeningBalance(
// /** vendor.id,
// * Handles the rewrite opening balance entries once opening balnace changed. trx,
// * @param {ICustomerOpeningBalanceEditedPayload} payload - );
// */ }
// private handleRewriteOpeningEntriesOnChanged = async ({ }
// tenantId, }
// vendor,
// trx,
// }: IVendorOpeningBalanceEditedPayload) => {
// if (vendor.openingBalance) {
// await this.vendorGLEntriesStorage.rewriteVendorOpeningBalance(
// tenantId,
// vendor.id,
// trx
// );
// } else {
// await this.vendorGLEntriesStorage.revertVendorOpeningBalance(
// tenantId,
// vendor.id,
// trx
// );
// }
// };
// }

View File

@@ -7,6 +7,7 @@ import { IDynamicListFilter } from '@/modules/DynamicListing/DynamicFilter/Dynam
import { IFilterMeta, IPaginationMeta } from '@/interfaces/Model'; import { IFilterMeta, IPaginationMeta } from '@/interfaces/Model';
import { CreateVendorDto } from '../dtos/CreateVendor.dto'; import { CreateVendorDto } from '../dtos/CreateVendor.dto';
import { EditVendorDto } from '../dtos/EditVendor.dto'; import { EditVendorDto } from '../dtos/EditVendor.dto';
import { VendorOpeningBalanceEditDto } from '../dtos/VendorOpeningBalanceEdit.dto';
// ---------------------------------- // ----------------------------------
export interface IVendorNewDTO extends IContactAddressDTO { export interface IVendorNewDTO extends IContactAddressDTO {
@@ -92,23 +93,16 @@ export interface IVendorEventEditedPayload {
trx?: Knex.Transaction; trx?: Knex.Transaction;
} }
export interface IVendorOpeningBalanceEditDTO {
openingBalance: number;
openingBalanceAt: Date | string;
openingBalanceExchangeRate: number;
openingBalanceBranchId?: number;
}
export interface IVendorOpeningBalanceEditingPayload { export interface IVendorOpeningBalanceEditingPayload {
oldVendor: Vendor; oldVendor: Vendor;
openingBalanceEditDTO: IVendorOpeningBalanceEditDTO; openingBalanceEditDTO: VendorOpeningBalanceEditDto;
trx?: Knex.Transaction; trx?: Knex.Transaction;
} }
export interface IVendorOpeningBalanceEditedPayload { export interface IVendorOpeningBalanceEditedPayload {
vendor: Vendor; vendor: Vendor;
oldVendor: Vendor; oldVendor: Vendor;
openingBalanceEditDTO: IVendorOpeningBalanceEditDTO; openingBalanceEditDTO: VendorOpeningBalanceEditDto;
trx: Knex.Transaction; trx: Knex.Transaction;
} }

View File

@@ -18,12 +18,21 @@ export default function FinancialReportPage(props) {
} }
export const FinancialComputeAlert = styled.div` export const FinancialComputeAlert = styled.div`
--x-background-color: #fdecda;
--x-text-color: #342515;
--x-button-text-color: #824400;
.bp4-dark & {
--x-background-color: rgba(200, 118, 25, 0.2);
--x-text-color: rgba(255, 255, 255, 0.8);
--x-button-text-color: rgba(255, 255, 255, 0.8);
}
position: relative; position: relative;
padding: 8px 20px; padding: 8px 20px;
border-radius: 2px; border-radius: 2px;
color: #342515; background-color: var(--x-background-color);
color: var(--x-text-color);
font-size: 13px; font-size: 13px;
background-color: var(--color-financial-report-background);
button { button {
font-size: 12px; font-size: 12px;
@@ -32,7 +41,7 @@ export const FinancialComputeAlert = styled.div`
&, &,
&:hover { &:hover {
color: #824400; color: var(--x-button-text-color);
text-decoration: underline; text-decoration: underline;
} }
} }
@@ -40,7 +49,7 @@ export const FinancialComputeAlert = styled.div`
margin-right: 6px; margin-right: 6px;
position: relative; position: relative;
top: -2px; top: -2px;
fill: #975f19; fill: var(--x-text-color);
} }
`; `;