Merge pull request #31890 from s-aga-r/fix/subcontracting/additional-cost
fix: additional-costs in SCO and SCR
This commit is contained in:
commit
1d28ea5458
@ -4,6 +4,8 @@
|
|||||||
# Decompiled by https://python-decompiler.com
|
# Decompiled by https://python-decompiler.com
|
||||||
|
|
||||||
|
|
||||||
|
import copy
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.tests.utils import FrappeTestCase
|
from frappe.tests.utils import FrappeTestCase
|
||||||
|
|
||||||
@ -11,10 +13,12 @@ from erpnext.buying.report.subcontracted_item_to_be_received.subcontracted_item_
|
|||||||
execute,
|
execute,
|
||||||
)
|
)
|
||||||
from erpnext.controllers.tests.test_subcontracting_controller import (
|
from erpnext.controllers.tests.test_subcontracting_controller import (
|
||||||
|
get_rm_items,
|
||||||
get_subcontracting_order,
|
get_subcontracting_order,
|
||||||
make_service_item,
|
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 (
|
from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
|
||||||
make_subcontracting_receipt,
|
make_subcontracting_receipt,
|
||||||
)
|
)
|
||||||
@ -36,15 +40,18 @@ class TestSubcontractedItemToBeReceived(FrappeTestCase):
|
|||||||
sco = get_subcontracting_order(
|
sco = get_subcontracting_order(
|
||||||
service_items=service_items, supplier_warehouse="_Test Warehouse 1 - _TC"
|
service_items=service_items, supplier_warehouse="_Test Warehouse 1 - _TC"
|
||||||
)
|
)
|
||||||
make_stock_entry(
|
rm_items = get_rm_items(sco.supplied_items)
|
||||||
item_code="_Test Item", target="_Test Warehouse 1 - _TC", qty=100, basic_rate=100
|
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||||
)
|
|
||||||
make_stock_entry(
|
for item in rm_items:
|
||||||
item_code="_Test Item Home Desktop 100",
|
item["sco_rm_detail"] = sco.items[0].name
|
||||||
target="_Test Warehouse 1 - _TC",
|
|
||||||
qty=100,
|
make_stock_transfer_entry(
|
||||||
basic_rate=100,
|
sco_no=sco.name,
|
||||||
|
rm_items=rm_items,
|
||||||
|
itemwise_details=copy.deepcopy(itemwise_details),
|
||||||
)
|
)
|
||||||
|
|
||||||
make_subcontracting_receipt_against_sco(sco.name)
|
make_subcontracting_receipt_against_sco(sco.name)
|
||||||
sco.reload()
|
sco.reload()
|
||||||
col, data = execute(
|
col, data = execute(
|
||||||
|
@ -490,7 +490,7 @@ class SubcontractingController(StockController):
|
|||||||
row.item_code,
|
row.item_code,
|
||||||
row.get(self.subcontract_data.order_field),
|
row.get(self.subcontract_data.order_field),
|
||||||
) and transfer_item.qty > 0:
|
) 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
|
transfer_item.qty -= qty
|
||||||
self.__add_supplied_item(row, transfer_item.get("item_details"), qty)
|
self.__add_supplied_item(row, transfer_item.get("item_details"), qty)
|
||||||
|
|
||||||
@ -720,6 +720,25 @@ class SubcontractingController(StockController):
|
|||||||
sco_doc = frappe.get_doc("Subcontracting Order", sco)
|
sco_doc = frappe.get_doc("Subcontracting Order", sco)
|
||||||
sco_doc.update_status()
|
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()
|
@frappe.whitelist()
|
||||||
def get_current_stock(self):
|
def get_current_stock(self):
|
||||||
if self.doctype in ["Purchase Receipt", "Subcontracting Receipt"]:
|
if self.doctype in ["Purchase Receipt", "Subcontracting Receipt"]:
|
||||||
@ -730,7 +749,7 @@ class SubcontractingController(StockController):
|
|||||||
{"item_code": item.rm_item_code, "warehouse": self.supplier_warehouse},
|
{"item_code": item.rm_item_code, "warehouse": self.supplier_warehouse},
|
||||||
"actual_qty",
|
"actual_qty",
|
||||||
)
|
)
|
||||||
item.current_stock = flt(actual_qty) or 0
|
item.current_stock = flt(actual_qty)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sub_contracted_items(self):
|
def sub_contracted_items(self):
|
||||||
|
@ -36,6 +36,36 @@ class TestSubcontractingController(FrappeTestCase):
|
|||||||
sco.remove_empty_rows()
|
sco.remove_empty_rows()
|
||||||
self.assertEqual((len_before - 1), len(sco.service_items))
|
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):
|
def test_create_raw_materials_supplied(self):
|
||||||
sco = get_subcontracting_order()
|
sco = get_subcontracting_order()
|
||||||
sco.supplied_items = None
|
sco.supplied_items = None
|
||||||
|
@ -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) => {
|
document_list.forEach((doctype) => {
|
||||||
frappe.ui.form.on(doctype, {
|
frappe.ui.form.on(doctype, {
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
frappe.provide('erpnext.buying');
|
frappe.provide('erpnext.buying');
|
||||||
|
|
||||||
|
{% include 'erpnext/stock/landed_taxes_and_charges_common.js' %};
|
||||||
|
|
||||||
frappe.ui.form.on('Subcontracting Order', {
|
frappe.ui.form.on('Subcontracting Order', {
|
||||||
setup: (frm) => {
|
setup: (frm) => {
|
||||||
frm.get_field("items").grid.cannot_add_rows = true;
|
frm.get_field("items").grid.cannot_add_rows = true;
|
||||||
@ -136,6 +138,16 @@ frappe.ui.form.on('Subcontracting Order', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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 {
|
erpnext.buying.SubcontractingOrderController = class SubcontractingOrderController {
|
||||||
setup() {
|
setup() {
|
||||||
this.frm.custom_make_buttons = {
|
this.frm.custom_make_buttons = {
|
||||||
|
@ -82,25 +82,6 @@ class SubcontractingOrder(SubcontractingController):
|
|||||||
self.set_missing_values_in_supplied_items()
|
self.set_missing_values_in_supplied_items()
|
||||||
self.set_missing_values_in_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):
|
def set_missing_values_in_service_items(self):
|
||||||
for idx, item in enumerate(self.get("service_items")):
|
for idx, item in enumerate(self.get("service_items")):
|
||||||
self.items[idx].service_cost_per_qty = item.amount / self.items[idx].qty
|
self.items[idx].service_cost_per_qty = item.amount / self.items[idx].qty
|
||||||
@ -114,9 +95,7 @@ class SubcontractingOrder(SubcontractingController):
|
|||||||
def set_missing_values_in_items(self):
|
def set_missing_values_in_items(self):
|
||||||
total_qty = total = 0
|
total_qty = total = 0
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
item.rate = (
|
item.rate = item.rm_cost_per_qty + item.service_cost_per_qty + flt(item.additional_cost_per_qty)
|
||||||
item.rm_cost_per_qty + item.service_cost_per_qty + (item.additional_cost_per_qty or 0)
|
|
||||||
)
|
|
||||||
item.amount = item.qty * item.rate
|
item.amount = item.qty * item.rate
|
||||||
total_qty += flt(item.qty)
|
total_qty += flt(item.qty)
|
||||||
total += flt(item.amount)
|
total += flt(item.amount)
|
||||||
@ -187,7 +166,7 @@ class SubcontractingOrder(SubcontractingController):
|
|||||||
total_required_qty = total_supplied_qty = 0
|
total_required_qty = total_supplied_qty = 0
|
||||||
for item in self.supplied_items:
|
for item in self.supplied_items:
|
||||||
total_required_qty += item.required_qty
|
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:
|
if total_supplied_qty:
|
||||||
status = "Partial Material Transferred"
|
status = "Partial Material Transferred"
|
||||||
if total_supplied_qty >= total_required_qty:
|
if total_supplied_qty >= total_required_qty:
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
frappe.provide('erpnext.buying');
|
frappe.provide('erpnext.buying');
|
||||||
|
|
||||||
|
{% include 'erpnext/stock/landed_taxes_and_charges_common.js' %};
|
||||||
|
|
||||||
frappe.ui.form.on('Subcontracting Receipt', {
|
frappe.ui.form.on('Subcontracting Receipt', {
|
||||||
setup: (frm) => {
|
setup: (frm) => {
|
||||||
frm.get_field('supplied_items').grid.cannot_add_rows = true;
|
frm.get_field('supplied_items').grid.cannot_add_rows = true;
|
||||||
@ -128,6 +130,16 @@ frappe.ui.form.on('Subcontracting Receipt', {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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', {
|
frappe.ui.form.on('Subcontracting Receipt Item', {
|
||||||
item_code(frm) {
|
item_code(frm) {
|
||||||
set_missing_values(frm);
|
set_missing_values(frm);
|
||||||
|
@ -47,6 +47,10 @@
|
|||||||
"raw_material_details",
|
"raw_material_details",
|
||||||
"get_current_stock",
|
"get_current_stock",
|
||||||
"supplied_items",
|
"supplied_items",
|
||||||
|
"additional_costs_section",
|
||||||
|
"distribute_additional_costs_based_on",
|
||||||
|
"additional_costs",
|
||||||
|
"total_additional_costs",
|
||||||
"section_break_46",
|
"section_break_46",
|
||||||
"in_words",
|
"in_words",
|
||||||
"bill_no",
|
"bill_no",
|
||||||
@ -580,11 +584,39 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Project",
|
"label": "Project",
|
||||||
"options": "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,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-08-16 09:56:41.199435",
|
"modified": "2022-08-18 15:48:57.419191",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Subcontracting",
|
"module": "Subcontracting",
|
||||||
"name": "Subcontracting Receipt",
|
"name": "Subcontracting Receipt",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
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
|
from erpnext.controllers.subcontracting_controller import SubcontractingController
|
||||||
|
|
||||||
@ -103,6 +103,7 @@ class SubcontractingReceipt(SubcontractingController):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def set_missing_values(self):
|
def set_missing_values(self):
|
||||||
|
self.set_missing_values_in_additional_costs()
|
||||||
self.set_missing_values_in_supplied_items()
|
self.set_missing_values_in_supplied_items()
|
||||||
self.set_missing_values_in_items()
|
self.set_missing_values_in_items()
|
||||||
|
|
||||||
@ -125,12 +126,12 @@ class SubcontractingReceipt(SubcontractingController):
|
|||||||
item.rm_cost_per_qty = item.rm_supp_cost / item.qty
|
item.rm_cost_per_qty = item.rm_supp_cost / item.qty
|
||||||
rm_supp_cost.pop(item.name)
|
rm_supp_cost.pop(item.name)
|
||||||
|
|
||||||
if self.is_new() and item.rm_supp_cost > 0:
|
if item.recalculate_rate:
|
||||||
item.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
|
item.amount = item.qty * item.rate
|
||||||
total_qty += item.qty
|
total_qty += item.qty
|
||||||
total_amount += item.amount
|
total_amount += item.amount
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
"rate_and_amount",
|
"rate_and_amount",
|
||||||
"rate",
|
"rate",
|
||||||
"amount",
|
"amount",
|
||||||
|
"recalculate_rate",
|
||||||
"column_break_19",
|
"column_break_19",
|
||||||
"rm_cost_per_qty",
|
"rm_cost_per_qty",
|
||||||
"service_cost_per_qty",
|
"service_cost_per_qty",
|
||||||
@ -460,12 +461,18 @@
|
|||||||
"fieldname": "accounting_details_section",
|
"fieldname": "accounting_details_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Accounting Details"
|
"label": "Accounting Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "1",
|
||||||
|
"fieldname": "recalculate_rate",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Recalculate Rate"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-08-15 14:51:10.613347",
|
"modified": "2022-08-18 19:42:24.313449",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Subcontracting",
|
"module": "Subcontracting",
|
||||||
"name": "Subcontracting Receipt Item",
|
"name": "Subcontracting Receipt Item",
|
||||||
|
Loading…
Reference in New Issue
Block a user