From 506d5ac3d58e6266037f16e9fab4dec506171334 Mon Sep 17 00:00:00 2001 From: GangaManoj Date: Mon, 28 Jun 2021 15:08:28 +0530 Subject: [PATCH] fix: Make exchange rate handling more efficient --- .../purchase_invoice/purchase_invoice.py | 77 ++++++++++--------- .../purchase_receipt/purchase_receipt.py | 48 +++++++++--- 2 files changed, 78 insertions(+), 47 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 32e2eb82f85..05d632219ac 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -517,7 +517,7 @@ class PurchaseInvoice(BuyingController): if d.category in ('Valuation', 'Total and Valuation') and flt(d.base_tax_amount_after_discount_amount)] - purchase_receipt_details = self.get_purchase_receipt_details() + exchange_rate_map, net_rate_map = self.get_purchase_receipt_details() for item in self.get("items"): if flt(item.base_net_amount): @@ -636,31 +636,33 @@ class PurchaseInvoice(BuyingController): "project": item.project or self.project }, account_currency, item=item)) - if purchase_receipt_details[item.item_code]["conversion_rate"] and \ - self.conversion_rate != purchase_receipt_details[item.item_code]["conversion_rate"] and \ - item.net_rate == purchase_receipt_details[item.item_code]["net_rate"]: + # check if the exchange rate has changed + if item.get('purchase_receipt'): + if exchange_rate_map[item.purchase_receipt] and \ + self.conversion_rate != exchange_rate_map[item.purchase_receipt] and \ + item.net_rate == net_rate_map[item.item_code]: - discrepancy_caused_by_exchange_rate_difference = (item.qty * item.net_rate) * \ - (purchase_receipt_details[item.item_code]["conversion_rate"] - self.conversion_rate) + discrepancy_caused_by_exchange_rate_difference = (item.qty * item.net_rate) * \ + (exchange_rate_map[item.purchase_receipt] - self.conversion_rate) - gl_entries.append( - self.get_gl_dict({ - "account": expense_account, - "against": self.supplier, - "debit": discrepancy_caused_by_exchange_rate_difference, - "cost_center": item.cost_center, - "project": item.project or self.project - }, account_currency, item=item) - ) - gl_entries.append( - self.get_gl_dict({ - "account": self.get_company_default("exchange_gain_loss_account"), - "against": self.supplier, - "credit": discrepancy_caused_by_exchange_rate_difference, - "cost_center": item.cost_center, - "project": item.project or self.project - }, account_currency, item=item) - ) + gl_entries.append( + self.get_gl_dict({ + "account": expense_account, + "against": self.supplier, + "debit": discrepancy_caused_by_exchange_rate_difference, + "cost_center": item.cost_center, + "project": item.project or self.project + }, account_currency, item=item) + ) + gl_entries.append( + self.get_gl_dict({ + "account": self.get_company_default("exchange_gain_loss_account"), + "against": self.supplier, + "credit": discrepancy_caused_by_exchange_rate_difference, + "cost_center": item.cost_center, + "project": item.project or self.project + }, account_currency, item=item) + ) # If asset is bought through this document and not linked to PR if self.update_stock and item.landed_cost_voucher_amount: @@ -716,21 +718,22 @@ class PurchaseInvoice(BuyingController): item.precision("item_tax_amount")) def get_purchase_receipt_details(self): - purchase_receipt_details = {} - for item in self.items: - if item.purchase_receipt: - purchase_receipt = frappe.get_doc('Purchase Receipt', item.purchase_receipt) - pr_item_details = { - "conversion_rate" : purchase_receipt.conversion_rate - } - - for pr_item in purchase_receipt.items: - if pr_item.item_code == item.item_code: - pr_item_details["net_rate"] = pr_item.net_rate + purchase_receipts = [] + pr_items = [] - purchase_receipt_details[item.item_code] = pr_item_details + for item in self.get('items'): + if item.get('purchase_receipt'): + purchase_receipts.append(item.purchase_receipt) + if item.get('pr_detail'): + pr_items.append(item.pr_detail) + + exchange_rate_map = frappe._dict(frappe.get_all('Purchase Receipt', filters={'name': ('in', + purchase_receipts)}, fields=['name', 'conversion_rate'], as_list=1)) - return purchase_receipt_details + net_rate_map = frappe._dict(frappe.get_all('Purchase Receipt Item', filters={'name': ('in', + pr_items)}, fields=['item_code', 'net_rate'], as_list=1)) + + return exchange_rate_map, net_rate_map def get_asset_gl_entry(self, gl_entries): arbnb_account = self.get_company_default("asset_received_but_not_billed") diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 305eb02714b..7b002b0fc61 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -262,6 +262,8 @@ class PurchaseReceipt(BuyingController): warehouse_with_no_account = [] stock_items = self.get_stock_items() + exchange_rate_map, net_rate_map = self.get_purchase_invoice_details() + for d in self.get("items"): if d.item_code in stock_items and flt(d.valuation_rate) and flt(d.qty): if warehouse_account.get(d.warehouse): @@ -303,19 +305,23 @@ class PurchaseReceipt(BuyingController): self.add_gl_entry(gl_entries, account, d.cost_center, -1 * flt(d.base_net_amount, d.precision("base_net_amount")), 0.0, remarks, warehouse_account_name, debit_in_account_currency=-1 * credit_amount, account_currency=credit_currency, item=d) - + # check if the exchange rate has changed - purchase_invoice_conversion_rate = frappe.db.get_value('Purchase Invoice', {'name': d.purchase_invoice}, ['conversion_rate']) - if purchase_invoice_conversion_rate and self.conversion_rate != purchase_invoice_conversion_rate: - discrepancy_caused_by_exchange_rate_difference = (d.qty * d.rate) * (purchase_invoice_conversion_rate - self.conversion_rate) + if d.get('purchase_invoice'): + if exchange_rate_map[d.purchase_invoice] and \ + self.conversion_rate != exchange_rate_map[d.purchase_invoice] and \ + d.net_rate == net_rate_map[d.item_code]: - self.add_gl_entry(gl_entries, account, d.cost_center, 0.0, discrepancy_caused_by_exchange_rate_difference, - remarks, self.supplier, debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference, - account_currency=credit_currency, item=d) + discrepancy_caused_by_exchange_rate_difference = (d.qty * d.net_rate) * \ + (exchange_rate_map[d.purchase_invoice] - self.conversion_rate) - self.add_gl_entry(gl_entries, self.get_company_default("exchange_gain_loss_account"), d.cost_center, discrepancy_caused_by_exchange_rate_difference, 0.0, - remarks, self.supplier, debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference, - account_currency=credit_currency, item=d) + self.add_gl_entry(gl_entries, account, d.cost_center, 0.0, discrepancy_caused_by_exchange_rate_difference, + remarks, self.supplier, debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference, + account_currency=credit_currency, item=d) + + self.add_gl_entry(gl_entries, self.get_company_default("exchange_gain_loss_account"), d.cost_center, discrepancy_caused_by_exchange_rate_difference, 0.0, + remarks, self.supplier, debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference, + account_currency=credit_currency, item=d) # Amount added through landed-cos-voucher if d.landed_cost_voucher_amount and landed_cost_entries: @@ -495,6 +501,28 @@ class PurchaseReceipt(BuyingController): self.add_gl_entry(gl_entries, asset_account, item.cost_center, 0.0, flt(item.landed_cost_voucher_amount), remarks, expenses_included_in_asset_valuation, project=item.project, item=item) + def get_purchase_invoice_details(self): + purchase_invoices = [] + pi_items = [] + + for item in self.get('items'): + if item.get('purchase_invoice'): + purchase_invoices.append(item.purchase_invoice) + if item.get('purchase_invoice_item'): + pi_items.append(item.purchase_invoice_item) + + exchange_rate_map = frappe._dict(frappe.get_all('Purchase Invoice', filters={'name': ('in', + purchase_invoices)}, fields=['name', 'conversion_rate'], as_list=1)) + print("*"*50) + print("In get_purchase_invoice_details:") + print("exchange_rate_map: ", exchange_rate_map) + + net_rate_map = frappe._dict(frappe.get_all('Purchase Invoice Item', filters={'name': ('in', + pi_items)}, fields=['item_code', 'net_rate'], as_list=1)) + print("net_rate_map: ", net_rate_map) + + return exchange_rate_map, net_rate_map + def update_assets(self, item, valuation_rate): assets = frappe.db.get_all('Asset', filters={ 'purchase_receipt': self.name, 'item_code': item.item_code }