From fdaf5fafda7d1d42fe04b5b85c8e7ce16f78a14d Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Mon, 17 Feb 2025 14:36:15 +0530 Subject: [PATCH 1/8] fix: set landed cost based on purchase invoice rate (cherry picked from commit 17d415b1054bbfc483a1733c930b820c493b43ff) # Conflicts: # erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py # erpnext/patches.txt # erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json --- .../purchase_invoice/test_purchase_invoice.py | 72 +++++++++++++++++++ erpnext/controllers/buying_controller.py | 2 +- erpnext/patches.txt | 8 +++ .../purchase_receipt/purchase_receipt.py | 49 ++++++++++--- .../purchase_receipt_item/patches/__init__.py | 0 .../recalculate_amount_difference_field.py | 37 ++++++++++ ...om_rate_difference_to_amount_difference.py | 17 +++++ .../purchase_receipt_item.json | 29 +++++--- .../purchase_receipt_item.py | 2 +- 9 files changed, 195 insertions(+), 21 deletions(-) create mode 100644 erpnext/stock/doctype/purchase_receipt_item/patches/__init__.py create mode 100644 erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py create mode 100644 erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index bc28edbf396..be6206965e0 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -2464,6 +2464,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 1) +<<<<<<< HEAD def test_last_purchase_rate(self): item = create_item("_Test Item For Last Purchase Rate from PI", is_stock_item=1) pi1 = make_purchase_invoice(item_code=item.item_code, qty=10, rate=100) @@ -2481,6 +2482,77 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): pi1.cancel() item.reload() self.assertEqual(item.last_purchase_rate, 0) +======= + def test_adjust_incoming_rate_from_pi_with_multi_currency_and_partial_billing(self): + frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 0) + + frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 1) + + pr = make_purchase_receipt( + qty=10, rate=10, currency="USD", do_not_save=1, supplier="_Test Supplier USD" + ) + pr.conversion_rate = 5300 + pr.save() + pr.submit() + + incoming_rate = frappe.db.get_value( + "Stock Ledger Entry", + {"voucher_type": "Purchase Receipt", "voucher_no": pr.name}, + "incoming_rate", + ) + self.assertEqual(incoming_rate, 53000) # Asserting to confirm if the default calculation is correct + + pi = create_purchase_invoice_from_receipt(pr.name) + for row in pi.items: + row.qty = 1 + + pi.save() + pi.submit() + + incoming_rate = frappe.db.get_value( + "Stock Ledger Entry", + {"voucher_type": "Purchase Receipt", "voucher_no": pr.name}, + "incoming_rate", + ) + # Test 1 : Incoming rate should not change as only the qty has changed and not the rate (this was not the case before) + self.assertEqual(incoming_rate, 53000) + + pi = create_purchase_invoice_from_receipt(pr.name) + for row in pi.items: + row.qty = 1 + row.rate = 9 + + pi.save() + pi.submit() + + incoming_rate = frappe.db.get_value( + "Stock Ledger Entry", + {"voucher_type": "Purchase Receipt", "voucher_no": pr.name}, + "incoming_rate", + ) + # Test 2 : Rate in new PI is lower than PR, so incoming rate should also be lower + self.assertEqual(incoming_rate, 50350) + + pi = create_purchase_invoice_from_receipt(pr.name) + for row in pi.items: + row.qty = 1 + row.rate = 12 + + pi.save() + pi.submit() + + incoming_rate = frappe.db.get_value( + "Stock Ledger Entry", + {"voucher_type": "Purchase Receipt", "voucher_no": pr.name}, + "incoming_rate", + ) + # Test 3 : Rate in new PI is higher than PR, so incoming rate should also be higher + self.assertEqual(incoming_rate, 54766.667) + + frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 0) + + frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 1) +>>>>>>> 17d415b105 (fix: set landed cost based on purchase invoice rate) def test_opening_invoice_rounding_adjustment_validation(self): pi = make_purchase_invoice(do_not_save=1) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 9643110b76a..c2a36ac36d0 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -333,7 +333,7 @@ class BuyingController(SubcontractingController): net_rate + item.item_tax_amount + flt(item.landed_cost_voucher_amount) - + flt(item.get("rate_difference_with_purchase_invoice")) + + flt(item.get("amount_difference_with_purchase_invoice")) ) / qty_in_stock_uom else: item.valuation_rate = 0.0 diff --git a/erpnext/patches.txt b/erpnext/patches.txt index a20b2a67bff..34794556022 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -261,7 +261,11 @@ erpnext.patches.v14_0.show_loan_management_deprecation_warning erpnext.patches.v14_0.clear_reconciliation_values_from_singles execute:frappe.rename_doc("Report", "TDS Payable Monthly", "Tax Withholding Details", force=True) erpnext.patches.v14_0.update_proprietorship_to_individual +<<<<<<< HEAD erpnext.patches.v15_0.rename_subcontracting_fields +======= +erpnext.stock.doctype.purchase_receipt_item.patches.rename_field_from_rate_difference_to_amount_difference +>>>>>>> 17d415b105 (fix: set landed cost based on purchase invoice rate) [post_model_sync] erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets @@ -393,8 +397,12 @@ erpnext.patches.v15_0.migrate_checkbox_to_select_for_reconciliation_effect erpnext.patches.v15_0.sync_auto_reconcile_config execute:frappe.db.set_single_value("Accounts Settings", "exchange_gain_loss_posting_date", "Payment") erpnext.patches.v14_0.disable_add_row_in_gross_profit +<<<<<<< HEAD erpnext.patches.v15_0.set_difference_amount_in_asset_value_adjustment erpnext.patches.v14_0.update_posting_datetime erpnext.stock.doctype.stock_ledger_entry.patches.ensure_sle_indexes erpnext.patches.v15_0.rename_sla_fields erpnext.patches.v15_0.update_query_report +======= +erpnext.stock.doctype.purchase_receipt_item.patches.recalculate_amount_difference_field +>>>>>>> 17d415b105 (fix: set landed cost based on purchase invoice rate) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 7aa23c8153b..7f2c04316e9 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -424,6 +424,14 @@ class PurchaseReceipt(BuyingController): self.delete_auto_created_batches() self.set_consumed_qty_in_subcontract_order() + def before_cancel(self): + super().before_cancel() + self.remove_amount_difference_with_purchase_invoice() + + def remove_amount_difference_with_purchase_invoice(self): + for item in self.items: + item.amount_difference_with_purchase_invoice = 0 + def get_gl_entries(self, warehouse_account=None, via_landed_cost_voucher=False): from erpnext.accounts.general_ledger import process_gl_map @@ -571,15 +579,15 @@ class PurchaseReceipt(BuyingController): item=item, ) - def make_rate_difference_entry(item): - if item.rate_difference_with_purchase_invoice and stock_asset_rbnb: + def make_amount_difference_entry(item): + if item.amount_difference_with_purchase_invoice and stock_asset_rbnb: account_currency = get_account_currency(stock_asset_rbnb) self.add_gl_entry( gl_entries=gl_entries, account=stock_asset_rbnb, cost_center=item.cost_center, debit=0.0, - credit=flt(item.rate_difference_with_purchase_invoice), + credit=flt(item.amount_difference_with_purchase_invoice), remarks=_("Adjustment based on Purchase Invoice rate"), against_account=stock_asset_account_name, account_currency=account_currency, @@ -612,7 +620,7 @@ class PurchaseReceipt(BuyingController): + flt(item.landed_cost_voucher_amount) + flt(item.rm_supp_cost) + flt(item.item_tax_amount) - + flt(item.rate_difference_with_purchase_invoice) + + flt(item.amount_difference_with_purchase_invoice) ) divisional_loss = flt( @@ -712,7 +720,7 @@ class PurchaseReceipt(BuyingController): make_item_asset_inward_gl_entry(d, stock_value_diff, stock_asset_account_name) outgoing_amount = make_stock_received_but_not_billed_entry(d) make_landed_cost_gl_entries(d) - make_rate_difference_entry(d) + make_amount_difference_entry(d) make_sub_contracting_gl_entries(d) make_divisional_loss_gl_entry(d, outgoing_amount) elif (d.warehouse and d.warehouse not in warehouse_with_no_account) or ( @@ -1094,11 +1102,19 @@ def update_billing_percentage(pr_doc, update_modified=True, adjust_incoming_rate if adjust_incoming_rate: adjusted_amt = 0.0 - if item.billed_amt is not None and item.amount is not None: - adjusted_amt = flt(item.billed_amt) - flt(item.amount) + item_wise_billed_qty = get_billed_qty_against_purchase_receipt(pr_doc) - adjusted_amt = adjusted_amt * flt(pr_doc.conversion_rate) - item.db_set("rate_difference_with_purchase_invoice", adjusted_amt, update_modified=False) + if ( + item.billed_amt is not None + and item.amount is not None + and item_wise_billed_qty.get(item.name) + ): + adjusted_amt = ( + flt(item.billed_amt / item_wise_billed_qty.get(item.name)) - flt(item.rate) + ) * item.qty + + adjusted_amt = flt(adjusted_amt * flt(pr_doc.conversion_rate), item.precision("amount")) + item.db_set("amount_difference_with_purchase_invoice", adjusted_amt, update_modified=False) percent_billed = round(100 * (total_billed_amount / (total_amount or 1)), 6) pr_doc.db_set("per_billed", percent_billed) @@ -1111,6 +1127,21 @@ def update_billing_percentage(pr_doc, update_modified=True, adjust_incoming_rate adjust_incoming_rate_for_pr(pr_doc) +def get_billed_qty_against_purchase_receipt(pr_doc): + pr_names = [d.name for d in pr_doc.items] + table = frappe.qb.DocType("Purchase Invoice Item") + query = ( + frappe.qb.from_(table) + .select(table.pr_detail, fn.Sum(table.qty).as_("qty")) + .where((table.pr_detail.isin(pr_names)) & (table.docstatus == 1)) + ) + invoice_data = query.run(as_list=1) + + if not invoice_data: + return frappe._dict() + return frappe._dict(invoice_data) + + def adjust_incoming_rate_for_pr(doc): doc.update_valuation_rate(reset_outgoing_rate=False) diff --git a/erpnext/stock/doctype/purchase_receipt_item/patches/__init__.py b/erpnext/stock/doctype/purchase_receipt_item/patches/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py b/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py new file mode 100644 index 00000000000..e2d8bedaa66 --- /dev/null +++ b/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py @@ -0,0 +1,37 @@ +import frappe +from frappe.utils import flt + +from erpnext.stock.doctype.purchase_receipt.purchase_receipt import ( + adjust_incoming_rate_for_pr, + get_billed_qty_against_purchase_receipt, +) + + +def execute(): + table = frappe.qb.DocType("Purchase Receipt Item") + query = ( + frappe.qb.from_(table) + .select(table.parent) + .distinct() + .where((table.amount_difference_with_purchase_invoice > 0) & (table.docstatus == 1)) + ) + pr_names = [item.parent for item in query.run(as_dict=True)] + + for pr_name in pr_names: + pr_doc = frappe.get_doc("Purchase Receipt", pr_name) + for item in pr_doc.items: + adjusted_amt = 0.0 + item_wise_billed_qty = get_billed_qty_against_purchase_receipt(pr_doc) + + if ( + item.billed_amt is not None + and item.amount is not None + and item_wise_billed_qty.get(item.name) + ): + adjusted_amt = ( + flt(item.billed_amt / item_wise_billed_qty.get(item.name)) - flt(item.rate) + ) * item.qty + + adjusted_amt = flt(adjusted_amt * flt(pr_doc.conversion_rate), item.precision("amount")) + item.db_set("amount_difference_with_purchase_invoice", adjusted_amt, update_modified=False) + adjust_incoming_rate_for_pr(pr_doc) diff --git a/erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py b/erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py new file mode 100644 index 00000000000..44c8c49cba8 --- /dev/null +++ b/erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py @@ -0,0 +1,17 @@ +import frappe +from frappe.model.utils.rename_field import rename_field + + +def execute(): + frappe.db.set_value( + "DocField", + {"parent": "Purchase Receipt Item", "fieldname": "rate_difference_with_purchase_invoice"}, + "label", + "Amount Difference with Purchase Invoice", + ) + rename_field( + "Purchase Receipt Item", + "rate_difference_with_purchase_invoice", + "amount_difference_with_purchase_invoice", + ) + frappe.clear_cache(doctype="Purchase Receipt Item") diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index 610bceddf0f..2f6598c3fb2 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -71,7 +71,7 @@ "item_tax_amount", "rm_supp_cost", "landed_cost_voucher_amount", - "rate_difference_with_purchase_invoice", + "amount_difference_with_purchase_invoice", "billed_amt", "warehouse_and_reference", "warehouse", @@ -998,14 +998,6 @@ "label": "Has Item Scanned", "read_only": 1 }, - { - "fieldname": "rate_difference_with_purchase_invoice", - "fieldtype": "Currency", - "label": "Rate Difference with Purchase Invoice", - "no_copy": 1, - "print_hide": 1, - "read_only": 1 - }, { "depends_on": "eval:doc.use_serial_batch_fields === 0 || doc.docstatus === 1", "fieldname": "serial_and_batch_bundle", @@ -1135,12 +1127,29 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1 +<<<<<<< HEAD +======= + }, + { + "fieldname": "distributed_discount_amount", + "fieldtype": "Currency", + "label": "Distributed Discount Amount", + "options": "currency" + }, + { + "fieldname": "amount_difference_with_purchase_invoice", + "fieldtype": "Currency", + "label": "Amount Difference with Purchase Invoice", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 +>>>>>>> 17d415b105 (fix: set landed cost based on purchase invoice rate) } ], "idx": 1, "istable": 1, "links": [], - "modified": "2024-07-19 12:14:21.521466", + "modified": "2025-02-17 13:15:36.692202", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py index 2154007771d..0db866f52c1 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.py @@ -16,6 +16,7 @@ class PurchaseReceiptItem(Document): allow_zero_valuation_rate: DF.Check amount: DF.Currency + amount_difference_with_purchase_invoice: DF.Currency apply_tds: DF.Check asset_category: DF.Link | None asset_location: DF.Link | None @@ -76,7 +77,6 @@ class PurchaseReceiptItem(Document): qty: DF.Float quality_inspection: DF.Link | None rate: DF.Currency - rate_difference_with_purchase_invoice: DF.Currency rate_with_margin: DF.Currency received_qty: DF.Float received_stock_qty: DF.Float From ee41e55343166f88cd105fd608a3792d0fb84bb0 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Mon, 17 Feb 2025 18:05:58 +0530 Subject: [PATCH 2/8] perf: patch (cherry picked from commit a41024813b22fea5d737be8fab50224c2b909cbc) --- .../recalculate_amount_difference_field.py | 81 +++++++++++++------ 1 file changed, 57 insertions(+), 24 deletions(-) diff --git a/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py b/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py index e2d8bedaa66..9def5aa8d3b 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py +++ b/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py @@ -1,37 +1,70 @@ import frappe +from frappe.query_builder.functions import Sum from frappe.utils import flt -from erpnext.stock.doctype.purchase_receipt.purchase_receipt import ( - adjust_incoming_rate_for_pr, - get_billed_qty_against_purchase_receipt, -) +from erpnext.accounts.utils import get_fiscal_year +from erpnext.stock.doctype.purchase_receipt.purchase_receipt import adjust_incoming_rate_for_pr def execute(): + fiscal_year_dates = get_fiscal_year(frappe.utils.datetime.date.today()) table = frappe.qb.DocType("Purchase Receipt Item") + parent = frappe.qb.DocType("Purchase Receipt") query = ( frappe.qb.from_(table) - .select(table.parent) - .distinct() - .where((table.amount_difference_with_purchase_invoice > 0) & (table.docstatus == 1)) + .join(parent) + .on(table.parent == parent.name) + .select( + table.parent, + table.name, + table.amount, + table.billed_amt, + table.amount_difference_with_purchase_invoice, + table.rate, + table.qty, + parent.conversion_rate, + ) + .where( + (table.amount_difference_with_purchase_invoice != 0) + & (table.docstatus == 1) + & (parent.posting_date.between(fiscal_year_dates[1], fiscal_year_dates[2])) + ) ) - pr_names = [item.parent for item in query.run(as_dict=True)] + result = query.run(as_dict=True) - for pr_name in pr_names: - pr_doc = frappe.get_doc("Purchase Receipt", pr_name) - for item in pr_doc.items: - adjusted_amt = 0.0 - item_wise_billed_qty = get_billed_qty_against_purchase_receipt(pr_doc) + item_wise_billed_qty = get_billed_qty_against_purchase_receipt([item.name for item in result]) - if ( - item.billed_amt is not None - and item.amount is not None - and item_wise_billed_qty.get(item.name) - ): - adjusted_amt = ( - flt(item.billed_amt / item_wise_billed_qty.get(item.name)) - flt(item.rate) - ) * item.qty + for item in result: + adjusted_amt = 0.0 - adjusted_amt = flt(adjusted_amt * flt(pr_doc.conversion_rate), item.precision("amount")) - item.db_set("amount_difference_with_purchase_invoice", adjusted_amt, update_modified=False) - adjust_incoming_rate_for_pr(pr_doc) + if item.billed_amt is not None and item.amount is not None and item_wise_billed_qty.get(item.name): + adjusted_amt = ( + flt(item.billed_amt / item_wise_billed_qty.get(item.name)) - flt(item.rate) + ) * item.qty + adjusted_amt = flt( + adjusted_amt * flt(item.conversion_rate), frappe.get_precision("Purchase Receipt Item", "amount") + ) + + if adjusted_amt != item.amount_difference_with_purchase_invoice: + frappe.db.set_value( + "Purchase Receipt Item", + item.name, + "amount_difference_with_purchase_invoice", + adjusted_amt, + update_modified=False, + ) + adjust_incoming_rate_for_pr(frappe.get_doc("Purchase Receipt", item.parent)) + + +def get_billed_qty_against_purchase_receipt(pr_names): + table = frappe.qb.DocType("Purchase Invoice Item") + query = ( + frappe.qb.from_(table) + .select(table.pr_detail, Sum(table.qty).as_("qty")) + .where((table.pr_detail.isin(pr_names)) & (table.docstatus == 1)) + ) + invoice_data = query.run(as_list=1) + + if not invoice_data: + return frappe._dict() + return frappe._dict(invoice_data) From 7b13d8cd98763a2936cdf1e56ba798f36f85c1e5 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Mon, 17 Feb 2025 18:44:33 +0530 Subject: [PATCH 3/8] fix: fiscal year error (cherry picked from commit 7cf8e498c4ea5b7d2927af205ca815b8c4451cae) --- .../patches/recalculate_amount_difference_field.py | 9 +++------ ...me_field_from_rate_difference_to_amount_difference.py | 1 + 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py b/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py index 9def5aa8d3b..0222388d270 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py +++ b/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py @@ -7,7 +7,6 @@ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import adjust_incom def execute(): - fiscal_year_dates = get_fiscal_year(frappe.utils.datetime.date.today()) table = frappe.qb.DocType("Purchase Receipt Item") parent = frappe.qb.DocType("Purchase Receipt") query = ( @@ -24,12 +23,10 @@ def execute(): table.qty, parent.conversion_rate, ) - .where( - (table.amount_difference_with_purchase_invoice != 0) - & (table.docstatus == 1) - & (parent.posting_date.between(fiscal_year_dates[1], fiscal_year_dates[2])) - ) + .where((table.amount_difference_with_purchase_invoice != 0) & (table.docstatus == 1)) ) + if fiscal_year_dates := get_fiscal_year(frappe.utils.datetime.date.today(), raise_on_missing=False): + query.where(parent.posting_date.between(fiscal_year_dates[1], fiscal_year_dates[2])) result = query.run(as_dict=True) item_wise_billed_qty = get_billed_qty_against_purchase_receipt([item.name for item in result]) diff --git a/erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py b/erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py index 44c8c49cba8..ce802b029da 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py +++ b/erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py @@ -13,5 +13,6 @@ def execute(): "Purchase Receipt Item", "rate_difference_with_purchase_invoice", "amount_difference_with_purchase_invoice", + validate=False, ) frappe.clear_cache(doctype="Purchase Receipt Item") From a09c57f0d1429d737a2819cd5b6ea87b44843fbb Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Mon, 17 Feb 2025 20:20:17 +0530 Subject: [PATCH 4/8] fix: revert last commit (cherry picked from commit 154e9813c4f27c2a7d51b133fd89cdfbaa1f1477) # Conflicts: # erpnext/patches.txt --- erpnext/patches.txt | 8 ++++ .../recalculate_amount_difference_field.py | 45 ++++++++++--------- ...om_rate_difference_to_amount_difference.py | 1 - 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 34794556022..604f0ff6141 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -262,10 +262,13 @@ erpnext.patches.v14_0.clear_reconciliation_values_from_singles execute:frappe.rename_doc("Report", "TDS Payable Monthly", "Tax Withholding Details", force=True) erpnext.patches.v14_0.update_proprietorship_to_individual <<<<<<< HEAD +<<<<<<< HEAD erpnext.patches.v15_0.rename_subcontracting_fields ======= erpnext.stock.doctype.purchase_receipt_item.patches.rename_field_from_rate_difference_to_amount_difference >>>>>>> 17d415b105 (fix: set landed cost based on purchase invoice rate) +======= +>>>>>>> 154e9813c4 (fix: revert last commit) [post_model_sync] erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets @@ -398,6 +401,7 @@ erpnext.patches.v15_0.sync_auto_reconcile_config execute:frappe.db.set_single_value("Accounts Settings", "exchange_gain_loss_posting_date", "Payment") erpnext.patches.v14_0.disable_add_row_in_gross_profit <<<<<<< HEAD +<<<<<<< HEAD erpnext.patches.v15_0.set_difference_amount_in_asset_value_adjustment erpnext.patches.v14_0.update_posting_datetime erpnext.stock.doctype.stock_ledger_entry.patches.ensure_sle_indexes @@ -406,3 +410,7 @@ erpnext.patches.v15_0.update_query_report ======= erpnext.stock.doctype.purchase_receipt_item.patches.recalculate_amount_difference_field >>>>>>> 17d415b105 (fix: set landed cost based on purchase invoice rate) +======= +erpnext.stock.doctype.purchase_receipt_item.patches.rename_field_from_rate_difference_to_amount_difference +erpnext.stock.doctype.purchase_receipt_item.patches.recalculate_amount_difference_field +>>>>>>> 154e9813c4 (fix: revert last commit) diff --git a/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py b/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py index 0222388d270..fc904baa927 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py +++ b/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py @@ -27,30 +27,35 @@ def execute(): ) if fiscal_year_dates := get_fiscal_year(frappe.utils.datetime.date.today(), raise_on_missing=False): query.where(parent.posting_date.between(fiscal_year_dates[1], fiscal_year_dates[2])) - result = query.run(as_dict=True) - item_wise_billed_qty = get_billed_qty_against_purchase_receipt([item.name for item in result]) + if result := query.run(as_dict=True): + item_wise_billed_qty = get_billed_qty_against_purchase_receipt([item.name for item in result]) - for item in result: - adjusted_amt = 0.0 + for item in result: + adjusted_amt = 0.0 - if item.billed_amt is not None and item.amount is not None and item_wise_billed_qty.get(item.name): - adjusted_amt = ( - flt(item.billed_amt / item_wise_billed_qty.get(item.name)) - flt(item.rate) - ) * item.qty - adjusted_amt = flt( - adjusted_amt * flt(item.conversion_rate), frappe.get_precision("Purchase Receipt Item", "amount") - ) - - if adjusted_amt != item.amount_difference_with_purchase_invoice: - frappe.db.set_value( - "Purchase Receipt Item", - item.name, - "amount_difference_with_purchase_invoice", - adjusted_amt, - update_modified=False, + if ( + item.billed_amt is not None + and item.amount is not None + and item_wise_billed_qty.get(item.name) + ): + adjusted_amt = ( + flt(item.billed_amt / item_wise_billed_qty.get(item.name)) - flt(item.rate) + ) * item.qty + adjusted_amt = flt( + adjusted_amt * flt(item.conversion_rate), + frappe.get_precision("Purchase Receipt Item", "amount"), ) - adjust_incoming_rate_for_pr(frappe.get_doc("Purchase Receipt", item.parent)) + + if adjusted_amt != item.amount_difference_with_purchase_invoice: + frappe.db.set_value( + "Purchase Receipt Item", + item.name, + "amount_difference_with_purchase_invoice", + adjusted_amt, + update_modified=False, + ) + adjust_incoming_rate_for_pr(frappe.get_doc("Purchase Receipt", item.parent)) def get_billed_qty_against_purchase_receipt(pr_names): diff --git a/erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py b/erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py index ce802b029da..44c8c49cba8 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py +++ b/erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py @@ -13,6 +13,5 @@ def execute(): "Purchase Receipt Item", "rate_difference_with_purchase_invoice", "amount_difference_with_purchase_invoice", - validate=False, ) frappe.clear_cache(doctype="Purchase Receipt Item") From 8f2fdcae88252cddaaeeb89f881671c2101ad886 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 19 Feb 2025 13:03:45 +0530 Subject: [PATCH 5/8] fix: patch (cherry picked from commit 1230127d24cc1ae97129ad8e592ca3cdf8f59c32) # Conflicts: # erpnext/patches.txt --- erpnext/patches.txt | 5 +++++ .../v15_0}/recalculate_amount_difference_field.py | 9 +++++++-- ...me_field_from_rate_difference_to_amount_difference.py | 0 .../doctype/purchase_receipt_item/patches/__init__.py | 0 4 files changed, 12 insertions(+), 2 deletions(-) rename erpnext/{stock/doctype/purchase_receipt_item/patches => patches/v15_0}/recalculate_amount_difference_field.py (88%) rename erpnext/{stock/doctype/purchase_receipt_item/patches => patches/v15_0}/rename_field_from_rate_difference_to_amount_difference.py (100%) delete mode 100644 erpnext/stock/doctype/purchase_receipt_item/patches/__init__.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 604f0ff6141..e0a1fcf3cbf 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -402,6 +402,7 @@ execute:frappe.db.set_single_value("Accounts Settings", "exchange_gain_loss_post erpnext.patches.v14_0.disable_add_row_in_gross_profit <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD erpnext.patches.v15_0.set_difference_amount_in_asset_value_adjustment erpnext.patches.v14_0.update_posting_datetime erpnext.stock.doctype.stock_ledger_entry.patches.ensure_sle_indexes @@ -414,3 +415,7 @@ erpnext.stock.doctype.purchase_receipt_item.patches.recalculate_amount_differenc erpnext.stock.doctype.purchase_receipt_item.patches.rename_field_from_rate_difference_to_amount_difference erpnext.stock.doctype.purchase_receipt_item.patches.recalculate_amount_difference_field >>>>>>> 154e9813c4 (fix: revert last commit) +======= +erpnext.patches.v15_0.rename_field_from_rate_difference_to_amount_difference +erpnext.patches.v15_0.recalculate_amount_difference_field +>>>>>>> 1230127d24 (fix: patch) diff --git a/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py b/erpnext/patches/v15_0/recalculate_amount_difference_field.py similarity index 88% rename from erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py rename to erpnext/patches/v15_0/recalculate_amount_difference_field.py index fc904baa927..5ece5f08ddb 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/patches/recalculate_amount_difference_field.py +++ b/erpnext/patches/v15_0/recalculate_amount_difference_field.py @@ -31,6 +31,8 @@ def execute(): if result := query.run(as_dict=True): item_wise_billed_qty = get_billed_qty_against_purchase_receipt([item.name for item in result]) + purchase_receipts = set() + precision = frappe.get_precision("Purchase Receipt Item", "amount") for item in result: adjusted_amt = 0.0 @@ -44,7 +46,7 @@ def execute(): ) * item.qty adjusted_amt = flt( adjusted_amt * flt(item.conversion_rate), - frappe.get_precision("Purchase Receipt Item", "amount"), + precision, ) if adjusted_amt != item.amount_difference_with_purchase_invoice: @@ -55,7 +57,10 @@ def execute(): adjusted_amt, update_modified=False, ) - adjust_incoming_rate_for_pr(frappe.get_doc("Purchase Receipt", item.parent)) + purchase_receipts.add(item.parent) + + for pr in purchase_receipts: + adjust_incoming_rate_for_pr(frappe.get_doc("Purchase Receipt", pr)) def get_billed_qty_against_purchase_receipt(pr_names): diff --git a/erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py b/erpnext/patches/v15_0/rename_field_from_rate_difference_to_amount_difference.py similarity index 100% rename from erpnext/stock/doctype/purchase_receipt_item/patches/rename_field_from_rate_difference_to_amount_difference.py rename to erpnext/patches/v15_0/rename_field_from_rate_difference_to_amount_difference.py diff --git a/erpnext/stock/doctype/purchase_receipt_item/patches/__init__.py b/erpnext/stock/doctype/purchase_receipt_item/patches/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 From 941d67a0b63b8010473f735a65cf73d36ae57846 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 5 Mar 2025 14:48:41 +0530 Subject: [PATCH 6/8] chore: resolve conflicts --- .../purchase_invoice/test_purchase_invoice.py | 4 +--- erpnext/patches.txt | 12 ------------ .../purchase_receipt_item/purchase_receipt_item.json | 9 --------- 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index be6206965e0..e2386122522 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -2464,7 +2464,6 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 1) -<<<<<<< HEAD def test_last_purchase_rate(self): item = create_item("_Test Item For Last Purchase Rate from PI", is_stock_item=1) pi1 = make_purchase_invoice(item_code=item.item_code, qty=10, rate=100) @@ -2482,7 +2481,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): pi1.cancel() item.reload() self.assertEqual(item.last_purchase_rate, 0) -======= + def test_adjust_incoming_rate_from_pi_with_multi_currency_and_partial_billing(self): frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 0) @@ -2552,7 +2551,6 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 0) frappe.db.set_single_value("Buying Settings", "maintain_same_rate", 1) ->>>>>>> 17d415b105 (fix: set landed cost based on purchase invoice rate) def test_opening_invoice_rounding_adjustment_validation(self): pi = make_purchase_invoice(do_not_save=1) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index e0a1fcf3cbf..18feaa19ee5 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -400,22 +400,10 @@ erpnext.patches.v15_0.migrate_checkbox_to_select_for_reconciliation_effect erpnext.patches.v15_0.sync_auto_reconcile_config execute:frappe.db.set_single_value("Accounts Settings", "exchange_gain_loss_posting_date", "Payment") erpnext.patches.v14_0.disable_add_row_in_gross_profit -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD erpnext.patches.v15_0.set_difference_amount_in_asset_value_adjustment erpnext.patches.v14_0.update_posting_datetime erpnext.stock.doctype.stock_ledger_entry.patches.ensure_sle_indexes erpnext.patches.v15_0.rename_sla_fields erpnext.patches.v15_0.update_query_report -======= -erpnext.stock.doctype.purchase_receipt_item.patches.recalculate_amount_difference_field ->>>>>>> 17d415b105 (fix: set landed cost based on purchase invoice rate) -======= -erpnext.stock.doctype.purchase_receipt_item.patches.rename_field_from_rate_difference_to_amount_difference -erpnext.stock.doctype.purchase_receipt_item.patches.recalculate_amount_difference_field ->>>>>>> 154e9813c4 (fix: revert last commit) -======= erpnext.patches.v15_0.rename_field_from_rate_difference_to_amount_difference erpnext.patches.v15_0.recalculate_amount_difference_field ->>>>>>> 1230127d24 (fix: patch) diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index 2f6598c3fb2..12d3f99e37b 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -1127,14 +1127,6 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1 -<<<<<<< HEAD -======= - }, - { - "fieldname": "distributed_discount_amount", - "fieldtype": "Currency", - "label": "Distributed Discount Amount", - "options": "currency" }, { "fieldname": "amount_difference_with_purchase_invoice", @@ -1143,7 +1135,6 @@ "no_copy": 1, "print_hide": 1, "read_only": 1 ->>>>>>> 17d415b105 (fix: set landed cost based on purchase invoice rate) } ], "idx": 1, From fe8c9a360556c86b505ef18d32facaff6af637af Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 5 Mar 2025 14:54:40 +0530 Subject: [PATCH 7/8] chore: resolve conflicts --- erpnext/patches.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 18feaa19ee5..8509989a2ca 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -261,14 +261,7 @@ erpnext.patches.v14_0.show_loan_management_deprecation_warning erpnext.patches.v14_0.clear_reconciliation_values_from_singles execute:frappe.rename_doc("Report", "TDS Payable Monthly", "Tax Withholding Details", force=True) erpnext.patches.v14_0.update_proprietorship_to_individual -<<<<<<< HEAD -<<<<<<< HEAD erpnext.patches.v15_0.rename_subcontracting_fields -======= -erpnext.stock.doctype.purchase_receipt_item.patches.rename_field_from_rate_difference_to_amount_difference ->>>>>>> 17d415b105 (fix: set landed cost based on purchase invoice rate) -======= ->>>>>>> 154e9813c4 (fix: revert last commit) [post_model_sync] erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets From 5e06e4accefcff184e3e5b2477cc04c1b60eace2 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 5 Mar 2025 16:32:26 +0530 Subject: [PATCH 8/8] fix: patch --- .../patches/v15_0/recalculate_amount_difference_field.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/erpnext/patches/v15_0/recalculate_amount_difference_field.py b/erpnext/patches/v15_0/recalculate_amount_difference_field.py index 5ece5f08ddb..fa45211be94 100644 --- a/erpnext/patches/v15_0/recalculate_amount_difference_field.py +++ b/erpnext/patches/v15_0/recalculate_amount_difference_field.py @@ -25,8 +25,11 @@ def execute(): ) .where((table.amount_difference_with_purchase_invoice != 0) & (table.docstatus == 1)) ) - if fiscal_year_dates := get_fiscal_year(frappe.utils.datetime.date.today(), raise_on_missing=False): - query.where(parent.posting_date.between(fiscal_year_dates[1], fiscal_year_dates[2])) + try: + if fiscal_year_dates := get_fiscal_year(frappe.utils.datetime.date.today()): + query.where(parent.posting_date.between(fiscal_year_dates[1], fiscal_year_dates[2])) + except Exception: + return if result := query.run(as_dict=True): item_wise_billed_qty = get_billed_qty_against_purchase_receipt([item.name for item in result])