mirror of
https://github.com/frappe/erpnext.git
synced 2026-09-15 18:01:41 +00:00
Merge pull request #57928 from Shllokkk/sales-register-ledger-pos-paid-v15
fix: reflect in-invoice receivable credits in Sales Register ledger view
This commit is contained in:
@@ -151,7 +151,13 @@ def _execute(filters, additional_table_columns=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if inv.doctype == "Sales Invoice":
|
if inv.doctype == "Sales Invoice":
|
||||||
row.update({"debit": inv.base_grand_total, "credit": 0.0})
|
# credit only settlements the invoice itself posts to the receivable (mirrors its GL)
|
||||||
|
row.update(
|
||||||
|
{
|
||||||
|
"debit": inv.base_grand_total,
|
||||||
|
"credit": get_in_invoice_receivable_credit(inv),
|
||||||
|
}
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
row.update({"debit": 0.0, "credit": inv.base_grand_total})
|
row.update({"debit": 0.0, "credit": inv.base_grand_total})
|
||||||
data.append(row)
|
data.append(row)
|
||||||
@@ -167,6 +173,14 @@ def _execute(filters, additional_table_columns=None):
|
|||||||
return columns, res, None, None, None, include_payments
|
return columns, res, None, None, None, include_payments
|
||||||
|
|
||||||
|
|
||||||
|
def get_in_invoice_receivable_credit(inv):
|
||||||
|
# amount the invoice settles against its own receivable, matching the invoice's GL entries
|
||||||
|
credit = flt(inv.loyalty_amount) # loyalty redemption, POS or not
|
||||||
|
if inv.is_pos: # POS payments and write-off credit the receivable only on POS invoices
|
||||||
|
credit += flt(inv.base_paid_amount) - flt(inv.base_change_amount) + flt(inv.base_write_off_amount)
|
||||||
|
return credit
|
||||||
|
|
||||||
|
|
||||||
def get_columns(invoice_list, additional_table_columns, include_payments=False):
|
def get_columns(invoice_list, additional_table_columns, include_payments=False):
|
||||||
"""return columns based on filters"""
|
"""return columns based on filters"""
|
||||||
columns = [
|
columns = [
|
||||||
@@ -433,6 +447,11 @@ def get_invoices(filters, additional_query_columns):
|
|||||||
si.base_net_total,
|
si.base_net_total,
|
||||||
si.base_grand_total,
|
si.base_grand_total,
|
||||||
si.base_rounded_total,
|
si.base_rounded_total,
|
||||||
|
si.is_pos,
|
||||||
|
si.base_paid_amount,
|
||||||
|
si.base_change_amount,
|
||||||
|
si.base_write_off_amount,
|
||||||
|
si.loyalty_amount,
|
||||||
si.outstanding_amount,
|
si.outstanding_amount,
|
||||||
si.is_internal_customer,
|
si.is_internal_customer,
|
||||||
si.represents_company,
|
si.represents_company,
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.tests.utils import FrappeTestCase
|
from frappe.tests.utils import FrappeTestCase
|
||||||
from frappe.utils import getdate, today
|
from frappe.utils import flt, getdate, today
|
||||||
|
|
||||||
|
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
|
||||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
from erpnext.accounts.report.sales_register.sales_register import execute
|
from erpnext.accounts.report.sales_register.sales_register import execute
|
||||||
from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
|
from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
|
||||||
@@ -54,6 +55,46 @@ class TestItemWiseSalesRegister(AccountsTestMixin, FrappeTestCase):
|
|||||||
si = si.submit()
|
si = si.submit()
|
||||||
return si
|
return si
|
||||||
|
|
||||||
|
def test_ledger_view_nets_pos_paid_invoice(self):
|
||||||
|
# A POS payment settles the receivable inside the invoice, so the ledger view must credit it
|
||||||
|
# and net to zero instead of showing a phantom outstanding.
|
||||||
|
make_pos_profile()
|
||||||
|
si = create_sales_invoice(
|
||||||
|
item=self.item,
|
||||||
|
company=self.company,
|
||||||
|
customer=self.customer,
|
||||||
|
debit_to=self.debit_to,
|
||||||
|
posting_date=today(),
|
||||||
|
parent_cost_center=self.cost_center,
|
||||||
|
cost_center=self.cost_center,
|
||||||
|
rate=100,
|
||||||
|
price_list_rate=100,
|
||||||
|
do_not_save=1,
|
||||||
|
)
|
||||||
|
si.is_pos = 1
|
||||||
|
si.append("payments", {"mode_of_payment": "Cash", "amount": 100})
|
||||||
|
si = si.save().submit()
|
||||||
|
self.assertEqual(flt(si.outstanding_amount), 0.0)
|
||||||
|
|
||||||
|
filters = frappe._dict(
|
||||||
|
{
|
||||||
|
"from_date": today(),
|
||||||
|
"to_date": today(),
|
||||||
|
"company": self.company,
|
||||||
|
"include_payments": True,
|
||||||
|
"customer": self.customer,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
rows = execute(filters)[1]
|
||||||
|
inv_row = next(x for x in rows if x.get("voucher_no") == si.name)
|
||||||
|
|
||||||
|
self.assertEqual(flt(inv_row.get("debit")), 100.0)
|
||||||
|
self.assertEqual(flt(inv_row.get("credit")), 100.0)
|
||||||
|
|
||||||
|
# running balance is unchanged by a fully-paid POS invoice
|
||||||
|
idx = rows.index(inv_row)
|
||||||
|
self.assertEqual(flt(inv_row.get("balance")), flt(rows[idx - 1].get("balance")))
|
||||||
|
|
||||||
def test_basic_report_output(self):
|
def test_basic_report_output(self):
|
||||||
si = self.create_sales_invoice(rate=98)
|
si = self.create_sales_invoice(rate=98)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user