fix(server): shouldn't write GL entries when save transaction as draft.

This commit is contained in:
Ahmed Bouhuolia
2023-08-16 23:05:39 +02:00
parent 01f7effc71
commit 5b2be2ac19
16 changed files with 122 additions and 18 deletions

View File

@@ -99,7 +99,7 @@ export interface IBillCreatedPayload {
trx: Knex.Transaction; trx: Knex.Transaction;
} }
export interface IBillCreatingPayload{ export interface IBillCreatingPayload {
tenantId: number; tenantId: number;
billDTO: IBillDTO; billDTO: IBillDTO;
trx: Knex.Transaction; trx: Knex.Transaction;
@@ -138,3 +138,16 @@ export enum BillAction {
View = 'View', View = 'View',
NotifyBySms = 'NotifyBySms', NotifyBySms = 'NotifyBySms',
} }
export interface IBillOpeningPayload {
trx: Knex.Transaction;
tenantId: number;
oldBill: IBill;
}
export interface IBillOpenedPayload {
trx: Knex.Transaction;
bill: IBill;
oldBill: IBill;
tenantId: number;
}

View File

@@ -1,6 +1,5 @@
import { ISystemUser } from '@/interfaces';
import { Knex } from 'knex'; import { Knex } from 'knex';
import { pick } from 'lodash'; import { ISystemUser } from '@/interfaces';
import { ILedgerEntry } from './Ledger'; import { ILedgerEntry } from './Ledger';
import { ISaleInvoice } from './SaleInvoice'; import { ISaleInvoice } from './SaleInvoice';

View File

@@ -156,6 +156,7 @@ export interface ISaleInvoiceEventDeliveredPayload {
tenantId: number; tenantId: number;
saleInvoiceId: number; saleInvoiceId: number;
saleInvoice: ISaleInvoice; saleInvoice: ISaleInvoice;
trx: Knex.Transaction;
} }
export interface ISaleInvoiceDeliveringPayload { export interface ISaleInvoiceDeliveringPayload {

View File

@@ -20,6 +20,10 @@ export class BillGLEntriesSubscriber {
events.bill.onCreated, events.bill.onCreated,
this.handlerWriteJournalEntriesOnCreate this.handlerWriteJournalEntriesOnCreate
); );
bus.subscribe(
events.bill.onOpened,
this.handlerWriteJournalEntriesOnCreate
);
bus.subscribe( bus.subscribe(
events.bill.onEdited, events.bill.onEdited,
this.handleOverwriteJournalEntriesOnEdit this.handleOverwriteJournalEntriesOnEdit
@@ -34,8 +38,11 @@ export class BillGLEntriesSubscriber {
private handlerWriteJournalEntriesOnCreate = async ({ private handlerWriteJournalEntriesOnCreate = async ({
tenantId, tenantId,
billId, billId,
bill,
trx, trx,
}: IBillCreatedPayload) => { }: IBillCreatedPayload) => {
if (!bill.openedAt) return null;
await this.billGLEntries.writeBillGLEntries(tenantId, billId, trx); await this.billGLEntries.writeBillGLEntries(tenantId, billId, trx);
}; };
@@ -46,8 +53,11 @@ export class BillGLEntriesSubscriber {
private handleOverwriteJournalEntriesOnEdit = async ({ private handleOverwriteJournalEntriesOnEdit = async ({
tenantId, tenantId,
billId, billId,
bill,
trx, trx,
}: IBillEditedPayload) => { }: IBillEditedPayload) => {
if (!bill.openedAt) return null;
await this.billGLEntries.rewriteBillGLEntries(tenantId, billId, trx); await this.billGLEntries.rewriteBillGLEntries(tenantId, billId, trx);
}; };

View File

@@ -132,7 +132,7 @@ export class EditBill {
} as IBillEditingPayload); } as IBillEditingPayload);
// Update the bill transaction. // Update the bill transaction.
const bill = await Bill.query(trx).upsertGraph({ const bill = await Bill.query(trx).upsertGraphAndFetch({
id: billId, id: billId,
...billObj, ...billObj,
}); });

View File

@@ -5,6 +5,9 @@ import { ERRORS } from './constants';
import HasTenancyService from '@/services/Tenancy/TenancyService'; import HasTenancyService from '@/services/Tenancy/TenancyService';
import UnitOfWork from '@/services/UnitOfWork'; import UnitOfWork from '@/services/UnitOfWork';
import { BillsValidators } from './BillsValidators'; import { BillsValidators } from './BillsValidators';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import events from '@/subscribers/events';
import { IBillOpenedPayload, IBillOpeningPayload } from '@/interfaces';
@Service() @Service()
export class OpenBill { export class OpenBill {
@@ -17,6 +20,9 @@ export class OpenBill {
@Inject() @Inject()
private validators: BillsValidators; private validators: BillsValidators;
@Inject()
private eventPublisher: EventPublisher;
/** /**
* Mark the bill as open. * Mark the bill as open.
* @param {number} tenantId * @param {number} tenantId
@@ -37,10 +43,24 @@ export class OpenBill {
throw new ServiceError(ERRORS.BILL_ALREADY_OPEN); throw new ServiceError(ERRORS.BILL_ALREADY_OPEN);
} }
return this.uow.withTransaction(tenantId, async (trx) => { return this.uow.withTransaction(tenantId, async (trx) => {
// Triggers `onBillCreating` event.
await this.eventPublisher.emitAsync(events.bill.onOpening, {
trx,
tenantId,
oldBill,
} as IBillOpeningPayload);
// Record the bill opened at on the storage. // Record the bill opened at on the storage.
await Bill.query(trx).findById(billId).patch({ const bill = await Bill.query(trx).patchAndFetchById(billId, {
openedAt: moment().toMySqlDateTime(), openedAt: moment().toMySqlDateTime(),
}); });
// Triggers `onBillCreating` event.
await this.eventPublisher.emitAsync(events.bill.onOpened, {
trx,
bill,
oldBill,
tenantId,
} as IBillOpenedPayload);
}); });
} }
} }

View File

@@ -63,14 +63,17 @@ export class DeliverSaleInvoice {
// Record the delivered at on the storage. // Record the delivered at on the storage.
const saleInvoice = await SaleInvoice.query(trx) const saleInvoice = await SaleInvoice.query(trx)
.where({ id: saleInvoiceId }) .patchAndFetchById(saleInvoiceId, {
.update({ deliveredAt: moment().toMySqlDateTime() }); deliveredAt: moment().toMySqlDateTime(),
})
.withGraphFetched('entries');
// Triggers `onSaleInvoiceDelivered` event. // Triggers `onSaleInvoiceDelivered` event.
await this.eventPublisher.emitAsync(events.saleInvoice.onDelivered, { await this.eventPublisher.emitAsync(events.saleInvoice.onDelivered, {
tenantId, tenantId,
saleInvoiceId, saleInvoiceId,
saleInvoice, saleInvoice,
trx,
} as ISaleInvoiceEventDeliveredPayload); } as ISaleInvoiceEventDeliveredPayload);
}); });
} }

View File

@@ -58,12 +58,12 @@ export class CloseSaleReceipt {
} as ISaleReceiptEventClosingPayload); } as ISaleReceiptEventClosingPayload);
// Mark the sale receipt as closed on the storage. // Mark the sale receipt as closed on the storage.
const saleReceipt = await SaleReceipt.query(trx) const saleReceipt = await SaleReceipt.query(trx).patchAndFetchById(
.findById(saleReceiptId) saleReceiptId,
.patch({ {
closedAt: moment().toMySqlDateTime(), closedAt: moment().toMySqlDateTime(),
}); }
);
// Triggers `onSaleReceiptClosed` event. // Triggers `onSaleReceiptClosed` event.
await this.eventPublisher.emitAsync(events.saleReceipt.onClosed, { await this.eventPublisher.emitAsync(events.saleReceipt.onClosed, {
saleReceiptId, saleReceiptId,

View File

@@ -36,8 +36,12 @@ export default class BillWriteInventoryTransactionsSubscriber {
private handleWritingInventoryTransactions = async ({ private handleWritingInventoryTransactions = async ({
tenantId, tenantId,
billId, billId,
bill,
trx, trx,
}: IBillCreatedPayload) => { }: IBillCreatedPayload) => {
// Can't continue if the bill is not opened yet.
if (!bill.openedAt) return null;
await this.billsInventory.recordInventoryTransactions( await this.billsInventory.recordInventoryTransactions(
tenantId, tenantId,
billId, billId,
@@ -52,8 +56,12 @@ export default class BillWriteInventoryTransactionsSubscriber {
private handleOverwritingInventoryTransactions = async ({ private handleOverwritingInventoryTransactions = async ({
tenantId, tenantId,
billId, billId,
bill,
trx, trx,
}: IBillEditedPayload) => { }: IBillEditedPayload) => {
// Can't continue if the bill is not opened yet.
if (!bill.openedAt) return null;
await this.billsInventory.recordInventoryTransactions( await this.billsInventory.recordInventoryTransactions(
tenantId, tenantId,
billId, billId,

View File

@@ -38,8 +38,12 @@ export default class BillWriteGLEntriesSubscriber {
private handlerWriteJournalEntriesOnCreate = async ({ private handlerWriteJournalEntriesOnCreate = async ({
tenantId, tenantId,
billId, billId,
bill,
trx, trx,
}: IBillCreatedPayload) => { }: IBillCreatedPayload) => {
// Can't continue if the bill is not opened yet.
if (!bill.openedAt) return null;
await this.billsService.recordJournalTransactions( await this.billsService.recordJournalTransactions(
tenantId, tenantId,
billId, billId,
@@ -55,8 +59,12 @@ export default class BillWriteGLEntriesSubscriber {
private handleOverwriteJournalEntriesOnEdit = async ({ private handleOverwriteJournalEntriesOnEdit = async ({
tenantId, tenantId,
billId, billId,
bill,
trx, trx,
}: IBillEditedPayload) => { }: IBillEditedPayload) => {
// Can't continue if the bill is not opened yet.
if (!bill.openedAt) return null;
await this.billsService.recordJournalTransactions( await this.billsService.recordJournalTransactions(
tenantId, tenantId,
billId, billId,

View File

@@ -36,8 +36,10 @@ export default class PaymentReceivesWriteGLEntriesSubscriber {
private handleWriteJournalEntriesOnceCreated = async ({ private handleWriteJournalEntriesOnceCreated = async ({
tenantId, tenantId,
paymentReceiveId, paymentReceiveId,
paymentReceive,
trx, trx,
}: IPaymentReceiveCreatedPayload) => { }: IPaymentReceiveCreatedPayload) => {
if (paymentReceive)
await this.paymentReceiveGLEntries.writePaymentGLEntries( await this.paymentReceiveGLEntries.writePaymentGLEntries(
tenantId, tenantId,
paymentReceiveId, paymentReceiveId,

View File

@@ -4,6 +4,7 @@ import {
ISaleInvoiceCreatedPayload, ISaleInvoiceCreatedPayload,
ISaleInvoiceDeletedPayload, ISaleInvoiceDeletedPayload,
ISaleInvoiceEditedPayload, ISaleInvoiceEditedPayload,
ISaleInvoiceEventDeliveredPayload,
} from '@/interfaces'; } from '@/interfaces';
import { InvoiceInventoryTransactions } from '@/services/Sales/Invoices/InvoiceInventoryTransactions'; import { InvoiceInventoryTransactions } from '@/services/Sales/Invoices/InvoiceInventoryTransactions';
@@ -20,6 +21,10 @@ export default class WriteInventoryTransactions {
events.saleInvoice.onCreated, events.saleInvoice.onCreated,
this.handleWritingInventoryTransactions this.handleWritingInventoryTransactions
); );
bus.subscribe(
events.saleInvoice.onDelivered,
this.handleWritingInventoryTransactions
);
bus.subscribe( bus.subscribe(
events.saleInvoice.onEdited, events.saleInvoice.onEdited,
this.handleRewritingInventoryTransactions this.handleRewritingInventoryTransactions
@@ -38,7 +43,10 @@ export default class WriteInventoryTransactions {
tenantId, tenantId,
saleInvoice, saleInvoice,
trx, trx,
}: ISaleInvoiceCreatedPayload) => { }: ISaleInvoiceCreatedPayload | ISaleInvoiceEventDeliveredPayload) => {
// Can't continue if the sale invoice is not delivered yet.
if (!saleInvoice.deliveredAt) return null;
await this.saleInvoiceInventory.recordInventoryTranscactions( await this.saleInvoiceInventory.recordInventoryTranscactions(
tenantId, tenantId,
saleInvoice, saleInvoice,

View File

@@ -15,11 +15,15 @@ export default class SaleInvoiceWriteGLEntriesSubscriber {
/** /**
* Constructor method. * Constructor method.
*/ */
attach(bus) { public attach(bus) {
bus.subscribe( bus.subscribe(
events.saleInvoice.onCreated, events.saleInvoice.onCreated,
this.handleWriteJournalEntriesOnInvoiceCreated this.handleWriteJournalEntriesOnInvoiceCreated
); );
bus.subscribe(
events.saleInvoice.onDelivered,
this.handleWriteJournalEntriesOnInvoiceCreated
);
bus.subscribe( bus.subscribe(
events.saleInvoice.onEdited, events.saleInvoice.onEdited,
this.handleRewriteJournalEntriesOnceInvoiceEdit this.handleRewriteJournalEntriesOnceInvoiceEdit
@@ -36,8 +40,12 @@ export default class SaleInvoiceWriteGLEntriesSubscriber {
private handleWriteJournalEntriesOnInvoiceCreated = async ({ private handleWriteJournalEntriesOnInvoiceCreated = async ({
tenantId, tenantId,
saleInvoiceId, saleInvoiceId,
saleInvoice,
trx, trx,
}: ISaleInvoiceCreatedPayload) => { }: ISaleInvoiceCreatedPayload) => {
// Can't continue if the sale invoice is not delivered yet.
if (!saleInvoice.deliveredAt) return null;
await this.saleInvoiceGLEntries.writeInvoiceGLEntries( await this.saleInvoiceGLEntries.writeInvoiceGLEntries(
tenantId, tenantId,
saleInvoiceId, saleInvoiceId,
@@ -53,6 +61,9 @@ export default class SaleInvoiceWriteGLEntriesSubscriber {
saleInvoice, saleInvoice,
trx, trx,
}: ISaleInvoiceEditedPayload) => { }: ISaleInvoiceEditedPayload) => {
// Can't continue if the sale invoice is not delivered yet.
if (!saleInvoice.deliveredAt) return null;
await this.saleInvoiceGLEntries.rewritesInvoiceGLEntries( await this.saleInvoiceGLEntries.rewritesInvoiceGLEntries(
tenantId, tenantId,
saleInvoice.id, saleInvoice.id,

View File

@@ -40,6 +40,9 @@ export default class SaleReceiptInventoryTransactionsSubscriber {
saleReceipt, saleReceipt,
trx, trx,
}: ISaleReceiptCreatedPayload) => { }: ISaleReceiptCreatedPayload) => {
// Can't continue if the sale receipt is not closed yet.
if (!saleReceipt.closedAt) return null;
await this.saleReceiptInventory.recordInventoryTransactions( await this.saleReceiptInventory.recordInventoryTransactions(
tenantId, tenantId,
saleReceipt, saleReceipt,
@@ -57,6 +60,9 @@ export default class SaleReceiptInventoryTransactionsSubscriber {
saleReceipt, saleReceipt,
trx, trx,
}: ISaleReceiptEditedPayload) => { }: ISaleReceiptEditedPayload) => {
// Can't continue if the sale receipt is not closed yet.
if (!saleReceipt.closedAt) return null;
await this.saleReceiptInventory.recordInventoryTransactions( await this.saleReceiptInventory.recordInventoryTransactions(
tenantId, tenantId,
saleReceipt, saleReceipt,

View File

@@ -21,6 +21,10 @@ export default class SaleReceiptWriteGLEntriesSubscriber {
events.saleReceipt.onCreated, events.saleReceipt.onCreated,
this.handleWriteReceiptIncomeJournalEntrieOnCreate this.handleWriteReceiptIncomeJournalEntrieOnCreate
); );
bus.subscribe(
events.saleReceipt.onClosed,
this.handleWriteReceiptIncomeJournalEntrieOnCreate
);
bus.subscribe( bus.subscribe(
events.saleReceipt.onEdited, events.saleReceipt.onEdited,
this.handleWriteReceiptIncomeJournalEntrieOnEdited this.handleWriteReceiptIncomeJournalEntrieOnEdited
@@ -38,8 +42,12 @@ export default class SaleReceiptWriteGLEntriesSubscriber {
public handleWriteReceiptIncomeJournalEntrieOnCreate = async ({ public handleWriteReceiptIncomeJournalEntrieOnCreate = async ({
tenantId, tenantId,
saleReceiptId, saleReceiptId,
saleReceipt,
trx, trx,
}: ISaleReceiptCreatedPayload) => { }: ISaleReceiptCreatedPayload) => {
// Can't continue if the sale receipt is not closed yet.
if (!saleReceipt.closedAt) return null;
// Writes the sale receipt income journal entries. // Writes the sale receipt income journal entries.
await this.saleReceiptGLEntries.writeIncomeGLEntries( await this.saleReceiptGLEntries.writeIncomeGLEntries(
tenantId, tenantId,
@@ -71,8 +79,12 @@ export default class SaleReceiptWriteGLEntriesSubscriber {
private handleWriteReceiptIncomeJournalEntrieOnEdited = async ({ private handleWriteReceiptIncomeJournalEntrieOnEdited = async ({
tenantId, tenantId,
saleReceiptId, saleReceiptId,
saleReceipt,
trx, trx,
}: ISaleReceiptEditedPayload) => { }: ISaleReceiptEditedPayload) => {
// Can't continue if the sale receipt is not closed yet.
if (!saleReceipt.closedAt) return null;
// Writes the sale receipt income journal entries. // Writes the sale receipt income journal entries.
await this.saleReceiptGLEntries.rewriteReceiptGLEntries( await this.saleReceiptGLEntries.rewriteReceiptGLEntries(
tenantId, tenantId,

View File

@@ -220,6 +220,9 @@ export default {
onPublishing: 'onBillPublishing', onPublishing: 'onBillPublishing',
onPublished: 'onBillPublished', onPublished: 'onBillPublished',
onOpening: 'onBillOpening',
onOpened: 'onBillOpened',
}, },
/** /**