This commit is contained in:
elforjani3
2021-01-02 16:07:20 +02:00
7 changed files with 398 additions and 258 deletions

View File

@@ -22,12 +22,14 @@ export default class CustomersController extends ContactsController {
router() { router() {
const router = Router(); const router = Router();
router.post('/', [ router.post(
...this.contactDTOSchema, '/',
...this.contactNewDTOSchema, [
...this.customerDTOSchema, ...this.contactDTOSchema,
...this.createCustomerDTOSchema, ...this.contactNewDTOSchema,
], ...this.customerDTOSchema,
...this.createCustomerDTOSchema,
],
this.validationResult, this.validationResult,
asyncMiddleware(this.newCustomer.bind(this)), asyncMiddleware(this.newCustomer.bind(this)),
this.handlerServiceErrors this.handlerServiceErrors
@@ -41,41 +43,43 @@ export default class CustomersController extends ContactsController {
], ],
this.validationResult, this.validationResult,
asyncMiddleware(this.editOpeningBalanceCustomer.bind(this)), asyncMiddleware(this.editOpeningBalanceCustomer.bind(this)),
this.handlerServiceErrors, this.handlerServiceErrors
); );
router.post('/:id', [ router.post(
...this.contactDTOSchema, '/:id',
...this.contactEditDTOSchema, [
...this.customerDTOSchema, ...this.contactDTOSchema,
], ...this.contactEditDTOSchema,
...this.customerDTOSchema,
],
this.validationResult, this.validationResult,
asyncMiddleware(this.editCustomer.bind(this)), asyncMiddleware(this.editCustomer.bind(this)),
this.handlerServiceErrors, this.handlerServiceErrors
); );
router.delete('/:id', [ router.delete(
...this.specificContactSchema, '/:id',
], [...this.specificContactSchema],
this.validationResult, this.validationResult,
asyncMiddleware(this.deleteCustomer.bind(this)), asyncMiddleware(this.deleteCustomer.bind(this)),
this.handlerServiceErrors, this.handlerServiceErrors
); );
router.delete('/', [ router.delete(
...this.bulkContactsSchema, '/',
], [...this.bulkContactsSchema],
this.validationResult, this.validationResult,
asyncMiddleware(this.deleteBulkCustomers.bind(this)), asyncMiddleware(this.deleteBulkCustomers.bind(this)),
this.handlerServiceErrors, this.handlerServiceErrors
); );
router.get('/', [ router.get(
...this.validateListQuerySchema, '/',
], [...this.validateListQuerySchema],
this.validationResult, this.validationResult,
asyncMiddleware(this.getCustomersList.bind(this)), asyncMiddleware(this.getCustomersList.bind(this)),
this.dynamicListService.handlerErrorsToResponse, this.dynamicListService.handlerErrorsToResponse
); );
router.get('/:id', [ router.get(
...this.specificContactSchema, '/:id',
], [...this.specificContactSchema],
this.validationResult, this.validationResult,
asyncMiddleware(this.getCustomer.bind(this)), asyncMiddleware(this.getCustomer.bind(this)),
this.handlerServiceErrors this.handlerServiceErrors
@@ -128,16 +132,20 @@ export default class CustomersController extends ContactsController {
/** /**
* Creates a new customer. * Creates a new customer.
* @param {Request} req * @param {Request} req
* @param {Response} res * @param {Response} res
* @param {NextFunction} next * @param {NextFunction} next
*/ */
async newCustomer(req: Request, res: Response, next: NextFunction) { async newCustomer(req: Request, res: Response, next: NextFunction) {
const contactDTO: ICustomerNewDTO = this.matchedBodyData(req); const contactDTO: ICustomerNewDTO = this.matchedBodyData(req);
const { tenantId } = req; const { tenantId, user } = req;
try { try {
const contact = await this.customersService.newCustomer(tenantId, contactDTO); const contact = await this.customersService.newCustomer(
tenantId,
contactDTO,
user
);
return res.status(200).send({ return res.status(200).send({
id: contact.id, id: contact.id,
@@ -150,17 +158,22 @@ export default class CustomersController extends ContactsController {
/** /**
* Edits the given customer details. * Edits the given customer details.
* @param {Request} req * @param {Request} req
* @param {Response} res * @param {Response} res
* @param {NextFunction} next * @param {NextFunction} next
*/ */
async editCustomer(req: Request, res: Response, next: NextFunction) { async editCustomer(req: Request, res: Response, next: NextFunction) {
const contactDTO: ICustomerEditDTO = this.matchedBodyData(req); const contactDTO: ICustomerEditDTO = this.matchedBodyData(req);
const { tenantId } = req; const { tenantId, user } = req;
const { id: contactId } = req.params; const { id: contactId } = req.params;
try { try {
await this.customersService.editCustomer(tenantId, contactId, contactDTO); await this.customersService.editCustomer(
tenantId,
contactId,
contactDTO,
user
);
return res.status(200).send({ return res.status(200).send({
id: contactId, id: contactId,
@@ -177,24 +190,26 @@ export default class CustomersController extends ContactsController {
* @param {Response} res - * @param {Response} res -
* @param {NextFunction} next - * @param {NextFunction} next -
*/ */
async editOpeningBalanceCustomer(req: Request, res: Response, next: NextFunction) { async editOpeningBalanceCustomer(
const { tenantId } = req; req: Request,
res: Response,
next: NextFunction
) {
const { tenantId, user } = req;
const { id: customerId } = req.params; const { id: customerId } = req.params;
const { const { openingBalance, openingBalanceAt } = this.matchedBodyData(req);
openingBalance,
openingBalanceAt,
} = this.matchedBodyData(req);
try { try {
await this.customersService.changeOpeningBalance( await this.customersService.changeOpeningBalance(
tenantId, tenantId,
customerId, customerId,
openingBalance, openingBalance,
openingBalanceAt, openingBalanceAt
); );
return res.status(200).send({ return res.status(200).send({
id: customerId, id: customerId,
message: 'The opening balance of the given customer has been changed successfully.', message:
'The opening balance of the given customer has been changed successfully.',
}); });
} catch (error) { } catch (error) {
next(error); next(error);
@@ -203,16 +218,20 @@ export default class CustomersController extends ContactsController {
/** /**
* Retrieve details of the given customer id. * Retrieve details of the given customer id.
* @param {Request} req * @param {Request} req
* @param {Response} res * @param {Response} res
* @param {NextFunction} next * @param {NextFunction} next
*/ */
async getCustomer(req: Request, res: Response, next: NextFunction) { async getCustomer(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req; const { tenantId, user } = req;
const { id: contactId } = req.params; const { id: contactId } = req.params;
try { try {
const customer = await this.customersService.getCustomer(tenantId, contactId); const customer = await this.customersService.getCustomer(
tenantId,
contactId,
user
);
return res.status(200).send({ return res.status(200).send({
customer: this.transfromToResponse(customer), customer: this.transfromToResponse(customer),
@@ -224,16 +243,16 @@ export default class CustomersController extends ContactsController {
/** /**
* Deletes the given customer from the storage. * Deletes the given customer from the storage.
* @param {Request} req * @param {Request} req
* @param {Response} res * @param {Response} res
* @param {NextFunction} next * @param {NextFunction} next
*/ */
async deleteCustomer(req: Request, res: Response, next: NextFunction) { async deleteCustomer(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req; const { tenantId, user } = req;
const { id: contactId } = req.params; const { id: contactId } = req.params;
try { try {
await this.customersService.deleteCustomer(tenantId, contactId); await this.customersService.deleteCustomer(tenantId, contactId, user);
return res.status(200).send({ return res.status(200).send({
id: contactId, id: contactId,
@@ -246,16 +265,20 @@ export default class CustomersController extends ContactsController {
/** /**
* Deletes customers in bulk. * Deletes customers in bulk.
* @param {Request} req * @param {Request} req
* @param {Response} res * @param {Response} res
* @param {NextFunction} next * @param {NextFunction} next
*/ */
async deleteBulkCustomers(req: Request, res: Response, next: NextFunction) { async deleteBulkCustomers(req: Request, res: Response, next: NextFunction) {
const { ids: contactsIds } = req.query; const { ids: contactsIds } = req.query;
const { tenantId } = req; const { tenantId, user } = req;
try { try {
await this.customersService.deleteBulkCustomers(tenantId, contactsIds) await this.customersService.deleteBulkCustomers(
tenantId,
contactsIds,
user
);
return res.status(200).send({ return res.status(200).send({
ids: contactsIds, ids: contactsIds,
@@ -268,9 +291,9 @@ export default class CustomersController extends ContactsController {
/** /**
* Retrieve customers paginated and filterable list. * Retrieve customers paginated and filterable list.
* @param {Request} req * @param {Request} req
* @param {Response} res * @param {Response} res
* @param {NextFunction} next * @param {NextFunction} next
*/ */
async getCustomersList(req: Request, res: Response, next: NextFunction) { async getCustomersList(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req; const { tenantId } = req;
@@ -305,12 +328,17 @@ export default class CustomersController extends ContactsController {
/** /**
* Handles service errors. * Handles service errors.
* @param {Error} error * @param {Error} error
* @param {Request} req * @param {Request} req
* @param {Response} res * @param {Response} res
* @param {NextFunction} next * @param {NextFunction} next
*/ */
handlerServiceErrors(error: Error, req: Request, res: Response, next: NextFunction) { handlerServiceErrors(
error: Error,
req: Request,
res: Response,
next: NextFunction
) {
if (error instanceof ServiceError) { if (error instanceof ServiceError) {
if (error.errorType === 'contact_not_found') { if (error.errorType === 'contact_not_found') {
return res.boom.badRequest(null, { return res.boom.badRequest(null, {
@@ -340,4 +368,4 @@ export default class CustomersController extends ContactsController {
} }
next(error); next(error);
} }
} }

View File

@@ -118,10 +118,10 @@ export default class VendorsController extends ContactsController {
*/ */
async newVendor(req: Request, res: Response, next: NextFunction) { async newVendor(req: Request, res: Response, next: NextFunction) {
const contactDTO: IVendorNewDTO = this.matchedBodyData(req); const contactDTO: IVendorNewDTO = this.matchedBodyData(req);
const { tenantId } = req; const { tenantId, user } = req;
try { try {
const vendor = await this.vendorsService.newVendor(tenantId, contactDTO); const vendor = await this.vendorsService.newVendor(tenantId, contactDTO, user);
return res.status(200).send({ return res.status(200).send({
id: vendor.id, id: vendor.id,
@@ -140,11 +140,11 @@ export default class VendorsController extends ContactsController {
*/ */
async editVendor(req: Request, res: Response, next: NextFunction) { async editVendor(req: Request, res: Response, next: NextFunction) {
const contactDTO: IVendorEditDTO = this.matchedBodyData(req); const contactDTO: IVendorEditDTO = this.matchedBodyData(req);
const { tenantId } = req; const { tenantId, user } = req;
const { id: contactId } = req.params; const { id: contactId } = req.params;
try { try {
await this.vendorsService.editVendor(tenantId, contactId, contactDTO); await this.vendorsService.editVendor(tenantId, contactId, contactDTO, user);
return res.status(200).send({ return res.status(200).send({
id: contactId, id: contactId,
@@ -162,7 +162,7 @@ export default class VendorsController extends ContactsController {
* @param {NextFunction} next - * @param {NextFunction} next -
*/ */
async editOpeningBalanceVendor(req: Request, res: Response, next: NextFunction) { async editOpeningBalanceVendor(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req; const { tenantId, user } = req;
const { id: vendorId } = req.params; const { id: vendorId } = req.params;
const { const {
openingBalance, openingBalance,
@@ -192,11 +192,11 @@ export default class VendorsController extends ContactsController {
* @param {NextFunction} next * @param {NextFunction} next
*/ */
async deleteVendor(req: Request, res: Response, next: NextFunction) { async deleteVendor(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req; const { tenantId, user } = req;
const { id: contactId } = req.params; const { id: contactId } = req.params;
try { try {
await this.vendorsService.deleteVendor(tenantId, contactId) await this.vendorsService.deleteVendor(tenantId, contactId, user)
return res.status(200).send({ return res.status(200).send({
id: contactId, id: contactId,
@@ -214,11 +214,12 @@ export default class VendorsController extends ContactsController {
* @param {NextFunction} next * @param {NextFunction} next
*/ */
async getVendor(req: Request, res: Response, next: NextFunction) { async getVendor(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req; const { tenantId, user } = req;
const { id: vendorId } = req.params; const { id: vendorId } = req.params;
try { try {
const vendor = await this.vendorsService.getVendor(tenantId, vendorId) const vendor = await this.vendorsService.getVendor(tenantId, vendorId, user)
return res.status(200).send({ vendor }); return res.status(200).send({ vendor });
} catch (error) { } catch (error) {
next(error); next(error);
@@ -233,10 +234,10 @@ export default class VendorsController extends ContactsController {
*/ */
async deleteBulkVendors(req: Request, res: Response, next: NextFunction) { async deleteBulkVendors(req: Request, res: Response, next: NextFunction) {
const { ids: contactsIds } = req.query; const { ids: contactsIds } = req.query;
const { tenantId } = req; const { tenantId, user } = req;
try { try {
await this.vendorsService.deleteBulkVendors(tenantId, contactsIds) await this.vendorsService.deleteBulkVendors(tenantId, contactsIds, user)
return res.status(200).send({ return res.status(200).send({
ids: contactsIds, ids: contactsIds,

View File

@@ -1,8 +1,8 @@
import { sumBy, chain } from 'lodash'; import { sumBy, chain } from 'lodash';
import moment from 'moment'; import moment from 'moment';
import { IBill } from 'interfaces'; import { IBill, ISystemUser } from 'interfaces';
import JournalPoster from "./JournalPoster"; import JournalPoster from './JournalPoster';
import JournalEntry from "./JournalEntry"; import JournalEntry from './JournalEntry';
import { AccountTransaction } from 'models'; import { AccountTransaction } from 'models';
import { import {
IInventoryTransaction, IInventoryTransaction,
@@ -16,37 +16,37 @@ import {
} from 'interfaces'; } from 'interfaces';
interface IInventoryCostEntity { interface IInventoryCostEntity {
date: Date, date: Date;
referenceType: string, referenceType: string;
referenceId: number, referenceId: number;
costAccount: number, costAccount: number;
incomeAccount: number, incomeAccount: number;
inventoryAccount: number, inventoryAccount: number;
inventory: number, inventory: number;
cost: number, cost: number;
income: number, income: number;
}; }
interface NonInventoryJEntries { interface NonInventoryJEntries {
date: Date, date: Date;
referenceType: string, referenceType: string;
referenceId: number, referenceId: number;
receivable: number, receivable: number;
payable: number, payable: number;
incomeAccountId: number, incomeAccountId: number;
income: number, income: number;
costAccountId: number, costAccountId: number;
cost: number, cost: number;
}; }
export default class JournalCommands{ export default class JournalCommands {
journal: JournalPoster; journal: JournalPoster;
models: any; models: any;
@@ -54,18 +54,18 @@ export default class JournalCommands{
/** /**
* Constructor method. * Constructor method.
* @param {JournalPoster} journal - * @param {JournalPoster} journal -
*/ */
constructor(journal: JournalPoster) { constructor(journal: JournalPoster) {
this.journal = journal; this.journal = journal;
this.repositories = this.journal.repositories; this.repositories = this.journal.repositories;
this.models = this.journal.models; this.models = this.journal.models;
} }
/** /**
* Records the bill journal entries. * Records the bill journal entries.
* @param {IBill} bill * @param {IBill} bill
* @param {boolean} override - Override the old bill entries. * @param {boolean} override - Override the old bill entries.
*/ */
async bill(bill: IBill, override: boolean = false): Promise<void> { async bill(bill: IBill, override: boolean = false): Promise<void> {
@@ -78,7 +78,9 @@ export default class JournalCommands{
const storedItems = await Item.query().whereIn('id', entriesItemsIds); const storedItems = await Item.query().whereIn('id', entriesItemsIds);
const storedItemsMap = new Map(storedItems.map((item) => [item.id, item])); const storedItemsMap = new Map(storedItems.map((item) => [item.id, item]));
const payableAccount = await accountRepository.findOne({ slug: 'accounts-payable' }); const payableAccount = await accountRepository.findOne({
slug: 'accounts-payable',
});
const formattedDate = moment(bill.billDate).format('YYYY-MM-DD'); const formattedDate = moment(bill.billDate).format('YYYY-MM-DD');
const commonJournalMeta = { const commonJournalMeta = {
@@ -127,32 +129,45 @@ export default class JournalCommands{
/** /**
* Customer opening balance journals. * Customer opening balance journals.
* @param {number} customerId * @param {number} customerId
* @param {number} openingBalance * @param {number} openingBalance
*/ */
async customerOpeningBalance(customerId: number, openingBalance: number) { async customerOpeningBalance(
customerId: number,
openingBalance: number,
openingBalanceAt: Date | string,
userId: number
) {
const { accountRepository } = this.repositories; const { accountRepository } = this.repositories;
const openingBalanceAccount = await accountRepository.findOne({ slug: 'opening-balance' }); const openingBalanceAccount = await accountRepository.findOne({
const receivableAccount = await accountRepository.findOne({ slug: 'accounts-receivable' }); slug: 'opening-balance',
});
const receivableAccount = await accountRepository.findOne({
slug: 'accounts-receivable',
});
const commonEntry = { const commonEntry = {
referenceType: 'CustomerOpeningBalance', referenceType: 'CustomerOpeningBalance',
referenceId: customerId, referenceId: customerId,
contactType: 'Customer', contactType: 'Customer',
contactId: customerId, contactId: customerId,
date: openingBalanceAt,
userId,
}; };
const creditEntry = new JournalEntry({
...commonEntry,
credit: openingBalance,
debit: 0,
account: openingBalanceAccount.id,
});
const debitEntry = new JournalEntry({ const debitEntry = new JournalEntry({
...commonEntry, ...commonEntry,
credit: 0, credit: 0,
debit: openingBalance, debit: openingBalance,
account: receivableAccount.id, account: receivableAccount.id,
index: 1,
});
const creditEntry = new JournalEntry({
...commonEntry,
credit: openingBalance,
debit: 0,
account: openingBalanceAccount.id,
index: 2,
}); });
this.journal.debit(debitEntry); this.journal.debit(debitEntry);
this.journal.credit(creditEntry); this.journal.credit(creditEntry);
@@ -160,32 +175,47 @@ export default class JournalCommands{
/** /**
* Vendor opening balance journals * Vendor opening balance journals
* @param {number} vendorId * @param {number} vendorId
* @param {number} openingBalance * @param {number} openingBalance
* @param {Date|string} openingBalanceAt
* @param {number} authorizedUserId
*/ */
async vendorOpeningBalance(vendorId: number, openingBalance: number) { async vendorOpeningBalance(
vendorId: number,
openingBalance: number,
openingBalanceAt: Date|string,
authorizedUserId: ISystemUser
) {
const { accountRepository } = this.repositories; const { accountRepository } = this.repositories;
const payableAccount = await accountRepository.findOne({ slug: 'accounts-payable' }); const payableAccount = await accountRepository.findOne({
const otherCost = await accountRepository.findOne({ slug: 'other-expenses' }); slug: 'accounts-payable',
});
const otherCost = await accountRepository.findOne({
slug: 'other-expenses',
});
const commonEntry = { const commonEntry = {
referenceType: 'VendorOpeningBalance', referenceType: 'VendorOpeningBalance',
referenceId: vendorId, referenceId: vendorId,
contactType: 'Vendor', contactType: 'Vendor',
contactId: vendorId, contactId: vendorId,
date: openingBalanceAt,
userId: authorizedUserId,
}; };
const creditEntry = new JournalEntry({ const creditEntry = new JournalEntry({
...commonEntry, ...commonEntry,
account: payableAccount.id, account: payableAccount.id,
credit: openingBalance, credit: openingBalance,
debit: 0, debit: 0,
index: 1,
}); });
const debitEntry = new JournalEntry({ const debitEntry = new JournalEntry({
...commonEntry, ...commonEntry,
account: otherCost.id, account: otherCost.id,
debit: openingBalance, debit: openingBalance,
credit: 0, credit: 0,
index: 2,
}); });
this.journal.debit(debitEntry); this.journal.debit(debitEntry);
this.journal.credit(creditEntry); this.journal.credit(creditEntry);
@@ -193,7 +223,7 @@ export default class JournalCommands{
/** /**
* Writes journal entries of expense model object. * Writes journal entries of expense model object.
* @param {IExpense} expense * @param {IExpense} expense
*/ */
expense(expense: IExpense) { expense(expense: IExpense) {
const mixinEntry = { const mixinEntry = {
@@ -224,32 +254,37 @@ export default class JournalCommands{
} }
/** /**
* *
* @param {number|number[]} referenceId * @param {number|number[]} referenceId
* @param {string} referenceType * @param {string} referenceType
*/ */
async revertJournalEntries( async revertJournalEntries(
referenceId: number|number[], referenceId: number | number[],
referenceType: string referenceType: string
) { ) {
const { AccountTransaction } = this.models; const { AccountTransaction } = this.models;
const transactions = await AccountTransaction.query() const transactions = await AccountTransaction.query()
.where('reference_type', referenceType) .where('reference_type', referenceType)
.whereIn('reference_id', Array.isArray(referenceId) ? referenceId : [referenceId]) .whereIn(
'reference_id',
Array.isArray(referenceId) ? referenceId : [referenceId]
)
.withGraphFetched('account.type'); .withGraphFetched('account.type');
this.journal.fromTransactions(transactions); this.journal.fromTransactions(transactions);
this.journal.removeEntries(); this.journal.removeEntries();
} }
/** /**
* Writes journal entries from manual journal model object. * Writes journal entries from manual journal model object.
* @param {IManualJournal} manualJournalObj * @param {IManualJournal} manualJournalObj
* @param {number} manualJournalId * @param {number} manualJournalId
*/ */
async manualJournal(manualJournalObj: IManualJournal, manualJournalId: number) { async manualJournal(
manualJournalObj: IManualJournal,
manualJournalId: number
) {
manualJournalObj.entries.forEach((entry) => { manualJournalObj.entries.forEach((entry) => {
const jouranlEntry = new JournalEntry({ const jouranlEntry = new JournalEntry({
debit: entry.debit, debit: entry.debit,
@@ -276,39 +311,49 @@ export default class JournalCommands{
/** /**
* Removes and revert accounts balance journal entries that associated * Removes and revert accounts balance journal entries that associated
* to the given inventory transactions. * to the given inventory transactions.
* @param {IInventoryTransaction[]} inventoryTransactions * @param {IInventoryTransaction[]} inventoryTransactions
* @param {Journal} journal * @param {Journal} journal
*/ */
revertEntriesFromInventoryTransactions(inventoryTransactions: IInventoryTransaction[]) { revertEntriesFromInventoryTransactions(
inventoryTransactions: IInventoryTransaction[]
) {
const groupedInvTransactions = chain(inventoryTransactions) const groupedInvTransactions = chain(inventoryTransactions)
.groupBy((invTransaction: IInventoryTransaction) => invTransaction.transactionType) .groupBy(
.map((groupedTrans: IInventoryTransaction[], transType: string) => [groupedTrans, transType]) (invTransaction: IInventoryTransaction) =>
invTransaction.transactionType
)
.map((groupedTrans: IInventoryTransaction[], transType: string) => [
groupedTrans,
transType,
])
.value(); .value();
return Promise.all( return Promise.all(
groupedInvTransactions.map(async (grouped: [IInventoryTransaction[], string]) => { groupedInvTransactions.map(
const [invTransGroup, referenceType] = grouped; async (grouped: [IInventoryTransaction[], string]) => {
const referencesIds = invTransGroup.map((trans: IInventoryTransaction) => trans.transactionId); const [invTransGroup, referenceType] = grouped;
const referencesIds = invTransGroup.map(
(trans: IInventoryTransaction) => trans.transactionId
);
const _transactions = await AccountTransaction.tenant() const _transactions = await AccountTransaction.tenant()
.query() .query()
.where('reference_type', referenceType) .where('reference_type', referenceType)
.whereIn('reference_id', referencesIds) .whereIn('reference_id', referencesIds)
.withGraphFetched('account.type'); .withGraphFetched('account.type');
if (_transactions.length > 0) { if (_transactions.length > 0) {
this.journal.loadEntries(_transactions); this.journal.loadEntries(_transactions);
this.journal.removeEntries(_transactions.map((t: any) => t.id)); this.journal.removeEntries(_transactions.map((t: any) => t.id));
}
} }
}) )
); );
} }
public async nonInventoryEntries( public async nonInventoryEntries(transactions: NonInventoryJEntries[]) {
transactions: NonInventoryJEntries[]
) {
const receivableAccount = { id: 10 }; const receivableAccount = { id: 10 };
const payableAccount = {id: 11}; const payableAccount = { id: 11 };
transactions.forEach((trans: NonInventoryJEntries) => { transactions.forEach((trans: NonInventoryJEntries) => {
const commonEntry = { const commonEntry = {
@@ -317,12 +362,12 @@ export default class JournalCommands{
referenceType: trans.referenceType, referenceType: trans.referenceType,
}; };
switch(trans.referenceType) { switch (trans.referenceType) {
case 'Bill': case 'Bill':
const payableEntry: JournalEntry = new JournalEntry({ const payableEntry: JournalEntry = new JournalEntry({
...commonEntry, ...commonEntry,
credit: trans.payable, credit: trans.payable,
account: payableAccount.id, account: payableAccount.id,
}); });
const costEntry: JournalEntry = new JournalEntry({ const costEntry: JournalEntry = new JournalEntry({
...commonEntry, ...commonEntry,
@@ -349,14 +394,12 @@ export default class JournalCommands{
} }
/** /**
* *
* @param {string} referenceType - * @param {string} referenceType -
* @param {number} referenceId - * @param {number} referenceId -
* @param {ISaleInvoice[]} sales - * @param {ISaleInvoice[]} sales -
*/ */
public async inventoryEntries( public async inventoryEntries(transactions: IInventoryCostEntity[]) {
transactions: IInventoryCostEntity[],
) {
const receivableAccount = { id: 10 }; const receivableAccount = { id: 10 };
const payableAccount = { id: 11 }; const payableAccount = { id: 11 };
@@ -366,12 +409,12 @@ export default class JournalCommands{
referenceId: sale.referenceId, referenceId: sale.referenceId,
referenceType: sale.referenceType, referenceType: sale.referenceType,
}; };
switch(sale.referenceType) { switch (sale.referenceType) {
case 'Bill': case 'Bill':
const inventoryDebit: JournalEntry = new JournalEntry({ const inventoryDebit: JournalEntry = new JournalEntry({
...commonEntry, ...commonEntry,
debit: sale.inventory, debit: sale.inventory,
account: sale.inventoryAccount, account: sale.inventoryAccount,
}); });
const payableEntry: JournalEntry = new JournalEntry({ const payableEntry: JournalEntry = new JournalEntry({
...commonEntry, ...commonEntry,
@@ -401,7 +444,7 @@ export default class JournalCommands{
const inventoryCredit: JournalEntry = new JournalEntry({ const inventoryCredit: JournalEntry = new JournalEntry({
...commonEntry, ...commonEntry,
credit: sale.cost, credit: sale.cost,
account: sale.inventoryAccount, account: sale.inventoryAccount,
}); });
this.journal.debit(receivableEntry); this.journal.debit(receivableEntry);
this.journal.debit(costEntry); this.journal.debit(costEntry);
@@ -418,19 +461,19 @@ export default class JournalCommands{
* ---------- * ----------
* - Receivable accounts -> Debit -> XXXX * - Receivable accounts -> Debit -> XXXX
* - Income -> Credit -> XXXX * - Income -> Credit -> XXXX
* *
* - Cost of goods sold -> Debit -> YYYY * - Cost of goods sold -> Debit -> YYYY
* - Inventory assets -> YYYY * - Inventory assets -> YYYY
* *
* @param {ISaleInvoice} saleInvoice * @param {ISaleInvoice} saleInvoice
* @param {JournalPoster} journal * @param {JournalPoster} journal
*/ */
saleInvoice( saleInvoice(
saleInvoice: ISaleInvoice & { saleInvoice: ISaleInvoice & {
costTransactions: IInventoryLotCost[], costTransactions: IInventoryLotCost[];
entries: IItemEntry & { item: IItem }, entries: IItemEntry & { item: IItem };
}, },
receivableAccountsId: number, receivableAccountsId: number
) { ) {
let inventoryTotal: number = 0; let inventoryTotal: number = 0;
@@ -441,8 +484,9 @@ export default class JournalCommands{
}; };
const costTransactions: Map<number, number> = new Map( const costTransactions: Map<number, number> = new Map(
saleInvoice.costTransactions.map((trans: IInventoryLotCost) => [ saleInvoice.costTransactions.map((trans: IInventoryLotCost) => [
trans.entryId, trans.cost, trans.entryId,
]), trans.cost,
])
); );
// XXX Debit - Receivable account. // XXX Debit - Receivable account.
const receivableEntry = new JournalEntry({ const receivableEntry = new JournalEntry({
@@ -453,50 +497,52 @@ export default class JournalCommands{
}); });
this.journal.debit(receivableEntry); this.journal.debit(receivableEntry);
saleInvoice.entries.forEach((entry: IItemEntry & { item: IItem }, index) => { saleInvoice.entries.forEach(
const cost: number = costTransactions.get(entry.id); (entry: IItemEntry & { item: IItem }, index) => {
const income: number = entry.quantity * entry.rate; const cost: number = costTransactions.get(entry.id);
const income: number = entry.quantity * entry.rate;
if (entry.item.type === 'inventory' && cost) {
// XXX Debit - Cost account.
const costEntry = new JournalEntry({
...commonEntry,
debit: cost,
account: entry.item.costAccountId,
note: entry.description,
index: index + 3,
});
this.journal.debit(costEntry);
inventoryTotal += cost;
}
// XXX Credit - Income account.
const incomeEntry = new JournalEntry({
...commonEntry,
credit: income,
account: entry.item.sellAccountId,
note: entry.description,
index: index + 2,
});
this.journal.credit(incomeEntry);
if (inventoryTotal > 0) { if (entry.item.type === 'inventory' && cost) {
// XXX Credit - Inventory account. // XXX Debit - Cost account.
const inventoryEntry = new JournalEntry({ const costEntry = new JournalEntry({
...commonEntry,
debit: cost,
account: entry.item.costAccountId,
note: entry.description,
index: index + 3,
});
this.journal.debit(costEntry);
inventoryTotal += cost;
}
// XXX Credit - Income account.
const incomeEntry = new JournalEntry({
...commonEntry, ...commonEntry,
credit: inventoryTotal, credit: income,
account: entry.item.inventoryAccountId, account: entry.item.sellAccountId,
index: index + 4, note: entry.description,
index: index + 2,
}); });
this.journal.credit(inventoryEntry); this.journal.credit(incomeEntry);
if (inventoryTotal > 0) {
// XXX Credit - Inventory account.
const inventoryEntry = new JournalEntry({
...commonEntry,
credit: inventoryTotal,
account: entry.item.inventoryAccountId,
index: index + 4,
});
this.journal.credit(inventoryEntry);
}
} }
}); );
} }
saleInvoiceNonInventory( saleInvoiceNonInventory(
saleInvoice: ISaleInvoice & { saleInvoice: ISaleInvoice & {
entries: IItemEntry & { item: IItem }, entries: IItemEntry & { item: IItem };
}, },
receivableAccountsId: number, receivableAccountsId: number
) { ) {
const commonEntry = { const commonEntry = {
referenceType: 'SaleInvoice', referenceType: 'SaleInvoice',
@@ -513,18 +559,20 @@ export default class JournalCommands{
}); });
this.journal.debit(receivableEntry); this.journal.debit(receivableEntry);
saleInvoice.entries.forEach((entry: IItemEntry & { item: IItem }, index: number) => { saleInvoice.entries.forEach(
const income: number = entry.quantity * entry.rate; (entry: IItemEntry & { item: IItem }, index: number) => {
const income: number = entry.quantity * entry.rate;
// XXX Credit - Income account.
const incomeEntry = new JournalEntry({ // XXX Credit - Income account.
...commonEntry, const incomeEntry = new JournalEntry({
credit: income, ...commonEntry,
account: entry.item.sellAccountId, credit: income,
note: entry.description, account: entry.item.sellAccountId,
index: index + 2, note: entry.description,
}); index: index + 2,
this.journal.credit(incomeEntry); });
}); this.journal.credit(incomeEntry);
}
);
} }
} }

View File

@@ -17,6 +17,8 @@ import {
IContactEditDTO, IContactEditDTO,
IContact, IContact,
ISaleInvoice, ISaleInvoice,
ISystemService,
ISystemUser,
} from 'interfaces'; } from 'interfaces';
import { ServiceError } from 'exceptions'; import { ServiceError } from 'exceptions';
import TenancyService from 'services/Tenancy/TenancyService'; import TenancyService from 'services/Tenancy/TenancyService';
@@ -90,20 +92,20 @@ export default class CustomersService {
*/ */
public async newCustomer( public async newCustomer(
tenantId: number, tenantId: number,
customerDTO: ICustomerNewDTO customerDTO: ICustomerNewDTO,
authorizedUser: ISystemUser
): Promise<ICustomer> { ): Promise<ICustomer> {
this.logger.info('[customer] trying to create a new customer.', { this.logger.info('[customer] trying to create a new customer.', {
tenantId, tenantId,
customerDTO, customerDTO,
}); });
const customerObj = this.transformNewCustomerDTO(customerDTO); const customerObj = this.transformNewCustomerDTO(customerDTO);
const customer = await this.contactService.newContact( const customer = await this.contactService.newContact(
tenantId, tenantId,
customerObj, customerObj,
'customer' 'customer'
); );
this.logger.info('[customer] created successfully.', { this.logger.info('[customer] created successfully.', {
tenantId, tenantId,
customerDTO, customerDTO,
@@ -112,6 +114,7 @@ export default class CustomersService {
customer, customer,
tenantId, tenantId,
customerId: customer.id, customerId: customer.id,
authorizedUser,
}); });
return customer; return customer;
@@ -127,7 +130,8 @@ export default class CustomersService {
public async editCustomer( public async editCustomer(
tenantId: number, tenantId: number,
customerId: number, customerId: number,
customerDTO: ICustomerEditDTO customerDTO: ICustomerEditDTO,
authorizedUser: ISystemUser
): Promise<ICustomer> { ): Promise<ICustomer> {
const contactDTO = this.customerToContactDTO(customerDTO); const contactDTO = this.customerToContactDTO(customerDTO);
@@ -143,11 +147,13 @@ export default class CustomersService {
'customer' 'customer'
); );
// Triggers `onCustomerEdited` event.
this.eventDispatcher.dispatch(events.customers.onEdited); this.eventDispatcher.dispatch(events.customers.onEdited);
this.logger.info('[customer] edited successfully.', { this.logger.info('[customer] edited successfully.', {
tenantId, tenantId,
customerId, customerId,
customer, customer,
authorizedUser,
}); });
return customer; return customer;
@@ -161,7 +167,8 @@ export default class CustomersService {
*/ */
public async deleteCustomer( public async deleteCustomer(
tenantId: number, tenantId: number,
customerId: number customerId: number,
authorizedUser: ISystemUser
): Promise<void> { ): Promise<void> {
this.logger.info('[customer] trying to delete customer.', { this.logger.info('[customer] trying to delete customer.', {
tenantId, tenantId,
@@ -184,6 +191,7 @@ export default class CustomersService {
this.logger.info('[customer] deleted successfully.', { this.logger.info('[customer] deleted successfully.', {
tenantId, tenantId,
customerId, customerId,
authorizedUser,
}); });
} }
@@ -192,7 +200,11 @@ export default class CustomersService {
* @param {number} tenantId * @param {number} tenantId
* @param {number} customerId * @param {number} customerId
*/ */
public async getCustomer(tenantId: number, customerId: number) { public async getCustomer(
tenantId: number,
customerId: number,
authorizedUser: ISystemUser
) {
const contact = await this.contactService.getContact( const contact = await this.contactService.getContact(
tenantId, tenantId,
customerId, customerId,
@@ -245,7 +257,8 @@ export default class CustomersService {
tenantId: number, tenantId: number,
customerId: number, customerId: number,
openingBalance: number, openingBalance: number,
openingBalanceAt: Date | string openingBalanceAt: Date | string,
authorizedUserId: number
) { ) {
const journal = new JournalPoster(tenantId); const journal = new JournalPoster(tenantId);
const journalCommands = new JournalCommands(journal); const journalCommands = new JournalCommands(journal);
@@ -253,7 +266,8 @@ export default class CustomersService {
await journalCommands.customerOpeningBalance( await journalCommands.customerOpeningBalance(
customerId, customerId,
openingBalance, openingBalance,
openingBalanceAt openingBalanceAt,
authorizedUserId
); );
await Promise.all([journal.saveBalance(), journal.saveEntries()]); await Promise.all([journal.saveBalance(), journal.saveEntries()]);
} }
@@ -316,7 +330,11 @@ export default class CustomersService {
* @param {number[]} customersIds * @param {number[]} customersIds
* @return {Promise<void>} * @return {Promise<void>}
*/ */
public async deleteBulkCustomers(tenantId: number, customersIds: number[]) { public async deleteBulkCustomers(
tenantId: number,
customersIds: number[],
authorizedUser: ISystemUser,
): Promise<void> {
const { Contact } = this.tenancy.models(tenantId); const { Contact } = this.tenancy.models(tenantId);
// Validate the customers existance on the storage. // Validate the customers existance on the storage.
@@ -332,6 +350,7 @@ export default class CustomersService {
await this.eventDispatcher.dispatch(events.customers.onBulkDeleted, { await this.eventDispatcher.dispatch(events.customers.onBulkDeleted, {
tenantId, tenantId,
customersIds, customersIds,
authorizedUser,
}); });
} }

View File

@@ -14,6 +14,7 @@ import {
IVendorsFilter, IVendorsFilter,
IPaginationMeta, IPaginationMeta,
IFilterMeta, IFilterMeta,
ISystemUser,
} from 'interfaces'; } from 'interfaces';
import { ServiceError } from 'exceptions'; import { ServiceError } from 'exceptions';
import DynamicListingService from 'services/DynamicListing/DynamicListService'; import DynamicListingService from 'services/DynamicListing/DynamicListService';
@@ -55,24 +56,28 @@ export default class VendorsService {
* @param {IVendorNewDTO} vendorDTO * @param {IVendorNewDTO} vendorDTO
* @return {Promise<void>} * @return {Promise<void>}
*/ */
public async newVendor(tenantId: number, vendorDTO: IVendorNewDTO) { public async newVendor(
tenantId: number,
vendorDTO: IVendorNewDTO,
authorizedUser: ISystemUser
) {
this.logger.info('[vendor] trying create a new vendor.', { this.logger.info('[vendor] trying create a new vendor.', {
tenantId, tenantId,
vendorDTO, vendorDTO,
}); });
const contactDTO = this.vendorToContactDTO(vendorDTO); const contactDTO = this.vendorToContactDTO(vendorDTO);
const vendor = await this.contactService.newContact( const vendor = await this.contactService.newContact(
tenantId, tenantId,
contactDTO, contactDTO,
'vendor' 'vendor'
); );
// Triggers `onVendorCreated` event. // Triggers `onVendorCreated` event.
await this.eventDispatcher.dispatch(events.vendors.onCreated, { await this.eventDispatcher.dispatch(events.vendors.onCreated, {
tenantId, tenantId,
vendorId: vendor.id, vendorId: vendor.id,
vendor, vendor,
authorizedUser,
}); });
return vendor; return vendor;
} }
@@ -85,7 +90,8 @@ export default class VendorsService {
public async editVendor( public async editVendor(
tenantId: number, tenantId: number,
vendorId: number, vendorId: number,
vendorDTO: IVendorEditDTO vendorDTO: IVendorEditDTO,
authorizedUser: ISystemUser
) { ) {
const contactDTO = this.vendorToContactDTO(vendorDTO); const contactDTO = this.vendorToContactDTO(vendorDTO);
const vendor = await this.contactService.editContact( const vendor = await this.contactService.editContact(
@@ -95,8 +101,13 @@ export default class VendorsService {
'vendor' 'vendor'
); );
await this.eventDispatcher.dispatch(events.vendors.onEdited); // Triggers `onVendorEdited` event.
await this.eventDispatcher.dispatch(events.vendors.onEdited, {
tenantId,
vendorId,
vendor,
authorizedUser,
});
return vendor; return vendor;
} }
@@ -119,8 +130,15 @@ export default class VendorsService {
* @param {number} vendorId * @param {number} vendorId
* @return {Promise<void>} * @return {Promise<void>}
*/ */
public async deleteVendor(tenantId: number, vendorId: number) { public async deleteVendor(
tenantId: number,
vendorId: number,
authorizedUser: ISystemUser
) {
// Validate the vendor existance on the storage.
await this.getVendorByIdOrThrowError(tenantId, vendorId); await this.getVendorByIdOrThrowError(tenantId, vendorId);
// Validate the vendor has no associated bills.
await this.vendorHasNoBillsOrThrowError(tenantId, vendorId); await this.vendorHasNoBillsOrThrowError(tenantId, vendorId);
this.logger.info('[vendor] trying to delete vendor.', { this.logger.info('[vendor] trying to delete vendor.', {
@@ -129,9 +147,11 @@ export default class VendorsService {
}); });
await this.contactService.deleteContact(tenantId, vendorId, 'vendor'); await this.contactService.deleteContact(tenantId, vendorId, 'vendor');
// Triggers `onVendorDeleted` event.
await this.eventDispatcher.dispatch(events.vendors.onDeleted, { await this.eventDispatcher.dispatch(events.vendors.onDeleted, {
tenantId, tenantId,
vendorId, vendorId,
authorizedUser,
}); });
this.logger.info('[vendor] deleted successfully.', { tenantId, vendorId }); this.logger.info('[vendor] deleted successfully.', { tenantId, vendorId });
} }
@@ -155,7 +175,9 @@ export default class VendorsService {
public async writeVendorOpeningBalanceJournal( public async writeVendorOpeningBalanceJournal(
tenantId: number, tenantId: number,
vendorId: number, vendorId: number,
openingBalance: number openingBalance: number,
openingBalanceAt: Date | string,
user: ISystemUser
) { ) {
const journal = new JournalPoster(tenantId); const journal = new JournalPoster(tenantId);
const journalCommands = new JournalCommands(journal); const journalCommands = new JournalCommands(journal);
@@ -164,8 +186,12 @@ export default class VendorsService {
tenantId, tenantId,
vendorId, vendorId,
}); });
await journalCommands.vendorOpeningBalance(vendorId, openingBalance); await journalCommands.vendorOpeningBalance(
vendorId,
openingBalance,
openingBalanceAt,
user
);
await Promise.all([journal.saveBalance(), journal.saveEntries()]); await Promise.all([journal.saveBalance(), journal.saveEntries()]);
} }
@@ -183,7 +209,7 @@ export default class VendorsService {
this.logger.info( this.logger.info(
'[customer] trying to revert opening balance journal entries.', '[customer] trying to revert opening balance journal entries.',
{ tenantId, customerId } { tenantId, vendorId }
); );
await this.contactService.revertJEntriesContactsOpeningBalance( await this.contactService.revertJEntriesContactsOpeningBalance(
tenantId, tenantId,
@@ -216,7 +242,8 @@ export default class VendorsService {
*/ */
public async deleteBulkVendors( public async deleteBulkVendors(
tenantId: number, tenantId: number,
vendorsIds: number[] vendorsIds: number[],
authorizedUser: ISystemUser
): Promise<void> { ): Promise<void> {
const { Contact } = this.tenancy.models(tenantId); const { Contact } = this.tenancy.models(tenantId);
@@ -228,9 +255,11 @@ export default class VendorsService {
await Contact.query().whereIn('id', vendorsIds).delete(); await Contact.query().whereIn('id', vendorsIds).delete();
// Triggers `onVendorsBulkDeleted` event.
await this.eventDispatcher.dispatch(events.vendors.onBulkDeleted, { await this.eventDispatcher.dispatch(events.vendors.onBulkDeleted, {
tenantId, tenantId,
vendorsIds, vendorsIds,
authorizedUser,
}); });
this.logger.info('[vendor] bulk deleted successfully.', { this.logger.info('[vendor] bulk deleted successfully.', {
@@ -266,7 +295,7 @@ export default class VendorsService {
*/ */
private async vendorsHaveNoBillsOrThrowError( private async vendorsHaveNoBillsOrThrowError(
tenantId: number, tenantId: number,
vendorsIds: number[], vendorsIds: number[]
) { ) {
const { billRepository } = this.tenancy.repositories(tenantId); const { billRepository } = this.tenancy.repositories(tenantId);
@@ -299,12 +328,12 @@ export default class VendorsService {
filterMeta: IFilterMeta; filterMeta: IFilterMeta;
}> { }> {
const { Vendor } = this.tenancy.models(tenantId); const { Vendor } = this.tenancy.models(tenantId);
const dynamicFilter = await this.dynamicListService.dynamicList( const dynamicFilter = await this.dynamicListService.dynamicList(
tenantId, tenantId,
Vendor, Vendor,
vendorsFilter vendorsFilter
); );
const { results, pagination } = await Vendor.query() const { results, pagination } = await Vendor.query()
.onBuild((builder) => { .onBuild((builder) => {
dynamicFilter.buildQuery()(builder); dynamicFilter.buildQuery()(builder);

View File

@@ -19,8 +19,12 @@ export default class CustomersSubscriber {
* Handles the writing opening balance journal entries once the customer created. * Handles the writing opening balance journal entries once the customer created.
*/ */
@On(events.customers.onCreated) @On(events.customers.onCreated)
async handleWriteOpenBalanceEntries({ tenantId, customerId, customer }) { async handleWriteOpenBalanceEntries({
tenantId,
customerId,
customer,
authorizedUser,
}) {
// Writes the customer opening balance journal entries. // Writes the customer opening balance journal entries.
if (customer.openingBalance) { if (customer.openingBalance) {
await this.customersService.writeCustomerOpeningBalanceJournal( await this.customersService.writeCustomerOpeningBalanceJournal(
@@ -28,6 +32,7 @@ export default class CustomersSubscriber {
customer.id, customer.id,
customer.openingBalance, customer.openingBalance,
customer.openingBalanceAt, customer.openingBalanceAt,
authorizedUser.id
); );
} }
} }
@@ -36,10 +41,14 @@ export default class CustomersSubscriber {
* Handles the deleting opeing balance journal entrise once the customer deleted. * Handles the deleting opeing balance journal entrise once the customer deleted.
*/ */
@On(events.customers.onDeleted) @On(events.customers.onDeleted)
async handleRevertOpeningBalanceEntries({ tenantId, customerId }) { async handleRevertOpeningBalanceEntries({
tenantId,
customerId,
authorizedUser,
}) {
await this.customersService.revertOpeningBalanceEntries( await this.customersService.revertOpeningBalanceEntries(
tenantId, customerId, tenantId,
customerId
); );
} }
@@ -48,10 +57,14 @@ export default class CustomersSubscriber {
* customers deleted. * customers deleted.
*/ */
@On(events.customers.onBulkDeleted) @On(events.customers.onBulkDeleted)
async handleBulkRevertOpeningBalanceEntries({ tenantId, customersIds }) { async handleBulkRevertOpeningBalanceEntries({
tenantId,
customersIds,
authorizedUser,
}) {
await this.customersService.revertOpeningBalanceEntries( await this.customersService.revertOpeningBalanceEntries(
tenantId, customersIds, tenantId,
customersIds
); );
} }
} }

View File

@@ -22,13 +22,15 @@ export default class VendorsSubscriber {
* Writes the open balance journal entries once the vendor created. * Writes the open balance journal entries once the vendor created.
*/ */
@On(events.vendors.onCreated) @On(events.vendors.onCreated)
async handleWriteOpeningBalanceEntries({ tenantId, vendorId, vendor }) { async handleWriteOpeningBalanceEntries({ tenantId, vendorId, vendor, authorizedUser }) {
// Writes the vendor opening balance journal entries. // Writes the vendor opening balance journal entries.
if (vendor.openingBalance) { if (vendor.openingBalance) {
await this.vendorsService.writeVendorOpeningBalanceJournal( await this.vendorsService.writeVendorOpeningBalanceJournal(
tenantId, tenantId,
vendor.id, vendor.id,
vendor.openingBalance, vendor.openingBalance,
vendor.openingBalanceAt,
authorizedUser.id
); );
} }
} }
@@ -37,7 +39,7 @@ export default class VendorsSubscriber {
* Revert the opening balance journal entries once the vendor deleted. * Revert the opening balance journal entries once the vendor deleted.
*/ */
@On(events.vendors.onDeleted) @On(events.vendors.onDeleted)
async handleRevertOpeningBalanceEntries({ tenantId, vendorId }) { async handleRevertOpeningBalanceEntries({ tenantId, vendorId, authorizedUser }) {
await this.vendorsService.revertOpeningBalanceEntries( await this.vendorsService.revertOpeningBalanceEntries(
tenantId, vendorId, tenantId, vendorId,
); );
@@ -47,7 +49,7 @@ export default class VendorsSubscriber {
* Revert the opening balance journal entries once the vendors deleted in bulk. * Revert the opening balance journal entries once the vendors deleted in bulk.
*/ */
@On(events.vendors.onBulkDeleted) @On(events.vendors.onBulkDeleted)
async handleBulkRevertOpeningBalanceEntries({ tenantId, vendorsIds }) { async handleBulkRevertOpeningBalanceEntries({ tenantId, vendorsIds, authorizedUser }) {
await this.vendorsService.revertOpeningBalanceEntries( await this.vendorsService.revertOpeningBalanceEntries(
tenantId, vendorsIds, tenantId, vendorsIds,
); );