From 8b15a965dd0ffea82c1d55a2893a79cf1fd243bb Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:51:33 +0530 Subject: [PATCH 01/45] fix: no permission to read Doctype (backport #44256) (#44258) fix: no permission to read Doctype (#44256) (cherry picked from commit 57293aa18a2d34b66b35dc346ec84c259c6d6c11) Co-authored-by: rohitwaghchaure --- .../report/serial_and_batch_summary/serial_and_batch_summary.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/erpnext/stock/report/serial_and_batch_summary/serial_and_batch_summary.py b/erpnext/stock/report/serial_and_batch_summary/serial_and_batch_summary.py index 15d9a12bc65..486828af1cc 100644 --- a/erpnext/stock/report/serial_and_batch_summary/serial_and_batch_summary.py +++ b/erpnext/stock/report/serial_and_batch_summary/serial_and_batch_summary.py @@ -106,8 +106,6 @@ def get_columns(filters, data): { "label": _("Voucher Type"), "fieldname": "voucher_type", - "fieldtype": "Link", - "options": "DocType", "width": 120, }, { From d4f0512a10550914b2aad1795fe8692658aab67a Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:52:37 +0530 Subject: [PATCH 02/45] fix: added Stock UOM field for RM in work order (backport #44185) (#44237) * fix: added Stock UOM field for RM in work order (#44185) fix: added UOM field for RM in work order (cherry picked from commit cc571aca8f56310b7f87244ebdbdb91fd6b57222) # Conflicts: # erpnext/manufacturing/doctype/work_order_item/work_order_item.json # erpnext/patches.txt * chore: fix conflicts * chore: fix conflicts --------- Co-authored-by: rohitwaghchaure --- .../doctype/work_order_item/work_order_item.json | 13 +++++++++++-- .../doctype/work_order_item/work_order_item.py | 2 ++ erpnext/patches.txt | 1 + .../v14_0/update_stock_uom_in_work_order_item.py | 15 +++++++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 erpnext/patches/v14_0/update_stock_uom_in_work_order_item.py diff --git a/erpnext/manufacturing/doctype/work_order_item/work_order_item.json b/erpnext/manufacturing/doctype/work_order_item/work_order_item.json index 0f4d693544e..580168180a7 100644 --- a/erpnext/manufacturing/doctype/work_order_item/work_order_item.json +++ b/erpnext/manufacturing/doctype/work_order_item/work_order_item.json @@ -15,6 +15,7 @@ "include_item_in_manufacturing", "qty_section", "required_qty", + "stock_uom", "rate", "amount", "column_break_11", @@ -138,11 +139,19 @@ "in_list_view": 1, "label": "Returned Qty ", "read_only": 1 + }, + { + "fetch_from": "item_code.stock_uom", + "fieldname": "stock_uom", + "fieldtype": "Link", + "label": "Stock UOM", + "options": "UOM", + "read_only": 1 } ], "istable": 1, "links": [], - "modified": "2024-02-11 15:45:32.318374", + "modified": "2024-11-19 15:48:16.823384", "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order Item", @@ -153,4 +162,4 @@ "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/manufacturing/doctype/work_order_item/work_order_item.py b/erpnext/manufacturing/doctype/work_order_item/work_order_item.py index 267ca5d21de..04f78eb1c3b 100644 --- a/erpnext/manufacturing/doctype/work_order_item/work_order_item.py +++ b/erpnext/manufacturing/doctype/work_order_item/work_order_item.py @@ -25,6 +25,7 @@ class WorkOrderItem(Document): item_code: DF.Link | None item_name: DF.Data | None operation: DF.Link | None + operation_row_id: DF.Int parent: DF.Data parentfield: DF.Data parenttype: DF.Data @@ -32,6 +33,7 @@ class WorkOrderItem(Document): required_qty: DF.Float returned_qty: DF.Float source_warehouse: DF.Link | None + stock_uom: DF.Link | None transferred_qty: DF.Float # end: auto-generated types diff --git a/erpnext/patches.txt b/erpnext/patches.txt index ab416d9d6c3..2716aa9883b 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -382,3 +382,4 @@ erpnext.patches.v15_0.link_purchase_item_to_asset_doc erpnext.patches.v14_0.update_currency_exchange_settings_for_frankfurter erpnext.patches.v15_0.update_task_assignee_email_field_in_asset_maintenance_log erpnext.patches.v15_0.update_sub_voucher_type_in_gl_entries +erpnext.patches.v14_0.update_stock_uom_in_work_order_item diff --git a/erpnext/patches/v14_0/update_stock_uom_in_work_order_item.py b/erpnext/patches/v14_0/update_stock_uom_in_work_order_item.py new file mode 100644 index 00000000000..d611065d8f1 --- /dev/null +++ b/erpnext/patches/v14_0/update_stock_uom_in_work_order_item.py @@ -0,0 +1,15 @@ +import frappe + + +def execute(): + frappe.db.sql( + """ + UPDATE + `tabWork Order Item`, `tabItem` + SET + `tabWork Order Item`.stock_uom = `tabItem`.stock_uom + WHERE + `tabWork Order Item`.item_code = `tabItem`.name + AND `tabWork Order Item`.docstatus = 1 + """ + ) From 0ffeb9f6adbc581ecc9a0403c2680079213f9d93 Mon Sep 17 00:00:00 2001 From: venkat102 Date: Mon, 18 Nov 2024 15:42:01 +0530 Subject: [PATCH 03/45] fix: include current invoice amount when tax_on_excess_amount is checked (cherry picked from commit b74f2896cdfc0571d352930d5d84737d0211cff3) --- .../tax_withholding_category/tax_withholding_category.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index 46a0916c79f..69c7eb1153c 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -568,7 +568,7 @@ def get_tds_amount(ldc, parties, inv, tax_details, vouchers): if (cumulative_threshold and supp_credit_amt >= cumulative_threshold) and cint( tax_details.tax_on_excess_amount ): - supp_credit_amt = net_total - cumulative_threshold + supp_credit_amt = net_total + tax_withholding_net_total - cumulative_threshold if ldc and is_valid_certificate(ldc, inv.get("posting_date") or inv.get("transaction_date"), 0): tds_amount = get_lower_deduction_amount( From 08b896fc2cee813170e477548e5cf6c194b8b8e8 Mon Sep 17 00:00:00 2001 From: venkat102 Date: Mon, 18 Nov 2024 15:48:39 +0530 Subject: [PATCH 04/45] test: add unit test for tax on excess amount (cherry picked from commit 4820273595be0f49f021685931f34972c39f1f70) --- .../test_tax_withholding_category.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py index 2b7ae5fd689..f9f34380d55 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py @@ -167,6 +167,45 @@ class TestTaxWithholdingCategory(FrappeTestCase): for d in reversed(invoices): d.cancel() + def test_cumulative_threshold_with_tax_on_excess_amount(self): + invoices = [] + frappe.db.set_value("Supplier", "Test TDS Supplier3", "tax_withholding_category", "New TDS Category") + + # Invoice with tax and without exceeding single and cumulative thresholds + for _ in range(2): + pi = create_purchase_invoice(supplier="Test TDS Supplier3", rate=10000, do_not_save=True) + pi.apply_tds = 1 + pi.append( + "taxes", + { + "category": "Total", + "charge_type": "Actual", + "account_head": "_Test Account VAT - _TC", + "cost_center": "Main - _TC", + "tax_amount": 500, + "description": "Test", + "add_deduct_tax": "Add", + }, + ) + pi.save() + pi.submit() + invoices.append(pi) + + # Third Invoice exceeds single threshold and not exceeding cumulative threshold + pi1 = create_purchase_invoice(supplier="Test TDS Supplier3", rate=20000) + pi1.apply_tds = 1 + pi1.save() + pi1.submit() + invoices.append(pi1) + + # Cumulative threshold is 10,000 + # Threshold calculation should be only on the third invoice + self.assertTrue(len(pi1.taxes) > 0) + self.assertEqual(pi1.taxes[0].tax_amount, 1000) + + for d in reversed(invoices): + d.cancel() + def test_cumulative_threshold_tcs(self): frappe.db.set_value( "Customer", "Test TCS Customer", "tax_withholding_category", "Cumulative Threshold TCS" From 8b02402f6295296e9465d813996c90e08ffa889e Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Mon, 18 Nov 2024 17:59:55 +0530 Subject: [PATCH 05/45] fix: patch (#44191) (cherry picked from commit 495528a758019ae2ba51d44649227c4d9cb889af) --- .../patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py index c0d715063a8..2441075de30 100644 --- a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py +++ b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py @@ -38,7 +38,7 @@ def execute(): data = frappe.db.sql( """ SELECT - name, item_code, warehouse, voucher_type, voucher_no, posting_date, posting_time, company + name, item_code, warehouse, voucher_type, voucher_no, posting_date, posting_time, company, creation FROM `tabStock Ledger Entry` WHERE @@ -67,6 +67,7 @@ def execute(): "voucher_type": d.voucher_type, "voucher_no": d.voucher_no, "sle_id": d.name, + "creation": d.creation, }, allow_negative_stock=True, ) From 7f8334f29a83a6e85fe32dcc9a2247c90046acee Mon Sep 17 00:00:00 2001 From: Smit Vora Date: Thu, 21 Nov 2024 18:30:37 +0530 Subject: [PATCH 06/45] fix: toggle debit credit amounts for transaction currency too; minor refactor (cherry picked from commit 8e759c32c431834f8e77c1665cf8c36ba881582b) --- erpnext/accounts/general_ledger.py | 78 ++++++++++++------------------ 1 file changed, 30 insertions(+), 48 deletions(-) diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index 7d7c6f49e12..19da840f543 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -315,66 +315,48 @@ def check_if_in_list(gle, gl_map): def toggle_debit_credit_if_negative(gl_map): + debit_credit_field_map = { + "debit": "credit", + "debit_in_account_currency": "credit_in_account_currency", + "debit_in_transaction_currency": "credit_in_transaction_currency", + } + for entry in gl_map: # toggle debit, credit if negative entry - if flt(entry.debit) < 0 and flt(entry.credit) < 0 and flt(entry.debit) == flt(entry.credit): - entry.credit *= -1 - entry.debit *= -1 + for debit_field, credit_field in debit_credit_field_map.items(): + debit = flt(entry.get(debit_field)) + credit = flt(entry.get(credit_field)) - if ( - flt(entry.debit_in_account_currency) < 0 - and flt(entry.credit_in_account_currency) < 0 - and flt(entry.debit_in_account_currency) == flt(entry.credit_in_account_currency) - ): - entry.credit_in_account_currency *= -1 - entry.debit_in_account_currency *= -1 + if debit < 0 and credit < 0 and debit == credit: + debit *= -1 + credit *= -1 - if flt(entry.debit) < 0: - entry.credit = flt(entry.credit) - flt(entry.debit) - entry.debit = 0.0 + if debit < 0: + credit = credit - debit + debit = 0.0 - if flt(entry.debit_in_account_currency) < 0: - entry.credit_in_account_currency = flt(entry.credit_in_account_currency) - flt( - entry.debit_in_account_currency - ) - entry.debit_in_account_currency = 0.0 + if credit < 0: + debit = debit - credit + credit = 0.0 - if flt(entry.credit) < 0: - entry.debit = flt(entry.debit) - flt(entry.credit) - entry.credit = 0.0 + # update net values + # In some scenarios net value needs to be shown in the ledger + # This method updates net values as debit or credit + if entry.post_net_value and debit and credit: + if debit > credit: + debit = debit - credit + credit = 0.0 - if flt(entry.credit_in_account_currency) < 0: - entry.debit_in_account_currency = flt(entry.debit_in_account_currency) - flt( - entry.credit_in_account_currency - ) - entry.credit_in_account_currency = 0.0 + else: + credit = credit - debit + debit = 0.0 - update_net_values(entry) + entry[debit_field] = debit + entry[credit_field] = credit return gl_map -def update_net_values(entry): - # In some scenarios net value needs to be shown in the ledger - # This method updates net values as debit or credit - if entry.post_net_value and entry.debit and entry.credit: - if entry.debit > entry.credit: - entry.debit = entry.debit - entry.credit - entry.debit_in_account_currency = ( - entry.debit_in_account_currency - entry.credit_in_account_currency - ) - entry.credit = 0 - entry.credit_in_account_currency = 0 - else: - entry.credit = entry.credit - entry.debit - entry.credit_in_account_currency = ( - entry.credit_in_account_currency - entry.debit_in_account_currency - ) - - entry.debit = 0 - entry.debit_in_account_currency = 0 - - def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False): if not from_repost: validate_cwip_accounts(gl_map) From 11deff98d9ad32e29c4eb35a414478d51260848f Mon Sep 17 00:00:00 2001 From: Smit Vora Date: Thu, 21 Nov 2024 19:44:02 +0530 Subject: [PATCH 07/45] test: test case for toggling debit and credit if negative (cherry picked from commit a10e175bc926219a6d534eb5a1e006e66bf7b8fd) --- .../journal_entry/test_journal_entry.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py index 3d4b182d52d..8f4c4e3ccda 100644 --- a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py @@ -515,6 +515,55 @@ class TestJournalEntry(unittest.TestCase): self.assertEqual(row.debit_in_account_currency, 100) self.assertEqual(row.credit_in_account_currency, 100) + def test_toggle_debit_credit_if_negative(self): + from erpnext.accounts.general_ledger import process_gl_map + + # Create JV with defaut cost center - _Test Cost Center + frappe.db.set_single_value("Accounts Settings", "merge_similar_account_heads", 0) + + jv = frappe.new_doc("Journal Entry") + jv.posting_date = nowdate() + jv.company = "_Test Company" + jv.user_remark = "test" + jv.extend( + "accounts", + [ + { + "account": "_Test Cash - _TC", + "debit": 100 * -1, + "debit_in_account_currency": 100 * -1, + "exchange_rate": 1, + }, + { + "account": "_Test Bank - _TC", + "credit": 100 * -1, + "credit_in_account_currency": 100 * -1, + "exchange_rate": 1, + }, + ], + ) + + jv.flags.ignore_validate = True + jv.save() + + self.assertEqual(len(jv.accounts), 2) + + gl_map = jv.build_gl_map() + + for row in gl_map: + if row.account == "_Test Cash - _TC": + self.assertEqual(row.debit, 100 * -1) + self.assertEqual(row.debit_in_account_currency, 100 * -1) + self.assertEqual(row.debit_in_transaction_currency, 100 * -1) + + gl_map = process_gl_map(gl_map, False) + + for row in gl_map: + if row.account == "_Test Cash - _TC": + self.assertEqual(row.credit, 100) + self.assertEqual(row.credit_in_account_currency, 100) + self.assertEqual(row.credit_in_transaction_currency, 100) + def test_transaction_exchange_rate_on_journals(self): jv = make_journal_entry("_Test Bank - _TC", "_Test Receivable USD - _TC", 100, save=False) jv.accounts[0].update({"debit_in_account_currency": 8500, "exchange_rate": 1}) From a4398626f66bae98b520d75f72e9d00222789174 Mon Sep 17 00:00:00 2001 From: venkat102 Date: Fri, 22 Nov 2024 11:53:07 +0530 Subject: [PATCH 08/45] fix: filter with item group only if it is mentioned in pos profile (cherry picked from commit 09641073e3ff013fe49f22127e3164b22639c41e) --- erpnext/selling/page/point_of_sale/point_of_sale.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py index 28eadec9bc5..206e51bbc5a 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.py +++ b/erpnext/selling/page/point_of_sale/point_of_sale.py @@ -96,6 +96,8 @@ def search_by_term(search_term, warehouse, price_list): def filter_result_items(result, pos_profile): if result and result.get("items"): pos_item_groups = frappe.db.get_all("POS Item Group", {"parent": pos_profile}, pluck="item_group") + if not pos_item_groups: + return result["items"] = [item for item in result.get("items") if item.get("item_group") in pos_item_groups] From 4856a9633e2e6cd46cf001799f01c7d290514b6a Mon Sep 17 00:00:00 2001 From: venkat102 Date: Thu, 21 Nov 2024 18:27:15 +0530 Subject: [PATCH 09/45] fix: make free qty round on large transaction qty (cherry picked from commit f9b816538584810aeb0721296899f7bb19dc1dd0) --- erpnext/accounts/doctype/pricing_rule/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index 572529580e8..087e2bffa4b 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -655,7 +655,7 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None): if transaction_qty: qty = flt(transaction_qty) * qty / pricing_rule.recurse_for if pricing_rule.round_free_qty: - qty = math.floor(qty) + qty = (flt(transaction_qty) // pricing_rule.recurse_for) * (pricing_rule.free_qty or 1) if not qty: return From db1bc8a3db238d0729790c71226aef7136d2b230 Mon Sep 17 00:00:00 2001 From: venkat102 Date: Thu, 21 Nov 2024 18:37:14 +0530 Subject: [PATCH 10/45] test: add unit test to validate free qty round on large transaction qty (cherry picked from commit 013a6fc6ec2ae28720845f973276db3739fc8fd5) --- .../doctype/pricing_rule/test_pricing_rule.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index b4c47a26eb1..965e2b267a3 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -1137,6 +1137,45 @@ class TestPricingRule(FrappeTestCase): so.save() self.assertEqual(len(so.items), 1) + def test_pricing_rule_for_product_free_item_round_free_qty(self): + frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule") + test_record = { + "doctype": "Pricing Rule", + "title": "_Test Pricing Rule", + "apply_on": "Item Code", + "currency": "USD", + "items": [ + { + "item_code": "_Test Item", + } + ], + "selling": 1, + "rate": 0, + "min_qty": 100, + "max_qty": 0, + "price_or_product_discount": "Product", + "same_item": 1, + "free_qty": 10, + "round_free_qty": 1, + "is_recursive": 1, + "recurse_for": 100, + "company": "_Test Company", + } + frappe.get_doc(test_record.copy()).insert() + + # With pricing rule + so = make_sales_order(item_code="_Test Item", qty=100) + so.load_from_db() + self.assertEqual(so.items[1].is_free_item, 1) + self.assertEqual(so.items[1].item_code, "_Test Item") + self.assertEqual(so.items[1].qty, 10) + + so = make_sales_order(item_code="_Test Item", qty=150) + so.load_from_db() + self.assertEqual(so.items[1].is_free_item, 1) + self.assertEqual(so.items[1].item_code, "_Test Item") + self.assertEqual(so.items[1].qty, 10) + def test_apply_multiple_pricing_rules_for_discount_percentage_and_amount(self): frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1") frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2") From af74a3c32fb5ec83439ed3417706aa3d1a0deefd Mon Sep 17 00:00:00 2001 From: vimalraj27 Date: Wed, 20 Nov 2024 13:27:21 +0530 Subject: [PATCH 11/45] fix: Get submitted documents in validate_for_closed_fiscal_year (cherry picked from commit c607e5f940d7032cc7c11d870d3bf99b30bcef4c) --- .../repost_accounting_ledger/repost_accounting_ledger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py index f37e542dd89..0bd9a2a0515 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.py @@ -45,7 +45,7 @@ class RepostAccountingLedger(Document): latest_pcv = ( frappe.db.get_all( "Period Closing Voucher", - filters={"company": self.company}, + filters={"company": self.company, "docstatus": 1}, order_by="period_end_date desc", pluck="period_end_date", limit=1, From 97f2341b98ea0cdb84cbf7dbaebdd32b208824b6 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sun, 24 Nov 2024 22:23:11 +0530 Subject: [PATCH 12/45] fix: not able to fetch batch item price --- erpnext/stock/get_item_details.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 50db899433f..d5d492a2c93 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -940,11 +940,12 @@ def get_batch_based_item_price(params, item_code) -> float: params = parse_json(params) item_price = get_item_price(params, item_code, force_batch_no=True) + if not item_price: item_price = get_item_price(params, item_code, ignore_party=True, force_batch_no=True) - if item_price and item_price[0].uom == params.get("uom"): - return item_price[0].price_list_rate + if item_price and item_price[0][2] == params.get("uom"): + return item_price[0][1] return 0.0 From 8928e062b18db3729b16f93cd2b2c5420c24ada3 Mon Sep 17 00:00:00 2001 From: Abdeali Chharchhoda Date: Fri, 22 Nov 2024 19:50:52 +0530 Subject: [PATCH 13/45] refactor: added translate function for some columns of report (cherry picked from commit e545c913b529b2d4e8ee4d3efc8f8cc87ee567a0) --- .../accounts_receivable/accounts_receivable.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 984d77dbad2..a58d4ab72ca 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -1013,15 +1013,15 @@ class ReceivablePayableReport: def get_columns(self): self.columns = [] - self.add_column("Posting Date", fieldtype="Date") + self.add_column(_("Posting Date"), fieldtype="Date") self.add_column( - label="Party Type", + label=_("Party Type"), fieldname="party_type", fieldtype="Data", width=100, ) self.add_column( - label="Party", + label=_("Party"), fieldname="party", fieldtype="Dynamic Link", options="party_type", @@ -1037,10 +1037,10 @@ class ReceivablePayableReport: if self.party_naming_by == "Naming Series": if self.account_type == "Payable": - label = "Supplier Name" + label = _("Supplier Name") fieldname = "supplier_name" else: - label = "Customer Name" + label = _("Customer Name") fieldname = "customer_name" self.add_column( label=label, @@ -1066,7 +1066,7 @@ class ReceivablePayableReport: width=180, ) - self.add_column(label="Due Date", fieldtype="Date") + self.add_column(label=_("Due Date"), fieldtype="Date") if self.account_type == "Payable": self.add_column(label=_("Bill No"), fieldname="bill_no", fieldtype="Data") From 0469b0d1ecca4b5d13232d3ba5a7f4275a582da4 Mon Sep 17 00:00:00 2001 From: l0gesh29 Date: Fri, 15 Nov 2024 12:54:04 +0530 Subject: [PATCH 14/45] feat: Show Aggregate Value from Subsidiary Companies (cherry picked from commit c23af6af41471b1d1e7b200d293ea4da95bbbb8e) # Conflicts: # erpnext/selling/report/sales_analytics/sales_analytics.js --- .../report/sales_analytics/sales_analytics.js | 21 ++++ .../report/sales_analytics/sales_analytics.py | 112 +++++++++++++----- 2 files changed, 101 insertions(+), 32 deletions(-) diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.js b/erpnext/selling/report/sales_analytics/sales_analytics.js index a01103afb96..95b742ea584 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.js +++ b/erpnext/selling/report/sales_analytics/sales_analytics.js @@ -73,6 +73,27 @@ frappe.query_reports["Sales Analytics"] = { default: "Monthly", reqd: 1, }, +<<<<<<< HEAD +======= + { + fieldname: "curves", + label: __("Curves"), + fieldtype: "Select", + options: [ + { value: "select", label: __("Select") }, + { value: "all", label: __("All") }, + { value: "non-zeros", label: __("Non-Zeros") }, + { value: "total", label: __("Total Only") }, + ], + default: "select", + reqd: 1, + }, + { + fieldname: "show_aggregate_value_from_subsidiary_companies", + label: __("Show Aggregate Value from Subsidiary Companies"), + fieldtype: "Check", + }, +>>>>>>> c23af6af41 (feat: Show Aggregate Value from Subsidiary Companies) ], get_datatable_options(options) { return Object.assign(options, { diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py index 27d2e6e555e..262687ef19d 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.py +++ b/erpnext/selling/report/sales_analytics/sales_analytics.py @@ -4,6 +4,8 @@ import frappe from frappe import _, scrub +from frappe.query_builder import DocType +from frappe.query_builder.functions import IfNull from frappe.utils import add_days, add_to_date, flt, getdate from erpnext.accounts.utils import get_fiscal_year @@ -37,7 +39,26 @@ class Analytics: ] self.get_period_date_ranges() + def update_company_list_for_parent_company(self): + company_list = [self.filters.get("company")] + + selected_company = self.filters.get("company") + if ( + selected_company + and self.filters.get("show_aggregate_value_from_subsidiary_companies") + and frappe.db.get_value("Company", selected_company, "is_group") + ): + lft, rgt = frappe.db.get_value("Company", selected_company, ["lft", "rgt"]) + child_companies = frappe.db.get_list( + "Company", filters={"lft": [">", lft], "rgt": ["<", rgt]}, pluck="name" + ) + + company_list.extend(child_companies) + + self.filters["company"] = company_list + def run(self): + self.update_company_list_for_parent_company() self.get_columns() self.get_data() self.get_chart_data() @@ -123,14 +144,23 @@ class Analytics: else: value_field = "total_qty" - self.entries = frappe.db.sql( - """ select s.order_type as entity, s.{value_field} as value_field, s.{date_field} - from `tab{doctype}` s where s.docstatus = 1 and s.company = %s and s.{date_field} between %s and %s - and ifnull(s.order_type, '') != '' order by s.order_type - """.format(date_field=self.date_field, value_field=value_field, doctype=self.filters.doc_type), - (self.filters.company, self.filters.from_date, self.filters.to_date), - as_dict=1, - ) + doctype = DocType(self.filters.doc_type) + + self.entries = ( + frappe.qb.from_(doctype) + .select( + doctype.order_type.as_("entity"), + doctype[self.date_field], + doctype[value_field].as_("value_field"), + ) + .where( + (doctype.docstatus == 1) + & (doctype.company.isin(self.filters.company)) + & (doctype[self.date_field].between(self.filters.from_date, self.filters.to_date)) + & (IfNull(doctype.order_type, "") != "") + ) + .orderby(doctype.order_type) + ).run(as_dict=True) self.get_teams() @@ -152,7 +182,7 @@ class Analytics: fields=[entity, entity_name, value_field, self.date_field], filters={ "docstatus": 1, - "company": self.filters.company, + "company": ["in", self.filters.company], self.date_field: ("between", [self.filters.from_date, self.filters.to_date]), }, ) @@ -167,16 +197,26 @@ class Analytics: else: value_field = "stock_qty" - self.entries = frappe.db.sql( - """ - select i.item_code as entity, i.item_name as entity_name, i.stock_uom, i.{value_field} as value_field, s.{date_field} - from `tab{doctype} Item` i , `tab{doctype}` s - where s.name = i.parent and i.docstatus = 1 and s.company = %s - and s.{date_field} between %s and %s - """.format(date_field=self.date_field, value_field=value_field, doctype=self.filters.doc_type), - (self.filters.company, self.filters.from_date, self.filters.to_date), - as_dict=1, - ) + doctype = DocType(self.filters.doc_type) + doctype_item = DocType(f"{self.filters.doc_type} Item") + + self.entries = ( + frappe.qb.from_(doctype_item) + .join(doctype) + .on(doctype.name == doctype_item.parent) + .select( + doctype_item.item_code.as_("entity"), + doctype_item.item_name.as_("entity_name"), + doctype_item.stock_uom, + doctype_item[value_field].as_("value_field"), + doctype[self.date_field], + ) + .where( + (doctype_item.docstatus == 1) + & (doctype.company.isin(self.filters.company)) + & (doctype[self.date_field].between(self.filters.from_date, self.filters.to_date)) + ) + ).run(as_dict=True) self.entity_names = {} for d in self.entries: @@ -201,7 +241,7 @@ class Analytics: fields=[entity_field, value_field, self.date_field], filters={ "docstatus": 1, - "company": self.filters.company, + "company": ["in", self.filters.company], self.date_field: ("between", [self.filters.from_date, self.filters.to_date]), }, ) @@ -213,16 +253,24 @@ class Analytics: else: value_field = "qty" - self.entries = frappe.db.sql( - f""" - select i.item_group as entity, i.{value_field} as value_field, s.{self.date_field} - from `tab{self.filters.doc_type} Item` i , `tab{self.filters.doc_type}` s - where s.name = i.parent and i.docstatus = 1 and s.company = %s - and s.{self.date_field} between %s and %s - """, - (self.filters.company, self.filters.from_date, self.filters.to_date), - as_dict=1, - ) + doctype = DocType(self.filters.doc_type) + doctype_item = DocType(f"{self.filters.doc_type} Item") + + self.entries = ( + frappe.qb.from_(doctype_item) + .join(doctype) + .on(doctype.name == doctype_item.parent) + .select( + doctype_item.item_group.as_("entity"), + doctype_item[value_field].as_("value_field"), + doctype[self.date_field], + ) + .where( + (doctype_item.docstatus == 1) + & (doctype.company.isin(self.filters.company)) + & (doctype[self.date_field].between(self.filters.from_date, self.filters.to_date)) + ) + ).run(as_dict=True) self.get_groups() @@ -239,7 +287,7 @@ class Analytics: fields=[entity, value_field, self.date_field], filters={ "docstatus": 1, - "company": self.filters.company, + "company": ["in", self.filters.company], "project": ["!=", ""], self.date_field: ("between", [self.filters.from_date, self.filters.to_date]), }, @@ -312,7 +360,7 @@ class Analytics: str(((posting_date.month - 1) // 3) + 1), str(posting_date.year) ) else: - year = get_fiscal_year(posting_date, company=self.filters.company) + year = get_fiscal_year(posting_date, company=self.filters.company[0]) period = str(year[0]) return period From 072c5b775377b9e9826215f3a1dbee2fdf728f44 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 25 Nov 2024 12:28:02 +0530 Subject: [PATCH 15/45] chore: resolve conflict --- .../report/sales_analytics/sales_analytics.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.js b/erpnext/selling/report/sales_analytics/sales_analytics.js index 95b742ea584..7c5d5436877 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.js +++ b/erpnext/selling/report/sales_analytics/sales_analytics.js @@ -73,27 +73,11 @@ frappe.query_reports["Sales Analytics"] = { default: "Monthly", reqd: 1, }, -<<<<<<< HEAD -======= - { - fieldname: "curves", - label: __("Curves"), - fieldtype: "Select", - options: [ - { value: "select", label: __("Select") }, - { value: "all", label: __("All") }, - { value: "non-zeros", label: __("Non-Zeros") }, - { value: "total", label: __("Total Only") }, - ], - default: "select", - reqd: 1, - }, { fieldname: "show_aggregate_value_from_subsidiary_companies", label: __("Show Aggregate Value from Subsidiary Companies"), fieldtype: "Check", }, ->>>>>>> c23af6af41 (feat: Show Aggregate Value from Subsidiary Companies) ], get_datatable_options(options) { return Object.assign(options, { From 8cd455b050c9687bc1c5cb91dd6360035cea4f30 Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Fri, 22 Nov 2024 11:36:57 +0530 Subject: [PATCH 16/45] fix: set price_list_currency only if it exists (cherry picked from commit f0b9cb4019ff6a13fc2166f5023ecae9c4c65af3) --- erpnext/public/js/controllers/transaction.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index ca1b1c8c590..77db3292eb7 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1904,8 +1904,14 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe callback: function(r) { if (!r.exc) { frappe.run_serially([ - () => me.frm.set_value("price_list_currency", r.message.parent.price_list_currency), - () => me.frm.set_value("plc_conversion_rate", r.message.parent.plc_conversion_rate), + () => { + if (r.message.parent.price_list_currency) + me.frm.set_value("price_list_currency", r.message.parent.price_list_currency); + }, + () => { + if (r.message.parent.plc_conversion_rate) + me.frm.set_value("plc_conversion_rate", r.message.parent.plc_conversion_rate); + }, () => { if(args.items.length) { me._set_values_for_item_list(r.message.children); From 20d0e95d7c3de85e0a0364dd9e7954f3aa6dbeee Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 20:29:13 +0530 Subject: [PATCH 17/45] feat: available qty at company in sales transactions (backport #44260) (#44325) * feat: available qty at company in sales transactions (cherry picked from commit d8b9aef14f0a615555067258889bdb09cd6d117e) # Conflicts: # erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json # erpnext/selling/doctype/quotation_item/quotation_item.json # erpnext/selling/doctype/sales_order_item/sales_order_item.json # erpnext/stock/doctype/delivery_note_item/delivery_note_item.json * chore: fix conflicts * chore: fix conflicts * chore: fix conflicts * chore: fix conflicts --------- Co-authored-by: Rohit Waghchaure --- .../sales_invoice_item.json | 28 ++++++++++++++-- .../sales_invoice_item/sales_invoice_item.py | 1 + erpnext/controllers/selling_controller.py | 10 ++++-- .../quotation_item/quotation_item.json | 31 +++++++++++++++--- .../doctype/quotation_item/quotation_item.py | 1 + .../sales_order_item/sales_order_item.json | 29 ++++++++++++++--- .../sales_order_item/sales_order_item.py | 1 + .../delivery_note_item.json | 32 +++++++++++++++---- .../delivery_note_item/delivery_note_item.py | 1 + 9 files changed, 115 insertions(+), 19 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 8b93f56a4c2..dd370ef414f 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -89,11 +89,14 @@ "incoming_rate", "item_tax_rate", "actual_batch_qty", - "actual_qty", "section_break_eoec", "serial_no", "column_break_ytgd", "batch_no", + "available_quantity_section", + "actual_qty", + "column_break_ogff", + "company_total_stock", "edit_references", "sales_order", "so_detail", @@ -675,7 +678,8 @@ "allow_on_submit": 1, "fieldname": "actual_qty", "fieldtype": "Float", - "label": "Available Qty at Warehouse", + "label": "Qty (Warehouse)", + "no_copy": 1, "oldfieldname": "actual_qty", "oldfieldtype": "Currency", "print_hide": 1, @@ -923,12 +927,30 @@ { "fieldname": "column_break_ytgd", "fieldtype": "Column Break" + }, + { + "fieldname": "available_quantity_section", + "fieldtype": "Section Break", + "label": "Available Quantity" + }, + { + "fieldname": "column_break_ogff", + "fieldtype": "Column Break" + }, + { + "allow_on_submit": 1, + "fieldname": "company_total_stock", + "fieldtype": "Float", + "label": "Qty (Company)", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2024-10-28 15:06:40.980995", + "modified": "2024-11-25 16:27:33.287341", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py index 9be1b42aab3..b7b0873c76b 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py @@ -28,6 +28,7 @@ class SalesInvoiceItem(Document): base_rate_with_margin: DF.Currency batch_no: DF.Link | None brand: DF.Data | None + company_total_stock: DF.Float conversion_factor: DF.Float cost_center: DF.Link customer_item_code: DF.Data | None diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 89a2111d50f..bb59166d3f8 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -21,9 +21,15 @@ class SellingController(StockController): def onload(self): super().onload() - if self.doctype in ("Sales Order", "Delivery Note", "Sales Invoice"): + if self.doctype in ("Sales Order", "Delivery Note", "Sales Invoice", "Quotation"): for item in self.get("items") + (self.get("packed_items") or []): - item.update(get_bin_details(item.item_code, item.warehouse, include_child_warehouses=True)) + company = self.company + + item.update( + get_bin_details( + item.item_code, item.warehouse, company=company, include_child_warehouses=True + ) + ) def validate(self): super().validate() diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json index 0e25313f76a..1ea19aaaf56 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.json +++ b/erpnext/selling/doctype/quotation_item/quotation_item.json @@ -24,6 +24,10 @@ "uom", "conversion_factor", "stock_qty", + "available_quantity_section", + "actual_qty", + "column_break_ylrv", + "company_total_stock", "section_break_16", "price_list_rate", "base_price_list_rate", @@ -70,7 +74,6 @@ "prevdoc_docname", "item_balance", "projected_qty", - "actual_qty", "col_break4", "stock_balance", "item_tax_rate", @@ -460,9 +463,10 @@ "report_hide": 1 }, { + "allow_on_submit": 1, "fieldname": "actual_qty", "fieldtype": "Float", - "label": "Actual Qty", + "label": "Qty (Warehouse)", "no_copy": 1, "print_hide": 1, "read_only": 1, @@ -662,12 +666,31 @@ "label": "Has Alternative Item", "print_hide": 1, "read_only": 1 + }, + { + "fieldname": "available_quantity_section", + "fieldtype": "Section Break", + "label": "Available Quantity" + }, + { + "fieldname": "column_break_ylrv", + "fieldtype": "Column Break" + }, + { + "allow_on_submit": 1, + "fieldname": "company_total_stock", + "fieldtype": "Float", + "label": "Qty (Company)", + "no_copy": 1, + "print_hide": 1, + "read_only": 1, + "report_hide": 1 } ], "idx": 1, "istable": 1, "links": [], - "modified": "2023-11-14 18:24:24.619832", + "modified": "2024-11-24 15:18:43.952844", "modified_by": "Administrator", "module": "Selling", "name": "Quotation Item", @@ -677,4 +700,4 @@ "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.py b/erpnext/selling/doctype/quotation_item/quotation_item.py index f209762c3ba..7d68eaf07ba 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.py +++ b/erpnext/selling/doctype/quotation_item/quotation_item.py @@ -27,6 +27,7 @@ class QuotationItem(Document): blanket_order: DF.Link | None blanket_order_rate: DF.Currency brand: DF.Link | None + company_total_stock: DF.Float conversion_factor: DF.Float customer_item_code: DF.Data | None description: DF.TextEditor | None diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index d451768eaab..fb9e895ccb7 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -78,11 +78,14 @@ "against_blanket_order", "blanket_order", "blanket_order_rate", + "available_quantity_section", + "actual_qty", + "column_break_jpky", + "company_total_stock", "manufacturing_section_section", "bom_no", "planning_section", "projected_qty", - "actual_qty", "ordered_qty", "planned_qty", "production_plan_qty", @@ -636,7 +639,7 @@ "allow_on_submit": 1, "fieldname": "actual_qty", "fieldtype": "Float", - "label": "Actual Qty", + "label": "Qty (Warehouse)", "no_copy": 1, "print_hide": 1, "print_width": "70px", @@ -905,12 +908,30 @@ "label": "Is Stock Item", "print_hide": 1, "report_hide": 1 + }, + { + "allow_on_submit": 1, + "fieldname": "company_total_stock", + "fieldtype": "Float", + "label": "Qty (Company)", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "column_break_jpky", + "fieldtype": "Column Break" + }, + { + "fieldname": "available_quantity_section", + "fieldtype": "Section Break", + "label": "Available Quantity" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2024-03-21 18:15:56.625005", + "modified": "2024-11-21 14:21:29.743474", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", @@ -921,4 +942,4 @@ "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.py b/erpnext/selling/doctype/sales_order_item/sales_order_item.py index fa7b9b968f3..888ea755e2e 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.py +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.py @@ -30,6 +30,7 @@ class SalesOrderItem(Document): blanket_order_rate: DF.Currency bom_no: DF.Link | None brand: DF.Link | None + company_total_stock: DF.Float conversion_factor: DF.Float customer_item_code: DF.Data | None delivered_by_supplier: DF.Check diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index b8164b25753..56e5209da59 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -87,16 +87,19 @@ "column_break_rxvc", "batch_no", "available_qty_section", - "actual_batch_qty", "actual_qty", - "installed_qty", - "item_tax_rate", + "actual_batch_qty", "column_break_atna", + "company_total_stock", + "section_break_kejd", + "installed_qty", "packed_qty", + "column_break_fguf", "received_qty", "accounting_details_section", "expense_account", "column_break_71", + "item_tax_rate", "internal_transfer_section", "material_request", "purchase_order", @@ -519,7 +522,7 @@ "allow_on_submit": 1, "fieldname": "actual_qty", "fieldtype": "Float", - "label": "Available Qty at From Warehouse", + "label": "Qty (Warehouse)", "no_copy": 1, "oldfieldname": "actual_qty", "oldfieldtype": "Currency", @@ -907,13 +910,30 @@ { "fieldname": "column_break_rxvc", "fieldtype": "Column Break" + }, + { + "allow_on_submit": 1, + "fieldname": "company_total_stock", + "fieldtype": "Float", + "label": "Qty (Company)", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "section_break_kejd", + "fieldtype": "Section Break" + }, + { + "fieldname": "column_break_fguf", + "fieldtype": "Column Break" } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2024-03-21 18:15:07.603672", + "modified": "2024-11-21 17:37:37.441498", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", @@ -923,4 +943,4 @@ "sort_field": "modified", "sort_order": "DESC", "states": [] -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py index b76f7429728..716cd7d4856 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.py @@ -30,6 +30,7 @@ class DeliveryNoteItem(Document): batch_no: DF.Link | None billed_amt: DF.Currency brand: DF.Link | None + company_total_stock: DF.Float conversion_factor: DF.Float cost_center: DF.Link | None customer_item_code: DF.Data | None From 0d3802873b62dae8c346a9e256ebaa04050acff6 Mon Sep 17 00:00:00 2001 From: Abdeali Chharchhoda Date: Mon, 25 Nov 2024 14:13:26 +0530 Subject: [PATCH 18/45] fix: Increase quantity by `1 UOM` when adding an item from the selector in POS (cherry picked from commit bbab850135efa852b3f2ee49ea644b0448f6dddf) --- erpnext/selling/page/point_of_sale/pos_controller.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js index c2dd591838d..3028e12d5a2 100644 --- a/erpnext/selling/page/point_of_sale/pos_controller.js +++ b/erpnext/selling/page/point_of_sale/pos_controller.js @@ -556,7 +556,9 @@ erpnext.PointOfSale.Controller = class { const item_row_exists = !$.isEmptyObject(item_row); const from_selector = field === "qty" && value === "+1"; - if (from_selector) value = flt(item_row.stock_qty) + flt(value); + if (from_selector) { + value = flt(item_row.qty) + 1; // increase qty by 1 UOM + } if (item_row_exists) { if (field === "qty") value = flt(value); From 49dad1a456bd22d154deafbfc5b27930721b2240 Mon Sep 17 00:00:00 2001 From: Abdeali Chharchhoda Date: Mon, 25 Nov 2024 14:48:41 +0530 Subject: [PATCH 19/45] fix: Show available stock qty in `stock_uom` instead of `uom` (cherry picked from commit 84dcbe6639f9d727a974aecd6ed7a932ca4bb7bc) --- erpnext/selling/page/point_of_sale/pos_controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js index 3028e12d5a2..9684c9635d9 100644 --- a/erpnext/selling/page/point_of_sale/pos_controller.js +++ b/erpnext/selling/page/point_of_sale/pos_controller.js @@ -689,7 +689,7 @@ erpnext.PointOfSale.Controller = class { const is_stock_item = resp[1]; frappe.dom.unfreeze(); - const bold_uom = item_row.uom.bold(); + const bold_uom = item_row.stock_uom.bold(); const bold_item_code = item_row.item_code.bold(); const bold_warehouse = warehouse.bold(); const bold_available_qty = available_qty.toString().bold(); From b65e16a91b71ca7e674c04d08c2a01a8a0fb1079 Mon Sep 17 00:00:00 2001 From: Abdeali Chharchhoda Date: Mon, 25 Nov 2024 16:17:03 +0530 Subject: [PATCH 20/45] revert: use `+ flt(value)` instead of direct increment (cherry picked from commit 112b4c705bbad2bd07e6be80e4d4128d73c14d73) --- erpnext/selling/page/point_of_sale/pos_controller.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js index 9684c9635d9..de3259ae2b7 100644 --- a/erpnext/selling/page/point_of_sale/pos_controller.js +++ b/erpnext/selling/page/point_of_sale/pos_controller.js @@ -556,9 +556,7 @@ erpnext.PointOfSale.Controller = class { const item_row_exists = !$.isEmptyObject(item_row); const from_selector = field === "qty" && value === "+1"; - if (from_selector) { - value = flt(item_row.qty) + 1; // increase qty by 1 UOM - } + if (from_selector) value = flt(item_row.qty) + flt(value); if (item_row_exists) { if (field === "qty") value = flt(value); From db21def58b21938dd3b2fc51fd0d432a97202665 Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Thu, 21 Nov 2024 11:05:49 +0530 Subject: [PATCH 21/45] fix: add company dynamic filters in number cards (cherry picked from commit 4e7725de669d544909124301c172b8c7d18221a2) --- .../number_card/total_incoming_bills/total_incoming_bills.json | 3 ++- .../total_incoming_payment/total_incoming_payment.json | 1 + .../number_card/total_outgoing_bills/total_outgoing_bills.json | 1 + .../total_outgoing_payment/total_outgoing_payment.json | 1 + erpnext/assets/number_card/asset_value/asset_value.json | 1 + .../new_assets_(this_year)/new_assets_(this_year).json | 1 + erpnext/assets/number_card/total_assets/total_assets.json | 1 + .../buying/number_card/active_suppliers/active_suppliers.json | 1 + erpnext/crm/number_card/open_opportunity/open_opportunity.json | 2 +- .../monthly_completed_work_order.json | 1 + .../monthly_quality_inspection/monthly_quality_inspection.json | 1 + .../monthly_total_work_order/monthly_total_work_order.json | 1 + .../number_card/ongoing_job_card/ongoing_job_card.json | 1 + .../selling/number_card/active_customers/active_customers.json | 2 +- .../number_card/total_active_items/total_active_items.json | 1 + .../stock/number_card/total_stock_value/total_stock_value.json | 1 + .../stock/number_card/total_warehouses/total_warehouses.json | 1 + 17 files changed, 18 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/number_card/total_incoming_bills/total_incoming_bills.json b/erpnext/accounts/number_card/total_incoming_bills/total_incoming_bills.json index 283e187b542..88c7cae3f69 100644 --- a/erpnext/accounts/number_card/total_incoming_bills/total_incoming_bills.json +++ b/erpnext/accounts/number_card/total_incoming_bills/total_incoming_bills.json @@ -4,13 +4,14 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Purchase Invoice", + "dynamic_filters_json": "[[\"Purchase Invoice\",\"company\",\"=\",\" frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Purchase Invoice\",\"docstatus\",\"=\",\"1\",false],[\"Purchase Invoice\",\"posting_date\",\"Timespan\",\"this year\",false]]", "function": "Sum", "idx": 0, "is_public": 1, "is_standard": 1, "label": "Total Incoming Bills", - "modified": "2020-07-22 13:06:46.045344", + "modified": "2024-11-20 19:08:37.043777", "modified_by": "Administrator", "module": "Accounts", "name": "Total Incoming Bills", diff --git a/erpnext/accounts/number_card/total_incoming_payment/total_incoming_payment.json b/erpnext/accounts/number_card/total_incoming_payment/total_incoming_payment.json index bc23c15b6a9..a53b222ed7d 100644 --- a/erpnext/accounts/number_card/total_incoming_payment/total_incoming_payment.json +++ b/erpnext/accounts/number_card/total_incoming_payment/total_incoming_payment.json @@ -4,6 +4,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Payment Entry", + "dynamic_filters_json": "[[\"Payment Entry\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Payment Entry\",\"docstatus\",\"=\",\"1\",false],[\"Payment Entry\",\"posting_date\",\"Timespan\",\"this year\",false],[\"Payment Entry\",\"payment_type\",\"=\",\"Receive\",false]]", "function": "Sum", "idx": 0, diff --git a/erpnext/accounts/number_card/total_outgoing_bills/total_outgoing_bills.json b/erpnext/accounts/number_card/total_outgoing_bills/total_outgoing_bills.json index fe916182102..092defd94bd 100644 --- a/erpnext/accounts/number_card/total_outgoing_bills/total_outgoing_bills.json +++ b/erpnext/accounts/number_card/total_outgoing_bills/total_outgoing_bills.json @@ -4,6 +4,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Sales Invoice", + "dynamic_filters_json": "[[\"Sales Invoice\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Sales Invoice\",\"docstatus\",\"=\",\"1\",false],[\"Sales Invoice\",\"posting_date\",\"Timespan\",\"this year\",false]]", "function": "Sum", "idx": 0, diff --git a/erpnext/accounts/number_card/total_outgoing_payment/total_outgoing_payment.json b/erpnext/accounts/number_card/total_outgoing_payment/total_outgoing_payment.json index d27be883500..d60f30f7c9a 100644 --- a/erpnext/accounts/number_card/total_outgoing_payment/total_outgoing_payment.json +++ b/erpnext/accounts/number_card/total_outgoing_payment/total_outgoing_payment.json @@ -4,6 +4,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Payment Entry", + "dynamic_filters_json": "[[\"Payment Entry\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Payment Entry\",\"docstatus\",\"=\",\"1\",false],[\"Payment Entry\",\"posting_date\",\"Timespan\",\"this year\",false],[\"Payment Entry\",\"payment_type\",\"=\",\"Pay\",false]]", "function": "Sum", "idx": 0, diff --git a/erpnext/assets/number_card/asset_value/asset_value.json b/erpnext/assets/number_card/asset_value/asset_value.json index 68e5f54c789..c437f4800f3 100644 --- a/erpnext/assets/number_card/asset_value/asset_value.json +++ b/erpnext/assets/number_card/asset_value/asset_value.json @@ -4,6 +4,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Asset", + "dynamic_filters_json": "[[\"Asset\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[]", "function": "Sum", "idx": 0, diff --git a/erpnext/assets/number_card/new_assets_(this_year)/new_assets_(this_year).json b/erpnext/assets/number_card/new_assets_(this_year)/new_assets_(this_year).json index 6c8fb356575..cdf52d011d4 100644 --- a/erpnext/assets/number_card/new_assets_(this_year)/new_assets_(this_year).json +++ b/erpnext/assets/number_card/new_assets_(this_year)/new_assets_(this_year).json @@ -3,6 +3,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Asset", + "dynamic_filters_json": "[[\"Asset\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Asset\",\"creation\",\"Timespan\",\"this year\",false]]", "function": "Count", "idx": 0, diff --git a/erpnext/assets/number_card/total_assets/total_assets.json b/erpnext/assets/number_card/total_assets/total_assets.json index d127de8f2c6..d8626da608c 100644 --- a/erpnext/assets/number_card/total_assets/total_assets.json +++ b/erpnext/assets/number_card/total_assets/total_assets.json @@ -3,6 +3,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Asset", + "dynamic_filters_json": "[[\"Asset\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[]", "function": "Count", "idx": 0, diff --git a/erpnext/buying/number_card/active_suppliers/active_suppliers.json b/erpnext/buying/number_card/active_suppliers/active_suppliers.json index 91d5b13b06f..61d34c6261e 100644 --- a/erpnext/buying/number_card/active_suppliers/active_suppliers.json +++ b/erpnext/buying/number_card/active_suppliers/active_suppliers.json @@ -3,6 +3,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Supplier", + "dynamic_filters_json": "[[\"Supplier\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Supplier\",\"disabled\",\"=\",\"0\"]]", "function": "Count", "idx": 0, diff --git a/erpnext/crm/number_card/open_opportunity/open_opportunity.json b/erpnext/crm/number_card/open_opportunity/open_opportunity.json index 6e06ed64da3..33a757feb14 100644 --- a/erpnext/crm/number_card/open_opportunity/open_opportunity.json +++ b/erpnext/crm/number_card/open_opportunity/open_opportunity.json @@ -3,7 +3,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Opportunity", - "dynamic_filters_json": "[[\"Opportunity\",\"status\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", + "dynamic_filters_json": "[[\"Opportunity\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Opportunity\",\"company\",\"=\",null,false]]", "function": "Count", "idx": 0, diff --git a/erpnext/manufacturing/number_card/monthly_completed_work_order/monthly_completed_work_order.json b/erpnext/manufacturing/number_card/monthly_completed_work_order/monthly_completed_work_order.json index 36c0b9ae75b..7381de707d7 100644 --- a/erpnext/manufacturing/number_card/monthly_completed_work_order/monthly_completed_work_order.json +++ b/erpnext/manufacturing/number_card/monthly_completed_work_order/monthly_completed_work_order.json @@ -3,6 +3,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Work Order", + "dynamic_filters_json": "[[\"Work Order\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Work Order\",\"status\",\"=\",\"Completed\"],[\"Work Order\",\"docstatus\",\"=\",1],[\"Work Order\",\"creation\",\"between\",[\"2020-06-08\",\"2020-07-08\"]]]", "function": "Count", "idx": 0, diff --git a/erpnext/manufacturing/number_card/monthly_quality_inspection/monthly_quality_inspection.json b/erpnext/manufacturing/number_card/monthly_quality_inspection/monthly_quality_inspection.json index 91a45365c0d..e716493483d 100644 --- a/erpnext/manufacturing/number_card/monthly_quality_inspection/monthly_quality_inspection.json +++ b/erpnext/manufacturing/number_card/monthly_quality_inspection/monthly_quality_inspection.json @@ -3,6 +3,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Quality Inspection", + "dynamic_filters_json": "[[\"Quality Inspection\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Quality Inspection\",\"docstatus\",\"=\",1],[\"Quality Inspection\",\"creation\",\"between\",[\"2020-06-08\",\"2020-07-08\"]]]", "function": "Count", "idx": 0, diff --git a/erpnext/manufacturing/number_card/monthly_total_work_order/monthly_total_work_order.json b/erpnext/manufacturing/number_card/monthly_total_work_order/monthly_total_work_order.json index 80d3b1520ae..e4b8c940454 100644 --- a/erpnext/manufacturing/number_card/monthly_total_work_order/monthly_total_work_order.json +++ b/erpnext/manufacturing/number_card/monthly_total_work_order/monthly_total_work_order.json @@ -3,6 +3,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Work Order", + "dynamic_filters_json": "[[\"Work Order\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Work Order\",\"docstatus\",\"=\",1],[\"Work Order\",\"creation\",\"between\",[\"2020-06-08\",\"2020-07-08\"]]]", "function": "Count", "idx": 0, diff --git a/erpnext/manufacturing/number_card/ongoing_job_card/ongoing_job_card.json b/erpnext/manufacturing/number_card/ongoing_job_card/ongoing_job_card.json index ba23ff34531..0138af827a6 100644 --- a/erpnext/manufacturing/number_card/ongoing_job_card/ongoing_job_card.json +++ b/erpnext/manufacturing/number_card/ongoing_job_card/ongoing_job_card.json @@ -3,6 +3,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Job Card", + "dynamic_filters_json": "[[\"Job Card\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Job Card\",\"status\",\"!=\",\"Completed\"],[\"Job Card\",\"docstatus\",\"=\",1]]", "function": "Count", "idx": 0, diff --git a/erpnext/selling/number_card/active_customers/active_customers.json b/erpnext/selling/number_card/active_customers/active_customers.json index 33776348477..8b027a14a0e 100644 --- a/erpnext/selling/number_card/active_customers/active_customers.json +++ b/erpnext/selling/number_card/active_customers/active_customers.json @@ -3,7 +3,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Customer", - "dynamic_filters_json": "", + "dynamic_filters_json": "[[\"Customer\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Customer\",\"disabled\",\"=\",\"0\"]]", "function": "Count", "idx": 0, diff --git a/erpnext/stock/number_card/total_active_items/total_active_items.json b/erpnext/stock/number_card/total_active_items/total_active_items.json index f6863b96d7c..e2db153be0a 100644 --- a/erpnext/stock/number_card/total_active_items/total_active_items.json +++ b/erpnext/stock/number_card/total_active_items/total_active_items.json @@ -3,6 +3,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Item", + "dynamic_filters_json": "[[\"Item\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Item\",\"disabled\",\"=\",0]]", "function": "Count", "idx": 0, diff --git a/erpnext/stock/number_card/total_stock_value/total_stock_value.json b/erpnext/stock/number_card/total_stock_value/total_stock_value.json index 8e480a6b3e6..001549ba4f5 100644 --- a/erpnext/stock/number_card/total_stock_value/total_stock_value.json +++ b/erpnext/stock/number_card/total_stock_value/total_stock_value.json @@ -4,6 +4,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Bin", + "dynamic_filters_json": "[[\"Bin\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[]", "function": "Sum", "idx": 0, diff --git a/erpnext/stock/number_card/total_warehouses/total_warehouses.json b/erpnext/stock/number_card/total_warehouses/total_warehouses.json index ab0836a3afe..8eadfac48d1 100644 --- a/erpnext/stock/number_card/total_warehouses/total_warehouses.json +++ b/erpnext/stock/number_card/total_warehouses/total_warehouses.json @@ -3,6 +3,7 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Warehouse", + "dynamic_filters_json": "[[\"Warehouse\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Warehouse\",\"disabled\",\"=\",0]]", "function": "Count", "idx": 0, From 7423d7d3372aecb0b6003e67313322061bdea673 Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Thu, 21 Nov 2024 12:09:24 +0530 Subject: [PATCH 22/45] fix: remove irrelavent filters (cherry picked from commit 29762c48265c21c62dfdb04f03736d076ef4ff68) --- .../buying/number_card/active_suppliers/active_suppliers.json | 1 - .../monthly_quality_inspection/monthly_quality_inspection.json | 1 - .../selling/number_card/active_customers/active_customers.json | 1 - .../stock/number_card/total_active_items/total_active_items.json | 1 - .../stock/number_card/total_stock_value/total_stock_value.json | 1 - 5 files changed, 5 deletions(-) diff --git a/erpnext/buying/number_card/active_suppliers/active_suppliers.json b/erpnext/buying/number_card/active_suppliers/active_suppliers.json index 61d34c6261e..91d5b13b06f 100644 --- a/erpnext/buying/number_card/active_suppliers/active_suppliers.json +++ b/erpnext/buying/number_card/active_suppliers/active_suppliers.json @@ -3,7 +3,6 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Supplier", - "dynamic_filters_json": "[[\"Supplier\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Supplier\",\"disabled\",\"=\",\"0\"]]", "function": "Count", "idx": 0, diff --git a/erpnext/manufacturing/number_card/monthly_quality_inspection/monthly_quality_inspection.json b/erpnext/manufacturing/number_card/monthly_quality_inspection/monthly_quality_inspection.json index e716493483d..91a45365c0d 100644 --- a/erpnext/manufacturing/number_card/monthly_quality_inspection/monthly_quality_inspection.json +++ b/erpnext/manufacturing/number_card/monthly_quality_inspection/monthly_quality_inspection.json @@ -3,7 +3,6 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Quality Inspection", - "dynamic_filters_json": "[[\"Quality Inspection\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Quality Inspection\",\"docstatus\",\"=\",1],[\"Quality Inspection\",\"creation\",\"between\",[\"2020-06-08\",\"2020-07-08\"]]]", "function": "Count", "idx": 0, diff --git a/erpnext/selling/number_card/active_customers/active_customers.json b/erpnext/selling/number_card/active_customers/active_customers.json index 8b027a14a0e..7a31a21f6fd 100644 --- a/erpnext/selling/number_card/active_customers/active_customers.json +++ b/erpnext/selling/number_card/active_customers/active_customers.json @@ -3,7 +3,6 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Customer", - "dynamic_filters_json": "[[\"Customer\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Customer\",\"disabled\",\"=\",\"0\"]]", "function": "Count", "idx": 0, diff --git a/erpnext/stock/number_card/total_active_items/total_active_items.json b/erpnext/stock/number_card/total_active_items/total_active_items.json index e2db153be0a..f6863b96d7c 100644 --- a/erpnext/stock/number_card/total_active_items/total_active_items.json +++ b/erpnext/stock/number_card/total_active_items/total_active_items.json @@ -3,7 +3,6 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Item", - "dynamic_filters_json": "[[\"Item\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[[\"Item\",\"disabled\",\"=\",0]]", "function": "Count", "idx": 0, diff --git a/erpnext/stock/number_card/total_stock_value/total_stock_value.json b/erpnext/stock/number_card/total_stock_value/total_stock_value.json index 001549ba4f5..8e480a6b3e6 100644 --- a/erpnext/stock/number_card/total_stock_value/total_stock_value.json +++ b/erpnext/stock/number_card/total_stock_value/total_stock_value.json @@ -4,7 +4,6 @@ "docstatus": 0, "doctype": "Number Card", "document_type": "Bin", - "dynamic_filters_json": "[[\"Bin\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", "filters_json": "[]", "function": "Sum", "idx": 0, From 465a26f714baaff2f8a3a1da6dc12fe91c699d1e Mon Sep 17 00:00:00 2001 From: Ernesto Ruiz Date: Sat, 23 Nov 2024 09:07:18 -0600 Subject: [PATCH 23/45] chore: Add translations to QI validations in Update stock_controller.py chore: Add translations to QI validations in Update stock_controller.py (cherry picked from commit 6754f15487edb51b60ebaecc6fc43d34e2154e07) --- erpnext/controllers/stock_controller.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 4eb67b6f42e..8f0a5d5edf5 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -1008,11 +1008,13 @@ class StockController(AccountsController): def validate_qi_presence(self, row): """Check if QI is present on row level. Warn on save and stop on submit if missing.""" if not row.quality_inspection: - msg = f"Row #{row.idx}: Quality Inspection is required for Item {frappe.bold(row.item_code)}" + msg = _("Row #{0}: Quality Inspection is required for Item {1}").format( + row.idx, frappe.bold(row.item_code) + ) if self.docstatus == 1: - frappe.throw(_(msg), title=_("Inspection Required"), exc=QualityInspectionRequiredError) + frappe.throw(msg, title=_("Inspection Required"), exc=QualityInspectionRequiredError) else: - frappe.msgprint(_(msg), title=_("Inspection Required"), indicator="blue") + frappe.msgprint(msg, title=_("Inspection Required"), indicator="blue") def validate_qi_submission(self, row): """Check if QI is submitted on row level, during submission""" @@ -1021,11 +1023,13 @@ class StockController(AccountsController): if not qa_docstatus == 1: link = frappe.utils.get_link_to_form("Quality Inspection", row.quality_inspection) - msg = f"Row #{row.idx}: Quality Inspection {link} is not submitted for the item: {row.item_code}" + msg = _("Row #{0}: Quality Inspection {1} is not submitted for the item: {2}").format( + row.idx, link, row.item_code + ) if action == "Stop": - frappe.throw(_(msg), title=_("Inspection Submission"), exc=QualityInspectionNotSubmittedError) + frappe.throw(msg, title=_("Inspection Submission"), exc=QualityInspectionNotSubmittedError) else: - frappe.msgprint(_(msg), alert=True, indicator="orange") + frappe.msgprint(msg, alert=True, indicator="orange") def validate_qi_rejection(self, row): """Check if QI is rejected on row level, during submission""" @@ -1034,11 +1038,13 @@ class StockController(AccountsController): if qa_status == "Rejected": link = frappe.utils.get_link_to_form("Quality Inspection", row.quality_inspection) - msg = f"Row #{row.idx}: Quality Inspection {link} was rejected for item {row.item_code}" + msg = _("Row #{0}: Quality Inspection {1} was rejected for item {2}").format( + row.idx, link, row.item_code + ) if action == "Stop": - frappe.throw(_(msg), title=_("Inspection Rejected"), exc=QualityInspectionRejectedError) + frappe.throw(msg, title=_("Inspection Rejected"), exc=QualityInspectionRejectedError) else: - frappe.msgprint(_(msg), alert=True, indicator="orange") + frappe.msgprint(msg, alert=True, indicator="orange") def update_blanket_order(self): blanket_orders = list(set([d.blanket_order for d in self.items if d.blanket_order])) From cde19066fe6b42aca5cae6971805973ac18a01dd Mon Sep 17 00:00:00 2001 From: vishakhdesai Date: Mon, 25 Nov 2024 12:50:35 +0530 Subject: [PATCH 24/45] fix: use field precision instead of hardcoded precision in so and po (cherry picked from commit 1a1e2c7e01f76ed9f9cc727fb802ade8faa99440) # Conflicts: # erpnext/buying/doctype/purchase_order/purchase_order.js --- .../doctype/purchase_order/purchase_order.js | 29 +++++++++++--- .../doctype/sales_order/sales_order.js | 39 +++++++++++++------ 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index de335bd6292..cb0aea0eb15 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -93,7 +93,10 @@ frappe.ui.form.on("Purchase Order", { get_materials_from_supplier: function (frm) { let po_details = []; - if (frm.doc.supplied_items && (flt(frm.doc.per_received, 2) == 100 || frm.doc.status === "Closed")) { + if ( + frm.doc.supplied_items && + (flt(frm.doc.per_received, precision("per_received")) == 100 || frm.doc.status === "Closed") + ) { frm.doc.supplied_items.forEach((d) => { if (d.total_supplied_qty && d.total_supplied_qty != d.consumed_qty) { po_details.push(d.name); @@ -329,8 +332,8 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( if (!["Closed", "Delivered"].includes(doc.status)) { if ( this.frm.doc.status !== "Closed" && - flt(this.frm.doc.per_received, 2) < 100 && - flt(this.frm.doc.per_billed, 2) < 100 + flt(this.frm.doc.per_received, precision("per_received")) < 100 && + flt(this.frm.doc.per_billed, precision("per_billed")) < 100 ) { if (!this.frm.doc.__onload || this.frm.doc.__onload.can_update_items) { this.frm.add_custom_button(__("Update Items"), () => { @@ -344,7 +347,10 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( } } if (this.frm.has_perm("submit")) { - if (flt(doc.per_billed, 2) < 100 || flt(doc.per_received, 2) < 100) { + if ( + flt(doc.per_billed, precision("per_billed")) < 100 || + flt(doc.per_received, precision("per_received")) < 100 + ) { if (doc.status != "On Hold") { this.frm.add_custom_button( __("Hold"), @@ -382,8 +388,13 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( } if (doc.status != "Closed") { if (doc.status != "On Hold") { +<<<<<<< HEAD if (flt(doc.per_received) < 100 && allow_receipt) { cur_frm.add_custom_button( +======= + if (flt(doc.per_received, precision("per_received")) < 100 && allow_receipt) { + this.frm.add_custom_button( +>>>>>>> 1a1e2c7e01 (fix: use field precision instead of hardcoded precision in so and po) __("Purchase Receipt"), this.make_purchase_receipt, __("Create") @@ -408,14 +419,20 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( } } } +<<<<<<< HEAD if (flt(doc.per_billed) < 100) cur_frm.add_custom_button( +======= + // Please do not add precision in the below flt function + if (flt(doc.per_billed, precision("per_billed")) < 100) + this.frm.add_custom_button( +>>>>>>> 1a1e2c7e01 (fix: use field precision instead of hardcoded precision in so and po) __("Purchase Invoice"), this.make_purchase_invoice, __("Create") ); - if (flt(doc.per_billed, 2) < 100 && doc.status != "Delivered") { + if (flt(doc.per_billed, precision("per_billed")) < 100 && doc.status != "Delivered") { this.frm.add_custom_button( __("Payment"), () => this.make_payment_entry(), @@ -423,7 +440,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( ); } - if (flt(doc.per_billed, 2) < 100) { + if (flt(doc.per_billed, precision("per_billed")) < 100) { this.frm.add_custom_button( __("Payment Request"), function () { diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 5387286c709..2c8a6cccceb 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -57,8 +57,8 @@ frappe.ui.form.on("Sales Order", { if (frm.doc.docstatus === 1) { if ( frm.doc.status !== "Closed" && - flt(frm.doc.per_delivered, 2) < 100 && - flt(frm.doc.per_billed, 2) < 100 && + flt(frm.doc.per_delivered, precision("per_delivered")) < 100 && + flt(frm.doc.per_billed, precision("per_billed")) < 100 && frm.has_perm("write") ) { frm.add_custom_button(__("Update Items"), () => { @@ -75,7 +75,7 @@ frappe.ui.form.on("Sales Order", { if ( frm.doc.__onload && frm.doc.__onload.has_unreserved_stock && - flt(frm.doc.per_picked) === 0 + flt(frm.doc.per_picked, precision("per_picked")) === 0 ) { frm.add_custom_button( __("Reserve"), @@ -604,7 +604,10 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex __("Status") ); - if (flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed, 2) < 100) { + if ( + flt(doc.per_delivered, precision("per_delivered")) < 100 || + flt(doc.per_billed, precision("per_billed")) < 100 + ) { // close this.frm.add_custom_button(__("Close"), () => this.close_sales_order(), __("Status")); } @@ -627,7 +630,10 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex ) && !this.frm.doc.skip_delivery_note; if (this.frm.has_perm("submit")) { - if (flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed, 2) < 100) { + if ( + flt(doc.per_delivered, precision("per_delivered")) < 100 || + flt(doc.per_billed, precision("per_billed")) < 100 + ) { // hold this.frm.add_custom_button( __("Hold"), @@ -645,8 +651,8 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex if ( (!doc.__onload || !doc.__onload.has_reserved_stock) && - flt(doc.per_picked, 2) < 100 && - flt(doc.per_delivered, 2) < 100 && + flt(doc.per_picked, precision("per_picked")) < 100 && + flt(doc.per_delivered, precision("per_delivered")) < 100 && frappe.model.can_create("Pick List") ) { this.frm.add_custom_button( @@ -664,7 +670,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex // delivery note if ( - flt(doc.per_delivered, 2) < 100 && + flt(doc.per_delivered, precision("per_delivered")) < 100 && (order_is_a_sale || order_is_a_custom_sale) && allow_delivery ) { @@ -686,7 +692,10 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex } // sales invoice - if (flt(doc.per_billed, 2) < 100 && frappe.model.can_create("Sales Invoice")) { + if ( + flt(doc.per_billed, precision("per_billed")) < 100 && + frappe.model.can_create("Sales Invoice") + ) { this.frm.add_custom_button( __("Sales Invoice"), () => me.make_sales_invoice(), @@ -698,7 +707,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex if ( (!doc.order_type || ((order_is_a_sale || order_is_a_custom_sale) && - flt(doc.per_delivered, 2) < 100)) && + flt(doc.per_delivered, precision("per_delivered")) < 100)) && frappe.model.can_create("Material Request") ) { this.frm.add_custom_button( @@ -723,7 +732,10 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex } // maintenance - if (flt(doc.per_delivered, 2) < 100 && (order_is_maintenance || order_is_a_custom_sale)) { + if ( + flt(doc.per_delivered, precision("per_delivered")) < 100 && + (order_is_maintenance || order_is_a_custom_sale) + ) { if (frappe.model.can_create("Maintenance Visit")) { this.frm.add_custom_button( __("Maintenance Visit"), @@ -741,7 +753,10 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex } // project - if (flt(doc.per_delivered, 2) < 100 && frappe.model.can_create("Project")) { + if ( + flt(doc.per_delivered, precision("per_delivered")) < 100 && + frappe.model.can_create("Project") + ) { this.frm.add_custom_button(__("Project"), () => this.make_project(), __("Create")); } From bc93de682b6de2cec6474c1067dd461fbc193732 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 26 Nov 2024 13:48:00 +0530 Subject: [PATCH 25/45] chore: resolve conflict --- .../buying/doctype/purchase_order/purchase_order.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index cb0aea0eb15..9718ab19b19 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -388,13 +388,8 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( } if (doc.status != "Closed") { if (doc.status != "On Hold") { -<<<<<<< HEAD - if (flt(doc.per_received) < 100 && allow_receipt) { - cur_frm.add_custom_button( -======= if (flt(doc.per_received, precision("per_received")) < 100 && allow_receipt) { this.frm.add_custom_button( ->>>>>>> 1a1e2c7e01 (fix: use field precision instead of hardcoded precision in so and po) __("Purchase Receipt"), this.make_purchase_receipt, __("Create") @@ -419,14 +414,9 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( } } } -<<<<<<< HEAD - if (flt(doc.per_billed) < 100) - cur_frm.add_custom_button( -======= // Please do not add precision in the below flt function if (flt(doc.per_billed, precision("per_billed")) < 100) this.frm.add_custom_button( ->>>>>>> 1a1e2c7e01 (fix: use field precision instead of hardcoded precision in so and po) __("Purchase Invoice"), this.make_purchase_invoice, __("Create") From ea0f24aa573e66d289be4af567405e072eb73968 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 19:43:51 +0530 Subject: [PATCH 26/45] fix: billed qty and received amount in PO analysis report (backport #44349) (#44354) fix: billed qty and received amount in PO analysis report (#44349) (cherry picked from commit 2ab7ec5437834a63e0a0ebe5e081236370d56e8b) Co-authored-by: rohitwaghchaure --- .../purchase_order_analysis.py | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py index 084c3b5fc2b..1a250acd4d2 100644 --- a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py +++ b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py @@ -18,6 +18,7 @@ def execute(filters=None): columns = get_columns(filters) data = get_data(filters) + update_received_amount(data) if not data: return [], [], None, [] @@ -40,7 +41,6 @@ def get_data(filters): po = frappe.qb.DocType("Purchase Order") po_item = frappe.qb.DocType("Purchase Order Item") pi_item = frappe.qb.DocType("Purchase Invoice Item") - pr_item = frappe.qb.DocType("Purchase Receipt Item") query = ( frappe.qb.from_(po) @@ -48,8 +48,6 @@ def get_data(filters): .on(po_item.parent == po.name) .left_join(pi_item) .on((pi_item.po_detail == po_item.name) & (pi_item.docstatus == 1)) - .left_join(pr_item) - .on((pr_item.purchase_order_item == po_item.name) & (pr_item.docstatus == 1)) .select( po.transaction_date.as_("date"), po_item.schedule_date.as_("required_date"), @@ -63,7 +61,6 @@ def get_data(filters): (po_item.qty - po_item.received_qty).as_("pending_qty"), Sum(IfNull(pi_item.qty, 0)).as_("billed_qty"), po_item.base_amount.as_("amount"), - (pr_item.base_amount).as_("received_qty_amount"), (po_item.billed_amt * IfNull(po.conversion_rate, 1)).as_("billed_amount"), (po_item.base_amount - (po_item.billed_amt * IfNull(po.conversion_rate, 1))).as_( "pending_amount" @@ -95,6 +92,39 @@ def get_data(filters): return data +def update_received_amount(data): + pr_data = get_received_amount_data(data) + + for row in data: + row.received_qty_amount = flt(pr_data.get(row.name)) + + +def get_received_amount_data(data): + pr = frappe.qb.DocType("Purchase Receipt") + pr_item = frappe.qb.DocType("Purchase Receipt Item") + + query = ( + frappe.qb.from_(pr) + .inner_join(pr_item) + .on(pr_item.parent == pr.name) + .select( + pr_item.purchase_order_item, + Sum(pr_item.base_amount).as_("received_qty_amount"), + ) + .where((pr_item.parent == pr.name) & (pr.docstatus == 1)) + .groupby(pr_item.purchase_order_item) + ) + + query = query.where(pr_item.purchase_order_item.isin([row.name for row in data])) + + data = query.run() + + if not data: + return frappe._dict() + + return frappe._dict(data) + + def prepare_data(data, filters): completed, pending = 0, 0 pending_field = "pending_amount" From 89bd4eba46894efba5cfe9bc3411448d41366807 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 21:18:26 +0530 Subject: [PATCH 27/45] fix: added validation for quality inspection (backport #44351) (#44357) fix: added validation for quality inspection (#44351) (cherry picked from commit 0fd50b504814e8f035be8d6cef62121513fb8639) Co-authored-by: rohitwaghchaure --- .../quality_inspection/quality_inspection.py | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py index 43efcbc8ca6..6890256dc04 100644 --- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py +++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py @@ -6,7 +6,7 @@ import frappe from frappe import _ from frappe.model.document import Document from frappe.model.mapper import get_mapped_doc -from frappe.utils import cint, cstr, flt, get_number_format_info +from frappe.utils import cint, cstr, flt, get_link_to_form, get_number_format_info from erpnext.stock.doctype.quality_inspection_template.quality_inspection_template import ( get_template_details, @@ -73,6 +73,27 @@ class QualityInspection(Document): if self.readings: self.inspect_and_set_status() + self.validate_inspection_required() + + def validate_inspection_required(self): + if self.reference_type in ["Purchase Receipt", "Purchase Invoice"] and not frappe.get_cached_value( + "Item", self.item_code, "inspection_required_before_purchase" + ): + frappe.throw( + _( + "'Inspection Required before Purchase' has disabled for the item {0}, no need to create the QI" + ).format(get_link_to_form("Item", self.item_code)) + ) + + if self.reference_type in ["Delivery Note", "Sales Invoice"] and not frappe.get_cached_value( + "Item", self.item_code, "inspection_required_before_delivery" + ): + frappe.throw( + _( + "'Inspection Required before Delivery' has disabled for the item {0}, no need to create the QI" + ).format(get_link_to_form("Item", self.item_code)) + ) + def before_submit(self): self.validate_readings_status_mandatory() From 7e61aca512c18adca6f8eb5b2300287898e8f3e4 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 20:16:24 +0100 Subject: [PATCH 28/45] fix: unify company address query in sales transactions (backport #44361) (#44365) fix: unify company address query in sales transactions (#44361) * fix: unify company address query in sales transactions * refactor: get the correct field label (cherry picked from commit 3f92a57d63edf5c5b478736e25d77b5eb43eac94) Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com> --- .../doctype/sales_invoice/sales_invoice.js | 14 -------------- erpnext/public/js/queries.js | 6 +++++- erpnext/public/js/utils/sales_common.js | 1 + erpnext/selling/doctype/quotation/quotation.js | 14 -------------- erpnext/selling/doctype/sales_order/sales_order.js | 14 -------------- 5 files changed, 6 insertions(+), 43 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 5e248c8b235..75c71ef6eb3 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -741,20 +741,6 @@ frappe.ui.form.on("Sales Invoice", { }; }; - frm.set_query("company_address", function (doc) { - if (!doc.company) { - frappe.throw(__("Please set Company")); - } - - return { - query: "frappe.contacts.doctype.address.address.address_query", - filters: { - link_doctype: "Company", - link_name: doc.company, - }, - }; - }); - frm.set_query("pos_profile", function (doc) { if (!doc.company) { frappe.throw(__("Please set Company")); diff --git a/erpnext/public/js/queries.js b/erpnext/public/js/queries.js index d7edac3cb9f..5350f91746c 100644 --- a/erpnext/public/js/queries.js +++ b/erpnext/public/js/queries.js @@ -77,9 +77,13 @@ $.extend(erpnext.queries, { }, company_address_query: function (doc) { + if (!doc.company) { + frappe.throw(__("Please set {0}", [__(frappe.meta.get_label(doc.doctype, "company", doc.name))])); + } + return { query: "frappe.contacts.doctype.address.address.address_query", - filters: { is_your_company_address: 1, link_doctype: "Company", link_name: doc.company || "" }, + filters: { link_doctype: "Company", link_name: doc.company }, }; }, diff --git a/erpnext/public/js/utils/sales_common.js b/erpnext/public/js/utils/sales_common.js index ac4ecf52e63..373bf3d2115 100644 --- a/erpnext/public/js/utils/sales_common.js +++ b/erpnext/public/js/utils/sales_common.js @@ -52,6 +52,7 @@ erpnext.sales_common = { me.frm.set_query("customer_address", erpnext.queries.address_query); me.frm.set_query("shipping_address_name", erpnext.queries.address_query); me.frm.set_query("dispatch_address_name", erpnext.queries.dispatch_address_query); + me.frm.set_query("company_address", erpnext.queries.company_address_query); erpnext.accounts.dimensions.setup_dimension_filters(me.frm, me.frm.doctype); diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js index a4c70d7f50f..7311857e350 100644 --- a/erpnext/selling/doctype/quotation/quotation.js +++ b/erpnext/selling/doctype/quotation/quotation.js @@ -24,20 +24,6 @@ frappe.ui.form.on("Quotation", { frm.set_df_property("packed_items", "cannot_add_rows", true); frm.set_df_property("packed_items", "cannot_delete_rows", true); - frm.set_query("company_address", function (doc) { - if (!doc.company) { - frappe.throw(__("Please set Company")); - } - - return { - query: "frappe.contacts.doctype.address.address.address_query", - filters: { - link_doctype: "Company", - link_name: doc.company, - }, - }; - }); - frm.set_query("serial_and_batch_bundle", "packed_items", (doc, cdt, cdn) => { let row = locals[cdt][cdn]; return { diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 2c8a6cccceb..f285d638322 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -26,20 +26,6 @@ frappe.ui.form.on("Sales Order", { return doc.stock_qty <= doc.delivered_qty ? "green" : "orange"; }); - frm.set_query("company_address", function (doc) { - if (!doc.company) { - frappe.throw(__("Please set Company")); - } - - return { - query: "frappe.contacts.doctype.address.address.address_query", - filters: { - link_doctype: "Company", - link_name: doc.company, - }, - }; - }); - frm.set_query("bom_no", "items", function (doc, cdt, cdn) { var row = locals[cdt][cdn]; return { From 67809c781a9088b381c51c0c997737e47a8c14df Mon Sep 17 00:00:00 2001 From: venkat102 Date: Tue, 26 Nov 2024 14:58:57 +0530 Subject: [PATCH 29/45] fix: show cc on the email (cherry picked from commit 2dd5699f6d6b3ae465490e60f44f1bcd772265f2) --- .../process_statement_of_accounts.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py index bc3ba26beb7..bf1c8c0b66e 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py @@ -474,6 +474,7 @@ def send_emails(document_name, from_scheduler=False, posting_date=None): reference_doctype="Process Statement Of Accounts", reference_name=document_name, attachments=attachments, + expose_recipients="header", ) if doc.enable_auto_email and from_scheduler: From ef882de509b43c5e7ef1cfd2e08f942df18df17b Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 27 Nov 2024 10:31:30 +0530 Subject: [PATCH 30/45] feat: provision to disable item attribute (backport #44358) (#44370) * feat: provision to disable item attribute (#44358) (cherry picked from commit 123e3ef263cdf36101064fa999180425204b9963) # Conflicts: # erpnext/stock/doctype/item_attribute/item_attribute.json # erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.json * chore: fix conflicts * chore: fix conflicts --------- Co-authored-by: rohitwaghchaure --- erpnext/stock/doctype/item/item.js | 105 +++++++++--------- .../item_attribute/item_attribute.json | 17 ++- .../doctype/item_attribute/item_attribute.py | 14 +++ .../item_variant_attribute.json | 12 +- .../item_variant_attribute.py | 1 + 5 files changed, 95 insertions(+), 54 deletions(-) diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index 81eeb914af0..4195506ad3b 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -663,39 +663,41 @@ $.extend(erpnext.item, { } frm.doc.attributes.forEach(function (d) { - let p = new Promise((resolve) => { - if (!d.numeric_values) { - frappe - .call({ - method: "frappe.client.get_list", - args: { - doctype: "Item Attribute Value", - filters: [["parent", "=", d.attribute]], - fields: ["attribute_value"], - limit_page_length: 0, - parent: "Item Attribute", - order_by: "idx", - }, - }) - .then((r) => { - if (r.message) { - attr_val_fields[d.attribute] = r.message.map(function (d) { - return d.attribute_value; - }); - resolve(); - } - }); - } else { - let values = []; - for (var i = d.from_range; i <= d.to_range; i = flt(i + d.increment, 6)) { - values.push(i); + if (!d.disabled) { + let p = new Promise((resolve) => { + if (!d.numeric_values) { + frappe + .call({ + method: "frappe.client.get_list", + args: { + doctype: "Item Attribute Value", + filters: [["parent", "=", d.attribute]], + fields: ["attribute_value"], + limit_page_length: 0, + parent: "Item Attribute", + order_by: "idx", + }, + }) + .then((r) => { + if (r.message) { + attr_val_fields[d.attribute] = r.message.map(function (d) { + return d.attribute_value; + }); + resolve(); + } + }); + } else { + let values = []; + for (var i = d.from_range; i <= d.to_range; i = flt(i + d.increment, 6)) { + values.push(i); + } + attr_val_fields[d.attribute] = values; + resolve(); } - attr_val_fields[d.attribute] = values; - resolve(); - } - }); + }); - promises.push(p); + promises.push(p); + } }, this); Promise.all(promises).then(() => { @@ -710,26 +712,29 @@ $.extend(erpnext.item, { for (var i = 0; i < frm.doc.attributes.length; i++) { var fieldtype, desc; var row = frm.doc.attributes[i]; - if (row.numeric_values) { - fieldtype = "Float"; - desc = - "Min Value: " + - row.from_range + - " , Max Value: " + - row.to_range + - ", in Increments of: " + - row.increment; - } else { - fieldtype = "Data"; - desc = ""; + + if (!row.disabled) { + if (row.numeric_values) { + fieldtype = "Float"; + desc = + "Min Value: " + + row.from_range + + " , Max Value: " + + row.to_range + + ", in Increments of: " + + row.increment; + } else { + fieldtype = "Data"; + desc = ""; + } + fields = fields.concat({ + label: row.attribute, + fieldname: row.attribute, + fieldtype: fieldtype, + reqd: 0, + description: desc, + }); } - fields = fields.concat({ - label: row.attribute, - fieldname: row.attribute, - fieldtype: fieldtype, - reqd: 0, - description: desc, - }); } if (frm.doc.image) { diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.json b/erpnext/stock/doctype/item_attribute/item_attribute.json index 5c4678916f3..d9b0898ca7f 100644 --- a/erpnext/stock/doctype/item_attribute/item_attribute.json +++ b/erpnext/stock/doctype/item_attribute/item_attribute.json @@ -10,6 +10,8 @@ "field_order": [ "attribute_name", "numeric_values", + "column_break_vbik", + "disabled", "section_break_4", "from_range", "increment", @@ -70,15 +72,26 @@ "fieldtype": "Table", "label": "Item Attribute Values", "options": "Item Attribute Value" + }, + { + "fieldname": "column_break_vbik", + "fieldtype": "Column Break" + }, + { + "default": "0", + "fieldname": "disabled", + "fieldtype": "Check", + "label": "Disabled" } ], "icon": "fa fa-edit", "index_web_pages_for_search": 1, "links": [], - "modified": "2020-10-02 12:03:02.359202", + "modified": "2024-11-26 20:05:29.421714", "modified_by": "Administrator", "module": "Stock", "name": "Item Attribute", + "naming_rule": "By fieldname", "owner": "Administrator", "permissions": [ { @@ -94,4 +107,4 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.py b/erpnext/stock/doctype/item_attribute/item_attribute.py index 04421d6292e..3b9bcf93288 100644 --- a/erpnext/stock/doctype/item_attribute/item_attribute.py +++ b/erpnext/stock/doctype/item_attribute/item_attribute.py @@ -30,6 +30,7 @@ class ItemAttribute(Document): from erpnext.stock.doctype.item_attribute_value.item_attribute_value import ItemAttributeValue attribute_name: DF.Data + disabled: DF.Check from_range: DF.Float increment: DF.Float item_attribute_values: DF.Table[ItemAttributeValue] @@ -47,6 +48,19 @@ class ItemAttribute(Document): def on_update(self): self.validate_exising_items() + self.set_enabled_disabled_in_items() + + def set_enabled_disabled_in_items(self): + db_value = self.get_doc_before_save() + if not db_value or db_value.disabled != self.disabled: + item_variant_table = frappe.qb.DocType("Item Variant Attribute") + query = ( + frappe.qb.update(item_variant_table) + .set(item_variant_table.disabled, self.disabled) + .where(item_variant_table.attribute == self.name) + ) + + query.run() def validate_exising_items(self): """Validate that if there are existing items with attributes, they are valid""" diff --git a/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.json b/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.json index 9699ecbb3db..cfc752c1f61 100644 --- a/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.json +++ b/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.json @@ -11,6 +11,7 @@ "column_break_2", "attribute_value", "numeric_values", + "disabled", "section_break_4", "from_range", "increment", @@ -74,11 +75,18 @@ "fieldname": "to_range", "fieldtype": "Float", "label": "To Range" + }, + { + "default": "0", + "fetch_from": "attribute.disabled", + "fieldname": "disabled", + "fieldtype": "Check", + "label": "Disabled" } ], "istable": 1, "links": [], - "modified": "2023-07-14 17:15:19.112119", + "modified": "2024-11-26 20:10:49.873339", "modified_by": "Administrator", "module": "Stock", "name": "Item Variant Attribute", @@ -87,4 +95,4 @@ "sort_field": "modified", "sort_order": "DESC", "states": [] -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.py b/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.py index 756b7421761..ea239d2ccc9 100644 --- a/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.py +++ b/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.py @@ -16,6 +16,7 @@ class ItemVariantAttribute(Document): attribute: DF.Link attribute_value: DF.Data | None + disabled: DF.Check from_range: DF.Float increment: DF.Float numeric_values: DF.Check From a523c14fd574f3e22d90aef3b73d98f7953625d4 Mon Sep 17 00:00:00 2001 From: ljain112 Date: Wed, 27 Nov 2024 13:44:33 +0530 Subject: [PATCH 31/45] fix: correct placeholder index in message (cherry picked from commit d61cb9a4bfa3913b208d2d30f40c9b34639344fb) --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index b9fad5c9010..3a80b5beb7a 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1746,7 +1746,7 @@ class PaymentEntry(AccountsController): if paid_amount > total_negative_outstanding: if total_negative_outstanding == 0: frappe.msgprint( - _("Cannot {0} from {2} without any negative outstanding invoice").format( + _("Cannot {0} from {1} without any negative outstanding invoice").format( self.payment_type, self.party_type, ) From 860350a5b329a49d078f70f22c38a0a1a4ca2032 Mon Sep 17 00:00:00 2001 From: vishakhdesai Date: Wed, 27 Nov 2024 12:43:34 +0530 Subject: [PATCH 32/45] fix: remove field precision in SO and PO for percentage fields (cherry picked from commit eff9cd10cd6dcf47ad05311c5730da267482b870) # Conflicts: # erpnext/selling/doctype/sales_order/sales_order_list.js --- .../doctype/purchase_order/purchase_order.js | 22 ++++----- .../doctype/sales_order/sales_order.js | 45 ++++++------------- .../doctype/sales_order/sales_order_list.js | 14 ++++-- 3 files changed, 31 insertions(+), 50 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 9718ab19b19..e71f2418794 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -93,10 +93,7 @@ frappe.ui.form.on("Purchase Order", { get_materials_from_supplier: function (frm) { let po_details = []; - if ( - frm.doc.supplied_items && - (flt(frm.doc.per_received, precision("per_received")) == 100 || frm.doc.status === "Closed") - ) { + if (frm.doc.supplied_items && (flt(frm.doc.per_received) == 100 || frm.doc.status === "Closed")) { frm.doc.supplied_items.forEach((d) => { if (d.total_supplied_qty && d.total_supplied_qty != d.consumed_qty) { po_details.push(d.name); @@ -332,8 +329,8 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( if (!["Closed", "Delivered"].includes(doc.status)) { if ( this.frm.doc.status !== "Closed" && - flt(this.frm.doc.per_received, precision("per_received")) < 100 && - flt(this.frm.doc.per_billed, precision("per_billed")) < 100 + flt(this.frm.doc.per_received) < 100 && + flt(this.frm.doc.per_billed) < 100 ) { if (!this.frm.doc.__onload || this.frm.doc.__onload.can_update_items) { this.frm.add_custom_button(__("Update Items"), () => { @@ -347,10 +344,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( } } if (this.frm.has_perm("submit")) { - if ( - flt(doc.per_billed, precision("per_billed")) < 100 || - flt(doc.per_received, precision("per_received")) < 100 - ) { + if (flt(doc.per_billed) < 100 || flt(doc.per_received) < 100) { if (doc.status != "On Hold") { this.frm.add_custom_button( __("Hold"), @@ -388,7 +382,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( } if (doc.status != "Closed") { if (doc.status != "On Hold") { - if (flt(doc.per_received, precision("per_received")) < 100 && allow_receipt) { + if (flt(doc.per_received) < 100 && allow_receipt) { this.frm.add_custom_button( __("Purchase Receipt"), this.make_purchase_receipt, @@ -415,14 +409,14 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( } } // Please do not add precision in the below flt function - if (flt(doc.per_billed, precision("per_billed")) < 100) + if (flt(doc.per_billed) < 100) this.frm.add_custom_button( __("Purchase Invoice"), this.make_purchase_invoice, __("Create") ); - if (flt(doc.per_billed, precision("per_billed")) < 100 && doc.status != "Delivered") { + if (flt(doc.per_billed) < 100 && doc.status != "Delivered") { this.frm.add_custom_button( __("Payment"), () => this.make_payment_entry(), @@ -430,7 +424,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( ); } - if (flt(doc.per_billed, precision("per_billed")) < 100) { + if (flt(doc.per_billed) < 100) { this.frm.add_custom_button( __("Payment Request"), function () { diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index f285d638322..45f6b364761 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -43,8 +43,8 @@ frappe.ui.form.on("Sales Order", { if (frm.doc.docstatus === 1) { if ( frm.doc.status !== "Closed" && - flt(frm.doc.per_delivered, precision("per_delivered")) < 100 && - flt(frm.doc.per_billed, precision("per_billed")) < 100 && + flt(frm.doc.per_delivered) < 100 && + flt(frm.doc.per_billed) < 100 && frm.has_perm("write") ) { frm.add_custom_button(__("Update Items"), () => { @@ -61,7 +61,7 @@ frappe.ui.form.on("Sales Order", { if ( frm.doc.__onload && frm.doc.__onload.has_unreserved_stock && - flt(frm.doc.per_picked, precision("per_picked")) === 0 + flt(frm.doc.per_picked) === 0 ) { frm.add_custom_button( __("Reserve"), @@ -590,10 +590,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex __("Status") ); - if ( - flt(doc.per_delivered, precision("per_delivered")) < 100 || - flt(doc.per_billed, precision("per_billed")) < 100 - ) { + if (flt(doc.per_delivered) < 100 || flt(doc.per_billed) < 100) { // close this.frm.add_custom_button(__("Close"), () => this.close_sales_order(), __("Status")); } @@ -616,10 +613,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex ) && !this.frm.doc.skip_delivery_note; if (this.frm.has_perm("submit")) { - if ( - flt(doc.per_delivered, precision("per_delivered")) < 100 || - flt(doc.per_billed, precision("per_billed")) < 100 - ) { + if (flt(doc.per_delivered) < 100 || flt(doc.per_billed) < 100) { // hold this.frm.add_custom_button( __("Hold"), @@ -637,8 +631,8 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex if ( (!doc.__onload || !doc.__onload.has_reserved_stock) && - flt(doc.per_picked, precision("per_picked")) < 100 && - flt(doc.per_delivered, precision("per_delivered")) < 100 && + flt(doc.per_picked) < 100 && + flt(doc.per_delivered) < 100 && frappe.model.can_create("Pick List") ) { this.frm.add_custom_button( @@ -656,7 +650,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex // delivery note if ( - flt(doc.per_delivered, precision("per_delivered")) < 100 && + flt(doc.per_delivered) < 100 && (order_is_a_sale || order_is_a_custom_sale) && allow_delivery ) { @@ -678,10 +672,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex } // sales invoice - if ( - flt(doc.per_billed, precision("per_billed")) < 100 && - frappe.model.can_create("Sales Invoice") - ) { + if (flt(doc.per_billed) < 100 && frappe.model.can_create("Sales Invoice")) { this.frm.add_custom_button( __("Sales Invoice"), () => me.make_sales_invoice(), @@ -692,8 +683,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex // material request if ( (!doc.order_type || - ((order_is_a_sale || order_is_a_custom_sale) && - flt(doc.per_delivered, precision("per_delivered")) < 100)) && + ((order_is_a_sale || order_is_a_custom_sale) && flt(doc.per_delivered) < 100)) && frappe.model.can_create("Material Request") ) { this.frm.add_custom_button( @@ -718,10 +708,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex } // maintenance - if ( - flt(doc.per_delivered, precision("per_delivered")) < 100 && - (order_is_maintenance || order_is_a_custom_sale) - ) { + if (flt(doc.per_delivered) < 100 && (order_is_maintenance || order_is_a_custom_sale)) { if (frappe.model.can_create("Maintenance Visit")) { this.frm.add_custom_button( __("Maintenance Visit"), @@ -739,10 +726,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex } // project - if ( - flt(doc.per_delivered, precision("per_delivered")) < 100 && - frappe.model.can_create("Project") - ) { + if (flt(doc.per_delivered) < 100 && frappe.model.can_create("Project")) { this.frm.add_custom_button(__("Project"), () => this.make_project(), __("Create")); } @@ -770,10 +754,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex } } // payment request - if ( - flt(doc.per_billed, precision("per_billed", doc)) < - 100 + frappe.boot.sysdefaults.over_billing_allowance - ) { + if (flt(doc.per_billed) < 100 + frappe.boot.sysdefaults.over_billing_allowance) { this.frm.add_custom_button( __("Payment Request"), () => this.make_payment_request(), diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js index 5ccd5d551cb..73ef164f5c1 100644 --- a/erpnext/selling/doctype/sales_order/sales_order_list.js +++ b/erpnext/selling/doctype/sales_order/sales_order_list.js @@ -20,14 +20,20 @@ frappe.listview_settings["Sales Order"] = { return [__("On Hold"), "orange", "status,=,On Hold"]; } else if (doc.status === "Completed") { return [__("Completed"), "green", "status,=,Completed"]; +<<<<<<< HEAD } else if (!doc.skip_delivery_note && flt(doc.per_delivered, 2) < 100) { +======= + } else if (doc.advance_payment_status === "Requested") { + return [__("To Pay"), "gray", "advance_payment_status,=,Requested"]; + } else if (!doc.skip_delivery_note && flt(doc.per_delivered) < 100) { +>>>>>>> eff9cd10cd (fix: remove field precision in SO and PO for percentage fields) if (frappe.datetime.get_diff(doc.delivery_date) < 0) { // not delivered & overdue return [__("Overdue"), "red", "per_delivered,<,100|delivery_date,<,Today|status,!=,Closed"]; } else if (flt(doc.grand_total) === 0) { // not delivered (zeroount order) return [__("To Deliver"), "orange", "per_delivered,<,100|grand_total,=,0|status,!=,Closed"]; - } else if (flt(doc.per_billed, 2) < 100) { + } else if (flt(doc.per_billed) < 100) { // not delivered & not billed return [ __("To Deliver and Bill"), @@ -39,13 +45,13 @@ frappe.listview_settings["Sales Order"] = { return [__("To Deliver"), "orange", "per_delivered,<,100|per_billed,=,100|status,!=,Closed"]; } } else if ( - flt(doc.per_delivered, 2) === 100 && + flt(doc.per_delivered) === 100 && flt(doc.grand_total) !== 0 && - flt(doc.per_billed, 2) < 100 + flt(doc.per_billed) < 100 ) { // to bill return [__("To Bill"), "orange", "per_delivered,=,100|per_billed,<,100|status,!=,Closed"]; - } else if (doc.skip_delivery_note && flt(doc.per_billed, 2) < 100) { + } else if (doc.skip_delivery_note && flt(doc.per_billed) < 100) { return [__("To Bill"), "orange", "per_billed,<,100|status,!=,Closed"]; } }, From ca56709295002f86c0b936a75ed250415784ea06 Mon Sep 17 00:00:00 2001 From: ljain112 Date: Mon, 25 Nov 2024 17:31:07 +0530 Subject: [PATCH 33/45] fix: update gross profit for returned invoices (cherry picked from commit 8a42601e99a298782f43f252c64b1d692875d202) --- .../report/gross_profit/gross_profit.py | 65 +++++++++---------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index a9039a9cada..12a4ca76aab 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -440,6 +440,7 @@ class GrossProfitGenerator: if grouped_by_invoice: buying_amount = 0 + base_amount = 0 for row in reversed(self.si_list): if self.filters.get("group_by") == "Monthly": @@ -480,12 +481,11 @@ class GrossProfitGenerator: else: row.buying_amount = flt(self.get_buying_amount(row, row.item_code), self.currency_precision) - if grouped_by_invoice: - if row.indent == 1.0: - buying_amount += row.buying_amount - elif row.indent == 0.0: - row.buying_amount = buying_amount - buying_amount = 0 + if grouped_by_invoice and row.indent == 0.0: + row.buying_amount = buying_amount + row.base_amount = base_amount + buying_amount = 0 + base_amount = 0 # get buying rate if flt(row.qty): @@ -495,11 +495,19 @@ class GrossProfitGenerator: if self.is_not_invoice_row(row): row.buying_rate, row.base_rate = 0.0, 0.0 + if self.is_not_invoice_row(row): + self.update_return_invoices(row) + + if grouped_by_invoice and row.indent == 1.0: + buying_amount += row.buying_amount + base_amount += row.base_amount + # calculate gross profit row.gross_profit = flt(row.base_amount - row.buying_amount, self.currency_precision) if row.base_amount: row.gross_profit_percent = flt( - (row.gross_profit / row.base_amount) * 100.0, self.currency_precision + (row.gross_profit / row.base_amount) * 100.0, + self.currency_precision, ) else: row.gross_profit_percent = 0.0 @@ -510,33 +518,24 @@ class GrossProfitGenerator: if self.grouped: self.get_average_rate_based_on_group_by() + def update_return_invoices(self, row): + if row.parent in self.returned_invoices and row.item_code in self.returned_invoices[row.parent]: + returned_item_rows = self.returned_invoices[row.parent][row.item_code] + for returned_item_row in returned_item_rows: + # returned_items 'qty' should be stateful + if returned_item_row.qty != 0: + if row.qty >= abs(returned_item_row.qty): + row.qty += returned_item_row.qty + returned_item_row.qty = 0 + else: + row.qty = 0 + returned_item_row.qty += row.qty + row.base_amount += flt(returned_item_row.base_amount, self.currency_precision) + row.buying_amount = flt(flt(row.qty) * flt(row.buying_rate), self.currency_precision) + def get_average_rate_based_on_group_by(self): for key in list(self.grouped): - if self.filters.get("group_by") == "Invoice": - for row in self.grouped[key]: - if row.indent == 1.0: - if ( - row.parent in self.returned_invoices - and row.item_code in self.returned_invoices[row.parent] - ): - returned_item_rows = self.returned_invoices[row.parent][row.item_code] - for returned_item_row in returned_item_rows: - # returned_items 'qty' should be stateful - if returned_item_row.qty != 0: - if row.qty >= abs(returned_item_row.qty): - row.qty += returned_item_row.qty - returned_item_row.qty = 0 - else: - row.qty = 0 - returned_item_row.qty += row.qty - row.base_amount += flt(returned_item_row.base_amount, self.currency_precision) - row.buying_amount = flt( - flt(row.qty) * flt(row.buying_rate), self.currency_precision - ) - if flt(row.qty) or row.base_amount: - row = self.set_average_rate(row) - self.grouped_data.append(row) - elif self.filters.get("group_by") == "Payment Term": + if self.filters.get("group_by") == "Payment Term": for i, row in enumerate(self.grouped[key]): invoice_portion = 0 @@ -556,7 +555,7 @@ class GrossProfitGenerator: new_row = self.set_average_rate(new_row) self.grouped_data.append(new_row) - else: + elif self.filters.get("group_by") != "Invoice": for i, row in enumerate(self.grouped[key]): if i == 0: new_row = row From f4518cac9a3ae9b4a018b24f3ea29ec525e2236a Mon Sep 17 00:00:00 2001 From: ljain112 Date: Mon, 25 Nov 2024 18:45:17 +0530 Subject: [PATCH 34/45] fix: gp for return invoice (cherry picked from commit 00403515a8ba005e5ac5c0e7a5ff88a5bda5b170) --- erpnext/accounts/report/gross_profit/gross_profit.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 12a4ca76aab..5ba1e41b624 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -526,11 +526,16 @@ class GrossProfitGenerator: if returned_item_row.qty != 0: if row.qty >= abs(returned_item_row.qty): row.qty += returned_item_row.qty + row.base_amount += flt(returned_item_row.base_amount, self.currency_precision) returned_item_row.qty = 0 + returned_item_row.base_amount = 0 + else: row.qty = 0 + row.base_amount = 0 returned_item_row.qty += row.qty - row.base_amount += flt(returned_item_row.base_amount, self.currency_precision) + returned_item_row.base_amount += row.base_amount + row.buying_amount = flt(flt(row.qty) * flt(row.buying_rate), self.currency_precision) def get_average_rate_based_on_group_by(self): From 66af7f4a14e58029f80aa87b62a056c04be60969 Mon Sep 17 00:00:00 2001 From: ljain112 Date: Mon, 25 Nov 2024 19:05:08 +0530 Subject: [PATCH 35/45] fix: test case (cherry picked from commit af5a3e5a48c7da329a078c3d0e177593061d123b) --- erpnext/accounts/report/gross_profit/test_gross_profit.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/gross_profit/test_gross_profit.py b/erpnext/accounts/report/gross_profit/test_gross_profit.py index 83de93891fe..721be79ed88 100644 --- a/erpnext/accounts/report/gross_profit/test_gross_profit.py +++ b/erpnext/accounts/report/gross_profit/test_gross_profit.py @@ -418,12 +418,12 @@ class TestGrossProfit(FrappeTestCase): "item_name": self.item, "warehouse": "Stores - _GP", "qty": 0.0, - "avg._selling_rate": 0.0, + "avg._selling_rate": 100, "valuation_rate": 0.0, - "selling_amount": -100.0, + "selling_amount": 0.0, "buying_amount": 0.0, - "gross_profit": -100.0, - "gross_profit_%": 100.0, + "gross_profit": 0.0, + "gross_profit_%": 0.0, } gp_entry = [x for x in data if x.parent_invoice == sinv.name] # Both items of Invoice should have '0' qty From d6ef43858cee5b3a05a306588c258eb1d41b7031 Mon Sep 17 00:00:00 2001 From: venkat102 Date: Tue, 26 Nov 2024 22:13:57 +0530 Subject: [PATCH 36/45] fix: check difference with company currency (cherry picked from commit e2bae4cf07918adf815384b3db81717df95d9413) --- .../doctype/period_closing_voucher/period_closing_voucher.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py index 1d4ee25241e..7e0145e91a4 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py +++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py @@ -171,9 +171,7 @@ class PeriodClosingVoucher(AccountsController): pl_account_balances = self.get_account_balances_based_on_dimensions(report_type="Profit and Loss") for dimensions, account_balances in pl_account_balances.items(): for acc, balances in account_balances.items(): - balance_in_company_currency = flt(balances.debit_in_account_currency) - flt( - balances.credit_in_account_currency - ) + balance_in_company_currency = flt(balances.debit) - flt(balances.credit) if balance_in_company_currency and acc != "balances": self.pl_accounts_reverse_gle.append( self.get_gle_for_pl_account(acc, balances, dimensions) From 45e41827c76526412ec29e5d5678d90360f65631 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Nov 2024 17:20:36 +0530 Subject: [PATCH 37/45] chore: resolve conflict --- erpnext/selling/doctype/sales_order/sales_order_list.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js index 73ef164f5c1..46d115a1713 100644 --- a/erpnext/selling/doctype/sales_order/sales_order_list.js +++ b/erpnext/selling/doctype/sales_order/sales_order_list.js @@ -20,13 +20,7 @@ frappe.listview_settings["Sales Order"] = { return [__("On Hold"), "orange", "status,=,On Hold"]; } else if (doc.status === "Completed") { return [__("Completed"), "green", "status,=,Completed"]; -<<<<<<< HEAD - } else if (!doc.skip_delivery_note && flt(doc.per_delivered, 2) < 100) { -======= - } else if (doc.advance_payment_status === "Requested") { - return [__("To Pay"), "gray", "advance_payment_status,=,Requested"]; } else if (!doc.skip_delivery_note && flt(doc.per_delivered) < 100) { ->>>>>>> eff9cd10cd (fix: remove field precision in SO and PO for percentage fields) if (frappe.datetime.get_diff(doc.delivery_date) < 0) { // not delivered & overdue return [__("Overdue"), "red", "per_delivered,<,100|delivery_date,<,Today|status,!=,Closed"]; From d073b005a8579e48266d1265ccf542f625ac595b Mon Sep 17 00:00:00 2001 From: venkat102 Date: Wed, 27 Nov 2024 14:02:11 +0530 Subject: [PATCH 38/45] fix: filter item with search fields (cherry picked from commit ebfbee3da50961019691d650d7d152502d541094) --- .../doctype/product_bundle/product_bundle.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/product_bundle/product_bundle.py b/erpnext/selling/doctype/product_bundle/product_bundle.py index 464cff01d7e..609f45a608f 100644 --- a/erpnext/selling/doctype/product_bundle/product_bundle.py +++ b/erpnext/selling/doctype/product_bundle/product_bundle.py @@ -5,6 +5,7 @@ import frappe from frappe import _ from frappe.model.document import Document +from frappe.query_builder import Criterion from frappe.utils import get_link_to_form @@ -93,15 +94,24 @@ class ProductBundle(Document): def get_new_item_code(doctype, txt, searchfield, start, page_len, filters): product_bundles = frappe.db.get_list("Product Bundle", {"disabled": 0}, pluck="name") + if not searchfield or searchfield == "name": + searchfield = frappe.get_meta("Item").get("search_fields") + + searchfield = searchfield.split(",") + searchfield.append("name") + item = frappe.qb.DocType("Item") query = ( frappe.qb.from_(item) - .select(item.item_code, item.item_name) - .where((item.is_stock_item == 0) & (item.is_fixed_asset == 0) & (item[searchfield].like(f"%{txt}%"))) + .select(item.name, item.item_name) + .where((item.is_stock_item == 0) & (item.is_fixed_asset == 0)) .limit(page_len) .offset(start) ) + if searchfield: + query = query.where(Criterion.any([item[fieldname].like(f"%{txt}%") for fieldname in searchfield])) + if product_bundles: query = query.where(item.name.notin(product_bundles)) From a2612d5f36eaeee10231b27b5c4bfea2c79208da Mon Sep 17 00:00:00 2001 From: venkat102 Date: Tue, 26 Nov 2024 00:03:42 +0530 Subject: [PATCH 39/45] fix: set debit transaction currency in gl entry (cherry picked from commit 6e19c06e58dd2ffa9cb4bee014a7c0671ff8bf80) --- .../doctype/payment_entry/payment_entry.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 3a80b5beb7a..89f52b46679 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1219,11 +1219,19 @@ class PaymentEntry(AccountsController): dr_or_cr = "debit" if dr_or_cr == "credit" else "credit" gle.update( - { - dr_or_cr: allocated_amount_in_company_currency, - dr_or_cr + "_in_account_currency": d.allocated_amount, - "cost_center": cost_center, - } + self.get_gl_dict( + { + "account": self.party_account, + "party_type": self.party_type, + "party": self.party, + "against": against_account, + "account_currency": self.party_account_currency, + "cost_center": cost_center, + dr_or_cr + "_in_account_currency": d.allocated_amount, + dr_or_cr: allocated_amount_in_company_currency, + }, + item=self, + ) ) if self.book_advance_payments_in_separate_party_account: From fd1cbf4b6f83dbcc8c955490120351197ffc5d7f Mon Sep 17 00:00:00 2001 From: vimalraj27 Date: Wed, 27 Nov 2024 18:03:39 +0530 Subject: [PATCH 40/45] chore: Fix typo "Purchase Reecipt" (cherry picked from commit 21049bae91846548d0640d9d63c2f2e20d35e4ea) --- erpnext/controllers/sales_and_purchase_return.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 32234e5c551..7f9a5a35a73 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -1036,7 +1036,7 @@ def filter_serial_batches(parent_doc, data, row, warehouse_field=None, qty_field available_serial_nos.append(serial_no) if available_serial_nos: - if parent_doc.doctype in ["Purchase Invoice", "Purchase Reecipt"]: + if parent_doc.doctype in ["Purchase Invoice", "Purchase Receipt"]: available_serial_nos = get_available_serial_nos(available_serial_nos, warehouse) if len(available_serial_nos) > qty: @@ -1052,7 +1052,7 @@ def filter_serial_batches(parent_doc, data, row, warehouse_field=None, qty_field if batch_qty <= 0: continue - if parent_doc.doctype in ["Purchase Invoice", "Purchase Reecipt"]: + if parent_doc.doctype in ["Purchase Invoice", "Purchase Receipt"]: batch_qty = get_available_batch_qty( parent_doc, batch_no, From 3f577779be3c8a2140ffb24947252c15b848a008 Mon Sep 17 00:00:00 2001 From: Ninad1306 Date: Mon, 25 Nov 2024 10:44:25 +0530 Subject: [PATCH 41/45] fix: initially closing amt should be equal to expected amt (cherry picked from commit af9524920bc1de7587b8f73363edeab2a486e5a8) --- .../doctype/pos_closing_entry/pos_closing_entry.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js index 5711b27da04..7504c79141b 100644 --- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js +++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js @@ -147,7 +147,7 @@ frappe.ui.form.on("POS Closing Entry", { frm.doc.grand_total += flt(doc.grand_total); frm.doc.net_total += flt(doc.net_total); frm.doc.total_quantity += flt(doc.total_qty); - refresh_payments(doc, frm); + refresh_payments(doc, frm, false); refresh_taxes(doc, frm); refresh_fields(frm); set_html_data(frm); @@ -172,7 +172,7 @@ function set_form_data(data, frm) { frm.doc.grand_total += flt(d.grand_total); frm.doc.net_total += flt(d.net_total); frm.doc.total_quantity += flt(d.total_qty); - refresh_payments(d, frm); + refresh_payments(d, frm, true); refresh_taxes(d, frm); }); } @@ -186,7 +186,7 @@ function add_to_pos_transaction(d, frm) { }); } -function refresh_payments(d, frm) { +function refresh_payments(d, frm, is_new) { d.payments.forEach((p) => { const payment = frm.doc.payment_reconciliation.find( (pay) => pay.mode_of_payment === p.mode_of_payment @@ -196,9 +196,7 @@ function refresh_payments(d, frm) { } if (payment) { payment.expected_amount += flt(p.amount); - if (payment.closing_amount === 0) { - payment.closing_amount = payment.expected_amount; - } + if (is_new) payment.closing_amount = payment.expected_amount; payment.difference = payment.closing_amount - payment.expected_amount; } else { frm.add_child("payment_reconciliation", { From 8d8027d4233f9181a34ee00b33ff15da2cae2da4 Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Tue, 26 Nov 2024 13:58:52 +0530 Subject: [PATCH 42/45] fix: set outstanding amount while creating payment request for invoices (cherry picked from commit 38e7d0a41e2a55ef98f2c6147c34b64708929854) --- erpnext/accounts/doctype/payment_request/payment_request.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index ae974a8cf0e..aaae8204a9b 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -667,11 +667,9 @@ def get_amount(ref_doc, payment_account=None): elif dt in ["Sales Invoice", "Purchase Invoice"]: if not ref_doc.get("is_pos"): if ref_doc.party_account_currency == ref_doc.currency: - grand_total = flt(ref_doc.rounded_total or ref_doc.grand_total) + grand_total = flt(ref_doc.outstanding_amount) else: - grand_total = flt( - flt(ref_doc.base_rounded_total or ref_doc.base_grand_total) / ref_doc.conversion_rate - ) + grand_total = flt(flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate) elif dt == "Sales Invoice": for pay in ref_doc.payments: if pay.type == "Phone" and pay.account == payment_account: From 81b9832917ebf5487f5471b007d47278252cde02 Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Tue, 26 Nov 2024 13:59:45 +0530 Subject: [PATCH 43/45] test: add unit test to validate outstanding amount in payment request (cherry picked from commit bbe3bc95d08950bebc9ede64c11c9660a564a8a6) # Conflicts: # erpnext/accounts/doctype/payment_request/test_payment_request.py --- .../payment_request/test_payment_request.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/erpnext/accounts/doctype/payment_request/test_payment_request.py b/erpnext/accounts/doctype/payment_request/test_payment_request.py index b0c3dbf4d5b..cd5a1a26575 100644 --- a/erpnext/accounts/doctype/payment_request/test_payment_request.py +++ b/erpnext/accounts/doctype/payment_request/test_payment_request.py @@ -7,6 +7,7 @@ import unittest import frappe from frappe.tests.utils import FrappeTestCase, change_settings +from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice @@ -524,3 +525,25 @@ class TestPaymentRequest(FrappeTestCase): self.assertEqual(pr.grand_total, 1000) so.load_from_db() +<<<<<<< HEAD +======= + self.assertEqual(so.advance_payment_status, "Requested") + + def test_partial_paid_invoice_with_payment_request(self): + si = create_sales_invoice(currency="INR", qty=1, rate=5000) + si.save() + si.submit() + + pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC") + pe.reference_no = "PAYEE0002" + pe.reference_date = frappe.utils.nowdate() + pe.paid_amount = 2500 + pe.references[0].allocated_amount = 2500 + pe.save() + pe.submit() + + si.load_from_db() + pr = make_payment_request(dt="Sales Invoice", dn=si.name, mute_email=1) + + self.assertEqual(pr.grand_total, si.outstanding_amount) +>>>>>>> bbe3bc95d0 (test: add unit test to validate outstanding amount in payment request) From d0d97c26a05ab961f88ece2609698ff37f3a5273 Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Wed, 27 Nov 2024 17:41:16 +0530 Subject: [PATCH 44/45] fix: reduce paid amount from grand total (cherry picked from commit 82907672d938b2b447f0f7382e8fc4e4c343e708) --- .../payment_request/payment_request.py | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index aaae8204a9b..1d31fd4b67b 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -3,7 +3,7 @@ import json import frappe from frappe import _, qb from frappe.model.document import Document -from frappe.query_builder.functions import Sum +from frappe.query_builder.functions import Abs, Sum from frappe.utils import flt, nowdate from frappe.utils.background_jobs import enqueue @@ -564,6 +564,8 @@ def make_payment_request(**args): # fetches existing payment request `grand_total` amount existing_payment_request_amount = get_existing_payment_request_amount(ref_doc.doctype, ref_doc.name) + existing_paid_amount = get_existing_paid_amount(ref_doc.doctype, ref_doc.name) + def validate_and_calculate_grand_total(grand_total, existing_payment_request_amount): grand_total -= existing_payment_request_amount if not grand_total: @@ -583,6 +585,15 @@ def make_payment_request(**args): else: grand_total = validate_and_calculate_grand_total(grand_total, existing_payment_request_amount) + if existing_paid_amount: + if ref_doc.party_account_currency == ref_doc.currency: + if ref_doc.conversion_rate: + grand_total -= flt(existing_paid_amount / ref_doc.conversion_rate) + else: + grand_total -= flt(existing_paid_amount) + else: + grand_total -= flt(existing_paid_amount / ref_doc.conversion_rate) + if draft_payment_request: frappe.db.set_value( "Payment Request", draft_payment_request, "grand_total", grand_total, update_modified=False @@ -667,9 +678,11 @@ def get_amount(ref_doc, payment_account=None): elif dt in ["Sales Invoice", "Purchase Invoice"]: if not ref_doc.get("is_pos"): if ref_doc.party_account_currency == ref_doc.currency: - grand_total = flt(ref_doc.outstanding_amount) + grand_total = flt(ref_doc.rounded_total or ref_doc.grand_total) else: - grand_total = flt(flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate) + grand_total = flt( + flt(ref_doc.base_rounded_total or ref_doc.base_grand_total) / ref_doc.conversion_rate + ) elif dt == "Sales Invoice": for pay in ref_doc.payments: if pay.type == "Phone" and pay.account == payment_account: @@ -751,6 +764,27 @@ def get_existing_payment_request_amount(ref_dt, ref_dn, statuses: list | None = return response[0][0] if response[0] else 0 +def get_existing_paid_amount(doctype, name): + PL = frappe.qb.DocType("Payment Ledger Entry") + PER = frappe.qb.DocType("Payment Entry Reference") + + query = ( + frappe.qb.from_(PL) + .left_join(PER) + .on( + (PER.reference_doctype == PL.against_voucher_type) & (PER.reference_name == PL.against_voucher_no) + ) + .select(Abs(Sum(PL.amount)).as_("total_paid_amount")) + .where(PL.against_voucher_type.eq(doctype)) + .where(PL.against_voucher_no.eq(name)) + .where(PL.amount < 0) + .where(PER.payment_request.isnull()) + ) + response = query.run() + + return response[0][0] if response[0] else 0 + + def get_gateway_details(args): # nosemgrep """ Return gateway and payment account of default payment gateway From 0ab0b4f716acee6837e7c62f875a99c2d11881ef Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Nov 2024 20:29:36 +0530 Subject: [PATCH 45/45] chore: resolve conflict --- .../accounts/doctype/payment_request/test_payment_request.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/test_payment_request.py b/erpnext/accounts/doctype/payment_request/test_payment_request.py index cd5a1a26575..4442dbdd7ea 100644 --- a/erpnext/accounts/doctype/payment_request/test_payment_request.py +++ b/erpnext/accounts/doctype/payment_request/test_payment_request.py @@ -525,9 +525,6 @@ class TestPaymentRequest(FrappeTestCase): self.assertEqual(pr.grand_total, 1000) so.load_from_db() -<<<<<<< HEAD -======= - self.assertEqual(so.advance_payment_status, "Requested") def test_partial_paid_invoice_with_payment_request(self): si = create_sales_invoice(currency="INR", qty=1, rate=5000) @@ -546,4 +543,3 @@ class TestPaymentRequest(FrappeTestCase): pr = make_payment_request(dt="Sales Invoice", dn=si.name, mute_email=1) self.assertEqual(pr.grand_total, si.outstanding_amount) ->>>>>>> bbe3bc95d0 (test: add unit test to validate outstanding amount in payment request)