From 227ce5f8a28b1d469f7ee9820d460ef05ff4a9df Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 19 Sep 2022 15:06:06 +0530 Subject: [PATCH 01/10] fix: Incoming rate precision fixes for intra company transfer (cherry picked from commit 083309c056512f86ece9b3276338108d1e5b98bf) --- erpnext/controllers/selling_controller.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 8a26d9e2c89..76a717b8317 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -439,11 +439,17 @@ class SellingController(StockController): # For internal transfers use incoming rate as the valuation rate if self.is_internal_transfer(): if d.doctype == "Packed Item": - incoming_rate = flt(d.incoming_rate * d.conversion_factor, d.precision("incoming_rate")) + incoming_rate = flt( + flt(d.incoming_rate, d.precision("incoming_rate")) * d.conversion_factor, + d.precision("incoming_rate"), + ) if d.incoming_rate != incoming_rate: d.incoming_rate = incoming_rate else: - rate = flt(d.incoming_rate * d.conversion_factor, d.precision("rate")) + rate = flt( + flt(d.incoming_rate, d.precision("incoming_rate")) * d.conversion_factor, + d.precision("rate"), + ) if d.rate != rate: d.rate = rate frappe.msgprint( From dd26ef96e0c1baeb650dab1fa07e3c2b6ef172b0 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 26 Sep 2022 21:15:57 +0530 Subject: [PATCH 02/10] fix: Hanlde rounding loss for internal transfer (cherry picked from commit 6e47fd54a0c4d4b77ed6bedac896286d591416f8) --- erpnext/controllers/stock_controller.py | 40 ++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 2eea0bde8c6..d232cd58f45 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -139,13 +139,15 @@ class StockController(AccountsController): warehouse_with_no_account = [] precision = self.get_debit_field_precision() for item_row in voucher_details: - sle_list = sle_map.get(item_row.name) + sle_rounding_diff = 0.0 if sle_list: for sle in sle_list: if warehouse_account.get(sle.warehouse): # from warehouse account + sle_rounding_diff += flt(sle.stock_value_difference, precision) + self.check_expense_account(item_row) # expense account/ target_warehouse / source_warehouse @@ -188,6 +190,42 @@ class StockController(AccountsController): elif sle.warehouse not in warehouse_with_no_account: warehouse_with_no_account.append(sle.warehouse) + if sle_rounding_diff > 0: + expense_account = item_row.get("expense_account") + target_warehouse_account = warehouse_account[item_row.get("target_warehouse")]["account"] + source_warehouse_account = warehouse_account[item_row.get("warehouse")]["account"] + + gl_list.append( + self.get_gl_dict( + { + "account": target_warehouse_account or expense_account, + "against": expense_account, + "cost_center": item_row.cost_center, + "project": item_row.project or self.get("project"), + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "debit": sle_rounding_diff, + "is_opening": item_row.get("is_opening") or self.get("is_opening") or "No", + }, + warehouse_account[sle.warehouse]["account_currency"], + item=item_row, + ) + ) + + gl_list.append( + self.get_gl_dict( + { + "account": source_warehouse_account or expense_account, + "against": target_warehouse_account, + "cost_center": item_row.cost_center, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "debit": -1 * sle_rounding_diff, + "project": item_row.get("project") or self.get("project"), + "is_opening": item_row.get("is_opening") or self.get("is_opening") or "No", + }, + item=item_row, + ) + ) + if warehouse_with_no_account: for wh in warehouse_with_no_account: if frappe.db.get_value("Warehouse", wh, "company"): From b531a38efe4b92e07e2e5437c83802c517978771 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 11 Oct 2022 14:53:26 +0530 Subject: [PATCH 03/10] chore: Increase incoming_rate field precision to 6 (cherry picked from commit b31c3bd35db39a1abdbb30aaebc017a833a5a61f) # Conflicts: # erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json --- .../doctype/sales_invoice_item/sales_invoice_item.json | 9 +++++++++ 1 file changed, 9 insertions(+) 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 7bb564b066a..f7d9c2bb161 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -812,6 +812,11 @@ "fieldtype": "Currency", "label": "Incoming Rate (Costing)", "no_copy": 1, +<<<<<<< HEAD +======= + "options": "Company:company:default_currency", + "precision": "6", +>>>>>>> b31c3bd35d (chore: Increase incoming_rate field precision to 6) "print_hide": 1 }, { @@ -841,7 +846,11 @@ "idx": 1, "istable": 1, "links": [], +<<<<<<< HEAD "modified": "2022-08-26 12:06:31.205417", +======= + "modified": "2022-10-10 20:57:38.340026", +>>>>>>> b31c3bd35d (chore: Increase incoming_rate field precision to 6) "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", From 0b48f1387341a089399140190dacc6bc1a4e2fd4 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 11 Oct 2022 14:54:27 +0530 Subject: [PATCH 04/10] test: Internal tranfer precision loss test (cherry picked from commit dc20b21fb5162c7905662c10d954a07b4c30ca54) # Conflicts: # erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py --- .../sales_invoice/test_sales_invoice.py | 247 ++++++++++++++---- erpnext/stock/doctype/item/test_item.py | 7 +- .../test_stock_ledger_entry.py | 18 +- .../stock_reconciliation.py | 4 +- 4 files changed, 212 insertions(+), 64 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index e300e0f35d3..81899c65bd3 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -31,10 +31,20 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import ( get_qty_after_transaction, make_stock_entry, ) -from erpnext.stock.utils import get_incoming_rate +from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ( + create_stock_reconciliation, +) +from erpnext.stock.utils import get_incoming_rate, get_stock_balance class TestSalesInvoice(unittest.TestCase): + def setUp(self): + from erpnext.stock.doctype.stock_ledger_entry.test_stock_ledger_entry import create_items + + create_items(["_Test Internal Transfer Item"], uoms=[{"uom": "Box", "conversion_factor": 10}]) + create_internal_parties() + setup_accounts() + def make(self): w = frappe.copy_doc(test_records[0]) w.is_pos = 0 @@ -1687,7 +1697,7 @@ class TestSalesInvoice(unittest.TestCase): si.save() self.assertEqual(si.get("items")[0].rate, flt((price_list_rate * 25) / 100 + price_list_rate)) - def test_outstanding_amount_after_advance_jv_cancelation(self): + def test_outstanding_amount_after_advance_jv_cancellation(self): from erpnext.accounts.doctype.journal_entry.test_journal_entry import ( test_records as jv_test_records, ) @@ -1731,7 +1741,7 @@ class TestSalesInvoice(unittest.TestCase): flt(si.rounded_total + si.total_advance, si.precision("outstanding_amount")), ) - def test_outstanding_amount_after_advance_payment_entry_cancelation(self): + def test_outstanding_amount_after_advance_payment_entry_cancellation(self): pe = frappe.get_doc( { "doctype": "Payment Entry", @@ -2369,29 +2379,6 @@ class TestSalesInvoice(unittest.TestCase): acc_settings.save() def test_inter_company_transaction(self): - from erpnext.selling.doctype.customer.test_customer import create_internal_customer - - create_internal_customer( - customer_name="_Test Internal Customer", - represents_company="_Test Company 1", - allowed_to_interact_with="Wind Power LLC", - ) - - if not frappe.db.exists("Supplier", "_Test Internal Supplier"): - supplier = frappe.get_doc( - { - "supplier_group": "_Test Supplier Group", - "supplier_name": "_Test Internal Supplier", - "doctype": "Supplier", - "is_internal_supplier": 1, - "represents_company": "Wind Power LLC", - } - ) - - supplier.append("companies", {"company": "_Test Company 1"}) - - supplier.insert() - si = create_sales_invoice( company="Wind Power LLC", customer="_Test Internal Customer", @@ -2420,6 +2407,69 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(target_doc.company, "_Test Company 1") self.assertEqual(target_doc.supplier, "_Test Internal Supplier") +<<<<<<< HEAD +======= + def test_inter_company_transaction_without_default_warehouse(self): + "Check mapping (expense account) of inter company SI to PI in absence of default warehouse." + # setup + old_negative_stock = frappe.db.get_single_value("Stock Settings", "allow_negative_stock") + frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) + + old_perpetual_inventory = erpnext.is_perpetual_inventory_enabled("_Test Company 1") + frappe.local.enable_perpetual_inventory["_Test Company 1"] = 1 + + frappe.db.set_value( + "Company", + "_Test Company 1", + "stock_received_but_not_billed", + "Stock Received But Not Billed - _TC1", + ) + frappe.db.set_value( + "Company", + "_Test Company 1", + "expenses_included_in_valuation", + "Expenses Included In Valuation - _TC1", + ) + + # begin test + si = create_sales_invoice( + company="Wind Power LLC", + customer="_Test Internal Customer", + debit_to="Debtors - WP", + warehouse="Stores - WP", + income_account="Sales - WP", + expense_account="Cost of Goods Sold - WP", + cost_center="Main - WP", + currency="USD", + update_stock=1, + do_not_save=1, + ) + si.selling_price_list = "_Test Price List Rest of the World" + si.submit() + + target_doc = make_inter_company_transaction("Sales Invoice", si.name) + + # in absence of warehouse Stock Received But Not Billed is set as expense account while mapping + # mapping is not obstructed + self.assertIsNone(target_doc.items[0].warehouse) + self.assertEqual(target_doc.items[0].expense_account, "Stock Received But Not Billed - _TC1") + + target_doc.items[0].update({"cost_center": "Main - _TC1"}) + + # missing warehouse is validated on save, after mapping + self.assertRaises(WarehouseMissingError, target_doc.save) + + target_doc.items[0].update({"warehouse": "Stores - _TC1"}) + target_doc.save() + + # after warehouse is set, linked account or default inventory account is set + self.assertEqual(target_doc.items[0].expense_account, "Stock In Hand - _TC1") + + # tear down + frappe.local.enable_perpetual_inventory["_Test Company 1"] = old_perpetual_inventory + frappe.db.set_value("Stock Settings", None, "allow_negative_stock", old_negative_stock) + +>>>>>>> dc20b21fb5 (test: Internal tranfer precision loss test) def test_sle_for_target_warehouse(self): se = make_stock_entry( item_code="138-CMS Shoe", @@ -2451,34 +2501,9 @@ class TestSalesInvoice(unittest.TestCase): se.cancel() def test_internal_transfer_gl_entry(self): - ## Create internal transfer account - from erpnext.selling.doctype.customer.test_customer import create_internal_customer - - account = create_account( - account_name="Unrealized Profit", - parent_account="Current Liabilities - TCP1", - company="_Test Company with perpetual inventory", - ) - - frappe.db.set_value( - "Company", "_Test Company with perpetual inventory", "unrealized_profit_loss_account", account - ) - - customer = create_internal_customer( - "_Test Internal Customer 2", - "_Test Company with perpetual inventory", - "_Test Company with perpetual inventory", - ) - - create_internal_supplier( - "_Test Internal Supplier 2", - "_Test Company with perpetual inventory", - "_Test Company with perpetual inventory", - ) - si = create_sales_invoice( company="_Test Company with perpetual inventory", - customer=customer, + customer="_Test Internal Customer 2", debit_to="Debtors - TCP1", warehouse="Stores - TCP1", income_account="Sales - TCP1", @@ -2492,7 +2517,7 @@ class TestSalesInvoice(unittest.TestCase): si.update_stock = 1 si.items[0].target_warehouse = "Work In Progress - TCP1" - # Add stock to stores for succesful stock transfer + # Add stock to stores for successful stock transfer make_stock_entry( target="Stores - TCP1", company="_Test Company with perpetual inventory", qty=1, basic_rate=100 ) @@ -2548,6 +2573,7 @@ class TestSalesInvoice(unittest.TestCase): check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1)) +<<<<<<< HEAD def test_eway_bill_json(self): si = make_sales_invoice_for_ewaybill() @@ -2829,6 +2855,78 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(einvoice["ItemList"][1]["Discount"], 0) self.assertEqual(einvoice["ItemList"][1]["UnitPrice"], 20) +======= + def test_internal_transfer_gl_precision_issues(self): + # Make a stock queue of an item with two valuations + + # Remove all existing stock for this + if get_stock_balance("_Test Internal Transfer Item", "Stores - TCP1", "2022-04-10"): + create_stock_reconciliation( + item_code="_Test Internal Transfer Item", + warehouse="Stores - TCP1", + qty=0, + rate=0, + company="_Test Company with perpetual inventory", + expense_account="Stock Adjustment - TCP1" + if frappe.get_all("Stock Ledger Entry") + else "Temporary Opening - TCP1", + posting_date="2020-04-10", + posting_time="14:00", + ) + + make_stock_entry( + item_code="_Test Internal Transfer Item", + target="Stores - TCP1", + qty=9000000, + basic_rate=52.0, + posting_date="2020-04-10", + posting_time="14:00", + ) + make_stock_entry( + item_code="_Test Internal Transfer Item", + target="Stores - TCP1", + qty=60000000, + basic_rate=52.349777, + posting_date="2020-04-10", + posting_time="14:00", + ) + + # Make an internal transfer Sales Invoice Stock in non stock uom to check + # for rounding errors while converting to stock uom + si = create_sales_invoice( + company="_Test Company with perpetual inventory", + customer="_Test Internal Customer 2", + item_code="_Test Internal Transfer Item", + qty=5000000, + uom="Box", + debit_to="Debtors - TCP1", + warehouse="Stores - TCP1", + income_account="Sales - TCP1", + expense_account="Cost of Goods Sold - TCP1", + cost_center="Main - TCP1", + currency="INR", + do_not_save=1, + ) + + # Check GL Entries with precision + si.update_stock = 1 + si.items[0].target_warehouse = "Work In Progress - TCP1" + si.items[0].conversion_factor = 10 + si.save() + si.submit() + + # Check if adjustment entry is created + self.assertTrue( + frappe.db.exists( + "GL Entry", + { + "voucher_type": "Sales Invoice", + "voucher_no": si.name, + "remarks": "Rounding gain/loss Entry for Stock Transfer", + }, + ) + ) +>>>>>>> dc20b21fb5 (test: Internal tranfer precision loss test) def test_item_tax_net_range(self): item = create_item("T Shirt") @@ -3278,7 +3376,7 @@ class TestSalesInvoice(unittest.TestCase): [deferred_account, 2022.47, 0.0, "2019-03-15"], ] - gl_entries = gl_entries = frappe.db.sql( + gl_entries = frappe.db.sql( """select account, debit, credit, posting_date from `tabGL Entry` where voucher_type='Journal Entry' and voucher_detail_no=%s and posting_date <= %s @@ -3809,6 +3907,34 @@ def get_taxes_and_charges(): ] +def create_internal_parties(): + from erpnext.selling.doctype.customer.test_customer import create_internal_customer + + create_internal_customer( + customer_name="_Test Internal Customer", + represents_company="_Test Company 1", + allowed_to_interact_with="Wind Power LLC", + ) + + create_internal_customer( + customer_name="_Test Internal Customer 2", + represents_company="_Test Company with perpetual inventory", + allowed_to_interact_with="_Test Company with perpetual inventory", + ) + + create_internal_supplier( + supplier_name="_Test Internal Supplier", + represents_company="Wind Power LLC", + allowed_to_interact_with="_Test Company 1", + ) + + create_internal_supplier( + supplier_name="_Test Internal Supplier 2", + represents_company="_Test Company with perpetual inventory", + allowed_to_interact_with="_Test Company with perpetual inventory", + ) + + def create_internal_supplier(supplier_name, represents_company, allowed_to_interact_with): if not frappe.db.exists("Supplier", supplier_name): supplier = frappe.get_doc( @@ -3831,6 +3957,19 @@ def create_internal_supplier(supplier_name, represents_company, allowed_to_inter return supplier_name +def setup_accounts(): + ## Create internal transfer account + account = create_account( + account_name="Unrealized Profit", + parent_account="Current Liabilities - TCP1", + company="_Test Company with perpetual inventory", + ) + + frappe.db.set_value( + "Company", "_Test Company with perpetual inventory", "unrealized_profit_loss_account", account + ) + + def add_taxes(doc): doc.append( "taxes", diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 179f7237f96..911c8d0a665 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -30,7 +30,7 @@ test_ignore = ["BOM"] test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand", "Item Attribute"] -def make_item(item_code=None, properties=None): +def make_item(item_code=None, properties=None, uoms=None): if not item_code: item_code = frappe.generate_hash(length=16) @@ -54,6 +54,11 @@ def make_item(item_code=None, properties=None): for item_default in [doc for doc in item.get("item_defaults") if not doc.default_warehouse]: item_default.default_warehouse = "_Test Warehouse - _TC" item_default.company = "_Test Company" + + if uoms: + for uom in uoms: + item.append("uoms", uom) + item.insert() return item diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py index e810c7933cc..1ec229d2e1f 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py @@ -902,13 +902,15 @@ def create_product_bundle_item(new_item_code, packed_items): item.save() -def create_items(): - items = [ - "_Test Item for Reposting", - "_Test Finished Item for Reposting", - "_Test Subcontracted Item for Reposting", - "_Test Bundled Item for Reposting", - ] +def create_items(items=None, uoms=None): + if not items: + items = [ + "_Test Item for Reposting", + "_Test Finished Item for Reposting", + "_Test Subcontracted Item for Reposting", + "_Test Bundled Item for Reposting", + ] + for d in items: properties = {"valuation_method": "FIFO"} if d == "_Test Bundled Item for Reposting": @@ -916,7 +918,7 @@ def create_items(): elif d == "_Test Subcontracted Item for Reposting": properties.update({"is_sub_contracted_item": 1}) - make_item(d, properties=properties) + make_item(d, properties=properties, uoms=uoms) return items diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 87cc8c6a957..823d0ed0b31 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -131,7 +131,9 @@ class StockReconciliation(StockController): key.append(row.get(field)) if key in item_warehouse_combinations: - self.validation_messages.append(_get_msg(row_num, _("Duplicate entry"))) + self.validation_messages.append( + _get_msg(row_num, _("Same item and warehouse combination already entered.")) + ) else: item_warehouse_combinations.append(key) From b966f107118b99f909d929a4a002f633534b87e5 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 11 Oct 2022 14:55:09 +0530 Subject: [PATCH 05/10] chore: GL Entries for SLE diff (cherry picked from commit df2a0e265b85010d92b1aab50ccccc531b26c8fe) --- erpnext/controllers/stock_controller.py | 29 +++++++++++++++---------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index d232cd58f45..7bfb9863558 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -146,7 +146,7 @@ class StockController(AccountsController): if warehouse_account.get(sle.warehouse): # from warehouse account - sle_rounding_diff += flt(sle.stock_value_difference, precision) + sle_rounding_diff += flt(sle.stock_value_difference) self.check_expense_account(item_row) @@ -190,19 +190,24 @@ class StockController(AccountsController): elif sle.warehouse not in warehouse_with_no_account: warehouse_with_no_account.append(sle.warehouse) - if sle_rounding_diff > 0: - expense_account = item_row.get("expense_account") - target_warehouse_account = warehouse_account[item_row.get("target_warehouse")]["account"] - source_warehouse_account = warehouse_account[item_row.get("warehouse")]["account"] + if abs(sle_rounding_diff) > 0.1 and ( + self.get("is_internal_customer") or self.get("is_internal_supplier") + ): + asset_account = "" + if self.get("is_internal_customer"): + asset_account = warehouse_account[item_row.get("target_warehouse")]["account"] + elif self.get("is_internal_supplier"): + asset_account = warehouse_account[item_row.get("from_warehouse")]["account"] + expense_account = item_row.get("expense_account") gl_list.append( self.get_gl_dict( { - "account": target_warehouse_account or expense_account, - "against": expense_account, + "account": expense_account, + "against": asset_account, "cost_center": item_row.cost_center, "project": item_row.project or self.get("project"), - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "remarks": _("Rounding gain/loss Entry for Stock Transfer"), "debit": sle_rounding_diff, "is_opening": item_row.get("is_opening") or self.get("is_opening") or "No", }, @@ -214,11 +219,11 @@ class StockController(AccountsController): gl_list.append( self.get_gl_dict( { - "account": source_warehouse_account or expense_account, - "against": target_warehouse_account, + "account": asset_account, + "against": expense_account, "cost_center": item_row.cost_center, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "debit": -1 * sle_rounding_diff, + "remarks": _("Rounding gain/loss Entry for Stock Transfer"), + "credit": sle_rounding_diff, "project": item_row.get("project") or self.get("project"), "is_opening": item_row.get("is_opening") or self.get("is_opening") or "No", }, From 151b9d4d7b4ee47dc7d969a20b2f657ed6adcfa5 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 12 Oct 2022 14:17:55 +0530 Subject: [PATCH 06/10] chore: Increase precision for other doc fields (cherry picked from commit c8d2181498616c8c6757e28255977c66a65a30d9) # Conflicts: # erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json # erpnext/stock/doctype/delivery_note_item/delivery_note_item.json --- .../doctype/purchase_invoice_item/purchase_invoice_item.json | 5 +++++ .../stock/doctype/delivery_note_item/delivery_note_item.json | 5 +++++ .../doctype/purchase_receipt_item/purchase_receipt_item.json | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index 4b12f9954e8..7775769dacc 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -706,6 +706,7 @@ "label": "Valuation Rate", "no_copy": 1, "options": "Company:company:default_currency", + "precision": "6", "print_hide": 1, "read_only": 1 }, @@ -871,7 +872,11 @@ "idx": 1, "istable": 1, "links": [], +<<<<<<< HEAD "modified": "2021-11-15 17:04:07.191013", +======= + "modified": "2022-10-12 03:37:29.032732", +>>>>>>> c8d2181498 (chore: Increase precision for other doc fields) "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", 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 2d7abc8a0d6..1e5d03a1cd2 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -746,6 +746,7 @@ "fieldtype": "Currency", "label": "Incoming Rate", "no_copy": 1, + "precision": "6", "print_hide": 1, "read_only": 1 }, @@ -780,7 +781,11 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], +<<<<<<< HEAD "modified": "2022-05-02 12:09:39.610075", +======= + "modified": "2022-10-12 03:36:05.344847", +>>>>>>> c8d2181498 (chore: Increase precision for other doc fields) "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note 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 5a04e7d2eec..3d30533a5e7 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -738,6 +738,7 @@ "oldfieldname": "valuation_rate", "oldfieldtype": "Currency", "options": "Company:company:default_currency", + "precision": "6", "print_hide": 1, "print_width": "80px", "read_only": 1, @@ -992,7 +993,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2022-07-28 19:27:54.880781", + "modified": "2022-10-12 03:37:59.516609", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", From 7a9e7b66ac5b48a534ff6f6d2f853cb1115a9a96 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 12 Oct 2022 14:19:09 +0530 Subject: [PATCH 07/10] chore: Use proper accounts (cherry picked from commit 1c05c004cd1739ecdf724a87edd2472991c16cfe) --- erpnext/controllers/stock_controller.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 7bfb9863558..d9b8db01b25 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -190,21 +190,22 @@ class StockController(AccountsController): elif sle.warehouse not in warehouse_with_no_account: warehouse_with_no_account.append(sle.warehouse) - if abs(sle_rounding_diff) > 0.1 and ( + if abs(sle_rounding_diff) < (1.0 / (10**precision)) and ( self.get("is_internal_customer") or self.get("is_internal_supplier") ): - asset_account = "" + warehouse_asset_account = "" if self.get("is_internal_customer"): - asset_account = warehouse_account[item_row.get("target_warehouse")]["account"] + warehouse_asset_account = warehouse_account[item_row.get("target_warehouse")]["account"] elif self.get("is_internal_supplier"): - asset_account = warehouse_account[item_row.get("from_warehouse")]["account"] + warehouse_asset_account = warehouse_account[item_row.get("warehouse")]["account"] + + expense_account = frappe.db.get_value("Company", self.company, "default_expense_account") - expense_account = item_row.get("expense_account") gl_list.append( self.get_gl_dict( { "account": expense_account, - "against": asset_account, + "against": warehouse_asset_account, "cost_center": item_row.cost_center, "project": item_row.project or self.get("project"), "remarks": _("Rounding gain/loss Entry for Stock Transfer"), @@ -219,7 +220,7 @@ class StockController(AccountsController): gl_list.append( self.get_gl_dict( { - "account": asset_account, + "account": warehouse_asset_account, "against": expense_account, "cost_center": item_row.cost_center, "remarks": _("Rounding gain/loss Entry for Stock Transfer"), From c67bdcf3c609cf09305a5e70d1e2f3f5a5f6a25d Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 12 Oct 2022 14:57:16 +0530 Subject: [PATCH 08/10] chore: fix precision condition (cherry picked from commit 49601558c6f10beafa64372dc3203645259d9264) --- erpnext/controllers/stock_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index d9b8db01b25..41e641f7a49 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -190,7 +190,7 @@ class StockController(AccountsController): elif sle.warehouse not in warehouse_with_no_account: warehouse_with_no_account.append(sle.warehouse) - if abs(sle_rounding_diff) < (1.0 / (10**precision)) and ( + if abs(sle_rounding_diff) > (1.0 / (10**precision)) and ( self.get("is_internal_customer") or self.get("is_internal_supplier") ): warehouse_asset_account = "" From 4a8c42d62b4f67dcae8f11e5f5236832032d27da Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 12 Oct 2022 15:53:28 +0530 Subject: [PATCH 09/10] chore: check only for inter-company transfers (cherry picked from commit 9aa5e20ef7a466713e33a35f35d3219b36358b51) --- erpnext/controllers/stock_controller.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 41e641f7a49..3a08051b2f3 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -190,9 +190,7 @@ class StockController(AccountsController): elif sle.warehouse not in warehouse_with_no_account: warehouse_with_no_account.append(sle.warehouse) - if abs(sle_rounding_diff) > (1.0 / (10**precision)) and ( - self.get("is_internal_customer") or self.get("is_internal_supplier") - ): + if abs(sle_rounding_diff) > (1.0 / (10**precision)) and self.is_internal_transfer(): warehouse_asset_account = "" if self.get("is_internal_customer"): warehouse_asset_account = warehouse_account[item_row.get("target_warehouse")]["account"] From 3b5889ef85856446370ec0e4c8d9b6042891c7f0 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 12 Oct 2022 16:30:23 +0530 Subject: [PATCH 10/10] chore: resolve conflicts --- .../purchase_invoice_item.json | 4 -- .../sales_invoice/test_sales_invoice.py | 67 +------------------ .../sales_invoice_item.json | 7 -- .../delivery_note_item.json | 4 -- 4 files changed, 1 insertion(+), 81 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index 7775769dacc..c0afa7fe691 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -872,11 +872,7 @@ "idx": 1, "istable": 1, "links": [], -<<<<<<< HEAD - "modified": "2021-11-15 17:04:07.191013", -======= "modified": "2022-10-12 03:37:29.032732", ->>>>>>> c8d2181498 (chore: Increase precision for other doc fields) "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 81899c65bd3..56323eeaf29 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2407,69 +2407,6 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(target_doc.company, "_Test Company 1") self.assertEqual(target_doc.supplier, "_Test Internal Supplier") -<<<<<<< HEAD -======= - def test_inter_company_transaction_without_default_warehouse(self): - "Check mapping (expense account) of inter company SI to PI in absence of default warehouse." - # setup - old_negative_stock = frappe.db.get_single_value("Stock Settings", "allow_negative_stock") - frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) - - old_perpetual_inventory = erpnext.is_perpetual_inventory_enabled("_Test Company 1") - frappe.local.enable_perpetual_inventory["_Test Company 1"] = 1 - - frappe.db.set_value( - "Company", - "_Test Company 1", - "stock_received_but_not_billed", - "Stock Received But Not Billed - _TC1", - ) - frappe.db.set_value( - "Company", - "_Test Company 1", - "expenses_included_in_valuation", - "Expenses Included In Valuation - _TC1", - ) - - # begin test - si = create_sales_invoice( - company="Wind Power LLC", - customer="_Test Internal Customer", - debit_to="Debtors - WP", - warehouse="Stores - WP", - income_account="Sales - WP", - expense_account="Cost of Goods Sold - WP", - cost_center="Main - WP", - currency="USD", - update_stock=1, - do_not_save=1, - ) - si.selling_price_list = "_Test Price List Rest of the World" - si.submit() - - target_doc = make_inter_company_transaction("Sales Invoice", si.name) - - # in absence of warehouse Stock Received But Not Billed is set as expense account while mapping - # mapping is not obstructed - self.assertIsNone(target_doc.items[0].warehouse) - self.assertEqual(target_doc.items[0].expense_account, "Stock Received But Not Billed - _TC1") - - target_doc.items[0].update({"cost_center": "Main - _TC1"}) - - # missing warehouse is validated on save, after mapping - self.assertRaises(WarehouseMissingError, target_doc.save) - - target_doc.items[0].update({"warehouse": "Stores - _TC1"}) - target_doc.save() - - # after warehouse is set, linked account or default inventory account is set - self.assertEqual(target_doc.items[0].expense_account, "Stock In Hand - _TC1") - - # tear down - frappe.local.enable_perpetual_inventory["_Test Company 1"] = old_perpetual_inventory - frappe.db.set_value("Stock Settings", None, "allow_negative_stock", old_negative_stock) - ->>>>>>> dc20b21fb5 (test: Internal tranfer precision loss test) def test_sle_for_target_warehouse(self): se = make_stock_entry( item_code="138-CMS Shoe", @@ -2573,7 +2510,6 @@ class TestSalesInvoice(unittest.TestCase): check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1)) -<<<<<<< HEAD def test_eway_bill_json(self): si = make_sales_invoice_for_ewaybill() @@ -2855,7 +2791,7 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(einvoice["ItemList"][1]["Discount"], 0) self.assertEqual(einvoice["ItemList"][1]["UnitPrice"], 20) -======= + def test_internal_transfer_gl_precision_issues(self): # Make a stock queue of an item with two valuations @@ -2926,7 +2862,6 @@ class TestSalesInvoice(unittest.TestCase): }, ) ) ->>>>>>> dc20b21fb5 (test: Internal tranfer precision loss test) def test_item_tax_net_range(self): item = create_item("T Shirt") 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 f7d9c2bb161..9b62c6a8f37 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -812,11 +812,8 @@ "fieldtype": "Currency", "label": "Incoming Rate (Costing)", "no_copy": 1, -<<<<<<< HEAD -======= "options": "Company:company:default_currency", "precision": "6", ->>>>>>> b31c3bd35d (chore: Increase incoming_rate field precision to 6) "print_hide": 1 }, { @@ -846,11 +843,7 @@ "idx": 1, "istable": 1, "links": [], -<<<<<<< HEAD - "modified": "2022-08-26 12:06:31.205417", -======= "modified": "2022-10-10 20:57:38.340026", ->>>>>>> b31c3bd35d (chore: Increase incoming_rate field precision to 6) "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", 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 1e5d03a1cd2..fb89aef5b26 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -781,11 +781,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], -<<<<<<< HEAD - "modified": "2022-05-02 12:09:39.610075", -======= "modified": "2022-10-12 03:36:05.344847", ->>>>>>> c8d2181498 (chore: Increase precision for other doc fields) "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item",