2018-12-17 09:43:33 +00:00
|
|
|
import unittest
|
2021-09-02 11:14:59 +00:00
|
|
|
|
2018-12-17 09:43:33 +00:00
|
|
|
import frappe
|
2022-12-18 07:09:54 +00:00
|
|
|
from frappe.tests.utils import FrappeTestCase, change_settings
|
|
|
|
from frappe.utils import add_days, flt, getdate, today
|
2021-09-02 11:14:59 +00:00
|
|
|
|
2022-12-18 07:09:54 +00:00
|
|
|
from erpnext import get_default_cost_center
|
2018-12-17 09:43:33 +00:00
|
|
|
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
|
|
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
|
|
|
from erpnext.accounts.report.accounts_receivable.accounts_receivable import execute
|
2022-08-24 08:28:11 +00:00
|
|
|
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
2021-09-02 11:14:59 +00:00
|
|
|
|
2018-12-17 09:43:33 +00:00
|
|
|
|
2022-08-24 08:28:11 +00:00
|
|
|
class TestAccountsReceivable(FrappeTestCase):
|
|
|
|
def setUp(self):
|
2018-12-17 09:43:33 +00:00
|
|
|
frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company 2'")
|
2022-08-24 08:28:11 +00:00
|
|
|
frappe.db.sql("delete from `tabSales Order` where company='_Test Company 2'")
|
|
|
|
frappe.db.sql("delete from `tabPayment Entry` where company='_Test Company 2'")
|
2018-12-17 09:43:33 +00:00
|
|
|
frappe.db.sql("delete from `tabGL Entry` where company='_Test Company 2'")
|
2022-05-23 10:08:56 +00:00
|
|
|
frappe.db.sql("delete from `tabPayment Ledger Entry` where company='_Test Company 2'")
|
2022-12-18 07:09:54 +00:00
|
|
|
frappe.db.sql("delete from `tabJournal Entry` where company='_Test Company 2'")
|
|
|
|
frappe.db.sql("delete from `tabExchange Rate Revaluation` where company='_Test Company 2'")
|
|
|
|
|
|
|
|
self.create_usd_account()
|
2018-12-17 09:43:33 +00:00
|
|
|
|
2022-08-24 08:28:11 +00:00
|
|
|
def tearDown(self):
|
|
|
|
frappe.db.rollback()
|
|
|
|
|
2022-12-18 07:09:54 +00:00
|
|
|
def create_usd_account(self):
|
|
|
|
name = "Debtors USD"
|
|
|
|
exists = frappe.db.get_list(
|
|
|
|
"Account", filters={"company": "_Test Company 2", "account_name": "Debtors USD"}
|
|
|
|
)
|
|
|
|
if exists:
|
|
|
|
self.debtors_usd = exists[0].name
|
|
|
|
else:
|
|
|
|
debtors = frappe.get_doc(
|
|
|
|
"Account",
|
|
|
|
frappe.db.get_list(
|
|
|
|
"Account", filters={"company": "_Test Company 2", "account_name": "Debtors"}
|
|
|
|
)[0].name,
|
|
|
|
)
|
|
|
|
|
|
|
|
debtors_usd = frappe.new_doc("Account")
|
|
|
|
debtors_usd.company = debtors.company
|
|
|
|
debtors_usd.account_name = "Debtors USD"
|
|
|
|
debtors_usd.account_currency = "USD"
|
|
|
|
debtors_usd.parent_account = debtors.parent_account
|
|
|
|
debtors_usd.account_type = debtors.account_type
|
|
|
|
self.debtors_usd = debtors_usd.save().name
|
|
|
|
|
2022-08-24 08:28:11 +00:00
|
|
|
def test_accounts_receivable(self):
|
2018-12-17 09:43:33 +00:00
|
|
|
filters = {
|
|
|
|
"company": "_Test Company 2",
|
2019-09-03 10:37:46 +00:00
|
|
|
"based_on_payment_terms": 1,
|
|
|
|
"report_date": today(),
|
|
|
|
"range1": 30,
|
|
|
|
"range2": 60,
|
|
|
|
"range3": 90,
|
|
|
|
"range4": 120,
|
2018-12-17 09:43:33 +00:00
|
|
|
}
|
|
|
|
|
2019-09-03 10:37:46 +00:00
|
|
|
# check invoice grand total and invoiced column's value for 3 payment terms
|
2022-12-18 07:09:54 +00:00
|
|
|
name = make_sales_invoice().name
|
2018-12-17 09:43:33 +00:00
|
|
|
report = execute(filters)
|
|
|
|
|
2019-09-03 10:37:46 +00:00
|
|
|
expected_data = [[100, 30], [100, 50], [100, 20]]
|
2018-12-17 09:43:33 +00:00
|
|
|
|
2019-09-03 10:37:46 +00:00
|
|
|
for i in range(3):
|
|
|
|
row = report[1][i - 1]
|
|
|
|
self.assertEqual(expected_data[i - 1], [row.invoice_grand_total, row.invoiced])
|
2018-12-17 09:43:33 +00:00
|
|
|
|
2019-09-03 10:37:46 +00:00
|
|
|
# check invoice grand total, invoiced, paid and outstanding column's value after payment
|
2018-12-17 09:43:33 +00:00
|
|
|
make_payment(name)
|
|
|
|
report = execute(filters)
|
|
|
|
|
2019-09-03 10:37:46 +00:00
|
|
|
expected_data_after_payment = [[100, 50, 10, 40], [100, 20, 0, 20]]
|
2018-12-17 09:43:33 +00:00
|
|
|
|
2019-09-03 10:37:46 +00:00
|
|
|
for i in range(2):
|
|
|
|
row = report[1][i - 1]
|
|
|
|
self.assertEqual(
|
|
|
|
expected_data_after_payment[i - 1],
|
|
|
|
[row.invoice_grand_total, row.invoiced, row.paid, row.outstanding],
|
|
|
|
)
|
2018-12-17 09:43:33 +00:00
|
|
|
|
2019-09-03 10:37:46 +00:00
|
|
|
# check invoice grand total, invoiced, paid and outstanding column's value after credit note
|
2018-12-17 09:43:33 +00:00
|
|
|
make_credit_note(name)
|
|
|
|
report = execute(filters)
|
|
|
|
|
2022-03-30 09:30:16 +00:00
|
|
|
expected_data_after_credit_note = [100, 0, 0, 40, -40, "Debtors - _TC2"]
|
2018-12-17 09:43:33 +00:00
|
|
|
|
2019-09-03 10:37:46 +00:00
|
|
|
row = report[1][0]
|
|
|
|
self.assertEqual(
|
|
|
|
expected_data_after_credit_note,
|
2022-03-30 09:30:16 +00:00
|
|
|
[
|
|
|
|
row.invoice_grand_total,
|
|
|
|
row.invoiced,
|
|
|
|
row.paid,
|
|
|
|
row.credit_note,
|
|
|
|
row.outstanding,
|
|
|
|
row.party_account,
|
|
|
|
],
|
2019-09-03 10:37:46 +00:00
|
|
|
)
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2022-08-24 08:28:11 +00:00
|
|
|
def test_payment_againt_po_in_receivable_report(self):
|
|
|
|
"""
|
|
|
|
Payments made against Purchase Order will show up as outstanding amount
|
|
|
|
"""
|
|
|
|
|
|
|
|
so = make_sales_order(
|
|
|
|
company="_Test Company 2",
|
|
|
|
customer="_Test Customer 2",
|
|
|
|
warehouse="Finished Goods - _TC2",
|
|
|
|
currency="EUR",
|
|
|
|
debit_to="Debtors - _TC2",
|
|
|
|
income_account="Sales - _TC2",
|
|
|
|
expense_account="Cost of Goods Sold - _TC2",
|
|
|
|
cost_center="Main - _TC2",
|
|
|
|
)
|
|
|
|
|
|
|
|
pe = get_payment_entry(so.doctype, so.name)
|
|
|
|
pe = pe.save().submit()
|
|
|
|
|
|
|
|
filters = {
|
|
|
|
"company": "_Test Company 2",
|
|
|
|
"based_on_payment_terms": 0,
|
|
|
|
"report_date": today(),
|
|
|
|
"range1": 30,
|
|
|
|
"range2": 60,
|
|
|
|
"range3": 90,
|
|
|
|
"range4": 120,
|
|
|
|
}
|
|
|
|
|
|
|
|
report = execute(filters)
|
|
|
|
|
|
|
|
expected_data_after_payment = [0, 1000, 0, -1000]
|
|
|
|
|
|
|
|
row = report[1][0]
|
|
|
|
self.assertEqual(
|
|
|
|
expected_data_after_payment,
|
|
|
|
[
|
|
|
|
row.invoiced,
|
|
|
|
row.paid,
|
|
|
|
row.credit_note,
|
|
|
|
row.outstanding,
|
|
|
|
],
|
|
|
|
)
|
|
|
|
|
2022-12-18 07:09:54 +00:00
|
|
|
@change_settings(
|
|
|
|
"Accounts Settings", {"allow_multi_currency_invoices_against_single_party_account": 1}
|
|
|
|
)
|
|
|
|
def test_exchange_revaluation_for_party(self):
|
|
|
|
"""
|
|
|
|
Exchange Revaluation for party on Receivable/Payable shoule be included
|
|
|
|
"""
|
|
|
|
|
|
|
|
company = "_Test Company 2"
|
|
|
|
customer = "_Test Customer 2"
|
|
|
|
|
|
|
|
# Using Exchange Gain/Loss account for unrealized as well.
|
|
|
|
company_doc = frappe.get_doc("Company", company)
|
|
|
|
company_doc.unrealized_exchange_gain_loss_account = company_doc.exchange_gain_loss_account
|
|
|
|
company_doc.save()
|
|
|
|
|
|
|
|
si = make_sales_invoice(no_payment_schedule=True, do_not_submit=True)
|
|
|
|
si.currency = "USD"
|
|
|
|
si.conversion_rate = 0.90
|
|
|
|
si.debit_to = self.debtors_usd
|
|
|
|
si = si.save().submit()
|
|
|
|
|
|
|
|
# Exchange Revaluation
|
|
|
|
err = frappe.new_doc("Exchange Rate Revaluation")
|
|
|
|
err.company = company
|
|
|
|
err.posting_date = today()
|
|
|
|
accounts = err.get_accounts_data()
|
|
|
|
err.extend("accounts", accounts)
|
|
|
|
err.accounts[0].new_exchange_rate = 0.95
|
|
|
|
row = err.accounts[0]
|
|
|
|
row.new_balance_in_base_currency = flt(
|
|
|
|
row.new_exchange_rate * flt(row.balance_in_account_currency)
|
|
|
|
)
|
|
|
|
row.gain_loss = row.new_balance_in_base_currency - flt(row.balance_in_base_currency)
|
|
|
|
err.set_total_gain_loss()
|
|
|
|
err = err.save().submit()
|
2018-12-17 09:43:33 +00:00
|
|
|
|
2022-12-18 07:09:54 +00:00
|
|
|
# Submit JV for ERR
|
2023-01-02 09:03:14 +00:00
|
|
|
err_journals = err.make_jv_entries()
|
|
|
|
je = frappe.get_doc("Journal Entry", err_journals.get("revaluation_jv"))
|
|
|
|
je = je.submit()
|
2022-12-18 07:09:54 +00:00
|
|
|
|
|
|
|
filters = {
|
|
|
|
"company": company,
|
|
|
|
"report_date": today(),
|
|
|
|
"range1": 30,
|
|
|
|
"range2": 60,
|
|
|
|
"range3": 90,
|
|
|
|
"range4": 120,
|
|
|
|
}
|
|
|
|
report = execute(filters)
|
|
|
|
|
|
|
|
expected_data_for_err = [0, -5, 0, 5]
|
2023-01-02 09:03:14 +00:00
|
|
|
row = [x for x in report[1] if x.voucher_type == je.doctype and x.voucher_no == je.name][0]
|
2022-12-18 07:09:54 +00:00
|
|
|
self.assertEqual(
|
|
|
|
expected_data_for_err,
|
|
|
|
[
|
|
|
|
row.invoiced,
|
|
|
|
row.paid,
|
|
|
|
row.credit_note,
|
|
|
|
row.outstanding,
|
|
|
|
],
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def make_sales_invoice(no_payment_schedule=False, do_not_submit=False):
|
2018-12-17 09:43:33 +00:00
|
|
|
frappe.set_user("Administrator")
|
|
|
|
|
|
|
|
si = create_sales_invoice(
|
|
|
|
company="_Test Company 2",
|
|
|
|
customer="_Test Customer 2",
|
|
|
|
currency="EUR",
|
|
|
|
warehouse="Finished Goods - _TC2",
|
|
|
|
debit_to="Debtors - _TC2",
|
|
|
|
income_account="Sales - _TC2",
|
|
|
|
expense_account="Cost of Goods Sold - _TC2",
|
2020-06-20 07:02:30 +00:00
|
|
|
cost_center="Main - _TC2",
|
2018-12-17 09:43:33 +00:00
|
|
|
do_not_save=1,
|
|
|
|
)
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2022-12-18 07:09:54 +00:00
|
|
|
if not no_payment_schedule:
|
|
|
|
si.append(
|
|
|
|
"payment_schedule",
|
|
|
|
dict(due_date=getdate(add_days(today(), 30)), invoice_portion=30.00, payment_amount=30),
|
|
|
|
)
|
|
|
|
si.append(
|
|
|
|
"payment_schedule",
|
|
|
|
dict(due_date=getdate(add_days(today(), 60)), invoice_portion=50.00, payment_amount=50),
|
|
|
|
)
|
|
|
|
si.append(
|
|
|
|
"payment_schedule",
|
|
|
|
dict(due_date=getdate(add_days(today(), 90)), invoice_portion=20.00, payment_amount=20),
|
|
|
|
)
|
|
|
|
|
|
|
|
si = si.save()
|
2018-12-17 09:43:33 +00:00
|
|
|
|
2022-12-18 07:09:54 +00:00
|
|
|
if not do_not_submit:
|
|
|
|
si = si.submit()
|
2018-12-17 09:43:33 +00:00
|
|
|
|
2022-12-18 07:09:54 +00:00
|
|
|
return si
|
2018-12-17 09:43:33 +00:00
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2018-12-17 09:43:33 +00:00
|
|
|
def make_payment(docname):
|
2019-09-03 10:37:46 +00:00
|
|
|
pe = get_payment_entry("Sales Invoice", docname, bank_account="Cash - _TC2", party_amount=40)
|
2018-12-17 09:43:33 +00:00
|
|
|
pe.paid_from = "Debtors - _TC2"
|
|
|
|
pe.insert()
|
|
|
|
pe.submit()
|
|
|
|
|
|
|
|
|
|
|
|
def make_credit_note(docname):
|
|
|
|
create_sales_invoice(
|
|
|
|
company="_Test Company 2",
|
2020-06-20 07:02:30 +00:00
|
|
|
customer="_Test Customer 2",
|
|
|
|
currency="EUR",
|
|
|
|
qty=-1,
|
|
|
|
warehouse="Finished Goods - _TC2",
|
|
|
|
debit_to="Debtors - _TC2",
|
|
|
|
income_account="Sales - _TC2",
|
|
|
|
expense_account="Cost of Goods Sold - _TC2",
|
|
|
|
cost_center="Main - _TC2",
|
|
|
|
is_return=1,
|
|
|
|
return_against=docname,
|
|
|
|
)
|