mirror of
https://github.com/frappe/books.git
synced 2024-12-23 11:29:03 +00:00
171 lines
3.7 KiB
JavaScript
171 lines
3.7 KiB
JavaScript
import frappe from 'frappe';
|
|
|
|
export default class AccountsReceivablePayable {
|
|
async run(reportType, { date }) {
|
|
const rows = await getReceivablePayable({
|
|
reportType,
|
|
date,
|
|
});
|
|
|
|
return { rows };
|
|
}
|
|
}
|
|
|
|
async function getReceivablePayable({ reportType = 'Receivable', date }) {
|
|
let entries = [];
|
|
const debitOrCredit = reportType === 'Receivable' ? 'debit' : 'credit';
|
|
const referenceType =
|
|
reportType === 'Receivable' ? 'SalesInvoice' : 'PurchaseInvoice';
|
|
|
|
entries = await getLedgerEntries();
|
|
const vouchers = await getVouchers();
|
|
|
|
const futureEntries = getFutureEntries();
|
|
const returnEntries = getReturnEntries();
|
|
const pdc = getPDC();
|
|
|
|
const validEntries = getValidEntries();
|
|
|
|
let data = [];
|
|
|
|
for (let entry of validEntries) {
|
|
const { outStandingAmount, creditNoteAmount } = getOutstandingAmount(entry);
|
|
|
|
if (outStandingAmount > 0.1 / 10) {
|
|
const row = {
|
|
date: entry.date,
|
|
party: entry.party,
|
|
};
|
|
|
|
// due date / bill date
|
|
|
|
row.voucherType = entry.referenceType;
|
|
row.voucherNo = entry.referenceName;
|
|
|
|
// bill details
|
|
|
|
const invoicedAmount = entry[debitOrCredit] || 0;
|
|
const paidAmount = invoicedAmount - outStandingAmount - creditNoteAmount;
|
|
|
|
Object.assign(row, {
|
|
invoicedAmount,
|
|
paidAmount,
|
|
outStandingAmount,
|
|
creditNoteAmount,
|
|
});
|
|
|
|
// ageing
|
|
|
|
data.push(row);
|
|
}
|
|
}
|
|
|
|
return data;
|
|
|
|
// helpers
|
|
|
|
async function getVouchers() {
|
|
return await frappe.db.getAll({
|
|
doctype: referenceType,
|
|
fields: ['name', 'date'],
|
|
filters: {
|
|
submitted: 1,
|
|
},
|
|
});
|
|
}
|
|
|
|
function getValidEntries() {
|
|
return entries.filter((entry) => {
|
|
return (
|
|
entry.date <= date &&
|
|
entry.referenceType === referenceType &&
|
|
entry[debitOrCredit] > 0
|
|
);
|
|
});
|
|
}
|
|
|
|
function getOutstandingAmount(entry) {
|
|
let paymentAmount = 0.0,
|
|
creditNoteAmount = 0.0;
|
|
let reverseDebitOrCredit = debitOrCredit === 'debit' ? 'credit' : 'debit';
|
|
|
|
for (let e of getEntriesFor(
|
|
entry.party,
|
|
entry.referenceType,
|
|
entry.referenceName
|
|
)) {
|
|
if (e.date <= date) {
|
|
const amount = e[reverseDebitOrCredit] - e[debitOrCredit];
|
|
|
|
if (!Object.keys(returnEntries).includes(e.referenceName)) {
|
|
paymentAmount += amount;
|
|
} else {
|
|
creditNoteAmount += amount;
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
outStandingAmount:
|
|
entry[debitOrCredit] -
|
|
entry[reverseDebitOrCredit] -
|
|
paymentAmount -
|
|
creditNoteAmount,
|
|
creditNoteAmount,
|
|
};
|
|
}
|
|
|
|
function getEntriesFor(party, againstVoucherType, againstVoucher) {
|
|
// TODO
|
|
return [];
|
|
}
|
|
|
|
function getFutureEntries() {
|
|
return entries.filter((entry) => entry.date > date);
|
|
}
|
|
|
|
function getReturnEntries() {
|
|
// TODO
|
|
return {};
|
|
}
|
|
|
|
function getPDC() {
|
|
return [];
|
|
}
|
|
|
|
async function getLedgerEntries() {
|
|
if (entries.length) {
|
|
return entries;
|
|
}
|
|
|
|
const partyType = reportType === 'Receivable' ? 'customer' : 'supplier';
|
|
const partyList = (
|
|
await frappe.db.getAll({
|
|
doctype: 'Party',
|
|
filters: {
|
|
[partyType]: 1,
|
|
},
|
|
})
|
|
).map((d) => d.name);
|
|
|
|
return await frappe.db.getAll({
|
|
doctype: 'AccountingLedgerEntry',
|
|
fields: [
|
|
'name',
|
|
'date',
|
|
'account',
|
|
'party',
|
|
'referenceType',
|
|
'referenceName',
|
|
'sum(debit) as debit',
|
|
'sum(credit) as credit',
|
|
],
|
|
filters: {
|
|
party: ['in', partyList],
|
|
},
|
|
groupBy: ['referenceType', 'referenceName', 'party'],
|
|
orderBy: 'date',
|
|
});
|
|
}
|
|
}
|