fix: sync inventory items quantity with services.

This commit is contained in:
a.bouhuolia
2021-02-28 14:45:13 +02:00
parent 0fd5eb34c6
commit fb9d68c2cf
9 changed files with 147 additions and 210 deletions

View File

@@ -29,4 +29,9 @@ export interface IInventoryLotCost {
transactionType: string,
transactionId: number,
entryId: number
}
};
export interface IItemsQuantityChanges {
itemId: number,
balanceChange: number,
};

View File

@@ -7,19 +7,16 @@ import 'subscribers/manualJournals';
import 'subscribers/expenses';
import 'subscribers/Bills';
import 'subscribers/Bills/SyncItemsQuantity';
import 'subscribers/Bills/SyncVendorsBalances';
import 'subscribers/Bills/WriteJournalEntries';
import 'subscribers/Bills/WriteInventoryTransactions';
import 'subscribers/SaleInvoices';
import 'subscribers/SaleInvoices/SyncCustomersBalance';
import 'subscribers/SaleInvoices/SyncItemsQuantity';
import 'subscribers/SaleInvoices/WriteInventoryTransactions';
import 'subscribers/SaleInvoices/WriteJournalEntries';
import 'subscribers/SaleReceipt';
import 'subscribers/SaleReceipt/SyncItemsQuantity';
import 'subscribers/SaleReceipt/WriteInventoryTransactions';
import 'subscribers/SaleReceipt/WriteJournalEntries';

View File

@@ -183,7 +183,7 @@ export default class InventoryAdjustmentService {
inventoryAdjustmentId: number
): Promise<void> {
// Retrieve the inventory adjustment or throw not found service error.
const adjustment = await this.getInventoryAdjustmentOrThrowError(
const oldInventoryAdjustment = await this.getInventoryAdjustmentOrThrowError(
tenantId,
inventoryAdjustmentId
);
@@ -208,6 +208,7 @@ export default class InventoryAdjustmentService {
await this.eventDispatcher.dispatch(events.inventoryAdjustment.onDeleted, {
tenantId,
inventoryAdjustmentId,
oldInventoryAdjustment
});
this.logger.info(
'[inventory_adjustment] the adjustment deleted successfully.',
@@ -317,7 +318,7 @@ export default class InventoryAdjustmentService {
});
});
// Saves the given inventory transactions to the storage.
this.inventoryService.recordInventoryTransactions(
await this.inventoryService.recordInventoryTransactions(
tenantId,
inventoryTransactions,
override

View File

@@ -0,0 +1,92 @@
import { Inject, Service } from 'typedi';
import { toSafeInteger } from 'lodash';
import { IInventoryTransaction, IItemsQuantityChanges } from 'interfaces';
import HasTenancyService from 'services/Tenancy/TenancyService';
/**
* Syncs the inventory transactions with inventory items quantity.
*/
@Service()
export default class InventoryItemsQuantitySync {
@Inject()
tenancy: HasTenancyService;
/**
* Reverse the given inventory transactions.
* @param {IInventoryTransaction[]} inventroyTransactions
* @return {IInventoryTransaction[]}
*/
reverseInventoryTransactions(
inventroyTransactions: IInventoryTransaction[]
): IInventoryTransaction[] {
return inventroyTransactions.map((transaction) => ({
...transaction,
direction: transaction.direction === 'OUT' ? 'IN' : 'OUT',
}));
}
/**
* Reverses the inventory transactions.
* @param {IInventoryTransaction[]} inventroyTransactions -
* @return {IItemsQuantityChanges[]}
*/
getReverseItemsQuantityChanges(
inventroyTransactions: IInventoryTransaction[]
): IItemsQuantityChanges[] {
const reversedTransactions = this.reverseInventoryTransactions(
inventroyTransactions
);
return this.getItemsQuantityChanges(reversedTransactions);
}
/**
* Retrieve the items quantity changes from the given inventory transactions.
* @param {IInventoryTransaction[]} inventroyTransactions - Inventory transactions.
* @return {IItemsQuantityChanges[]}
*/
getItemsQuantityChanges(
inventroyTransactions: IInventoryTransaction[]
): IItemsQuantityChanges[] {
const balanceMap: { [itemId: number]: number } = {};
inventroyTransactions.forEach(
(inventoryTransaction: IInventoryTransaction) => {
const { itemId, direction, quantity } = inventoryTransaction;
if (!balanceMap[itemId]) {
balanceMap[itemId] = 0;
}
balanceMap[itemId] += direction === 'IN' ? quantity : 0;
balanceMap[itemId] -= direction === 'OUT' ? quantity : 0;
}
);
return Object.entries(balanceMap).map(([itemId, balanceChange]) => ({
itemId: toSafeInteger(itemId),
balanceChange,
}));
}
/**
* Changes the items quantity changes.
* @param {IItemsQuantityChanges[]} itemsQuantity - Items quantity changes.
* @return {Promise<void>}
*/
async changeItemsQuantity(
tenantId: number,
itemsQuantity: IItemsQuantityChanges[]
): Promise<void> {
const { itemRepository } = this.tenancy.repositories(tenantId);
const opers = [];
itemsQuantity.forEach((itemQuantity: IItemsQuantityChanges) => {
const changeQuantityOper = itemRepository.changeNumber(
{ id: itemQuantity.itemId, type: 'inventory' },
'quantityOnHand',
itemQuantity.balanceChange
);
opers.push(changeQuantityOper);
});
await Promise.all(opers);
}
}

View File

@@ -1,59 +0,0 @@
import { Container } from 'typedi';
import { EventSubscriber, On } from 'event-dispatch';
import events from 'subscribers/events';
import TenancyService from 'services/Tenancy/TenancyService';
import ItemsEntriesService from 'services/Items/ItemsEntriesService';
@EventSubscriber()
export default class BillSubscriber {
tenancy: TenancyService;
logger: any;
itemsEntriesService: ItemsEntriesService;
/**
* Constructor method.
*/
constructor() {
this.tenancy = Container.get(TenancyService);
this.logger = Container.get('logger');
this.itemsEntriesService = Container.get(ItemsEntriesService);
}
/**
* Increments the sale invoice items once the invoice created.
*/
@On(events.bill.onCreated)
public async handleDecrementSaleInvoiceItemsQuantity({ tenantId, bill }) {
await this.itemsEntriesService.incrementItemsEntries(
tenantId,
bill.entries
);
}
/**
* Decrements the sale invoice items once the invoice deleted.
*/
@On(events.bill.onDeleted)
public async handleIncrementSaleInvoiceItemsQuantity({ tenantId, oldBill }) {
await this.itemsEntriesService.decrementItemsQuantity(
tenantId,
oldBill.entries
);
}
/**
* Handle increment/decrement the different items quantity once the sale invoice be edited.
*/
@On(events.bill.onEdited)
public async handleChangeSaleInvoiceItemsQuantityOnEdit({
tenantId,
bill,
oldBill,
}) {
await this.itemsEntriesService.changeItemsQuantity(
tenantId,
bill.entries,
oldBill.entries
);
}
}

View File

@@ -3,16 +3,21 @@ import { EventSubscriber, On } from 'event-dispatch';
import { map, head } from 'lodash';
import events from 'subscribers/events';
import SaleInvoicesCost from 'services/Sales/SalesInvoicesCost';
import InventoryItemsQuantitySync from 'services/Inventory/InventoryItemsQuantitySync';
import { InventoryTransaction } from 'models';
@EventSubscriber()
export class InventorySubscriber {
depends: number = 0;
startingDate: Date;
saleInvoicesCost: SaleInvoicesCost;
itemsQuantitySync: InventoryItemsQuantitySync;
agenda: any;
constructor() {
this.saleInvoicesCost = Container.get(SaleInvoicesCost);
this.itemsQuantitySync = Container.get(InventoryItemsQuantitySync);
this.agenda = Container.get('agenda');
}
@@ -30,7 +35,7 @@ export class InventorySubscriber {
if (dependsComputeJobs.length === 0) {
this.startingDate = null;
await this.saleInvoicesCost.scheduleWriteJournalEntries(
await this.saleInvoicesCost.scheduleWriteJournalEntries(
tenantId,
startingDate
);
@@ -38,12 +43,46 @@ export class InventorySubscriber {
}
/**
*
* Sync inventory items quantity once inventory transactions created.
*/
@On(events.inventory.onInventoryTransactionsCreated)
async syncItemsQuantityOnceInventoryTransactionsCreated({
tenantId,
inventoryTransactions,
}) {
const itemsQuantityChanges = this.itemsQuantitySync.getItemsQuantityChanges(
inventoryTransactions
);
await this.itemsQuantitySync.changeItemsQuantity(
tenantId,
itemsQuantityChanges
);
}
/**
* Sync inventory items quantity once inventory transactions deleted.
*/
@On(events.inventory.onInventoryTransactionsDeleted)
async syncItemsQuantityOnceInventoryTransactionsDeleted({
tenantId,
oldInventoryTransactions,
}) {
const itemsQuantityChanges = this.itemsQuantitySync.getReverseItemsQuantityChanges(
oldInventoryTransactions
);
await this.itemsQuantitySync.changeItemsQuantity(
tenantId,
itemsQuantityChanges
);
}
/**
*
*/
@On(events.inventory.onInventoryTransactionsCreated)
async handleScheduleItemsCostOnInventoryTransactionsCreated({
tenantId,
inventoryTransactions
inventoryTransactions,
}) {
const inventoryItemsIds = map(inventoryTransactions, 'itemId');
@@ -61,7 +100,7 @@ export class InventorySubscriber {
tenantId,
transactionType,
transactionId,
oldInventoryTransactions
oldInventoryTransactions,
}) {
// Ignore compute item cost with theses transaction types.
const ignoreWithTransactionTypes = ['OpeningItem'];

View File

@@ -33,7 +33,7 @@ export default class InventoryAdjustmentsSubscriber {
await this.inventoryAdjustment.writeInventoryTransactions(
tenantId,
inventoryAdjustment
)
);
}
/**
@@ -43,10 +43,10 @@ export default class InventoryAdjustmentsSubscriber {
async handleRevertInventoryTransactionsOnceDeleted({
tenantId,
inventoryAdjustmentId,
oldInventoryTransaction,
oldInventoryAdjustment,
}) {
// Can't continue if the inventory adjustment is not published.
if (!oldInventoryTransaction.isPublished) { return; }
if (!oldInventoryAdjustment.isPublished) { return; }
await this.inventoryAdjustment.revertInventoryTransactions(
tenantId,

View File

@@ -1,71 +0,0 @@
import { Container } from 'typedi';
import { On, EventSubscriber } from 'event-dispatch';
import events from 'subscribers/events';
import TenancyService from 'services/Tenancy/TenancyService';
import ItemsEntriesService from 'services/Items/ItemsEntriesService';
@EventSubscriber()
export default class SyncItemsQuantityWithInvoices {
logger: any;
tenancy: TenancyService;
itemsEntriesService: ItemsEntriesService;
/**
* Constructor method.
*/
constructor() {
this.logger = Container.get('logger');
this.tenancy = Container.get(TenancyService);
this.itemsEntriesService = Container.get(ItemsEntriesService);
}
/**
* Increments the sale invoice items once the invoice created.
*/
@On(events.saleInvoice.onCreated)
public async handleDecrementSaleInvoiceItemsQuantity({
tenantId,
saleInvoice,
}) {
await this.itemsEntriesService.decrementItemsQuantity(
tenantId,
saleInvoice.entries
);
}
/**
* Decrements the sale invoice items once the invoice deleted.
*/
@On(events.saleInvoice.onDeleted)
public async handleIncrementSaleInvoiceItemsQuantity({
tenantId,
oldSaleInvoice,
}) {
await this.itemsEntriesService.incrementItemsEntries(
tenantId,
oldSaleInvoice.entries
);
}
/**
* Handle increment/decrement the different items quantity once the sale invoice be edited.
*/
@On(events.saleInvoice.onEdited)
public async handleChangeSaleInvoiceItemsQuantityOnEdit({
tenantId,
saleInvoice,
oldSaleInvoice,
}) {
await this.itemsEntriesService.changeItemsQuantity(
tenantId,
saleInvoice.entries.map((entry) => ({
...entry,
quantity: entry.quantity * -1,
})),
oldSaleInvoice.entries.map((entry) => ({
...entry,
quantity: entry.quantity * -1,
}))
);
}
}

View File

@@ -1,67 +0,0 @@
import { Container } from 'typedi';
import { On, EventSubscriber } from 'event-dispatch';
import events from 'subscribers/events';
import TenancyService from 'services/Tenancy/TenancyService';
import ItemsEntriesService from 'services/Items/ItemsEntriesService';
import SalesInvoicesCost from 'services/Sales/SalesInvoicesCost';
@EventSubscriber()
export default class SaleReceiptSubscriber {
logger: any;
tenancy: TenancyService;
itemsEntriesService: ItemsEntriesService;
constructor() {
this.logger = Container.get('logger');
this.tenancy = Container.get(TenancyService);
this.itemsEntriesService = Container.get(ItemsEntriesService);
}
/**
* Increments the sale receipt items once be created.
*/
@On(events.saleReceipt.onCreated)
public async handleDecremenReceiptItemsQuantity({ tenantId, saleReceipt }) {
await this.itemsEntriesService.decrementItemsQuantity(
tenantId,
saleReceipt.entries
);
}
/**
* Decrements the sale receipt items once be deleted.
*/
@On(events.saleReceipt.onDeleted)
public async handleIncrementReceiptItemsQuantity({
tenantId,
oldSaleReceipt,
}) {
await this.itemsEntriesService.incrementItemsEntries(
tenantId,
oldSaleReceipt.entries
);
}
/**
* Handle increment/decrement the different items quantity once
* the sale receipt be edited.
*/
@On(events.saleReceipt.onEdited)
public async handleChangeSaleInvoiceItemsQuantityOnEdit({
tenantId,
saleReceipt,
oldSaleReceipt,
}) {
await this.itemsEntriesService.changeItemsQuantity(
tenantId,
saleReceipt.entries.map((entry) => ({
...entry,
quantity: entry.quantity * -1,
})),
oldSaleReceipt.entries.map((entry) => ({
...entry,
quantity: entry.quantity * -1,
}))
);
}
}