Merge pull request #31890 from s-aga-r/fix/subcontracting/additional-cost

fix: additional-costs in SCO and SCR
diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
index c772c1a..d13d970 100644
--- a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
+++ b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
@@ -4,6 +4,8 @@
 # Decompiled by https://python-decompiler.com
 
 
+import copy
+
 import frappe
 from frappe.tests.utils import FrappeTestCase
 
@@ -11,10 +13,12 @@
 	execute,
 )
 from erpnext.controllers.tests.test_subcontracting_controller import (
+	get_rm_items,
 	get_subcontracting_order,
 	make_service_item,
+	make_stock_in_entry,
+	make_stock_transfer_entry,
 )
-from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
 from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
 	make_subcontracting_receipt,
 )
@@ -36,15 +40,18 @@
 		sco = get_subcontracting_order(
 			service_items=service_items, supplier_warehouse="_Test Warehouse 1 - _TC"
 		)
-		make_stock_entry(
-			item_code="_Test Item", target="_Test Warehouse 1 - _TC", qty=100, basic_rate=100
+		rm_items = get_rm_items(sco.supplied_items)
+		itemwise_details = make_stock_in_entry(rm_items=rm_items)
+
+		for item in rm_items:
+			item["sco_rm_detail"] = sco.items[0].name
+
+		make_stock_transfer_entry(
+			sco_no=sco.name,
+			rm_items=rm_items,
+			itemwise_details=copy.deepcopy(itemwise_details),
 		)
-		make_stock_entry(
-			item_code="_Test Item Home Desktop 100",
-			target="_Test Warehouse 1 - _TC",
-			qty=100,
-			basic_rate=100,
-		)
+
 		make_subcontracting_receipt_against_sco(sco.name)
 		sco.reload()
 		col, data = execute(
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index 2a2f8f5..1372c89 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -490,7 +490,7 @@
 						row.item_code,
 						row.get(self.subcontract_data.order_field),
 					) and transfer_item.qty > 0:
-						qty = self.__get_qty_based_on_material_transfer(row, transfer_item) or 0
+						qty = flt(self.__get_qty_based_on_material_transfer(row, transfer_item))
 						transfer_item.qty -= qty
 						self.__add_supplied_item(row, transfer_item.get("item_details"), qty)
 
@@ -720,6 +720,25 @@
 					sco_doc = frappe.get_doc("Subcontracting Order", sco)
 					sco_doc.update_status()
 
+	def set_missing_values_in_additional_costs(self):
+		self.total_additional_costs = sum(flt(item.amount) for item in self.get("additional_costs"))
+
+		if self.total_additional_costs:
+			if self.distribute_additional_costs_based_on == "Amount":
+				total_amt = sum(flt(item.amount) for item in self.get("items"))
+				for item in self.items:
+					item.additional_cost_per_qty = (
+						(item.amount * self.total_additional_costs) / total_amt
+					) / item.qty
+			else:
+				total_qty = sum(flt(item.qty) for item in self.get("items"))
+				additional_cost_per_qty = self.total_additional_costs / total_qty
+				for item in self.items:
+					item.additional_cost_per_qty = additional_cost_per_qty
+		else:
+			for item in self.items:
+				item.additional_cost_per_qty = 0
+
 	@frappe.whitelist()
 	def get_current_stock(self):
 		if self.doctype in ["Purchase Receipt", "Subcontracting Receipt"]:
@@ -730,7 +749,7 @@
 						{"item_code": item.rm_item_code, "warehouse": self.supplier_warehouse},
 						"actual_qty",
 					)
-					item.current_stock = flt(actual_qty) or 0
+					item.current_stock = flt(actual_qty)
 
 	@property
 	def sub_contracted_items(self):
diff --git a/erpnext/controllers/tests/test_subcontracting_controller.py b/erpnext/controllers/tests/test_subcontracting_controller.py
index 4fab805..bc503f5 100644
--- a/erpnext/controllers/tests/test_subcontracting_controller.py
+++ b/erpnext/controllers/tests/test_subcontracting_controller.py
@@ -36,6 +36,36 @@
 		sco.remove_empty_rows()
 		self.assertEqual((len_before - 1), len(sco.service_items))
 
+	def test_set_missing_values_in_additional_costs(self):
+		sco = get_subcontracting_order(do_not_submit=1)
+
+		rate_without_additional_cost = sco.items[0].rate
+		amount_without_additional_cost = sco.items[0].amount
+
+		additional_amount = 120
+		sco.append(
+			"additional_costs",
+			{
+				"expense_account": "Cost of Goods Sold - _TC",
+				"description": "Test",
+				"amount": additional_amount,
+			},
+		)
+		sco.save()
+
+		additional_cost_per_qty = additional_amount / sco.items[0].qty
+
+		self.assertEqual(sco.items[0].additional_cost_per_qty, additional_cost_per_qty)
+		self.assertEqual(rate_without_additional_cost + additional_cost_per_qty, sco.items[0].rate)
+		self.assertEqual(amount_without_additional_cost + additional_amount, sco.items[0].amount)
+
+		sco.additional_costs = []
+		sco.save()
+
+		self.assertEqual(sco.items[0].additional_cost_per_qty, 0)
+		self.assertEqual(rate_without_additional_cost, sco.items[0].rate)
+		self.assertEqual(amount_without_additional_cost, sco.items[0].amount)
+
 	def test_create_raw_materials_supplied(self):
 		sco = get_subcontracting_order()
 		sco.supplied_items = None
diff --git a/erpnext/stock/landed_taxes_and_charges_common.js b/erpnext/stock/landed_taxes_and_charges_common.js
index ff8a69f..1d76a3d 100644
--- a/erpnext/stock/landed_taxes_and_charges_common.js
+++ b/erpnext/stock/landed_taxes_and_charges_common.js
@@ -1,4 +1,4 @@
-let document_list = ['Landed Cost Voucher', 'Stock Entry'];
+let document_list = ['Landed Cost Voucher', 'Stock Entry', 'Subcontracting Order', 'Subcontracting Receipt'];
 
 document_list.forEach((doctype) => {
 	frappe.ui.form.on(doctype, {
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js
index dbd337a..c20f8ab 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js
+++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js
@@ -3,6 +3,8 @@
 
 frappe.provide('erpnext.buying');
 
+{% include 'erpnext/stock/landed_taxes_and_charges_common.js' %};
+
 frappe.ui.form.on('Subcontracting Order', {
 	setup: (frm) => {
 		frm.get_field("items").grid.cannot_add_rows = true;
@@ -136,6 +138,16 @@
 	}
 });
 
+frappe.ui.form.on('Landed Cost Taxes and Charges', {
+	amount: function (frm, cdt, cdn) {
+		frm.events.set_base_amount(frm, cdt, cdn);
+	},
+
+	expense_account: function (frm, cdt, cdn) {
+		frm.events.set_account_currency(frm, cdt, cdn);
+	}
+});
+
 erpnext.buying.SubcontractingOrderController = class SubcontractingOrderController {
 	setup() {
 		this.frm.custom_make_buttons = {
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
index 71cdc94..156f027 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
+++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
@@ -82,25 +82,6 @@
 		self.set_missing_values_in_supplied_items()
 		self.set_missing_values_in_items()
 
-	def set_missing_values_in_additional_costs(self):
-		if self.get("additional_costs"):
-			self.total_additional_costs = sum(flt(item.amount) for item in self.get("additional_costs"))
-
-			if self.total_additional_costs:
-				if self.distribute_additional_costs_based_on == "Amount":
-					total_amt = sum(flt(item.amount) for item in self.get("items"))
-					for item in self.items:
-						item.additional_cost_per_qty = (
-							(item.amount * self.total_additional_costs) / total_amt
-						) / item.qty
-				else:
-					total_qty = sum(flt(item.qty) for item in self.get("items"))
-					additional_cost_per_qty = self.total_additional_costs / total_qty
-					for item in self.items:
-						item.additional_cost_per_qty = additional_cost_per_qty
-		else:
-			self.total_additional_costs = 0
-
 	def set_missing_values_in_service_items(self):
 		for idx, item in enumerate(self.get("service_items")):
 			self.items[idx].service_cost_per_qty = item.amount / self.items[idx].qty
@@ -114,9 +95,7 @@
 	def set_missing_values_in_items(self):
 		total_qty = total = 0
 		for item in self.items:
-			item.rate = (
-				item.rm_cost_per_qty + item.service_cost_per_qty + (item.additional_cost_per_qty or 0)
-			)
+			item.rate = item.rm_cost_per_qty + item.service_cost_per_qty + flt(item.additional_cost_per_qty)
 			item.amount = item.qty * item.rate
 			total_qty += flt(item.qty)
 			total += flt(item.amount)
@@ -187,7 +166,7 @@
 					total_required_qty = total_supplied_qty = 0
 					for item in self.supplied_items:
 						total_required_qty += item.required_qty
-						total_supplied_qty += item.supplied_qty or 0
+						total_supplied_qty += flt(item.supplied_qty)
 					if total_supplied_qty:
 						status = "Partial Material Transferred"
 						if total_supplied_qty >= total_required_qty:
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
index 35fec8b..aff76eb 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
@@ -3,6 +3,8 @@
 
 frappe.provide('erpnext.buying');
 
+{% include 'erpnext/stock/landed_taxes_and_charges_common.js' %};
+
 frappe.ui.form.on('Subcontracting Receipt', {
 	setup: (frm) => {
 		frm.get_field('supplied_items').grid.cannot_add_rows = true;
@@ -128,6 +130,16 @@
 	},
 });
 
+frappe.ui.form.on('Landed Cost Taxes and Charges', {
+	amount: function (frm, cdt, cdn) {
+		frm.events.set_base_amount(frm, cdt, cdn);
+	},
+
+	expense_account: function (frm, cdt, cdn) {
+		frm.events.set_account_currency(frm, cdt, cdn);
+	}
+});
+
 frappe.ui.form.on('Subcontracting Receipt Item', {
 	item_code(frm) {
 		set_missing_values(frm);
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json
index cb5b8c0..3aa8e61 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json
@@ -47,6 +47,10 @@
         "raw_material_details",
         "get_current_stock",
         "supplied_items",
+        "additional_costs_section",
+        "distribute_additional_costs_based_on",
+        "additional_costs",
+        "total_additional_costs",
         "section_break_46",
         "in_words",
         "bill_no",
@@ -580,11 +584,39 @@
             "fieldtype": "Link",
             "label": "Project",
             "options": "Project"
+        },
+        {
+            "collapsible": 1,
+            "collapsible_depends_on": "total_additional_costs",
+            "depends_on": "eval:(doc.docstatus == 0 || doc.total_additional_costs)",
+            "fieldname": "additional_costs_section",
+            "fieldtype": "Section Break",
+            "label": "Additional Costs"
+        },
+        {
+            "default": "Qty",
+            "fieldname": "distribute_additional_costs_based_on",
+            "fieldtype": "Select",
+            "label": "Distribute Additional Costs Based On ",
+            "options": "Qty\nAmount"
+        },
+        {
+            "fieldname": "additional_costs",
+            "fieldtype": "Table",
+            "label": "Additional Costs",
+            "options": "Landed Cost Taxes and Charges"
+        },
+        {
+            "fieldname": "total_additional_costs",
+            "fieldtype": "Currency",
+            "label": "Total Additional Costs",
+            "print_hide_if_no_value": 1,
+            "read_only": 1
         }
     ],
     "is_submittable": 1,
     "links": [],
-    "modified": "2022-08-16 09:56:41.199435",
+    "modified": "2022-08-18 15:48:57.419191",
     "modified_by": "Administrator",
     "module": "Subcontracting",
     "name": "Subcontracting Receipt",
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index 0c4ec6f..021d9aa 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -3,7 +3,7 @@
 
 import frappe
 from frappe import _
-from frappe.utils import cint, getdate, nowdate
+from frappe.utils import cint, flt, getdate, nowdate
 
 from erpnext.controllers.subcontracting_controller import SubcontractingController
 
@@ -103,6 +103,7 @@
 
 	@frappe.whitelist()
 	def set_missing_values(self):
+		self.set_missing_values_in_additional_costs()
 		self.set_missing_values_in_supplied_items()
 		self.set_missing_values_in_items()
 
@@ -125,12 +126,12 @@
 				item.rm_cost_per_qty = item.rm_supp_cost / item.qty
 				rm_supp_cost.pop(item.name)
 
-			if self.is_new() and item.rm_supp_cost > 0:
+			if item.recalculate_rate:
 				item.rate = (
-					item.rm_cost_per_qty + (item.service_cost_per_qty or 0) + item.additional_cost_per_qty
+					flt(item.rm_cost_per_qty) + flt(item.service_cost_per_qty) + flt(item.additional_cost_per_qty)
 				)
 
-			item.received_qty = item.qty + (item.rejected_qty or 0)
+			item.received_qty = item.qty + flt(item.rejected_qty)
 			item.amount = item.qty * item.rate
 			total_qty += item.qty
 			total_amount += item.amount
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
index 437fc41..dcde635 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
@@ -29,6 +29,7 @@
         "rate_and_amount",
         "rate",
         "amount",
+        "recalculate_rate",
         "column_break_19",
         "rm_cost_per_qty",
         "service_cost_per_qty",
@@ -460,12 +461,18 @@
             "fieldname": "accounting_details_section",
             "fieldtype": "Section Break",
             "label": "Accounting Details"
+        },
+        {
+            "default": "1",
+            "fieldname": "recalculate_rate",
+            "fieldtype": "Check",
+            "label": "Recalculate Rate"
         }
     ],
     "idx": 1,
     "istable": 1,
     "links": [],
-    "modified": "2022-08-15 14:51:10.613347",
+    "modified": "2022-08-18 19:42:24.313449",
     "modified_by": "Administrator",
     "module": "Subcontracting",
     "name": "Subcontracting Receipt Item",