- feat: Sales estimates.

- feat: Sales invoices.
- feat: Sales payment receives.
- feat: Purchases bills.
- feat: Purchases bills payments that made to the vendors.
This commit is contained in:
Ahmed Bouhuolia
2020-08-03 22:46:50 +02:00
parent 56278a25f0
commit db28cd2aef
56 changed files with 3290 additions and 1208 deletions

View File

@@ -1,9 +1,24 @@
import { Account } from '@/models';
import { Account, AccountType } from '@/models';
export default class AccountsService {
static async isAccountExists(accountId) {
const foundAccounts = await Account.tenant().query().where('id', accountId);
return foundAccounts.length > 0;
}
}
static async getAccountByType(accountTypeKey) {
const accountType = await AccountType.tenant()
.query()
.where('key', accountTypeKey)
.first();
const account = await Account.tenant()
.query()
.where('account_type_id', accountType.id)
.first();
console.log(account);
return account;
}
}

View File

@@ -0,0 +1,16 @@
import { InventoryTransaction } from "../../models";
export default class InventoryService {
async isInventoryPurchaseSold(transactionType, transactionId) {
}
static deleteTransactions(transactionId, transactionType) {
return InventoryTransaction.tenant().query()
.where('transaction_type', transactionType)
.where('transaction_id', transactionId)
.delete();
}
}

View File

@@ -1,30 +1,244 @@
import { omit } from "lodash";
import { BillPayment } from '@/models';
export default class BillPaymentsService {
import express from 'express';
import { omit } from 'lodash';
import { check, query, validationResult, param } from 'express-validator';
import { BillPayment, BillPaymentEntry, Vendor } from '@/models';
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
import ServiceItemsEntries from '../Sales/ServiceItemsEntries';
import AccountsService from '../Accounts/AccountsService';
import JournalPoster from '../Accounting/JournalPoster';
import JournalEntry from '../Accounting/JournalEntry';
export default class BillPaymentsService {
/**
* Creates a new bill payment transcations and store it to the storage
* with associated bills entries and journal transactions.
*
* Precedures
* ------
* - Records the bill payment transaction.
* - Records the bill payment associated entries.
* - Increment the payment amount of the given vendor bills.
* - Decrement the vendor balance.
* - Records payment journal entries.
*
* @param {IBillPayment} billPayment
*/
static async createBillPayment(billPayment) {
const storedBillPayment = await BillPayment.tenant().query().insert({
...omit(billPayment, ['entries']),
const amount = sumBy(billPayment.entries, 'paymentAmount');
const storedBillPayment = await BillPayment.tenant()
.query()
.insert({
amount,
...omit(billPayment, ['entries']),
});
const storeOpers = [];
billPayment.entries.forEach((entry) => {
const oper = BillPaymentEntry.tenant()
.query()
.insert({
bill_payment_id: storedBillPayment.id,
...entry,
});
// Increment the bill payment amount.
const billOper = BillPayment.changePaymentAmount(
entry.billId,
entry.paymentAmount
);
storeOpers.push(billOper);
storeOpers.push(oper);
});
// Decrement the vendor balance after bills payments.
const vendorDecrementOper = Vendor.changeBalanace(
billPayment.vendor_id,
amount * -1
);
// Records the journal transactions after bills payment
// and change diff acoount balance.
const recordJournalTransaction = this.recordPaymentReceiveJournalEntries({
id: storedBillPayment.id,
...billPayment,
});
await Promise.all([
...storeOpers,
recordJournalTransaction,
vendorDecrementOper,
]);
return storedBillPayment;
}
editBillPayment(billPaymentId, billPayment) {
/**
* Edits the details of the given bill payment.
*
* Preceducres.
* -------
* - Update the bill payment transaction.
* - Insert the new bill payment entries that have no ids.
* - Update the bill paymeny entries that have ids.
* - Delete the bill payment entries that not presented.
* - Re-insert the journal transactions and update the diff accounts balance.
* - Update the diff vendor balance.
* - Update the diff bill payment amount.
*
* @param {Integer} billPaymentId
* @param {IBillPayment} billPayment
* @param {IBillPayment} oldBillPayment
*/
static async editBillPayment(billPaymentId, billPayment, oldBillPayment) {
const amount = sumBy(bilPayment.entries, 'payment_amount');
const updateBillPayment = await BillPayment.tenant()
.query()
.where('id', billPaymentId)
.update({
amount,
...omit(billPayment, ['entries']),
});
const opers = [];
const entriesHasIds = billpayment.entries.filter((i) => i.id);
const entriesHasNoIds = billPayment.entries.filter((e) => !e.id);
const entriesIds = entriesHasIds.map((e) => e.id);
const entriesIdsShouldDelete = ServiceItemsEntries.entriesShouldDeleted(
oldBillPayment.entries,
entriesHasIds
);
if (entriesIdsShouldDelete.length > 0) {
const deleteOper = BillPaymentEntry.tenant()
.query()
.bulkDelete(entriesIdsShouldDelete);
opers.push(deleteOper);
}
// Entries that should be update to the storage.
if (entriesHasIds.length > 0) {
const updateOper = BillPaymentEntry.tenant()
.query()
.bulkUpdate(entriesHasIds, { where: 'id' });
opers.push(updateOper);
}
// Entries that should be inserted to the storage.
if (entriesHasNoIds.length > 0) {
const insertOper = BillPaymentEntry.tenant()
.query()
.bulkInsert(
entriesHasNoIds.map((e) => ({ ...e, bill_payment_id: billPaymentId }))
);
opers.push(insertOper);
}
// Records the journal transactions after bills payment and change
// different acoount balance.
const recordJournalTransaction = this.recordPaymentReceiveJournalEntries({
id: storedBillPayment.id,
...billPayment,
});
// Change the different vendor balance between the new and old one.
const changeDiffBalance = Vendor.changeDiffBalance(
billPayment.vendor_id,
oldBillPayment.vendor_id,
billPayment.amount,
oldBillPayment.amount
);
await Promise.all([
...opers,
recordJournalTransaction,
changeDiffBalance,
]);
}
static async isBillPaymentExists(billPaymentId) {
const foundBillPayments = await BillPayment.tenant().query().where('id', billPaymentId);
return foundBillPayments.lengh > 0;
/**
* Deletes the bill payment and associated transactions.
* @param {Integer} billPaymentId -
* @return {Promise}
*/
static async deleteBillPayment(billPaymentId) {
const billPayment = await BillPayment.tenant().query().where('id', billPaymentId).first();
await BillPayment.tenant().query().where('id', billPaymentId).delete();
await BillPaymentEntry.tenant()
.query()
.where('bill_payment_id', billPaymentId)
.delete();
const deleteTransactionsOper = this.deleteJournalTransactions(
billPaymentId,
'BillPayment'
);
const revertVendorBalance = Vendor.changeBalanace(
billpayment.vendor_id,
billPayment.amount * -1,
);
return Promise.all([
deleteTransactionsOper,
revertVendorBalance,
]);
}
static async isBillPaymentNumberExists(billPaymentNumber) {
const foundPayments = await Bill.tenant().query().where('bill_payment_number', billPaymentNumber);
return foundPayments.length > 0;
/**
* Records bill payment receive journal transactions.
* @param {BillPayment} billPayment
* @param {Integer} billPaymentId
*/
static async recordPaymentReceiveJournalEntries(billPayment) {
const paymentAmount = sumBy(billPayment.entries, 'payment_amount');
const formattedDate = moment(billPayment.payment_date).format('YYYY-MM-DD');
const payableAccount = await AccountsService.getAccountByType(
'accounts_payable'
);
const accountsDepGraph = await Account.tenant().depGraph().query();
const journal = new JournalPoster(accountsDepGraph);
const commonJournal = {
debit: 0,
credit: 0,
referenceId: billPayment.id,
referenceType: 'BillPayment',
date: formattedDate,
};
if (billPayment.id) {
const transactions = await AccountTransaction.tenant()
.query()
.whereIn('reference_type', ['BillPayment'])
.where('reference_id', billPayment.id)
.withGraphFetched('account.type');
journal.loadEntries(transactions);
journal.removeEntries();
}
const debitReceivable = new JournalEntry({
...commonJournal,
debit: paymentAmount,
contactType: 'Vendor',
contactId: billpayment.vendor_id,
account: payableAccount.id,
});
const creditPaymentAccount = new JournalEntry({
...commonJournal,
credit: paymentAmount,
account: billPayment.payment_account_id,
});
journal.debit(debitReceivable);
journal.credit(creditPaymentAccount);
await Promise.all([
journal.deleteEntries(),
journal.saveEntries(),
journal.saveBalance(),
]);
}
isBillPaymentsExist(billPaymentIds) {
static async getBillPayment(billPaymentId) {
}
}
/**
* Detarmines whether the bill payment exists on the storage.
* @param {Integer} billPaymentId
*/
static async isBillPaymentExists(billPaymentId) {
const billPayment = await BillPayment.tenant().query()
.where('id', billPaymentId)
.first();
return billPayment.length > 0;
}
}

View File

@@ -1,96 +1,316 @@
import { omit } from 'lodash';
import { Bill, BillPayment } from '@/models';
import { Item } from '@/models';
import { Account } from '../../models';
import JournalPoster from '../Accounting/JournalPoster';
import { omit, sumBy, difference } from 'lodash';
import moment from 'moment';
import {
Bill,
Vendor,
InventoryTransaction,
ItemEntry,
Item,
Account,
} from '@/models';
import JournalPoster from '@/services/Accounting/JournalPoster';
import JournalEntry from '@/services/Accounting/JournalEntry';
import AccountsService from '@/services/Accounts/AccountsService';
import JournalPosterService from '@/services/Sales/JournalPosterService';
import InventoryService from '../Inventory/Inventory';
import { AccountTransaction } from '../../models';
/**
* Vendor bills services.
*/
export default class BillsService {
/**
* Creates a new bill and stored it to the storage.
*
* Precedures.
* ----
* - Insert bill transactions to the storage.
* - Insert bill entries to the storage.
* - Increment the given vendor id.
* - Record bill journal transactions on the given accounts.
* - Record bill items inventory transactions.
*
* @param {IBill} bill -
* @return {void}
*/
static async createBill(bill) {
const storedBill = await Bill.tenant().query().insert({
...omit(bill, ['entries']),
const amount = sumBy(bill.entries, 'amount');
const saveEntriesOpers = [];
const storedBill = await Bill.tenant()
.query()
.insert({
amount,
...omit(bill, ['entries']),
});
bill.entries.forEach((entry) => {
const oper = ItemEntry.tenant()
.query()
.insert({
reference_type: 'Bill',
reference_id: storedBill.id,
...omit(entry, ['amount']),
});
saveEntriesOpers.push(oper);
});
// Increment vendor balance.
const incrementOper = Vendor.changeBalance(bill.vendor_id, amount);
await Promise.all([
...saveEntriesOpers,
incrementOper,
this.recordInventoryTransactions(bill, storedBill.id),
this.recordJournalTransactions({ ...bill, id: storedBill.id }),
]);
return storedBill;
}
/**
* Patch items entries to the storage.
*
* @param {Array} newEntries
* @param {Array} oldEntries
* @param {String} referenceType
*
* @return {Promise}
*/
static async patchItemsEntries(newEntries, oldEntries, referenceType, billId) {
const entriesHasIds = newEntries.filter((entry) => entry.id);
const entriesHasNoIds = newEntries.filter((entry) => !entry.id);
const entriesIds = entriesHasIds.map(entry => entry.id);
const oldEntriesIds = oldEntries.map((e) => e.id);
const opers = [];
const entriesIdsShouldDelete = difference(
oldEntriesIds,
entriesIds,
);
if (entriesIdsShouldDelete.length > 0) {
const deleteOper = ItemEntry.tenant()
.query()
.whereIn('id', entriesIdsShouldDelete)
.delete();
opers.push(deleteOper);
}
entriesHasIds.forEach((entry) => {
const updateOper = ItemEntry.tenant()
.query()
.where('id', entry.id)
.update({
...omit(entry, ['id']),
});
opers.push(updateOper);
});
entriesHasNoIds.forEach((entry) => {
const insertOper = ItemEntry.tenant()
.query()
.insert({
reference_id: billId,
reference_type: referenceType,
...omit(entry, ['id', 'amount']),
});
opers.push(insertOper);
});
return Promise.all([...opers]);
};
/**
* Edits details of the given bill id with associated entries.
* @param {Integer} billId
* @param {IBill} bill
*
* Precedures:
* -------
* - Update the bill transaction on the storage.
* - Update the bill entries on the storage and insert the not have id and delete
* once that not presented.
* - Increment the diff amount on the given vendor id.
* - Re-write the inventory transactions.
* - Re-write the bill journal transactions.
*
* @param {Integer} billId
* @param {IBill} bill
*/
static async editBill(billId, bill) {
const updatedBill = await Bill.tenant().query().insert({
...omit(bill, ['entries']),
const amount = sumBy(bill.entries, 'amount');
// Update the bill transaction.
const updatedBill = await Bill.tenant()
.query()
.where('id', billId)
.update({
amount,
...omit(bill, ['entries'])
});
// Old stored entries.
const storedEntries = await ItemEntry.tenant()
.query()
.where('reference_id', billId)
.where('reference_type', 'Bill');
// Patch the bill entries.
const patchEntriesOper = this.patchItemsEntries(bill.entries, storedEntries, 'Bill', billId);
// Record bill journal transactions.
const recordTransactionsOper = this.recordJournalTransactions(bill, billId);
await Promise.all([
patchEntriesOper,
recordTransactionsOper,
]);
}
/**
* Records inventory transactions.
* @param {IBill} bill -
* @return {void}
*/
static async recordInventoryTransactions(bill, billId) {
const storeInventoryTransactions = [];
const entriesItemsIds = bill.entries.map((e) => e.item_id);
const inventoryItems = await Item.tenant()
.query()
.whereIn('id', entriesItemsIds)
.where('type', 'inventory');
const inventoryItemsIds = inventoryItems.map((i) => i.id);
const inventoryEntries = bill.entries.filter(
(entry) => inventoryItemsIds.indexOf(entry.item_id) !== -1
);
inventoryEntries.forEach((entry) => {
const oper = InventoryTransaction.tenant().query().insert({
direction: 'IN',
date: bill.bill_date,
item_id: entry.item_id,
quantity: entry.quantity,
rate: entry.rate,
remaining: entry.quantity,
transaction_type: 'Bill',
transaction_id: billId,
});
storeInventoryTransactions.push(oper);
});
return Promise.all([...storeInventoryTransactions]);
}
/**
* Records the bill journal transactions.
* @param {IBill} bill
* @async
* @param {IBill} bill
* @param {Integer} billId
*/
async recordJournalTransactions(bill) {
const entriesItemsIds = bill.entries.map(entry => entry.item_id);
const payableTotal = sumBy(bill, 'entries.total');
const storedItems = await Item.tenant().query().whereIn('id', entriesItemsIds);
static async recordJournalTransactions(bill, billId) {
const entriesItemsIds = bill.entries.map((entry) => entry.item_id);
const payableTotal = sumBy(bill.entries, 'amount');
const formattedDate = moment(bill.bill_date).format('YYYY-MM-DD');
const payableAccount = await Account.tenant().query();
const formattedDate = moment(saleInvoice.invoice_date).format('YYYY-MM-DD');
const storedItems = await Item.tenant()
.query()
.whereIn('id', entriesItemsIds);
const accountsDepGraph = await Account.depGraph().query().remember();
const storedItemsMap = new Map(storedItems.map((item) => [item.id, item]));
const payableAccount = await AccountsService.getAccountByType(
'accounts_payable'
);
if (!payableAccount) {
throw new Error('New payable account on the storage.');
}
const accountsDepGraph = await Account.tenant().depGraph().query();
const journal = new JournalPoster(accountsDepGraph);
const commonJournalMeta = {
debit: 0,
credit: 0,
referenceId: bill.id,
referenceId: billId,
referenceType: 'Bill',
date: formattedDate,
accural: true,
};
const payableEntry = await JournalEntry({
if (billId) {
const transactions = await AccountTransaction.tenant()
.query()
.whereIn('reference_type', ['Bill'])
.whereIn('reference_id', [billId])
.withGraphFetched('account.type');
journal.loadEntries(transactions);
journal.removeEntries();
}
const payableEntry = new JournalEntry({
...commonJournalMeta,
credit: payableTotal,
contactId: bill.vendorId,
account: payableAccount.id,
contactId: bill.vendor_id,
contactType: 'Vendor',
});
journal.credit(payableEntry);
bill.entries.forEach((item) => {
if (['inventory'].indexOf(item.type) !== -1) {
const inventoryEntry = new JournalEntry({
...commonJournalMeta,
account: item.inventoryAccountId,
});
journal.debit(inventoryEntry);
} else {
const costEntry = new JournalEntry({
...commonJournalMeta,
account: item.costAccountId,
});
journal.debit(costEntry);
}
bill.entries.forEach((entry) => {
const item = storedItemsMap.get(entry.item_id);
const debitEntry = new JournalEntry({
...commonJournalMeta,
debit: entry.amount,
account:
['inventory'].indexOf(item.type) !== -1
? item.inventoryAccountId
: item.costAccountId,
});
journal.debit(debitEntry);
});
await Promise.all([
journal.deleteEntries(),
journal.saveEntries(),
journal.saveBalance(),
])
]);
}
/**
* Deletes the bill with associated entries.
* @param {Integer} billId
* @param {Integer} billId
* @return {void}
*/
static async deleteBill(billId) {
await BillPayment.tenant().query().where('id', billId);
const bill = await Bill.tenant().query().where('id', billId).first();
// Delete all associated bill entries.
const deleteBillEntriesOper = ItemEntry.tenant()
.query()
.where('reference_type', 'Bill')
.where('reference_id', billId)
.delete();
// Delete the bill transaction.
const deleteBillOper = Bill.tenant().query().where('id', billId).delete();
// Delete associated bill journal transactions.
const deleteTransactionsOper = JournalPosterService.deleteJournalTransactions(
billId,
'Bill'
);
// Delete bill associated inventory transactions.
const deleteInventoryTransOper = InventoryService.deleteTransactions(
billId,
'Bill'
);
// Revert vendor balance.
const revertVendorBalance = Vendor.changeBalance(billId, bill.amount * -1);
await Promise.all([
deleteBillOper,
deleteBillEntriesOper,
deleteTransactionsOper,
deleteInventoryTransOper,
revertVendorBalance,
]);
}
/**
* Detarmines whether the bill exists on the storage.
* @param {Integer} billId
* @param {Integer} billId
* @return {Boolean}
*/
static async isBillExists(billId) {
@@ -100,15 +320,31 @@ export default class BillsService {
/**
* Detarmines whether the given bills exist on the storage in bulk.
* @param {Array} billsIds
* @param {Array} billsIds
* @return {Boolean}
*/
isBillsExist(billsIds) {
static async isBillsExist(billsIds) {
const bills = await Bill.tenant().query().whereIn('id', billsIds);
return bills.length > 0;
}
/**
* Detarmines whether the given bill id exists on the storage.
* @param {Integer} billNumber
*/
static async isBillNoExists(billNumber) {
const foundBills = await Bill.tenant().query().where('bill_number', billNumber);
const foundBills = await Bill.tenant()
.query()
.where('bill_number', billNumber);
return foundBills.length > 0;
}
}
/**
* Retrieve the given bill details with associated items entries.
* @param {Integer} billId -
* @returns {Promise}
*/
static getBill(billId) {
return Bill.tenant().query().where('id', billId).first();
}
}

View File

@@ -6,10 +6,10 @@ export default class JournalPosterService {
/**
* Deletes the journal transactions that associated to the given reference id.
*/
static async deleteJournalTransactions(referenceId) {
static async deleteJournalTransactions(referenceId, referenceType) {
const transactions = await AccountTransaction.tenant()
.query()
.whereIn('reference_type', ['SaleInvoice'])
.whereIn('reference_type', [referenceType])
.where('reference_id', referenceId)
.withGraphFetched('account.type');
@@ -21,5 +21,4 @@ export default class JournalPosterService {
await Promise.all([journal.deleteEntries(), journal.saveBalance()]);
}
}
}

View File

@@ -1,116 +1,371 @@
import { omit } from 'lodash';
import { PaymentReceive, PaymentReceiveEntry } from '@/models';
import { omit, sumBy, mapValues, groupBy, chain } from 'lodash';
import moment, { updateLocale } from 'moment';
import {
AccountTransaction,
PaymentReceive,
PaymentReceiveEntry,
SaleInvoice,
Customer,
Account,
} from '@/models';
import AccountsService from '@/services/Accounts/AccountsService';
import JournalPoster from '@/services/Accounting/JournalPoster';
import JournalEntry from '@/services/Accounting/JournalEntry';
import JournalPosterService from '@/services/Sales/JournalPosterService';
import ServiceItemsEntries from '@/services/Sales/ServiceItemsEntries';
import PaymentReceiveEntryRepository from '@/repositories/PaymentReceiveEntryRepository';
import CustomerRepository from '@/repositories/CustomerRepository';
export default class PaymentReceiveService extends JournalPosterService {
/**
* Creates a new payment receive and store it to the storage
* with associated invoices payment and journal transactions.
* @async
* @param {IPaymentReceive} paymentReceive
* @param {IPaymentReceive} paymentReceive
*/
static async createPaymentReceive(paymentReceive) {
const paymentAmount = sumBy(paymentReceive.entries, 'payment_amount');
const storedPaymentReceive = await PaymentReceive.tenant()
.query()
.insert({
amount: paymentAmount,
...omit(paymentReceive, ['entries']),
});
const storeOpers = [];
paymentReceive.entries.forEach((invoice) => {
const oper = PaymentReceiveEntry.tenant().query().insert({
payment_receive_id: storedPaymentReceive.id,
...invoice,
});
storeOpers.push(oper);
});
await Promise.all([ ...storeOpers ]);
paymentReceive.entries.forEach((entry) => {
const oper = PaymentReceiveEntry.tenant()
.query()
.insert({
payment_receive_id: storedPaymentReceive.id,
...entry,
});
// Increment the invoice payment amount.
const invoice = SaleInvoice.tenant()
.query()
.where('id', entry.invoice_id)
.increment('payment_amount', entry.payment_amount);
storeOpers.push(oper);
storeOpers.push(invoice);
});
const customerIncrementOper = Customer.decrementBalance(
paymentReceive.customer_id,
paymentAmount
);
const recordJournalTransactions = this.recordPaymentReceiveJournalEntries({
id: storedPaymentReceive.id,
...paymentReceive,
});
await Promise.all([
...storeOpers,
customerIncrementOper,
recordJournalTransactions,
]);
return storedPaymentReceive;
}
/**
* Edit details the given payment receive with associated entries.
* ------
* - Update the payment receive transactions.
* - Insert the new payment receive entries.
* - Update the given payment receive entries.
* - Delete the not presented payment receive entries.
* - Re-insert the journal transactions and update the different accounts balance.
* - Update the different customer balances.
* - Update the different invoice payment amount.
* @async
* @param {Integer} paymentReceiveId
* @param {IPaymentReceive} paymentReceive
* @param {Integer} paymentReceiveId
* @param {IPaymentReceive} paymentReceive
* @param {IPaymentReceive} oldPaymentReceive
*/
static async editPaymentReceive(paymentReceiveId, paymentReceive) {
const updatePaymentReceive = await PaymentReceive.tenant().query()
static async editPaymentReceive(
paymentReceiveId,
paymentReceive,
oldPaymentReceive
) {
const paymentAmount = sumBy(paymentReceive.entries, 'payment_amount');
// Update the payment receive transaction.
const updatePaymentReceive = await PaymentReceive.tenant()
.query()
.where('id', paymentReceiveId)
.update({
amount: paymentAmount,
...omit(paymentReceive, ['entries']),
});
const storedEntries = await PaymentReceiveEntry.tenant().query()
.where('payment_receive_id', paymentReceiveId);
const entriesIds = paymentReceive.entries.filter(i => i.id);
const opers = [];
const entriesIds = paymentReceive.entries.filter((i) => i.id);
const entriesShouldInsert = paymentReceive.entries.filter((i) => !i.id);
const entriesIdsShouldDelete = this.entriesShouldDeleted(
storedEntries,
entriesIds,
// Detarmines which entries ids should be deleted.
const entriesIdsShouldDelete = ServiceItemsEntries.entriesShouldDeleted(
oldPaymentReceive.entries,
entriesIds
);
if (entriesIdsShouldDelete.length > 0) {
const deleteOper = PaymentReceiveEntry.tenant().query()
.whereIn('id', entriesIdsShouldDelete)
.delete();
// Deletes the given payment receive entries.
const deleteOper = PaymentReceiveEntryRepository.deleteBulk(
entriesIdsShouldDelete
);
opers.push(deleteOper);
}
entriesIds.forEach((entry) => {
const updateOper = PaymentReceiveEntry.tenant()
.query()
.pathAndFetchById(entry.id, {
...omit(entry, ['id']),
});
// Entries that should be updated to the storage.
if (entriesIds.length > 0) {
const updateOper = PaymentReceiveEntryRepository.updateBulk(entriesIds);
opers.push(updateOper);
});
await Promise.all([...opers]);
}
// Entries should insert to the storage.
if (entriesShouldInsert.length > 0) {
const insertOper = PaymentReceiveEntryRepository.insertBulk(
entriesShouldInsert,
paymentReceiveId
);
opers.push(insertOper);
}
// Re-write the journal transactions of the given payment receive.
const recordJournalTransactions = this.recordPaymentReceiveJournalEntries(
{
id: oldPaymentReceive.id,
...paymentReceive,
},
paymentReceiveId
);
// Increment/decrement the customer balance after calc the diff
// between old and new value.
const changeCustomerBalance = CustomerRepository.changeDiffBalance(
paymentReceive.customer_id,
oldPaymentReceive.customerId,
paymentAmount,
oldPaymentReceive.amount,
);
// Change the difference between the old and new invoice payment amount.
const diffInvoicePaymentAmount = this.saveChangeInvoicePaymentAmount(
oldPaymentReceive.entries,
paymentReceive.entries
);
// Await the async operations.
await Promise.all([
...opers,
recordJournalTransactions,
changeCustomerBalance,
diffInvoicePaymentAmount,
]);
}
/**
* Deletes the given payment receive with associated entries
* Deletes the given payment receive with associated entries
* and journal transactions.
* @param {Integer} paymentReceiveId
* -----
* - Deletes the payment receive transaction.
* - Deletes the payment receive associated entries.
* - Deletes the payment receive associated journal transactions.
* - Revert the customer balance.
* - Revert the payment amount of the associated invoices.
* @async
* @param {Integer} paymentReceiveId
*/
static async deletePaymentReceive(paymentReceiveId) {
await PaymentReceive.tenant().query().where('id', paymentReceiveId).delete();
await PaymentReceiveEntry.tenant().query().where('payment_receive_id', paymentReceiveId).delete();
static async deletePaymentReceive(paymentReceiveId, paymentReceive) {
// Deletes the payment receive transaction.
await PaymentReceive.tenant()
.query()
.where('id', paymentReceiveId)
.delete();
await this.deleteJournalTransactions(paymentReceiveId);
// Deletes the payment receive associated entries.
await PaymentReceiveEntry.tenant()
.query()
.where('payment_receive_id', paymentReceiveId)
.delete();
// Delete all associated journal transactions to payment receive transaction.
const deleteTransactionsOper = this.deleteJournalTransactions(
paymentReceiveId,
'PaymentReceive'
);
// Revert the customer balance.
const revertCustomerBalance = Customer.incrementBalance(
paymentReceive.customerId,
paymentReceive.amount
);
// Revert the invoices payments amount.
const revertInvoicesPaymentAmount = this.revertInvoicePaymentAmount(
paymentReceive.entries.map((entry) => ({
invoiceId: entry.invoiceId,
revertAmount: entry.paymentAmount,
}))
);
await Promise.all([
deleteTransactionsOper,
revertCustomerBalance,
revertInvoicesPaymentAmount,
]);
}
/**
* Retrieve the payment receive details of the given id.
* @param {Integer} paymentReceiveId
* @param {Integer} paymentReceiveId
*/
static async getPaymentReceive(paymentReceiveId) {
const paymentReceive = await PaymentReceive.tenant().query().where('id', paymentReceiveId).first();
const paymentReceive = await PaymentReceive.tenant()
.query()
.where('id', paymentReceiveId)
.withGraphFetched('entries')
.first();
return paymentReceive;
}
/**
* Retrieve the payment receive details with associated invoices.
* @param {Integer} paymentReceiveId
* @param {Integer} paymentReceiveId
*/
static async getPaymentReceiveWithInvoices(paymentReceiveId) {
const paymentReceive = await PaymentReceive.tenant().query()
return PaymentReceive.tenant()
.query()
.where('id', paymentReceiveId)
.withGraphFetched('invoices')
.first();
return paymentReceive;
}
/**
* Detarmines whether the payment receive exists on the storage.
* @param {Integer} paymentReceiveId
*/
static async isPaymentReceiveExists(paymentReceiveId) {
const paymentReceives = await PaymentReceive.tenant().query().where('id', paymentReceiveId)
const paymentReceives = await PaymentReceive.tenant()
.query()
.where('id', paymentReceiveId);
return paymentReceives.length > 0;
}
/**
* Detarmines the payment receive number existance.
* @async
* @param {Integer} paymentReceiveNumber - Payment receive number.
* @param {Integer} paymentReceiveId - Payment receive id.
*/
static async isPaymentReceiveNoExists(paymentReceiveNumber) {
const paymentReceives = await PaymentReceive.tenant().query().where('payment_receive_no', paymentReceiveNumber);
static async isPaymentReceiveNoExists(
paymentReceiveNumber,
paymentReceiveId
) {
const paymentReceives = await PaymentReceive.tenant()
.query()
.where('payment_receive_no', paymentReceiveNumber)
.onBuild((query) => {
if (paymentReceiveId) {
query.whereNot('id', paymentReceiveId);
}
});
return paymentReceives.length > 0;
}
}
/**
* Records payment receive journal transactions.
* @async
* @param {IPaymentReceive} paymentReceive
*/
static async recordPaymentReceiveJournalEntries(
paymentReceive,
paymentReceiveId
) {
const paymentAmount = sumBy(paymentReceive.entries, 'payment_amount');
const formattedDate = moment(paymentReceive.payment_date).format(
'YYYY-MM-DD'
);
const receivableAccount = await AccountsService.getAccountByType(
'accounts_receivable'
);
const accountsDepGraph = await Account.tenant().depGraph().query();
const journal = new JournalPoster(accountsDepGraph);
const commonJournal = {
debit: 0,
credit: 0,
referenceId: paymentReceive.id,
referenceType: 'PaymentReceive',
date: formattedDate,
};
if (paymentReceiveId) {
const transactions = await AccountTransaction.tenant()
.query()
.whereIn('reference_type', ['PaymentReceive'])
.where('reference_id', paymentReceiveId)
.withGraphFetched('account.type');
journal.loadEntries(transactions);
journal.removeEntries();
}
const creditReceivable = new JournalEntry({
...commonJournal,
credit: paymentAmount,
contactType: 'Customer',
contactId: paymentReceive.customer_id,
account: receivableAccount.id,
});
const debitDepositAccount = new JournalEntry({
...commonJournal,
debit: paymentAmount,
account: paymentReceive.deposit_account_id,
});
journal.credit(creditReceivable);
journal.debit(debitDepositAccount);
await Promise.all([
journal.deleteEntries(),
journal.saveEntries(),
journal.saveBalance(),
]);
}
/**
* Revert the payment amount of the given invoices ids.
* @param {Array} revertInvoices
*/
static async revertInvoicePaymentAmount(revertInvoices) {
const opers = [];
revertInvoices.forEach((revertInvoice) => {
const { revertAmount, invoiceId } = revertInvoice;
const oper = SaleInvoice.tenant()
.query()
.where('id', invoiceId)
.decrement('payment_amount', revertAmount);
opers.push(oper);
});
await Promise.all(opers);
}
/**
* Saves difference changing between old and new invoice payment amount.
* @param {Array} paymentReceiveEntries
* @param {Array} newPaymentReceiveEntries
* @return
*/
static async saveChangeInvoicePaymentAmount(
paymentReceiveEntries,
newPaymentReceiveEntries
) {
const opers = [];
const newEntriesTable = chain(newPaymentReceiveEntries)
.groupBy('invoice_id')
.mapValues((group) => (sumBy(group, 'payment_amount') || 0) * -1)
.value();
const diffEntries = chain(paymentReceiveEntries)
.groupBy('invoiceId')
.mapValues((group) => (sumBy(group, 'paymentAmount') || 0) * -1)
.mapValues((value, key) => value - (newEntriesTable[key] || 0))
.mapValues((value, key) => ({ invoice_id: key, payment_amount: value }))
.filter((entry) => entry.payment_amount != 0)
.values()
.value();
diffEntries.forEach((diffEntry) => {
const oper = SaleInvoice.changePaymentAmount(
diffEntry.invoice_id,
diffEntry.payment_amount
);
opers.push(oper);
});
return Promise.all([ ...opers ]);
}
}

View File

@@ -1,10 +1,11 @@
import { omit, update, difference } from 'lodash';
import { omit, sumBy, difference } from 'lodash';
import {
SaleInvoice,
SaleInvoiceEntry,
AccountTransaction,
Account,
Item,
ItemEntry,
Customer,
} from '@/models';
import JournalPoster from '@/services/Accounting/JournalPoster';
import ServiceItemsEntries from '@/services/Sales/ServiceItemsEntries';
@@ -17,47 +18,37 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
* @return {ISaleInvoice}
*/
static async createSaleInvoice(saleInvoice) {
const balance = sumBy(saleInvoice.entries, 'amount');
const storedInvoice = await SaleInvoice.tenant()
.query()
.insert({
...omit(saleInvoice, ['entries']),
balance,
payment_amount: 0,
});
const opers = [];
saleInvoice.entries.forEach((entry) => {
const oper = SaleInvoiceEntry.tenant()
const oper = ItemEntry.tenant()
.query()
.insert({
sale_invoice_id: storedInvoice.id,
...entry,
reference_type: 'SaleInvoice',
reference_id: storedInvoice.id,
...omit(entry, ['amount', 'id']),
});
opers.push(oper);
});
await Promise.all([
...opers,
this.recordCreateJournalEntries(saleInvoice),
]);
const incrementOper = Customer.incrementBalance(
saleInvoice.customer_id,
balance,
);
await Promise.all([...opers, incrementOper]);
return storedInvoice;
}
/**
* Calculates total of the sale invoice entries.
* @param {ISaleInvoice} saleInvoice
* @return {ISaleInvoice}
*/
calcSaleInvoiceEntriesTotal(saleInvoice) {
return {
...saleInvoice,
entries: saleInvoice.entries.map((entry) => ({
...entry,
total: 0,
})),
};
}
/**
* Records the journal entries of sale invoice.
* @param {ISaleInvoice} saleInvoice
* @param {ISaleInvoice} saleInvoice
* @return {void}
*/
async recordJournalEntries(saleInvoice) {
@@ -69,8 +60,10 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
const formattedDate = moment(saleInvoice.invoice_date).format('YYYY-MM-DD');
const saleItemsIds = saleInvoice.entries.map((e) => e.item_id);
const storedInvoiceItems = await Item.tenant().query().whereIn('id', saleItemsIds)
const storedInvoiceItems = await Item.tenant()
.query()
.whereIn('id', saleItemsIds);
const commonJournalMeta = {
debit: 0,
credit: 0,
@@ -111,7 +104,6 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
accountNormal: 'debit',
note: '',
});
journal.debit(costEntry);
}
journal.credit(incomeEntry);
@@ -129,9 +121,10 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
*/
static async deleteSaleInvoice(saleInvoiceId) {
await SaleInvoice.tenant().query().where('id', saleInvoiceId).delete();
await SaleInvoiceEntry.tenant()
await ItemEntry.tenant()
.query()
.where('sale_invoice_id', saleInvoiceId)
.where('reference_id', saleInvoiceId)
.where('reference_type', 'SaleInvoice')
.delete();
const invoiceTransactions = await AccountTransaction.tenant()
@@ -151,39 +144,69 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
/**
* Edit the given sale invoice.
* @param {Integer} saleInvoiceId -
* @param {ISaleInvoice} saleInvoice -
* @param {Integer} saleInvoiceId -
* @param {ISaleInvoice} saleInvoice -
*/
static async editSaleInvoice(saleInvoiceId, saleInvoice) {
const updatedSaleInvoices = await SaleInvoice.tenant().query()
const updatedSaleInvoices = await SaleInvoice.tenant()
.query()
.where('id', saleInvoiceId)
.update({
...omit(saleInvoice, ['entries']),
});
const opers = [];
const entriesIds = saleInvoice.entries.filter((entry) => entry.id);
const storedEntries = await SaleInvoiceEntry.tenant().query()
.where('sale_invoice_id', saleInvoiceId);
const entriesNoIds = saleInvoice.entries.filter((entry) => !entry.id);
const storedEntries = await ItemEntry.tenant()
.query()
.where('reference_id', saleInvoiceId)
.where('reference_type', 'SaleInvoice');
const entriesIdsShouldDelete = this.entriesShouldDeleted(
storedEntries,
entriesIds,
entriesIds
);
if (entriesIdsShouldDelete.length > 0) {
const updateOper = SaleInvoiceEntry.tenant().query().where('id', entriesIdsShouldDelete);
const updateOper = ItemEntry.tenant()
.query()
.whereIn('id', entriesIdsShouldDelete)
.delete();
opers.push(updateOper);
}
entriesIds.forEach((entry) => {
const updateOper = SaleInvoiceEntry.tenant()
const updateOper = ItemEntry.tenant()
.query()
.patchAndFetchById(entry.id, {
.where('id', entry.id)
.update({
...omit(entry, ['id']),
});
opers.push(updateOper);
});
entriesNoIds.forEach((entry) => {
const insertOper = ItemEntry.tenant()
.query()
.insert({
reference_type: 'SaleInvoice',
reference_id: saleInvoiceId,
...omit(entry, ['id']),
});
opers.push(insertOper);
})
await Promise.all([...opers]);
}
/**
* Retrieve sale invoice with associated entries.
* @param {Integer} saleInvoiceId
*/
static async getSaleInvoiceWithEntries(saleInvoiceId) {
return SaleInvoice.tenant().query()
.where('id', saleInvoiceId)
.withGraphFetched('entries')
.first();
}
/**
* Detarmines the sale invoice number id exists on the storage.
* @param {Integer} saleInvoiceId
@@ -208,7 +231,7 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
query.where('invoice_no', saleInvoiceNumber);
if (saleInvoiceId) {
query.whereNot('id', saleInvoiceId)
query.whereNot('id', saleInvoiceId);
}
return query;
});
@@ -217,7 +240,7 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
/**
* Detarmine the invoices IDs in bulk and returns the not found ones.
* @param {Array} invoicesIds
* @param {Array} invoicesIds
* @return {Array}
*/
static async isInvoicesExist(invoicesIds) {
@@ -227,11 +250,8 @@ export default class SaleInvoicesService extends ServiceItemsEntries {
builder.whereIn('id', invoicesIds);
return builder;
});
const storedInvoicesIds = storedInvoices.map(i => i.id);
const notStoredInvoices = difference(
invoicesIds,
storedInvoicesIds,
);
const storedInvoicesIds = storedInvoices.map((i) => i.id);
const notStoredInvoices = difference(invoicesIds, storedInvoicesIds);
return notStoredInvoices;
}
}

View File

@@ -1,9 +1,8 @@
import { omit, difference } from 'lodash';
import { SaleEstimate, SaleEstimateEntry } from '@/models';
export default class SaleEstimateService {
constructor() {}
import { omit, difference, sumBy } from 'lodash';
import { SaleEstimate, ItemEntry } from '@/models';
import ServiceItemsEntries from '@/services/Sales/ServiceItemsEntries';
export default class SaleEstimateService extends ServiceItemsEntries {
/**
* Creates a new estimate with associated entries.
* @async
@@ -11,23 +10,27 @@ export default class SaleEstimateService {
* @return {void}
*/
static async createEstimate(estimate) {
const amount = sumBy(estimate.entries, 'amount');
const storedEstimate = await SaleEstimate.tenant()
.query()
.insert({
amount,
...omit(estimate, ['entries']),
});
const storeEstimateEntriesOpers = [];
estimate.entries.forEach((entry) => {
const oper = SaleEstimateEntry.tenant()
const oper = ItemEntry.tenant()
.query()
.insert({
estimate_id: storedEstimate.id,
...entry,
reference_type: 'SaleEstimate',
reference_id: storedEstimate.id,
...omit(entry, ['total', 'amount']),
});
storeEstimateEntriesOpers.push(oper);
});
await Promise.all([...storeEstimateEntriesOpers]);
return storedEstimate;
}
@@ -38,9 +41,10 @@ export default class SaleEstimateService {
* @return {void}
*/
static async deleteEstimate(estimateId) {
await SaleEstimateEntry.tenant()
await ItemEntry.tenant()
.query()
.where('estimate_id', estimateId)
.where('reference_id', estimateId)
.where('reference_type', 'SaleEstimate')
.delete();
await SaleEstimate.tenant().query().where('id', estimateId).delete();
}
@@ -53,43 +57,57 @@ export default class SaleEstimateService {
* @return {void}
*/
static async editEstimate(estimateId, estimate) {
const amount = sumBy(estimate.entries, 'amount');
const updatedEstimate = await SaleEstimate.tenant()
.query()
.update({
amount,
...omit(estimate, ['entries']),
});
const storedEstimateEntries = await SaleEstimateEntry.tenant()
const storedEstimateEntries = await ItemEntry.tenant()
.query()
.where('estimate_id', estimateId);
.where('reference_id', estimateId)
.where('reference_type', 'SaleEstimate');
const opers = [];
const storedEstimateEntriesIds = storedEstimateEntries.map((e) => e.id);
const estimateEntriesHasID = estimate.entries.filter((entry) => entry.id);
const formEstimateEntriesIds = estimateEntriesHasID.map(
(entry) => entry.id
);
const entriesHasID = estimate.entries.filter((entry) => entry.id);
const entriesHasNoIDs = estimate.entries.filter((entry) => !entry.id);
const storedEntriesIds = storedEstimateEntries.map((e) => e.id);
const formEstimateEntriesIds = entriesHasID.map((entry) => entry.id);
const entriesIdsShouldBeDeleted = difference(
storedEstimateEntriesIds,
storedEntriesIds,
formEstimateEntriesIds,
);
console.log(entriesIdsShouldBeDeleted);
// Deletes the given sale estimate entries ids.
if (entriesIdsShouldBeDeleted.length > 0) {
const oper = SaleEstimateEntry.tenant()
const oper = ItemEntry.tenant()
.query()
.where('id', entriesIdsShouldBeDeleted)
.whereIn('id', entriesIdsShouldBeDeleted)
.delete();
opers.push(oper);
}
estimateEntriesHasID.forEach((entry) => {
const oper = SaleEstimateEntry.tenant()
// Insert the new sale estimate entries.
entriesHasNoIDs.forEach((entry) => {
const oper = ItemEntry.tenant()
.query()
.insert({
reference_type: 'SaleEstimate',
reference_id: estimateId,
...entry,
});
opers.push(oper);
});
entriesHasID.forEach((entry) => {
const oper = ItemEntry.tenant()
.query()
.patchAndFetchById(entry.id, {
...omit(entry, ['id']),
});
opers.push(oper);
});
await Promise.all([...opers]);
return Promise.all([...opers]);
}
/**
@@ -116,10 +134,11 @@ export default class SaleEstimateService {
.filter((e) => e.id)
.map((e) => e.id);
const estimateEntries = await SaleEstimateEntry.tenant()
const estimateEntries = await ItemEntry.tenant()
.query()
.whereIn('id', estimateEntriesIds)
.where('estimate_id', estimateId);
.where('reference_id', estimateId)
.where('reference_type', 'SaleEstimate');
const storedEstimateEntriesIds = estimateEntries.map((e) => e.id);
const notFoundEntriesIDs = difference(

View File

@@ -1,33 +1,36 @@
import { omit, difference } from 'lodash';
import { omit, difference, sumBy } from 'lodash';
import {
SaleReceipt,
SaleReceiptEntry,
AccountTransaction,
Account,
} from '@/models';
import JournalPoster from '@/services/Accounting/JournalPoster';
import ItemEntry from '../../models/ItemEntry';
import JournalPosterService from '@/services/Sales/JournalPosterService';
export default class SalesReceipt {
constructor() {}
export default class SalesReceipt extends JournalPosterService {
/**
* Creates a new sale receipt with associated entries.
* @async
* @param {ISaleReceipt} saleReceipt
* @return {Object}
*/
static async createSaleReceipt(saleReceipt) {
const amount = sumBy(saleReceipt.entries, 'amount');
const storedSaleReceipt = await SaleReceipt.tenant()
.query()
.insert({
amount,
...omit(saleReceipt, ['entries']),
});
const storeSaleReceiptEntriesOpers = [];
saleReceipt.entries.forEach((entry) => {
const oper = SaleReceiptEntry.tenant()
const oper = ItemEntry.tenant()
.query()
.insert({
sale_receipt_id: storedSaleReceipt.id,
...entry,
reference_type: 'SaleReceipt',
reference_id: storedSaleReceipt.id,
...omit(entry, ['id', 'amount']),
});
storeSaleReceiptEntriesOpers.push(oper);
});
@@ -38,34 +41,11 @@ export default class SalesReceipt {
/**
* Records journal transactions for sale receipt.
* @param {ISaleReceipt} saleReceipt
* @return {Promise}
*/
static async _recordJournalTransactions(saleReceipt) {
const accountsDepGraph = await Account.tenant().depGraph().query();
const journalPoster = new JournalPoster(accountsDepGraph);
const creditEntry = new journalEntry({
debit: 0,
credit: saleReceipt.total,
account: saleReceipt.incomeAccountId,
referenceType: 'SaleReceipt',
referenceId: saleReceipt.id,
note: saleReceipt.note,
});
const debitEntry = new journalEntry({
debit: saleReceipt.total,
credit: 0,
account: saleReceipt.incomeAccountId,
referenceType: 'SaleReceipt',
referenceId: saleReceipt.id,
note: saleReceipt.note,
});
journalPoster.credit(creditEntry);
journalPoster.credit(debitEntry);
await Promise.all([
journalPoster.saveEntries(),
journalPoster.saveBalance(),
]);
}
/**
@@ -75,42 +55,45 @@ export default class SalesReceipt {
* @return {void}
*/
static async editSaleReceipt(saleReceiptId, saleReceipt) {
const amount = sumBy(saleReceipt.entries, 'amount');
const updatedSaleReceipt = await SaleReceipt.tenant()
.query()
.where('id', saleReceiptId)
.update({
amount,
...omit(saleReceipt, ['entries']),
});
const storedSaleReceiptEntries = await SaleReceiptEntry.tenant()
const storedSaleReceiptEntries = await ItemEntry.tenant()
.query()
.where('sale_receipt_id', saleReceiptId);
.where('reference_id', saleReceiptId)
.where('reference_type', 'SaleReceipt');
const storedSaleReceiptsIds = storedSaleReceiptEntries.map((e) => e.id);
const entriesHasID = saleReceipt.entries.filter((entry) => entry.id);
const entriesIds = entriesHasID.map((e) => e.id);
const opers = [];
const entriesIdsShouldBeDeleted = difference(
storedSaleReceiptsIds,
entriesIds
);
const opers = [];
if (entriesIdsShouldBeDeleted.length > 0) {
const deleteOper = SaleReceiptEntry.tenant()
const deleteOper = ItemEntry.tenant()
.query()
.where('id', entriesIdsShouldBeDeleted)
.whereIn('id', entriesIdsShouldBeDeleted)
.where('reference_type', 'SaleReceipt')
.delete();
opers.push(deleteOper);
}
entriesHasID.forEach((entry) => {
const updateOper = SaleReceiptEntry.tenant()
const updateOper = ItemEntry.tenant()
.query()
.patchAndFetchById(entry.id, {
...omit(entry, ['id']),
});
opers.push(updateOper);
});
await Promise.all([...opers]);
return Promise.all([...opers]);
}
/**
@@ -120,27 +103,20 @@ export default class SalesReceipt {
*/
static async deleteSaleReceipt(saleReceiptId) {
await SaleReceipt.tenant().query().where('id', saleReceiptId).delete();
await SaleReceiptEntry.tenant()
await ItemEntry.tenant()
.query()
.where('sale_receipt_id', saleReceiptId)
.where('reference_id', saleReceiptId)
.where('reference_type', 'SaleReceipt')
.delete();
const receiptTransactions = await AccountTransaction.tenant()
.query()
.whereIn('reference_type', ['SaleReceipt'])
.where('reference_id', saleReceiptId)
.withGraphFetched('account.type');
const accountsDepGraph = await Account.tenant()
.depGraph()
.query()
.remember();
const journal = new JournalPoster(accountsDepGraph);
journal.loadEntries(receiptTransactions);
journal.removeEntries();
await Promise.all([journal.deleteEntries(), journal.saveBalance()]);
// Delete all associated journal transactions to payment receive transaction.
const deleteTransactionsOper = this.deleteJournalTransactions(
saleReceiptId,
'SaleReceipt'
);
return Promise.all([
deleteTransactionsOper,
]);
}
/**
@@ -165,10 +141,11 @@ export default class SalesReceipt {
.filter((e) => e.id)
.map((e) => e.id);
const storedEntries = await SaleReceiptEntry.tenant()
const storedEntries = await ItemEntry.tenant()
.query()
.whereIn('id', entriesIDs)
.where('sale_receipt_id', saleReceiptId);
.where('reference_id', saleReceiptId)
.where('reference_type', 'SaleReceipt');
const storedEntriesIDs = storedEntries.map((e) => e.id);
const notFoundEntriesIDs = difference(
@@ -178,6 +155,10 @@ export default class SalesReceipt {
return notFoundEntriesIDs;
}
/**
* Retrieve sale receipt with associated entries.
* @param {Integer} saleReceiptId
*/
static async getSaleReceiptWithEntries(saleReceiptId) {
const saleReceipt = await SaleReceipt.tenant().query()
.where('id', saleReceiptId)