mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-18 00:48:42 +00:00
Merge pull request #56249 from mihir-kandoi/pg-test-helpers-parity
test(postgres): make test-helper SQL Postgres-valid across the suite
This commit is contained in:
@@ -43,18 +43,18 @@ class TestJournalEntry(ERPNextTestSuite):
|
||||
|
||||
if test_voucher.doctype == "Journal Entry":
|
||||
self.assertTrue(
|
||||
frappe.db.sql(
|
||||
"""select name from `tabJournal Entry Account`
|
||||
where account = %s and docstatus = 1 and parent = %s""",
|
||||
("Debtors - _TC", test_voucher.name),
|
||||
frappe.get_all(
|
||||
"Journal Entry Account",
|
||||
filters={"account": "Debtors - _TC", "docstatus": 1, "parent": test_voucher.name},
|
||||
pluck="name",
|
||||
)
|
||||
)
|
||||
|
||||
self.assertFalse(
|
||||
frappe.db.sql(
|
||||
"""select name from `tabJournal Entry Account`
|
||||
where reference_type = %s and reference_name = %s""",
|
||||
(test_voucher.doctype, test_voucher.name),
|
||||
frappe.get_all(
|
||||
"Journal Entry Account",
|
||||
filters={"reference_type": test_voucher.doctype, "reference_name": test_voucher.name},
|
||||
pluck="name",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -69,10 +69,14 @@ class TestJournalEntry(ERPNextTestSuite):
|
||||
submitted_voucher = frappe.get_doc(test_voucher.doctype, test_voucher.name)
|
||||
|
||||
self.assertTrue(
|
||||
frappe.db.sql(
|
||||
f"""select name from `tabJournal Entry Account`
|
||||
where reference_type = %s and reference_name = %s and {dr_or_cr}=400""",
|
||||
(submitted_voucher.doctype, submitted_voucher.name),
|
||||
frappe.get_all(
|
||||
"Journal Entry Account",
|
||||
filters={
|
||||
"reference_type": submitted_voucher.doctype,
|
||||
"reference_name": submitted_voucher.name,
|
||||
dr_or_cr: 400,
|
||||
},
|
||||
pluck="name",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -82,24 +86,20 @@ class TestJournalEntry(ERPNextTestSuite):
|
||||
|
||||
def advance_paid_testcase(self, base_jv, test_voucher, dr_or_cr):
|
||||
# Test advance paid field
|
||||
advance_paid = frappe.db.sql(
|
||||
"""select advance_paid from `tab{}`
|
||||
where name={}""".format(test_voucher.doctype, "%s"),
|
||||
(test_voucher.name),
|
||||
)
|
||||
advance_paid = frappe.db.get_value(test_voucher.doctype, test_voucher.name, "advance_paid")
|
||||
payment_against_order = base_jv.get("accounts")[0].get(dr_or_cr)
|
||||
|
||||
self.assertEqual(flt(advance_paid[0][0]), flt(payment_against_order))
|
||||
self.assertEqual(flt(advance_paid), flt(payment_against_order))
|
||||
|
||||
def cancel_against_voucher_testcase(self, test_voucher):
|
||||
if test_voucher.doctype == "Journal Entry":
|
||||
# if test_voucher is a Journal Entry, test cancellation of test_voucher
|
||||
test_voucher.cancel()
|
||||
self.assertFalse(
|
||||
frappe.db.sql(
|
||||
"""select name from `tabJournal Entry Account`
|
||||
where reference_type='Journal Entry' and reference_name=%s""",
|
||||
test_voucher.name,
|
||||
frappe.get_all(
|
||||
"Journal Entry Account",
|
||||
filters={"reference_type": "Journal Entry", "reference_name": test_voucher.name},
|
||||
pluck="name",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -202,10 +202,10 @@ class TestJournalEntry(ERPNextTestSuite):
|
||||
# cancel
|
||||
jv.cancel()
|
||||
|
||||
gle = frappe.db.sql(
|
||||
"""select name from `tabGL Entry`
|
||||
where voucher_type='Sales Invoice' and voucher_no=%s""",
|
||||
jv.name,
|
||||
gle = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": jv.name},
|
||||
pluck="name",
|
||||
)
|
||||
|
||||
self.assertFalse(gle)
|
||||
@@ -526,9 +526,16 @@ class TestJournalEntry(ERPNextTestSuite):
|
||||
|
||||
gl_entries = query.run(as_dict=True)
|
||||
|
||||
for i in range(len(self.expected_gle)):
|
||||
# MariaDB and Postgres collate `account` differently, so the DB ordering isn't portable;
|
||||
# sort both sides identically before the positional comparison.
|
||||
def _key(row):
|
||||
return tuple(str(row[f]) for f in self.fields)
|
||||
|
||||
gl_entries = sorted(gl_entries, key=_key)
|
||||
expected_gle = sorted(self.expected_gle, key=_key)
|
||||
for i in range(len(expected_gle)):
|
||||
for field in self.fields:
|
||||
self.assertEqual(self.expected_gle[i][field], gl_entries[i][field])
|
||||
self.assertEqual(expected_gle[i][field], gl_entries[i][field])
|
||||
|
||||
def test_negative_debit_and_credit_with_same_account_head(self):
|
||||
from erpnext.accounts.general_ledger import process_gl_map
|
||||
|
||||
@@ -818,12 +818,11 @@ class TestPaymentEntry(ERPNextTestSuite):
|
||||
self.assertEqual(expected_gle[gle.account][3], gle.against_voucher)
|
||||
|
||||
def get_gle(self, voucher_no):
|
||||
return frappe.db.sql(
|
||||
"""select account, debit, credit, against_voucher
|
||||
from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
|
||||
order by account asc""",
|
||||
voucher_no,
|
||||
as_dict=1,
|
||||
return frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Payment Entry", "voucher_no": voucher_no},
|
||||
fields=["account", "debit", "credit", "against_voucher"],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
def test_payment_entry_write_off_difference(self):
|
||||
@@ -918,13 +917,19 @@ class TestPaymentEntry(ERPNextTestSuite):
|
||||
"Debtors - _TC": {"cost_center": cost_center},
|
||||
}
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, cost_center, account_currency, debit, credit,
|
||||
debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pe.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Payment Entry", "voucher_no": pe.name},
|
||||
fields=[
|
||||
"account",
|
||||
"cost_center",
|
||||
"account_currency",
|
||||
"debit",
|
||||
"credit",
|
||||
"debit_in_account_currency",
|
||||
"credit_in_account_currency",
|
||||
],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -955,13 +960,19 @@ class TestPaymentEntry(ERPNextTestSuite):
|
||||
"Creditors - _TC": {"cost_center": cost_center},
|
||||
}
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, cost_center, account_currency, debit, credit,
|
||||
debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pe.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Payment Entry", "voucher_no": pe.name},
|
||||
fields=[
|
||||
"account",
|
||||
"cost_center",
|
||||
"account_currency",
|
||||
"debit",
|
||||
"credit",
|
||||
"debit_in_account_currency",
|
||||
"credit_in_account_currency",
|
||||
],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -1770,9 +1781,18 @@ class TestPaymentEntry(ERPNextTestSuite):
|
||||
.where((gle.voucher_no == self.voucher_no) & (gle.is_cancelled == 0))
|
||||
.orderby(gle.account, gle.debit, gle.credit, order=frappe.qb.desc)
|
||||
).run(as_dict=True)
|
||||
for row in range(len(self.expected_gle)):
|
||||
for field in ["account", "debit", "credit"]:
|
||||
self.assertEqual(self.expected_gle[row][field], gl_entries[row][field])
|
||||
# MariaDB and Postgres collate `account` differently, so the DB ordering isn't portable;
|
||||
# sort both sides identically before the positional comparison.
|
||||
fields = ["account", "debit", "credit"]
|
||||
|
||||
def _key(row):
|
||||
return tuple(str(row[f]) for f in fields)
|
||||
|
||||
gl_entries = sorted(gl_entries, key=_key)
|
||||
expected_gle = sorted(self.expected_gle, key=_key)
|
||||
for row in range(len(expected_gle)):
|
||||
for field in fields:
|
||||
self.assertEqual(expected_gle[row][field], gl_entries[row][field])
|
||||
|
||||
def test_reverse_payment_reconciliation(self):
|
||||
customer = create_customer(frappe.generate_hash(length=10), "INR")
|
||||
|
||||
@@ -347,12 +347,11 @@ class TestPaymentRequest(ERPNextTestSuite):
|
||||
]
|
||||
)
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit, against_voucher
|
||||
from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pe.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Payment Entry", "voucher_no": pe.name},
|
||||
fields=["account", "debit", "credit", "against_voucher"],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
import frappe
|
||||
from frappe.query_builder.functions import Sum
|
||||
from frappe.utils import add_days, cint, flt, getdate, nowdate, today
|
||||
|
||||
import erpnext
|
||||
@@ -123,11 +124,10 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
"_Test Account Discount - _TC": [0, 168.03],
|
||||
"Round Off - _TC": [0, 0.3],
|
||||
}
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit from `tabGL Entry`
|
||||
where voucher_type = 'Purchase Invoice' and voucher_no = %s""",
|
||||
pi.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Purchase Invoice", "voucher_no": pi.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
)
|
||||
for d in gl_entries:
|
||||
self.assertEqual([d.debit, d.credit], expected_gl_entries.get(d.account))
|
||||
@@ -317,12 +317,11 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
self.check_gle_for_pi(pi.name)
|
||||
|
||||
def check_gle_for_pi(self, pi):
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, sum(debit) as debit, sum(credit) as credit
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
group by account""",
|
||||
pi,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Purchase Invoice", "voucher_no": pi},
|
||||
fields=["account", {"SUM": "debit", "as": "debit"}, {"SUM": "credit", "as": "credit"}],
|
||||
group_by="account",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -461,12 +460,11 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
|
||||
self.assertTrue(pi.status, "Unpaid")
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pi.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Purchase Invoice", "voucher_no": pi.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
order_by="account asc",
|
||||
)
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
@@ -475,10 +473,11 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
["Creditors - TCP1", 0, 250],
|
||||
]
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
self.assertEqual(expected_values[i][0], gle.account)
|
||||
self.assertEqual(expected_values[i][1], gle.debit)
|
||||
self.assertEqual(expected_values[i][2], gle.credit)
|
||||
# DB account collation isn't portable across MariaDB/Postgres; compare order-independently.
|
||||
self.assertEqual(
|
||||
sorted((gle.account, gle.debit, gle.credit) for gle in gl_entries),
|
||||
sorted((e[0], e[1], e[2]) for e in expected_values),
|
||||
)
|
||||
|
||||
def test_purchase_invoice_calculation(self):
|
||||
pi = frappe.copy_doc(self.globalTestRecords["Purchase Invoice"][0])
|
||||
@@ -546,21 +545,24 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
pi.load_from_db()
|
||||
|
||||
self.assertTrue(
|
||||
frappe.db.sql(
|
||||
"""select name from `tabJournal Entry Account`
|
||||
where reference_type='Purchase Invoice'
|
||||
and reference_name=%s and debit_in_account_currency=300""",
|
||||
pi.name,
|
||||
frappe.get_all(
|
||||
"Journal Entry Account",
|
||||
filters={
|
||||
"reference_type": "Purchase Invoice",
|
||||
"reference_name": pi.name,
|
||||
"debit_in_account_currency": 300,
|
||||
},
|
||||
pluck="name",
|
||||
)
|
||||
)
|
||||
|
||||
pi.cancel()
|
||||
|
||||
self.assertFalse(
|
||||
frappe.db.sql(
|
||||
"""select name from `tabJournal Entry Account`
|
||||
where reference_type='Purchase Invoice' and reference_name=%s""",
|
||||
pi.name,
|
||||
frappe.get_all(
|
||||
"Journal Entry Account",
|
||||
filters={"reference_type": "Purchase Invoice", "reference_name": pi.name},
|
||||
pluck="name",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -604,10 +606,14 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
pi.load_from_db()
|
||||
|
||||
self.assertTrue(
|
||||
frappe.db.sql(
|
||||
"select name from `tabJournal Entry Account` where reference_type='Purchase Invoice' and "
|
||||
"reference_name=%s and debit_in_account_currency=300",
|
||||
pi.name,
|
||||
frappe.get_all(
|
||||
"Journal Entry Account",
|
||||
filters={
|
||||
"reference_type": "Purchase Invoice",
|
||||
"reference_name": pi.name,
|
||||
"debit_in_account_currency": 300,
|
||||
},
|
||||
pluck="name",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -616,10 +622,10 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
pi.cancel()
|
||||
|
||||
self.assertFalse(
|
||||
frappe.db.sql(
|
||||
"select name from `tabJournal Entry Account` where reference_type='Purchase Invoice' and "
|
||||
"reference_name=%s",
|
||||
pi.name,
|
||||
frappe.get_all(
|
||||
"Journal Entry Account",
|
||||
filters={"reference_type": "Purchase Invoice", "reference_name": pi.name},
|
||||
pluck="name",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -629,13 +635,12 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
else:
|
||||
project = frappe.get_doc("Project", {"project_name": "_Test Project for Purchase"})
|
||||
|
||||
existing_purchase_cost = frappe.db.sql(
|
||||
f"""select sum(base_net_amount)
|
||||
from `tabPurchase Invoice Item`
|
||||
where project = '{project.name}'
|
||||
and docstatus=1"""
|
||||
existing_purchase_cost = frappe.get_all(
|
||||
"Purchase Invoice Item",
|
||||
filters={"project": project.name, "docstatus": 1},
|
||||
fields=[{"SUM": "base_net_amount", "as": "base_net_amount"}],
|
||||
)
|
||||
existing_purchase_cost = existing_purchase_cost and existing_purchase_cost[0][0] or 0
|
||||
existing_purchase_cost = existing_purchase_cost and existing_purchase_cost[0].base_net_amount or 0
|
||||
|
||||
pi = make_purchase_invoice(currency="USD", conversion_rate=60, project=project.name)
|
||||
self.assertEqual(
|
||||
@@ -679,12 +684,11 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
)
|
||||
|
||||
# check gl entries for return
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type=%s and voucher_no=%s
|
||||
order by account desc""",
|
||||
("Purchase Invoice", return_pi.name),
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Purchase Invoice", "voucher_no": return_pi.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
order_by="account desc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -773,13 +777,18 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
conversion_rate=50,
|
||||
)
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, account_currency, debit, credit,
|
||||
debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pi.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Purchase Invoice", "voucher_no": pi.name},
|
||||
fields=[
|
||||
"account",
|
||||
"account_currency",
|
||||
"debit",
|
||||
"credit",
|
||||
"debit_in_account_currency",
|
||||
"credit_in_account_currency",
|
||||
],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -821,10 +830,10 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
# cancel
|
||||
pi.cancel()
|
||||
|
||||
gle = frappe.db.sql(
|
||||
"""select name from `tabGL Entry`
|
||||
where voucher_type='Sales Invoice' and voucher_no=%s""",
|
||||
pi.name,
|
||||
gle = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": pi.name},
|
||||
pluck="name",
|
||||
)
|
||||
|
||||
self.assertFalse(gle)
|
||||
@@ -842,13 +851,18 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
expense_account="_Test Account Cost for Goods Sold - TCP1",
|
||||
)
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, account_currency, debit, credit,
|
||||
debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pi.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Purchase Invoice", "voucher_no": pi.name},
|
||||
fields=[
|
||||
"account",
|
||||
"account_currency",
|
||||
"debit",
|
||||
"credit",
|
||||
"debit_in_account_currency",
|
||||
"credit_in_account_currency",
|
||||
],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -877,13 +891,16 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
expense_account="_Test Account Cost for Goods Sold - TCP1",
|
||||
)
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, account_currency, sum(debit) as debit,
|
||||
sum(credit) as credit, debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
group by account, voucher_no order by account asc;""",
|
||||
pi.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Purchase Invoice", "voucher_no": pi.name},
|
||||
fields=[
|
||||
"account",
|
||||
{"SUM": "debit", "as": "debit"},
|
||||
{"SUM": "credit", "as": "credit"},
|
||||
],
|
||||
group_by="account, voucher_no",
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
stock_in_hand_account = get_inventory_account(pi.company, pi.get("items")[0].warehouse)
|
||||
@@ -1145,13 +1162,19 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
"_Test Account Cost for Goods Sold - _TC": {"cost_center": cost_center},
|
||||
}
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, cost_center, account_currency, debit, credit,
|
||||
debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pi.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Purchase Invoice", "voucher_no": pi.name},
|
||||
fields=[
|
||||
"account",
|
||||
"cost_center",
|
||||
"account_currency",
|
||||
"debit",
|
||||
"credit",
|
||||
"debit_in_account_currency",
|
||||
"credit_in_account_currency",
|
||||
],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -1168,13 +1191,19 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
"_Test Account Cost for Goods Sold - _TC": {"cost_center": cost_center},
|
||||
}
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, cost_center, account_currency, debit, credit,
|
||||
debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pi.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Purchase Invoice", "voucher_no": pi.name},
|
||||
fields=[
|
||||
"account",
|
||||
"cost_center",
|
||||
"account_currency",
|
||||
"debit",
|
||||
"credit",
|
||||
"debit_in_account_currency",
|
||||
"credit_in_account_currency",
|
||||
],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -1209,13 +1238,20 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
"_Test Account Cost for Goods Sold - _TC": {"project": item_project.name},
|
||||
}
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, cost_center, project, account_currency, debit, credit,
|
||||
debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pi.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Purchase Invoice", "voucher_no": pi.name},
|
||||
fields=[
|
||||
"account",
|
||||
"cost_center",
|
||||
"project",
|
||||
"account_currency",
|
||||
"debit",
|
||||
"credit",
|
||||
"debit_in_account_currency",
|
||||
"credit_in_account_currency",
|
||||
],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -1269,13 +1305,15 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
[deferred_account, 23.07, 0.0, "2019-03-15"],
|
||||
]
|
||||
|
||||
gl_entries = gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit, posting_date
|
||||
from `tabGL Entry`
|
||||
where voucher_type='Journal Entry' and voucher_detail_no=%s and posting_date <= %s
|
||||
order by posting_date asc, account asc""",
|
||||
(pi.items[0].name, pi.posting_date),
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={
|
||||
"voucher_type": "Journal Entry",
|
||||
"voucher_detail_no": pi.items[0].name,
|
||||
"posting_date": ["<=", pi.posting_date],
|
||||
},
|
||||
fields=["account", "debit", "credit", "posting_date"],
|
||||
order_by="posting_date asc, account asc",
|
||||
)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
@@ -1350,14 +1388,14 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
["_Test Payable USD - _TC", -37500.0],
|
||||
]
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""
|
||||
select account, sum(debit - credit) as balance from `tabGL Entry`
|
||||
where voucher_no=%s
|
||||
group by account
|
||||
order by account asc""",
|
||||
(pi.name),
|
||||
as_dict=1,
|
||||
gle = frappe.qb.DocType("GL Entry")
|
||||
gl_entries = (
|
||||
frappe.qb.from_(gle)
|
||||
.select(gle.account, Sum(gle.debit - gle.credit).as_("balance"))
|
||||
.where(gle.voucher_no == pi.name)
|
||||
.groupby(gle.account)
|
||||
.orderby(gle.account)
|
||||
.run(as_dict=1)
|
||||
)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
@@ -1421,13 +1459,14 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
["_Test Payable USD - _TC", -36500.0],
|
||||
]
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""
|
||||
select account, sum(debit - credit) as balance from `tabGL Entry`
|
||||
where voucher_no=%s
|
||||
group by account order by account asc""",
|
||||
(pi_2.name),
|
||||
as_dict=1,
|
||||
gle = frappe.qb.DocType("GL Entry")
|
||||
gl_entries = (
|
||||
frappe.qb.from_(gle)
|
||||
.select(gle.account, Sum(gle.debit - gle.credit).as_("balance"))
|
||||
.where(gle.voucher_no == pi_2.name)
|
||||
.groupby(gle.account)
|
||||
.orderby(gle.account)
|
||||
.run(as_dict=1)
|
||||
)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
@@ -1436,18 +1475,21 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
|
||||
expected_gle = [["_Test Payable USD - _TC", 70000.0], ["Cash - _TC", -70000.0]]
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""
|
||||
select account, sum(debit - credit) as balance from `tabGL Entry`
|
||||
where voucher_no=%s and is_cancelled=0
|
||||
group by account order by account asc""",
|
||||
(pay.name),
|
||||
as_dict=1,
|
||||
gle = frappe.qb.DocType("GL Entry")
|
||||
gl_entries = (
|
||||
frappe.qb.from_(gle)
|
||||
.select(gle.account, Sum(gle.debit - gle.credit).as_("balance"))
|
||||
.where((gle.voucher_no == pay.name) & (gle.is_cancelled == 0))
|
||||
.groupby(gle.account)
|
||||
.orderby(gle.account)
|
||||
.run(as_dict=1)
|
||||
)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
self.assertEqual(expected_gle[i][0], gle.account)
|
||||
self.assertEqual(expected_gle[i][1], gle.balance)
|
||||
# DB account collation isn't portable across MariaDB/Postgres; compare order-independently.
|
||||
self.assertEqual(
|
||||
sorted((gle.account, gle.balance) for gle in gl_entries),
|
||||
sorted((e[0], e[1]) for e in expected_gle),
|
||||
)
|
||||
|
||||
total_debit_amount = frappe.db.get_all(
|
||||
"Journal Entry Account",
|
||||
@@ -1546,19 +1588,18 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
[tds_account, 0, 3000],
|
||||
]
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry`
|
||||
where voucher_type='Payment Entry' and voucher_no=%s
|
||||
order by account asc""",
|
||||
(payment_entry.name),
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Payment Entry", "voucher_no": payment_entry.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
self.assertEqual(expected_gle[i][0], gle.account)
|
||||
self.assertEqual(expected_gle[i][1], gle.debit)
|
||||
self.assertEqual(expected_gle[i][2], gle.credit)
|
||||
# DB account collation isn't portable across MariaDB/Postgres; compare order-independently.
|
||||
self.assertEqual(
|
||||
sorted((gle.account, gle.debit, gle.credit) for gle in gl_entries),
|
||||
sorted((e[0], e[1], e[2]) for e in expected_gle),
|
||||
)
|
||||
|
||||
# Create Purchase Invoice against Purchase Order
|
||||
purchase_invoice = get_mapped_purchase_invoice(po.name)
|
||||
@@ -1572,19 +1613,21 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
# Zero net effect on final TDS payable on invoice
|
||||
expected_gle = [["_Test Account Cost for Goods Sold - _TC", 30000], ["Creditors - _TC", -30000]]
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, sum(debit - credit) as amount
|
||||
from `tabGL Entry`
|
||||
where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
group by account
|
||||
order by account asc""",
|
||||
(purchase_invoice.name),
|
||||
as_dict=1,
|
||||
gle = frappe.qb.DocType("GL Entry")
|
||||
gl_entries = (
|
||||
frappe.qb.from_(gle)
|
||||
.select(gle.account, Sum(gle.debit - gle.credit).as_("amount"))
|
||||
.where((gle.voucher_type == "Purchase Invoice") & (gle.voucher_no == purchase_invoice.name))
|
||||
.groupby(gle.account)
|
||||
.orderby(gle.account)
|
||||
.run(as_dict=1)
|
||||
)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
self.assertEqual(expected_gle[i][0], gle.account)
|
||||
self.assertEqual(expected_gle[i][1], gle.amount)
|
||||
# DB account collation isn't portable across MariaDB/Postgres; compare order-independently.
|
||||
self.assertEqual(
|
||||
sorted((gle.account, gle.amount) for gle in gl_entries),
|
||||
sorted((e[0], e[1]) for e in expected_gle),
|
||||
)
|
||||
|
||||
payment_entry.load_from_db()
|
||||
tax_allocated = sum(
|
||||
@@ -2476,12 +2519,11 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
pi.insert()
|
||||
pi.submit()
|
||||
|
||||
pr_gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Purchase Receipt' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pr.name,
|
||||
as_dict=1,
|
||||
pr_gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Purchase Receipt", "voucher_no": pr.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
pr_expected_values = [
|
||||
@@ -2494,12 +2536,11 @@ class TestPurchaseInvoice(ERPNextTestSuite, StockTestMixin):
|
||||
self.assertEqual(pr_expected_values[i][1], gle.debit)
|
||||
self.assertEqual(pr_expected_values[i][2], gle.credit)
|
||||
|
||||
pi_gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
pi.name,
|
||||
as_dict=1,
|
||||
pi_gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Purchase Invoice", "voucher_no": pi.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
order_by="account asc",
|
||||
)
|
||||
pi_expected_values = [
|
||||
["Asset Received But Not Billed - _TC", 5000, 0],
|
||||
@@ -3047,17 +3088,25 @@ def check_gl_entries(
|
||||
|
||||
gl_entries = query.run(as_dict=True)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
doc.assertEqual(expected_gle[i][0], gle.account)
|
||||
doc.assertEqual(expected_gle[i][1], gle.debit)
|
||||
doc.assertEqual(expected_gle[i][2], gle.credit)
|
||||
doc.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
|
||||
# MariaDB and Postgres collate `account` differently, so the DB row order isn't portable.
|
||||
# Match each actual GL row against the expected set instead of comparing positionally; like the
|
||||
# original loop (which iterated the actual rows), extra expected rows are tolerated.
|
||||
cols = additional_columns or []
|
||||
|
||||
if additional_columns:
|
||||
j = 4
|
||||
for col in additional_columns:
|
||||
doc.assertEqual(expected_gle[i][j], gle[col])
|
||||
j += 1
|
||||
def _key(account, debit, credit, posting_date, extras):
|
||||
return (account, flt(debit), flt(credit), getdate(posting_date), *(str(v) for v in extras))
|
||||
|
||||
remaining = {}
|
||||
for e in expected_gle:
|
||||
k = _key(e[0], e[1], e[2], e[3], e[4 : 4 + len(cols)])
|
||||
remaining[k] = remaining.get(k, 0) + 1
|
||||
|
||||
for gle in gl_entries:
|
||||
k = _key(gle.account, gle.debit, gle.credit, gle.posting_date, [gle[c] for c in cols])
|
||||
doc.assertGreater(
|
||||
remaining.get(k, 0), 0, msg=f"Unexpected GL entry {k}; expected one of {list(remaining)}"
|
||||
)
|
||||
remaining[k] -= 1
|
||||
|
||||
|
||||
def create_tax_witholding_category(category_name, company, account):
|
||||
|
||||
@@ -69,6 +69,7 @@ class TestRepostAccountingLedger(ERPNextTestSuite):
|
||||
qb.from_(gl)
|
||||
.select(gl.voucher_no, Sum(gl.debit).as_("debit"), Sum(gl.credit).as_("credit"))
|
||||
.where((gl.voucher_no == si.name) & (gl.is_cancelled == 0))
|
||||
.groupby(gl.voucher_no)
|
||||
.run()
|
||||
)
|
||||
|
||||
@@ -82,6 +83,7 @@ class TestRepostAccountingLedger(ERPNextTestSuite):
|
||||
qb.from_(gl)
|
||||
.select(gl.voucher_no, Sum(gl.debit).as_("debit"), Sum(gl.credit).as_("credit"))
|
||||
.where((gl.voucher_no == si.name) & (gl.is_cancelled == 0))
|
||||
.groupby(gl.voucher_no)
|
||||
.run()
|
||||
)
|
||||
|
||||
|
||||
@@ -745,12 +745,11 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
si.insert()
|
||||
si.submit()
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -781,10 +780,10 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
# cancel
|
||||
si.cancel()
|
||||
|
||||
gle = frappe.db.sql(
|
||||
"""select * from `tabGL Entry`
|
||||
where voucher_type='Sales Invoice' and voucher_no=%s""",
|
||||
si.name,
|
||||
gle = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=["*"],
|
||||
)
|
||||
|
||||
self.assertTrue(gle)
|
||||
@@ -1201,12 +1200,11 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
si.insert()
|
||||
si.submit()
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -1229,10 +1227,10 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
# cancel
|
||||
si.cancel()
|
||||
|
||||
gle = frappe.db.sql(
|
||||
"""select * from `tabGL Entry`
|
||||
where voucher_type='Sales Invoice' and voucher_no=%s""",
|
||||
si.name,
|
||||
gle = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=["*"],
|
||||
)
|
||||
|
||||
self.assertTrue(gle)
|
||||
@@ -1651,11 +1649,10 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
cash_amount -= pos.change_amount
|
||||
|
||||
# check stock ledger entries
|
||||
sle = frappe.db.sql(
|
||||
"""select * from `tabStock Ledger Entry`
|
||||
where voucher_type = 'Sales Invoice' and voucher_no = %s""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
sle = frappe.get_all(
|
||||
"Stock Ledger Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=["*"],
|
||||
)[0]
|
||||
self.assertTrue(sle)
|
||||
self.assertEqual(
|
||||
@@ -1663,12 +1660,11 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
)
|
||||
|
||||
# check gl entries
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc, debit asc, credit asc""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
order_by="account asc, debit asc, credit asc",
|
||||
)
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
@@ -1695,15 +1691,15 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
self.assertEqual(expected_gl_entries[i][2], gle.credit)
|
||||
|
||||
si.cancel()
|
||||
gle = frappe.db.sql(
|
||||
"""select * from `tabGL Entry`
|
||||
where voucher_type='Sales Invoice' and voucher_no=%s""",
|
||||
si.name,
|
||||
gle = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=["*"],
|
||||
)
|
||||
|
||||
self.assertTrue(gle)
|
||||
|
||||
frappe.db.sql("delete from `tabPOS Profile`")
|
||||
frappe.db.delete("POS Profile")
|
||||
|
||||
def test_bin_details_of_packed_item(self):
|
||||
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
|
||||
@@ -1770,12 +1766,11 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
si.insert()
|
||||
si.submit()
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
order_by="account asc",
|
||||
)
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
@@ -1790,12 +1785,11 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
def test_sales_invoice_gl_entry_with_perpetual_inventory_non_stock_item(self):
|
||||
si = create_sales_invoice(item="_Test Non Stock Item")
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
order_by="account asc",
|
||||
)
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
@@ -1849,18 +1843,18 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
si.load_from_db()
|
||||
|
||||
self.assertTrue(
|
||||
frappe.db.sql(
|
||||
"""select name from `tabJournal Entry Account`
|
||||
where reference_name=%s""",
|
||||
si.name,
|
||||
frappe.get_all(
|
||||
"Journal Entry Account",
|
||||
filters={"reference_name": si.name},
|
||||
pluck="name",
|
||||
)
|
||||
)
|
||||
|
||||
self.assertTrue(
|
||||
frappe.db.sql(
|
||||
"""select name from `tabJournal Entry Account`
|
||||
where reference_name=%s and credit_in_account_currency=300""",
|
||||
si.name,
|
||||
frappe.get_all(
|
||||
"Journal Entry Account",
|
||||
filters={"reference_name": si.name, "credit_in_account_currency": 300},
|
||||
pluck="name",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -2172,13 +2166,18 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
conversion_rate=50,
|
||||
)
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, account_currency, debit, credit,
|
||||
debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=[
|
||||
"account",
|
||||
"account_currency",
|
||||
"debit",
|
||||
"credit",
|
||||
"debit_in_account_currency",
|
||||
"credit_in_account_currency",
|
||||
],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -2213,10 +2212,10 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
# cancel
|
||||
si.cancel()
|
||||
|
||||
gle = frappe.db.sql(
|
||||
"""select name from `tabGL Entry`
|
||||
where voucher_type='Sales Invoice' and voucher_no=%s""",
|
||||
si.name,
|
||||
gle = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
pluck="name",
|
||||
)
|
||||
|
||||
self.assertTrue(gle)
|
||||
@@ -2243,14 +2242,16 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
)
|
||||
si.submit()
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select transaction_currency, transaction_exchange_rate,
|
||||
debit_in_transaction_currency, credit_in_transaction_currency
|
||||
from `tabGL Entry`
|
||||
where voucher_type='Sales Invoice' and voucher_no=%s and account = 'Sales - _TC'
|
||||
order by account asc""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name, "account": "Sales - _TC"},
|
||||
fields=[
|
||||
"transaction_currency",
|
||||
"transaction_exchange_rate",
|
||||
"debit_in_transaction_currency",
|
||||
"credit_in_transaction_currency",
|
||||
],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
expected_gle = {
|
||||
@@ -2595,12 +2596,11 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
]
|
||||
)
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
for gle in gl_entries:
|
||||
@@ -2652,13 +2652,12 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
"Sales - _TC": [0.0, 1272.20],
|
||||
}
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, sum(debit) as debit, sum(credit) as credit
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
group by account
|
||||
order by account asc""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=["account", {"SUM": "debit", "as": "debit"}, {"SUM": "credit", "as": "credit"}],
|
||||
group_by="account",
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
for gle in gl_entries:
|
||||
@@ -2719,13 +2718,12 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
]
|
||||
)
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, sum(debit) as debit, sum(credit) as credit
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
group by account
|
||||
order by account asc""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=["account", {"SUM": "debit", "as": "debit"}, {"SUM": "credit", "as": "credit"}],
|
||||
group_by="account",
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
debit_credit_diff = 0
|
||||
@@ -2735,7 +2733,9 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
self.assertEqual(expected_values[gle.account][2], gle.credit)
|
||||
debit_credit_diff += gle.debit - gle.credit
|
||||
|
||||
self.assertEqual(debit_credit_diff, 0)
|
||||
# Postgres returns DECIMAL columns as float (DEC2FLOAT), so a debit-credit sum carries a
|
||||
# tiny FP residue where MariaDB's DECIMAL arithmetic is exact; assert it's ~0.
|
||||
self.assertAlmostEqual(debit_credit_diff, 0)
|
||||
|
||||
round_off_gle = frappe.db.get_value(
|
||||
"GL Entry",
|
||||
@@ -2819,13 +2819,19 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
"Sales - _TC": {"cost_center": cost_center},
|
||||
}
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, cost_center, account_currency, debit, credit,
|
||||
debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=[
|
||||
"account",
|
||||
"cost_center",
|
||||
"account_currency",
|
||||
"debit",
|
||||
"credit",
|
||||
"debit_in_account_currency",
|
||||
"credit_in_account_currency",
|
||||
],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -2862,13 +2868,20 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
"Sales - _TC": {"project": item_project.name},
|
||||
}
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, cost_center, project, account_currency, debit, credit,
|
||||
debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
sales_invoice.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": sales_invoice.name},
|
||||
fields=[
|
||||
"account",
|
||||
"cost_center",
|
||||
"project",
|
||||
"account_currency",
|
||||
"debit",
|
||||
"credit",
|
||||
"debit_in_account_currency",
|
||||
"credit_in_account_currency",
|
||||
],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -2885,13 +2898,19 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
"Sales - _TC": {"cost_center": cost_center},
|
||||
}
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, cost_center, account_currency, debit, credit,
|
||||
debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc""",
|
||||
si.name,
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"voucher_type": "Sales Invoice", "voucher_no": si.name},
|
||||
fields=[
|
||||
"account",
|
||||
"cost_center",
|
||||
"account_currency",
|
||||
"debit",
|
||||
"credit",
|
||||
"debit_in_account_currency",
|
||||
"credit_in_account_currency",
|
||||
],
|
||||
order_by="account asc",
|
||||
)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@@ -4169,13 +4188,15 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
[deferred_account, 2022.47, 0.0, "2019-03-15"],
|
||||
]
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""select account, debit, credit, posting_date
|
||||
from `tabGL Entry`
|
||||
where voucher_type='Journal Entry' and voucher_detail_no=%s and posting_date <= %s
|
||||
order by posting_date asc, account asc""",
|
||||
(si.items[0].name, si.posting_date),
|
||||
as_dict=1,
|
||||
gl_entries = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={
|
||||
"voucher_type": "Journal Entry",
|
||||
"voucher_detail_no": si.items[0].name,
|
||||
"posting_date": ["<=", si.posting_date],
|
||||
},
|
||||
fields=["account", "debit", "credit", "posting_date"],
|
||||
order_by="posting_date asc, account asc",
|
||||
)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
@@ -4817,7 +4838,8 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
{"account": "Temporary Opening - _TC", "debit": 0.0, "credit": 138.09, "is_opening": "Yes"},
|
||||
]
|
||||
self.assertEqual(len(actual), 4)
|
||||
self.assertEqual(expected, actual)
|
||||
# DB account collation isn't portable across MariaDB/Postgres; compare order-independently.
|
||||
self.assertCountEqual(actual, expected)
|
||||
|
||||
@ERPNextTestSuite.change_settings("Accounts Settings", {"enable_common_party_accounting": True})
|
||||
def test_common_party_with_foreign_currency_jv(self):
|
||||
@@ -5122,7 +5144,7 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
|
||||
def test_pos_sales_invoice_creation_during_pos_invoice_mode(self):
|
||||
# Deleting all opening entry
|
||||
frappe.db.sql("delete from `tabPOS Opening Entry`")
|
||||
frappe.db.delete("POS Opening Entry")
|
||||
|
||||
with self.change_settings("POS Settings", {"invoice_type": "POS Invoice"}):
|
||||
pos_profile = make_pos_profile()
|
||||
@@ -5492,6 +5514,11 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date, voucher_type="
|
||||
|
||||
doc.assertGreater(len(gl_entries), 0)
|
||||
|
||||
# MariaDB and Postgres collate `account` differently, so the DB ordering isn't portable;
|
||||
# sort both sides identically (by the compared values) before the positional check.
|
||||
gl_entries = sorted(gl_entries, key=lambda g: (g.account, g.debit, g.credit))
|
||||
expected_gle = sorted(expected_gle, key=lambda e: (e[0], e[1], e[2]))
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
doc.assertEqual(expected_gle[i][0], gle.account)
|
||||
doc.assertEqual(expected_gle[i][1], gle.debit)
|
||||
@@ -5639,17 +5666,21 @@ def create_sales_invoice_against_cost_center(**args):
|
||||
|
||||
|
||||
def get_outstanding_amount(against_voucher_type, against_voucher, account, party, party_type):
|
||||
bal = flt(
|
||||
frappe.db.sql(
|
||||
"""
|
||||
select sum(debit_in_account_currency) - sum(credit_in_account_currency)
|
||||
from `tabGL Entry`
|
||||
where against_voucher_type=%s and against_voucher=%s
|
||||
and account = %s and party = %s and party_type = %s""",
|
||||
(against_voucher_type, against_voucher, account, party, party_type),
|
||||
)[0][0]
|
||||
or 0.0
|
||||
balance = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={
|
||||
"against_voucher_type": against_voucher_type,
|
||||
"against_voucher": against_voucher,
|
||||
"account": account,
|
||||
"party": party,
|
||||
"party_type": party_type,
|
||||
},
|
||||
fields=[
|
||||
{"SUM": "debit_in_account_currency", "as": "debit"},
|
||||
{"SUM": "credit_in_account_currency", "as": "credit"},
|
||||
],
|
||||
)
|
||||
bal = flt(balance[0].debit) - flt(balance[0].credit)
|
||||
|
||||
if against_voucher_type == "Purchase Invoice":
|
||||
bal = bal * -1
|
||||
|
||||
@@ -85,8 +85,8 @@ class TestAsset(AssetSetup):
|
||||
self.assertRaises(frappe.ValidationError, asset.save)
|
||||
|
||||
def test_validate_item(self):
|
||||
asset = create_asset(item_code="MacBook Pro", do_not_save=1)
|
||||
item = frappe.get_doc("Item", "MacBook Pro")
|
||||
asset = create_asset(item_code="Macbook Pro", do_not_save=1)
|
||||
item = frappe.get_doc("Item", "Macbook Pro")
|
||||
|
||||
item.disabled = 1
|
||||
item.save()
|
||||
@@ -140,7 +140,7 @@ class TestAsset(AssetSetup):
|
||||
)
|
||||
|
||||
gle = get_gl_entries("Purchase Invoice", pi.name)
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
self.assertCountEqual(gle, expected_gle)
|
||||
|
||||
pi.cancel()
|
||||
asset.cancel()
|
||||
@@ -283,7 +283,7 @@ class TestAsset(AssetSetup):
|
||||
)
|
||||
|
||||
gle = get_gl_entries("Journal Entry", asset.journal_entry_for_scrap)
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
self.assertCountEqual(gle, expected_gle)
|
||||
|
||||
restore_asset(asset.name)
|
||||
second_asset_depr_schedule.load_from_db()
|
||||
@@ -362,7 +362,7 @@ class TestAsset(AssetSetup):
|
||||
("Debtors - _TC", 25000.0, 0.0),
|
||||
)
|
||||
gle = get_gl_entries("Sales Invoice", si.name)
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
self.assertCountEqual(gle, expected_gle)
|
||||
|
||||
si.cancel()
|
||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
|
||||
@@ -436,7 +436,7 @@ class TestAsset(AssetSetup):
|
||||
)
|
||||
|
||||
gle = get_gl_entries("Sales Invoice", si.name)
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
self.assertCountEqual(gle, expected_gle)
|
||||
|
||||
def test_asset_with_maintenance_required_status_after_sale(self):
|
||||
asset = create_asset(
|
||||
@@ -577,7 +577,7 @@ class TestAsset(AssetSetup):
|
||||
)
|
||||
|
||||
pr_gle = get_gl_entries("Purchase Receipt", pr.name)
|
||||
self.assertSequenceEqual(pr_gle, expected_gle)
|
||||
self.assertCountEqual(pr_gle, expected_gle)
|
||||
|
||||
pi = make_invoice(pr.name)
|
||||
pi.submit()
|
||||
@@ -590,7 +590,7 @@ class TestAsset(AssetSetup):
|
||||
)
|
||||
|
||||
pi_gle = get_gl_entries("Purchase Invoice", pi.name)
|
||||
self.assertSequenceEqual(pi_gle, expected_gle)
|
||||
self.assertCountEqual(pi_gle, expected_gle)
|
||||
|
||||
asset = frappe.db.get_value("Asset", {"purchase_receipt": pr.name, "docstatus": 0}, "name")
|
||||
|
||||
@@ -617,7 +617,7 @@ class TestAsset(AssetSetup):
|
||||
expected_gle = (("_Test Fixed Asset - _TC", 5250.0, 0.0), ("CWIP Account - _TC", 0.0, 5250.0))
|
||||
|
||||
gle = get_gl_entries("Asset", asset_doc.name)
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
self.assertCountEqual(gle, expected_gle)
|
||||
|
||||
def test_asset_cwip_toggling_cases(self):
|
||||
cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting")
|
||||
@@ -1732,14 +1732,18 @@ class TestDepreciationBasics(AssetSetup):
|
||||
("_Test Depreciations - _TC", 30000.0, 0.0),
|
||||
)
|
||||
|
||||
gle = frappe.db.sql(
|
||||
"""select account, debit, credit from `tabGL Entry`
|
||||
where against_voucher_type='Asset' and against_voucher = %s
|
||||
order by account""",
|
||||
asset.name,
|
||||
)
|
||||
gle = [
|
||||
tuple(row)
|
||||
for row in frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={"against_voucher_type": "Asset", "against_voucher": asset.name},
|
||||
fields=["account", "debit", "credit"],
|
||||
order_by="account",
|
||||
as_list=True,
|
||||
)
|
||||
]
|
||||
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
self.assertCountEqual(gle, expected_gle)
|
||||
self.assertEqual(asset.get("value_after_depreciation"), 70000)
|
||||
|
||||
def test_expected_value_change(self):
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# See license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.query_builder.functions import Sum
|
||||
from frappe.utils import cint, flt, now_datetime
|
||||
|
||||
from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries
|
||||
@@ -549,34 +550,33 @@ def create_depreciation_asset(**args):
|
||||
|
||||
|
||||
def get_actual_gle_dict(name):
|
||||
gle = frappe.qb.DocType("GL Entry")
|
||||
diff = Sum(gle.debit - gle.credit)
|
||||
return dict(
|
||||
frappe.db.sql(
|
||||
"""
|
||||
select account, sum(debit-credit) as diff
|
||||
from `tabGL Entry`
|
||||
where voucher_type = 'Asset Capitalization' and voucher_no = %s
|
||||
group by account
|
||||
having diff != 0
|
||||
""",
|
||||
name,
|
||||
)
|
||||
frappe.qb.from_(gle)
|
||||
.select(gle.account, diff.as_("diff"))
|
||||
.where((gle.voucher_type == "Asset Capitalization") & (gle.voucher_no == name))
|
||||
.groupby(gle.account)
|
||||
.having(diff != 0)
|
||||
.run()
|
||||
)
|
||||
|
||||
|
||||
def get_actual_sle_dict(name):
|
||||
sles = frappe.db.sql(
|
||||
"""
|
||||
select
|
||||
item_code, warehouse,
|
||||
sum(actual_qty) as actual_qty,
|
||||
sum(stock_value_difference) as stock_value_difference
|
||||
from `tabStock Ledger Entry`
|
||||
where voucher_type = 'Asset Capitalization' and voucher_no = %s
|
||||
group by item_code, warehouse
|
||||
having actual_qty != 0
|
||||
""",
|
||||
name,
|
||||
as_dict=1,
|
||||
sle = frappe.qb.DocType("Stock Ledger Entry")
|
||||
actual_qty = Sum(sle.actual_qty)
|
||||
sles = (
|
||||
frappe.qb.from_(sle)
|
||||
.select(
|
||||
sle.item_code,
|
||||
sle.warehouse,
|
||||
actual_qty.as_("actual_qty"),
|
||||
Sum(sle.stock_value_difference).as_("stock_value_difference"),
|
||||
)
|
||||
.where((sle.voucher_type == "Asset Capitalization") & (sle.voucher_no == name))
|
||||
.groupby(sle.item_code, sle.warehouse)
|
||||
.having(actual_qty != 0)
|
||||
.run(as_dict=1)
|
||||
)
|
||||
|
||||
sle_dict = {}
|
||||
|
||||
@@ -477,10 +477,8 @@ class TestPurchaseOrder(ERPNextTestSuite):
|
||||
item_doc.save()
|
||||
else:
|
||||
# update valid from
|
||||
frappe.db.sql(
|
||||
"""UPDATE `tabItem Tax` set valid_from = CURRENT_DATE
|
||||
where parent = %(item)s and item_tax_template = %(tax)s""",
|
||||
{"item": item, "tax": tax_template},
|
||||
frappe.db.set_value(
|
||||
"Item Tax", {"parent": item, "item_tax_template": tax_template}, "valid_from", nowdate()
|
||||
)
|
||||
|
||||
po = create_purchase_order(item_code=item, qty=1, do_not_save=1)
|
||||
@@ -527,10 +525,8 @@ class TestPurchaseOrder(ERPNextTestSuite):
|
||||
self.assertEqual(po.taxes[1].total, 840)
|
||||
|
||||
# teardown
|
||||
frappe.db.sql(
|
||||
"""UPDATE `tabItem Tax` set valid_from = NULL
|
||||
where parent = %(item)s and item_tax_template = %(tax)s""",
|
||||
{"item": item, "tax": tax_template},
|
||||
frappe.db.set_value(
|
||||
"Item Tax", {"parent": item, "item_tax_template": tax_template}, "valid_from", None
|
||||
)
|
||||
po.cancel()
|
||||
po.delete()
|
||||
@@ -652,7 +648,7 @@ class TestPurchaseOrder(ERPNextTestSuite):
|
||||
|
||||
def test_purchase_order_on_hold(self):
|
||||
po = create_purchase_order(item_code="_Test Product Bundle Item")
|
||||
po.db_set("Status", "On Hold")
|
||||
po.db_set("status", "On Hold")
|
||||
pi = make_pi_from_po(po.name)
|
||||
pr = make_purchase_receipt(po.name)
|
||||
self.assertRaises(frappe.ValidationError, pr.submit)
|
||||
|
||||
@@ -56,7 +56,7 @@ class TestEmployee(ERPNextTestSuite):
|
||||
frappe.qb.from_(Employee)
|
||||
.select(Employee.name)
|
||||
.where(Criterion.all(build_qb_match_conditions("Employee")))
|
||||
.orderby(Employee.Name)
|
||||
.orderby(Employee.name)
|
||||
).run(pluck=Employee.name)
|
||||
employee_list = frappe.db.get_list("Employee", pluck="name", order_by="name")
|
||||
|
||||
|
||||
@@ -924,12 +924,15 @@ class TestDeliveryNote(ERPNextTestSuite):
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
stock_value_difference = abs(
|
||||
frappe.db.sql(
|
||||
"""select sum(stock_value_difference)
|
||||
from `tabStock Ledger Entry` where voucher_type='Delivery Note' and voucher_no=%s
|
||||
and warehouse='Stores - TCP1'""",
|
||||
dn.name,
|
||||
)[0][0]
|
||||
frappe.get_all(
|
||||
"Stock Ledger Entry",
|
||||
filters={
|
||||
"voucher_type": "Delivery Note",
|
||||
"voucher_no": dn.name,
|
||||
"warehouse": "Stores - TCP1",
|
||||
},
|
||||
fields=[{"SUM": "stock_value_difference", "as": "svd"}],
|
||||
)[0].svd
|
||||
)
|
||||
|
||||
expected_values = {
|
||||
@@ -955,7 +958,7 @@ class TestDeliveryNote(ERPNextTestSuite):
|
||||
dn.submit()
|
||||
|
||||
update_delivery_note_status(dn.name, "Closed")
|
||||
self.assertEqual(frappe.db.get_value("Delivery Note", dn.name, "Status"), "Closed")
|
||||
self.assertEqual(frappe.db.get_value("Delivery Note", dn.name, "status"), "Closed")
|
||||
|
||||
# Check cancelling closed delivery note
|
||||
dn.load_from_db()
|
||||
|
||||
@@ -1267,6 +1267,10 @@ class TestPurchaseReceipt(ERPNextTestSuite):
|
||||
for sle in sl_entries:
|
||||
self.assertEqual(expected_sle[sle.warehouse], sle.actual_qty)
|
||||
|
||||
# MariaDB and Postgres collate `account` differently, so the DB ordering isn't portable;
|
||||
# sort both sides identically (by the compared values) before the positional check.
|
||||
gl_entries = sorted(gl_entries, key=lambda g: (g.account, g.debit, g.credit))
|
||||
expected_gle = sorted(expected_gle, key=lambda e: (e[0], e[1], e[2]))
|
||||
for i, gle in enumerate(gl_entries):
|
||||
self.assertEqual(gle.account, expected_gle[i][0])
|
||||
self.assertEqual(gle.debit, expected_gle[i][1])
|
||||
@@ -6099,12 +6103,11 @@ def prepare_data_for_internal_transfer():
|
||||
|
||||
|
||||
def get_sl_entries(voucher_type, voucher_no):
|
||||
return frappe.db.sql(
|
||||
""" select actual_qty, warehouse, stock_value_difference
|
||||
from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s
|
||||
order by posting_time desc""",
|
||||
(voucher_type, voucher_no),
|
||||
as_dict=1,
|
||||
return frappe.get_all(
|
||||
"Stock Ledger Entry",
|
||||
filters={"voucher_type": voucher_type, "voucher_no": voucher_no},
|
||||
fields=["actual_qty", "warehouse", "stock_value_difference"],
|
||||
order_by="posting_time desc",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ from uuid import uuid4
|
||||
|
||||
import frappe
|
||||
from frappe.core.page.permission_manager.permission_manager import reset
|
||||
from frappe.query_builder.functions import Timestamp
|
||||
from frappe.query_builder.functions import CombineDatetime
|
||||
from frappe.utils import add_days, add_to_date, flt, today
|
||||
|
||||
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
|
||||
@@ -34,6 +34,54 @@ class TestStockLedgerEntry(ERPNextTestSuite, StockTestMixin):
|
||||
create_items()
|
||||
reset("Stock Entry")
|
||||
|
||||
def test_incoming_value_for_transferred_serial_no_is_deterministic(self):
|
||||
"""get_incoming_value_for_serial_nos picks the latest SLE (posting_date desc, limit 1) for a
|
||||
serial transferred to another company. posting_date alone is non-total, so two same-date SLEs
|
||||
with different incoming_rate could be resolved differently on MariaDB vs Postgres. creation/name
|
||||
tie-breaks make the latest SLE win identically on both engines."""
|
||||
from erpnext.stock.stock_ledger import update_entries_after
|
||||
|
||||
item = "_Test Serialized Item"
|
||||
serial = "_Test SN Tie 9"
|
||||
company_a, company_b = "_Test Company", "_Test Company 1"
|
||||
if frappe.db.exists("Serial No", serial):
|
||||
frappe.delete_doc("Serial No", serial, force=1)
|
||||
frappe.get_doc(
|
||||
{"doctype": "Serial No", "serial_no": serial, "item_code": item, "company": company_b}
|
||||
).insert(ignore_permissions=True)
|
||||
|
||||
def mk_sle(name, rate):
|
||||
if frappe.db.exists("Stock Ledger Entry", name):
|
||||
frappe.delete_doc("Stock Ledger Entry", name, force=1)
|
||||
doc = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Stock Ledger Entry",
|
||||
"item_code": item,
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"company": company_a,
|
||||
"posting_date": "2026-06-01",
|
||||
"posting_time": "10:00:00",
|
||||
"actual_qty": 1,
|
||||
"incoming_rate": rate,
|
||||
"is_cancelled": 0,
|
||||
"serial_no": serial,
|
||||
"voucher_type": "Stock Entry",
|
||||
"voucher_no": "TEST-TIE",
|
||||
}
|
||||
)
|
||||
doc.name = name
|
||||
doc.flags.name_set = True
|
||||
doc.db_insert()
|
||||
|
||||
mk_sle("MAT-SLE-TIE-A", 100)
|
||||
mk_sle("MAT-SLE-TIE-B", 200) # later/larger name -> deterministic winner
|
||||
|
||||
value = update_entries_after.get_incoming_value_for_serial_nos(
|
||||
None, frappe._dict(company=company_a), [serial]
|
||||
)
|
||||
# the latest (creation/name desc) same-date SLE wins -> 200 on both engines
|
||||
self.assertEqual(value, 200.0)
|
||||
|
||||
def test_item_cost_reposting(self):
|
||||
company = "_Test Company"
|
||||
|
||||
@@ -1275,7 +1323,7 @@ class TestStockLedgerEntry(ERPNextTestSuite, StockTestMixin):
|
||||
.where(sle.voucher_no == transfer.name)
|
||||
.where(sle.voucher_type == transfer.doctype)
|
||||
.where(sle.is_cancelled == 0)
|
||||
.orderby(Timestamp(sle.posting_date, sle.posting_time))
|
||||
.orderby(CombineDatetime(sle.posting_date, sle.posting_time))
|
||||
.orderby(sle.creation)
|
||||
.run(as_dict=True)
|
||||
)
|
||||
@@ -1530,17 +1578,12 @@ def create_delivery_note_entries_for_batchwise_item_valuation_test(dn_entry_list
|
||||
|
||||
|
||||
def fetch_sle_details_for_doc_list(doc_list, columns, as_dict=1):
|
||||
return frappe.db.sql(
|
||||
f"""
|
||||
SELECT { ', '.join(columns)}
|
||||
FROM `tabStock Ledger Entry`
|
||||
WHERE
|
||||
voucher_no IN %(voucher_nos)s
|
||||
and docstatus = 1
|
||||
ORDER BY timestamp(posting_date, posting_time) ASC, CREATION ASC
|
||||
""",
|
||||
dict(voucher_nos=[doc.name for doc in doc_list]),
|
||||
as_dict=as_dict,
|
||||
return frappe.get_all(
|
||||
"Stock Ledger Entry",
|
||||
filters={"voucher_no": ["in", [doc.name for doc in doc_list]], "docstatus": 1},
|
||||
fields=columns,
|
||||
order_by="posting_datetime asc, creation asc",
|
||||
as_list=not as_dict,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -40,24 +40,15 @@ class TestStockBalance(ERPNextTestSuite):
|
||||
make_stock_entry(item_code=item_code, **movement)
|
||||
|
||||
def assertInvariants(self, rows):
|
||||
last_balance = frappe.db.sql(
|
||||
"""
|
||||
WITH last_balances AS (
|
||||
SELECT item_code, warehouse,
|
||||
stock_value, qty_after_transaction,
|
||||
ROW_NUMBER() OVER (PARTITION BY item_code, warehouse
|
||||
ORDER BY timestamp(posting_date, posting_time) desc, creation desc)
|
||||
AS rn
|
||||
FROM `tabStock Ledger Entry`
|
||||
where is_cancelled=0
|
||||
)
|
||||
SELECT * FROM last_balances WHERE rn = 1""",
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
item_wh_stock = _dict()
|
||||
|
||||
for line in last_balance:
|
||||
# Latest balance per (item_code, warehouse): first row wins because of the desc ordering.
|
||||
for line in frappe.get_all(
|
||||
"Stock Ledger Entry",
|
||||
filters={"is_cancelled": 0},
|
||||
fields=["item_code", "warehouse", "stock_value", "qty_after_transaction"],
|
||||
order_by="posting_datetime desc, creation desc",
|
||||
):
|
||||
item_wh_stock.setdefault((line.item_code, line.warehouse), line)
|
||||
|
||||
for row in rows:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import json
|
||||
|
||||
import frappe
|
||||
from frappe.query_builder.functions import Timestamp
|
||||
from frappe.query_builder.functions import CombineDatetime
|
||||
|
||||
from erpnext.stock.utils import scan_barcode
|
||||
from erpnext.tests.utils import ERPNextTestSuite
|
||||
@@ -35,7 +35,7 @@ class StockTestMixin:
|
||||
query = query.where(sle[key] == value)
|
||||
|
||||
sles = (
|
||||
query.orderby(Timestamp(sle.posting_date, sle.posting_time))
|
||||
query.orderby(CombineDatetime(sle.posting_date, sle.posting_time))
|
||||
.orderby(sle.creation)
|
||||
.run(as_dict=True)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user