mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 14:50:32 +00:00
fix: writing inventory transactions on invoice and bill created.
This commit is contained in:
@@ -81,7 +81,6 @@ export default () => {
|
|||||||
dashboard.use(EnsureConfiguredMiddleware);
|
dashboard.use(EnsureConfiguredMiddleware);
|
||||||
dashboard.use(EnsureTenantIsSeeded);
|
dashboard.use(EnsureTenantIsSeeded);
|
||||||
|
|
||||||
|
|
||||||
dashboard.use('/users', Container.get(Users).router());
|
dashboard.use('/users', Container.get(Users).router());
|
||||||
dashboard.use('/invite', Container.get(InviteUsers).authRouter());
|
dashboard.use('/invite', Container.get(InviteUsers).authRouter());
|
||||||
dashboard.use('/currencies', Container.get(Currencies).router());
|
dashboard.use('/currencies', Container.get(Currencies).router());
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export interface IInventoryTransaction {
|
|||||||
rate: number,
|
rate: number,
|
||||||
transactionType: string,
|
transactionType: string,
|
||||||
transactionId: string,
|
transactionId: string,
|
||||||
|
lotNumber: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IInventoryLotCost {
|
export interface IInventoryLotCost {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Container, Service, Inject } from 'typedi';
|
import { Container, Service, Inject } from 'typedi';
|
||||||
|
import { IInventoryTransaction, IItem } from 'interfaces'
|
||||||
import InventoryAverageCost from 'services/Inventory/InventoryAverageCost';
|
import InventoryAverageCost from 'services/Inventory/InventoryAverageCost';
|
||||||
import InventoryCostLotTracker from 'services/Inventory/InventoryCostLotTracker';
|
import InventoryCostLotTracker from 'services/Inventory/InventoryCostLotTracker';
|
||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
@@ -61,26 +62,29 @@ export default class InventoryService {
|
|||||||
/**
|
/**
|
||||||
* Records the inventory transactions.
|
* Records the inventory transactions.
|
||||||
* @param {number} tenantId - Tenant id.
|
* @param {number} tenantId - Tenant id.
|
||||||
* @param {Bill} bill
|
* @param {Bill} bill - Bill model object.
|
||||||
* @param {number} billId
|
* @param {number} billId - Bill id.
|
||||||
|
* @return {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async recordInventoryTransactions(
|
async recordInventoryTransactions(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
entries: [],
|
entries: IInventoryTransaction[],
|
||||||
deleteOld: boolean,
|
deleteOld: boolean,
|
||||||
) {
|
): Promise<void> {
|
||||||
const { InventoryTransaction, Item } = this.tenancy.models(tenantId);
|
const { InventoryTransaction, Item } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
const entriesItemsIds = entries.map((e: any) => e.item_id);
|
// Mapping the inventory entries items ids.
|
||||||
|
const entriesItemsIds = entries.map((e: any) => e.itemId);
|
||||||
const inventoryItems = await Item.query()
|
const inventoryItems = await Item.query()
|
||||||
.whereIn('id', entriesItemsIds)
|
.whereIn('id', entriesItemsIds)
|
||||||
.where('type', 'inventory');
|
.where('type', 'inventory');
|
||||||
|
|
||||||
const inventoryItemsIds = inventoryItems.map((i: any) => i.id);
|
// Mapping the inventory items ids.
|
||||||
|
const inventoryItemsIds = inventoryItems.map((i: IItem) => i.id);
|
||||||
|
|
||||||
// Filter the bill entries that have inventory items.
|
// Filter the bill entries that have inventory items.
|
||||||
const inventoryEntries = entries.filter(
|
const inventoryEntries = entries.filter(
|
||||||
(entry: any) => inventoryItemsIds.indexOf(entry.item_id) !== -1
|
(entry: IInventoryTransaction) => inventoryItemsIds.indexOf(entry.itemId) !== -1
|
||||||
);
|
);
|
||||||
inventoryEntries.forEach(async (entry: any) => {
|
inventoryEntries.forEach(async (entry: any) => {
|
||||||
if (deleteOld) {
|
if (deleteOld) {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
IPaginationMeta,
|
IPaginationMeta,
|
||||||
IFilterMeta,
|
IFilterMeta,
|
||||||
IBillsFilter,
|
IBillsFilter,
|
||||||
|
IItemEntry,
|
||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
import { ServiceError } from 'exceptions';
|
import { ServiceError } from 'exceptions';
|
||||||
import ItemsService from 'services/Items/ItemsService';
|
import ItemsService from 'services/Items/ItemsService';
|
||||||
@@ -221,7 +222,6 @@ export default class BillsService extends SalesInvoicesCost {
|
|||||||
authorizedUser,
|
authorizedUser,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
// Retrieve vendor or throw not found service error.
|
// Retrieve vendor or throw not found service error.
|
||||||
await this.getVendorOrThrowError(tenantId, billDTO.vendorId);
|
await this.getVendorOrThrowError(tenantId, billDTO.vendorId);
|
||||||
|
|
||||||
@@ -372,29 +372,42 @@ export default class BillsService extends SalesInvoicesCost {
|
|||||||
* @param {Bill} bill
|
* @param {Bill} bill
|
||||||
* @param {number} billId
|
* @param {number} billId
|
||||||
*/
|
*/
|
||||||
public recordInventoryTransactions(
|
public async recordInventoryTransactions(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
bill: any,
|
bill: IBill,
|
||||||
billId: number,
|
|
||||||
override?: boolean
|
override?: boolean
|
||||||
) {
|
): Promise<void> {
|
||||||
const inventoryTransactions = bill.entries.map((entry) => ({
|
const invTransactions = bill.entries.map((entry: IItemEntry) => ({
|
||||||
...pick(entry, ['item_id', 'quantity', 'rate']),
|
...pick(entry, ['itemId', 'quantity', 'rate']),
|
||||||
lotNumber: bill.invLotNumber,
|
lotNumber: bill.invLotNumber,
|
||||||
transactionType: 'Bill',
|
transactionType: 'Bill',
|
||||||
transactionId: billId,
|
transactionId: bill.id,
|
||||||
direction: 'IN',
|
direction: 'IN',
|
||||||
date: bill.bill_date,
|
date: bill.billDate,
|
||||||
entryId: entry.id,
|
entryId: entry.id,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return this.inventoryService.recordInventoryTransactions(
|
await this.inventoryService.recordInventoryTransactions(
|
||||||
tenantId,
|
tenantId,
|
||||||
inventoryTransactions,
|
invTransactions,
|
||||||
override
|
override
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverts the inventory transactions of the given bill id.
|
||||||
|
* @param {number} tenantId - Tenant id.
|
||||||
|
* @param {number} billId - Bill id.
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
public async revertInventoryTransactions(tenantId: number, billId: number) {
|
||||||
|
await this.inventoryService.deleteInventoryTransactions(
|
||||||
|
tenantId,
|
||||||
|
billId,
|
||||||
|
'Bill',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records the bill journal transactions.
|
* Records the bill journal transactions.
|
||||||
* @async
|
* @async
|
||||||
@@ -437,7 +450,6 @@ export default class BillsService extends SalesInvoicesCost {
|
|||||||
Bill,
|
Bill,
|
||||||
billsFilter
|
billsFilter
|
||||||
);
|
);
|
||||||
|
|
||||||
this.logger.info('[bills] trying to get bills data table.', {
|
this.logger.info('[bills] trying to get bills data table.', {
|
||||||
tenantId,
|
tenantId,
|
||||||
billsFilter,
|
billsFilter,
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import {
|
|||||||
} from 'decorators/eventDispatcher';
|
} from 'decorators/eventDispatcher';
|
||||||
import {
|
import {
|
||||||
ISaleInvoice,
|
ISaleInvoice,
|
||||||
ISaleInvoiceDTO,
|
|
||||||
IItemEntry,
|
IItemEntry,
|
||||||
|
ISaleInvoiceCreateDTO,
|
||||||
|
ISaleInvoiceEditDTO,
|
||||||
|
IInventoryTransaction,
|
||||||
ISalesInvoicesFilter,
|
ISalesInvoicesFilter,
|
||||||
IPaginationMeta,
|
IPaginationMeta,
|
||||||
IFilterMeta,
|
IFilterMeta,
|
||||||
ISaleInvoiceCreateDTO,
|
|
||||||
ISaleInvoiceEditDTO,
|
|
||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
import events from 'subscribers/events';
|
import events from 'subscribers/events';
|
||||||
import JournalPoster from 'services/Accounting/JournalPoster';
|
import JournalPoster from 'services/Accounting/JournalPoster';
|
||||||
@@ -351,48 +351,68 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
|||||||
.where('reference_type', 'SaleInvoice')
|
.where('reference_type', 'SaleInvoice')
|
||||||
.delete();
|
.delete();
|
||||||
|
|
||||||
|
// Triggers `onSaleInvoiceDeleted` event.
|
||||||
await this.eventDispatcher.dispatch(events.saleInvoice.onDeleted, {
|
await this.eventDispatcher.dispatch(events.saleInvoice.onDeleted, {
|
||||||
tenantId,
|
tenantId,
|
||||||
oldSaleInvoice,
|
oldSaleInvoice,
|
||||||
|
saleInvoiceId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records the inventory transactions from the givne sale invoice input.
|
* Records the inventory transactions from the givne sale invoice input.
|
||||||
* @param {SaleInvoice} saleInvoice -
|
* @parma {number} tenantId - Tenant id.
|
||||||
* @param {number} saleInvoiceId -
|
* @param {SaleInvoice} saleInvoice - Sale invoice DTO.
|
||||||
* @param {boolean} override -
|
* @param {number} saleInvoiceId - Sale invoice id.
|
||||||
|
* @param {boolean} override - Allow to override old transactions.
|
||||||
*/
|
*/
|
||||||
private recordInventoryTranscactions(
|
public recordInventoryTranscactions(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
saleInvoice,
|
saleInvoice: ISaleInvoice,
|
||||||
saleInvoiceId: number,
|
|
||||||
override?: boolean
|
override?: boolean
|
||||||
) {
|
) {
|
||||||
this.logger.info('[sale_invoice] saving inventory transactions');
|
this.logger.info('[sale_invoice] saving inventory transactions');
|
||||||
const inventortyTransactions = saleInvoice.entries.map((entry) => ({
|
const invTransactions: IInventoryTransaction[] = saleInvoice.entries.map(
|
||||||
...pick(entry, ['item_id', 'quantity', 'rate']),
|
(entry: IItemEntry) => ({
|
||||||
lotNumber: saleInvoice.invLotNumber,
|
...pick(entry, ['itemId', 'quantity', 'rate']),
|
||||||
|
lotNumber: 1,
|
||||||
transactionType: 'SaleInvoice',
|
transactionType: 'SaleInvoice',
|
||||||
transactionId: saleInvoiceId,
|
transactionId: saleInvoice.id,
|
||||||
direction: 'OUT',
|
direction: 'OUT',
|
||||||
date: saleInvoice.invoice_date,
|
date: saleInvoice.invoiceDate,
|
||||||
entryId: entry.id,
|
entryId: entry.id,
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
|
||||||
return this.inventoryService.recordInventoryTransactions(
|
return this.inventoryService.recordInventoryTransactions(
|
||||||
tenantId,
|
tenantId,
|
||||||
inventortyTransactions,
|
invTransactions,
|
||||||
override
|
override
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverting the inventory transactions once the invoice deleted.
|
||||||
|
* @param {number} tenantId - Tenant id.
|
||||||
|
* @param {number} billId - Bill id.
|
||||||
|
*/
|
||||||
|
public revertInventoryTransactions(
|
||||||
|
tenantId: number,
|
||||||
|
billId: number
|
||||||
|
): Promise<void> {
|
||||||
|
return this.inventoryService.deleteInventoryTransactions(
|
||||||
|
tenantId,
|
||||||
|
billId,
|
||||||
|
'SaleInvoice'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the inventory transactions.
|
* Deletes the inventory transactions.
|
||||||
* @param {string} transactionType
|
* @param {string} transactionType
|
||||||
* @param {number} transactionId
|
* @param {number} transactionId
|
||||||
*/
|
*/
|
||||||
private async revertInventoryTransactions(
|
private async revertInventoryTransactions_(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
inventoryTransactions: array
|
inventoryTransactions: array
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -108,4 +108,41 @@ export default class BillSubscriber {
|
|||||||
oldBill.vendorId
|
oldBill.vendorId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles writing the inventory transactions once bill created.
|
||||||
|
*/
|
||||||
|
@On(events.bill.onCreated)
|
||||||
|
async handleWritingInventoryTransactions({ tenantId, bill }) {
|
||||||
|
this.logger.info('[bill] writing the inventory transactions', { tenantId });
|
||||||
|
this.billsService.recordInventoryTransactions(
|
||||||
|
tenantId,
|
||||||
|
bill,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the overwriting the inventory transactions once bill edited.
|
||||||
|
*/
|
||||||
|
@On(events.bill.onEdited)
|
||||||
|
async handleOverwritingInventoryTransactions({ tenantId, bill }) {
|
||||||
|
this.logger.info('[bill] overwriting the inventory transactions.', { tenantId });
|
||||||
|
this.billsService.recordInventoryTransactions(
|
||||||
|
tenantId,
|
||||||
|
bill,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the reverting the inventory transactions once the bill deleted.
|
||||||
|
*/
|
||||||
|
@On(events.bill.onDeleted)
|
||||||
|
async handleRevertInventoryTransactions({ tenantId, billId }) {
|
||||||
|
this.logger.info('[bill] reverting the bill inventory transactions', { tenantId, billId });
|
||||||
|
this.billsService.revertInventoryTransactions(
|
||||||
|
tenantId,
|
||||||
|
billId,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import events from 'subscribers/events';
|
|||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
import SettingsService from 'services/Settings/SettingsService';
|
import SettingsService from 'services/Settings/SettingsService';
|
||||||
import SaleEstimateService from 'services/Sales/SalesEstimate';
|
import SaleEstimateService from 'services/Sales/SalesEstimate';
|
||||||
|
import SaleInvoicesService from 'services/Sales/SalesInvoices';
|
||||||
|
|
||||||
@EventSubscriber()
|
@EventSubscriber()
|
||||||
export default class SaleInvoiceSubscriber {
|
export default class SaleInvoiceSubscriber {
|
||||||
@@ -11,12 +12,14 @@ export default class SaleInvoiceSubscriber {
|
|||||||
tenancy: TenancyService;
|
tenancy: TenancyService;
|
||||||
settingsService: SettingsService;
|
settingsService: SettingsService;
|
||||||
saleEstimatesService: SaleEstimateService;
|
saleEstimatesService: SaleEstimateService;
|
||||||
|
saleInvoicesService: SaleInvoicesService;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.logger = Container.get('logger');
|
this.logger = Container.get('logger');
|
||||||
this.tenancy = Container.get(TenancyService);
|
this.tenancy = Container.get(TenancyService);
|
||||||
this.settingsService = Container.get(SettingsService);
|
this.settingsService = Container.get(SettingsService);
|
||||||
this.saleEstimatesService = Container.get(SaleEstimateService);
|
this.saleEstimatesService = Container.get(SaleEstimateService);
|
||||||
|
this.saleInvoicesService = Container.get(SaleInvoicesService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,4 +117,32 @@ export default class SaleInvoiceSubscriber {
|
|||||||
group: 'sales_invoices',
|
group: 'sales_invoices',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the writing inventory transactions once the invoice created.
|
||||||
|
*/
|
||||||
|
@On(events.saleInvoice.onCreated)
|
||||||
|
public async handleWritingInventoryTransactions({ tenantId, saleInvoice }) {
|
||||||
|
this.logger.info('[sale_invoice] trying to write inventory transactions.', {
|
||||||
|
tenantId,
|
||||||
|
});
|
||||||
|
await this.saleInvoicesService.recordInventoryTranscactions(
|
||||||
|
tenantId,
|
||||||
|
saleInvoice,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles deleting the inventory transactions once the invoice deleted.
|
||||||
|
*/
|
||||||
|
@On(events.saleInvoice.onDeleted)
|
||||||
|
public async handleDeletingInventoryTransactions({ tenantId, saleInvoiceId }) {
|
||||||
|
this.logger.info('[sale_invoice] trying to revert inventory transactions.', {
|
||||||
|
tenantId, saleInvoiceId,
|
||||||
|
});
|
||||||
|
await this.saleInvoicesService.revertInventoryTransactions(
|
||||||
|
tenantId,
|
||||||
|
saleInvoiceId,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user