mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-02 11:49:10 +00:00
refactor!: Make required changes to create SCO from PO
This commit is contained in:
@@ -28,6 +28,11 @@ frappe.ui.form.on("Purchase Order", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frm.set_query("fg_item", "items", function() {
|
||||||
|
return {
|
||||||
|
filters: {'is_sub_contracted_item': 1}
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
company: function(frm) {
|
company: function(frm) {
|
||||||
@@ -109,6 +114,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
|
|||||||
'Purchase Invoice': 'Purchase Invoice',
|
'Purchase Invoice': 'Purchase Invoice',
|
||||||
'Stock Entry': 'Material to Supplier',
|
'Stock Entry': 'Material to Supplier',
|
||||||
'Payment Entry': 'Payment',
|
'Payment Entry': 'Payment',
|
||||||
|
'Subcontracting Order': 'Subcontracting Order'
|
||||||
}
|
}
|
||||||
|
|
||||||
super.setup();
|
super.setup();
|
||||||
@@ -183,6 +189,9 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
|
|||||||
cur_frm.add_custom_button(__('Material to Supplier'),
|
cur_frm.add_custom_button(__('Material to Supplier'),
|
||||||
function() { me.make_stock_entry(); }, __("Transfer"));
|
function() { me.make_stock_entry(); }, __("Transfer"));
|
||||||
}
|
}
|
||||||
|
if (doc.is_subcontracted) {
|
||||||
|
cur_frm.add_custom_button(__('Subcontracting Order'), this.make_subcontracting_order, __('Create'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(flt(doc.per_billed) < 100)
|
if(flt(doc.per_billed) < 100)
|
||||||
cur_frm.add_custom_button(__('Purchase Invoice'),
|
cur_frm.add_custom_button(__('Purchase Invoice'),
|
||||||
@@ -407,6 +416,14 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
make_subcontracting_order() {
|
||||||
|
frappe.model.open_mapped_doc({
|
||||||
|
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_subcontracting_order",
|
||||||
|
frm: cur_frm,
|
||||||
|
freeze_message: __("Creating Subcontracting Order ...")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
add_from_mappers() {
|
add_from_mappers() {
|
||||||
var me = this;
|
var me = this;
|
||||||
this.frm.add_custom_button(__('Material Request'),
|
this.frm.add_custom_button(__('Material Request'),
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
"supplier_name",
|
"supplier_name",
|
||||||
"apply_tds",
|
"apply_tds",
|
||||||
"tax_withholding_category",
|
"tax_withholding_category",
|
||||||
|
"is_subcontracted",
|
||||||
|
"supplier_warehouse",
|
||||||
"column_break1",
|
"column_break1",
|
||||||
"company",
|
"company",
|
||||||
"transaction_date",
|
"transaction_date",
|
||||||
@@ -51,10 +53,7 @@
|
|||||||
"price_list_currency",
|
"price_list_currency",
|
||||||
"plc_conversion_rate",
|
"plc_conversion_rate",
|
||||||
"ignore_pricing_rule",
|
"ignore_pricing_rule",
|
||||||
"sec_warehouse",
|
"section_break_45",
|
||||||
"is_subcontracted",
|
|
||||||
"col_break_warehouse",
|
|
||||||
"supplier_warehouse",
|
|
||||||
"before_items_section",
|
"before_items_section",
|
||||||
"scan_barcode",
|
"scan_barcode",
|
||||||
"items_col_break",
|
"items_col_break",
|
||||||
@@ -154,7 +153,8 @@
|
|||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"label": "Title",
|
"label": "Title",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"print_hide": 1
|
"print_hide": 1,
|
||||||
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "naming_series",
|
"fieldname": "naming_series",
|
||||||
@@ -439,11 +439,6 @@
|
|||||||
"permlevel": 1,
|
"permlevel": 1,
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "sec_warehouse",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"label": "Subcontracting"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "Sets 'Warehouse' in each row of the Items table.",
|
"description": "Sets 'Warehouse' in each row of the Items table.",
|
||||||
"fieldname": "set_warehouse",
|
"fieldname": "set_warehouse",
|
||||||
@@ -452,15 +447,10 @@
|
|||||||
"options": "Warehouse",
|
"options": "Warehouse",
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "col_break_warehouse",
|
|
||||||
"fieldtype": "Column Break"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"default": "No",
|
"default": "No",
|
||||||
"fieldname": "is_subcontracted",
|
"fieldname": "is_subcontracted",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"in_standard_filter": 1,
|
|
||||||
"label": "Supply Raw Materials",
|
"label": "Supply Raw Materials",
|
||||||
"options": "No\nYes",
|
"options": "No\nYes",
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
@@ -1138,16 +1128,21 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Tax Withholding Category",
|
"label": "Tax Withholding Category",
|
||||||
"options": "Tax Withholding Category"
|
"options": "Tax Withholding Category"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_45",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"idx": 105,
|
"idx": 105,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-09-28 13:10:47.955401",
|
"modified": "2022-04-26 18:46:58.863174",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order",
|
"name": "Purchase Order",
|
||||||
|
"naming_rule": "By \"Naming Series\" field",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
@@ -1194,6 +1189,7 @@
|
|||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
"timeline_field": "supplier",
|
"timeline_field": "supplier",
|
||||||
"title_field": "supplier_name",
|
"title_field": "supplier_name",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class PurchaseOrder(BuyingController):
|
|||||||
self.validate_with_previous_doc()
|
self.validate_with_previous_doc()
|
||||||
self.validate_for_subcontracting()
|
self.validate_for_subcontracting()
|
||||||
self.validate_minimum_order_qty()
|
self.validate_minimum_order_qty()
|
||||||
self.validate_bom_for_subcontracting_items()
|
self.validate_fg_item_for_subcontracting()
|
||||||
self.create_raw_materials_supplied("supplied_items")
|
self.create_raw_materials_supplied("supplied_items")
|
||||||
self.set_received_qty_for_drop_ship_items()
|
self.set_received_qty_for_drop_ship_items()
|
||||||
validate_inter_company_party(
|
validate_inter_company_party(
|
||||||
@@ -193,12 +193,25 @@ class PurchaseOrder(BuyingController):
|
|||||||
).format(item_code, qty, itemwise_min_order_qty.get(item_code))
|
).format(item_code, qty, itemwise_min_order_qty.get(item_code))
|
||||||
)
|
)
|
||||||
|
|
||||||
def validate_bom_for_subcontracting_items(self):
|
def validate_fg_item_for_subcontracting(self):
|
||||||
if self.is_subcontracted == "Yes":
|
if self.is_subcontracted:
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
if not item.bom:
|
if not item.fg_item:
|
||||||
frappe.throw(
|
frappe.throw(
|
||||||
_("BOM is not specified for subcontracting item {0} at row {1}").format(
|
_("Finished Good Item is not specified for service item {0} at row {1}").format(
|
||||||
|
item.item_code, item.idx
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if not frappe.get_value("Item", item.fg_item, "is_sub_contracted_item"):
|
||||||
|
frappe.throw(
|
||||||
|
_(
|
||||||
|
"Finished Good Item {0} must be a sub-contracted item for service item {1} at row {2}"
|
||||||
|
).format(item.fg_item, item.item_code, item.idx)
|
||||||
|
)
|
||||||
|
if not item.fg_item_qty:
|
||||||
|
frappe.throw(
|
||||||
|
_("Finished Good Item Qty is not specified for service item {0} at row {1}").format(
|
||||||
item.item_code, item.idx
|
item.item_code, item.idx
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -746,3 +759,43 @@ def add_items_in_ste(ste_doc, row, qty, po_details, batch_no=None):
|
|||||||
"serial_no": "\n".join(row.serial_no) if row.serial_no else "",
|
"serial_no": "\n".join(row.serial_no) if row.serial_no else "",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def make_subcontracting_order(source_name, target_doc=None):
|
||||||
|
return get_mapped_subcontracting_order(source_name, target_doc)
|
||||||
|
|
||||||
|
|
||||||
|
def get_mapped_subcontracting_order(source_name, target_doc=None):
|
||||||
|
|
||||||
|
if target_doc and isinstance(target_doc, str):
|
||||||
|
target_doc = json.loads(target_doc)
|
||||||
|
for key in ["service_items", "items", "supplied_items"]:
|
||||||
|
if key in target_doc:
|
||||||
|
del target_doc[key]
|
||||||
|
target_doc = json.dumps(target_doc)
|
||||||
|
|
||||||
|
target_doc = get_mapped_doc(
|
||||||
|
"Purchase Order",
|
||||||
|
source_name,
|
||||||
|
{
|
||||||
|
"Purchase Order": {
|
||||||
|
"doctype": "Subcontracting Order",
|
||||||
|
"field_map": {},
|
||||||
|
"field_no_map": ["total_qty", "total", "net_total"],
|
||||||
|
"validation": {
|
||||||
|
"docstatus": ["=", 1],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Purchase Order Item": {
|
||||||
|
"doctype": "Subcontracting Order Service Item",
|
||||||
|
"field_map": {},
|
||||||
|
"field_no_map": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
target_doc,
|
||||||
|
)
|
||||||
|
|
||||||
|
target_doc.populate_items_table()
|
||||||
|
|
||||||
|
return target_doc
|
||||||
|
|||||||
@@ -22,6 +22,6 @@ def get_data():
|
|||||||
"label": _("Reference"),
|
"label": _("Reference"),
|
||||||
"items": ["Material Request", "Supplier Quotation", "Project", "Auto Repeat"],
|
"items": ["Material Request", "Supplier Quotation", "Project", "Auto Repeat"],
|
||||||
},
|
},
|
||||||
{"label": _("Sub-contracting"), "items": ["Stock Entry"]},
|
{"label": _("Sub-contracting"), "items": ["Subcontracting Order"]},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
"supplier_part_no",
|
"supplier_part_no",
|
||||||
"item_name",
|
"item_name",
|
||||||
"product_bundle",
|
"product_bundle",
|
||||||
|
"fg_item",
|
||||||
|
"fg_item_qty",
|
||||||
"column_break_4",
|
"column_break_4",
|
||||||
"schedule_date",
|
"schedule_date",
|
||||||
"expected_delivery_date",
|
"expected_delivery_date",
|
||||||
@@ -572,18 +574,18 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:parent.is_subcontracted == 'Yes'",
|
|
||||||
"fieldname": "bom",
|
"fieldname": "bom",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "BOM",
|
"label": "BOM",
|
||||||
"options": "BOM",
|
"options": "BOM",
|
||||||
"print_hide": 1
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"depends_on": "eval:parent.is_subcontracted == 'Yes'",
|
|
||||||
"fieldname": "include_exploded_items",
|
"fieldname": "include_exploded_items",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
|
"hidden": 1,
|
||||||
"label": "Include Exploded Items",
|
"label": "Include Exploded Items",
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
@@ -845,13 +847,29 @@
|
|||||||
"label": "Sales Order Packed Item",
|
"label": "Sales Order Packed Item",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:parent.is_subcontracted == 'Yes'",
|
||||||
|
"fieldname": "fg_item",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Finished Good Item",
|
||||||
|
"mandatory_depends_on": "eval:parent.is_subcontracted == 'Yes'",
|
||||||
|
"options": "Item"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "1",
|
||||||
|
"depends_on": "eval:parent.is_subcontracted == 'Yes'",
|
||||||
|
"fieldname": "fg_item_qty",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"label": "Finished Good Item Qty",
|
||||||
|
"mandatory_depends_on": "eval:parent.is_subcontracted == 'Yes'"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-02-02 13:10:18.398976",
|
"modified": "2022-04-07 14:53:16.684010",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order Item",
|
"name": "Purchase Order Item",
|
||||||
|
|||||||
@@ -803,10 +803,7 @@ class BuyingController(StockController, Subcontracting):
|
|||||||
if self.doctype == "Material Request":
|
if self.doctype == "Material Request":
|
||||||
return
|
return
|
||||||
|
|
||||||
if hasattr(self, "is_subcontracted") and self.is_subcontracted == "Yes":
|
validate_item_type(self, "is_purchase_item", "purchase")
|
||||||
validate_item_type(self, "is_sub_contracted_item", "subcontracted")
|
|
||||||
else:
|
|
||||||
validate_item_type(self, "is_purchase_item", "purchase")
|
|
||||||
|
|
||||||
|
|
||||||
def get_asset_item_details(asset_items):
|
def get_asset_item_details(asset_items):
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ erpnext.buying.BuyingController = class BuyingController extends erpnext.Transac
|
|||||||
if (me.frm.doc.is_subcontracted == "Yes") {
|
if (me.frm.doc.is_subcontracted == "Yes") {
|
||||||
return{
|
return{
|
||||||
query: "erpnext.controllers.queries.item_query",
|
query: "erpnext.controllers.queries.item_query",
|
||||||
filters:{ 'supplier': me.frm.doc.supplier, 'is_sub_contracted_item': 1 }
|
filters:{ 'supplier': me.frm.doc.supplier, 'is_stock_item': 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -484,7 +484,7 @@ erpnext.utils.update_child_items = function(opts) {
|
|||||||
filters = {"is_sales_item": 1};
|
filters = {"is_sales_item": 1};
|
||||||
} else if (frm.doc.doctype == 'Purchase Order') {
|
} else if (frm.doc.doctype == 'Purchase Order') {
|
||||||
if (frm.doc.is_subcontracted == "Yes") {
|
if (frm.doc.is_subcontracted == "Yes") {
|
||||||
filters = {"is_sub_contracted_item": 1};
|
filters = {"is_stock_item": 0};
|
||||||
} else {
|
} else {
|
||||||
filters = {"is_purchase_item": 1};
|
filters = {"is_purchase_item": 1};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,20 +43,19 @@ class Bin(Document):
|
|||||||
def update_reserved_qty_for_sub_contracting(self):
|
def update_reserved_qty_for_sub_contracting(self):
|
||||||
# reserved qty
|
# reserved qty
|
||||||
|
|
||||||
po = frappe.qb.DocType("Purchase Order")
|
sco = frappe.qb.DocType("Subcontracting Order")
|
||||||
supplied_item = frappe.qb.DocType("Purchase Order Item Supplied")
|
supplied_item = frappe.qb.DocType("Subcontracting Order Supplied Item")
|
||||||
|
|
||||||
reserved_qty_for_sub_contract = (
|
reserved_qty_for_sub_contract = (
|
||||||
frappe.qb.from_(po)
|
frappe.qb.from_(sco)
|
||||||
.from_(supplied_item)
|
.from_(supplied_item)
|
||||||
.select(Sum(Coalesce(supplied_item.required_qty, 0)))
|
.select(Sum(Coalesce(supplied_item.required_qty, 0)))
|
||||||
.where(
|
.where(
|
||||||
(supplied_item.rm_item_code == self.item_code)
|
(supplied_item.rm_item_code == self.item_code)
|
||||||
& (po.name == supplied_item.parent)
|
& (sco.name == supplied_item.parent)
|
||||||
& (po.docstatus == 1)
|
& (sco.docstatus == 1)
|
||||||
& (po.is_subcontracted == "Yes")
|
& (sco.status != "Closed")
|
||||||
& (po.status != "Closed")
|
& (sco.per_received < 100)
|
||||||
& (po.per_received < 100)
|
|
||||||
& (supplied_item.reserve_warehouse == self.warehouse)
|
& (supplied_item.reserve_warehouse == self.warehouse)
|
||||||
)
|
)
|
||||||
).run()[0][0] or 0.0
|
).run()[0][0] or 0.0
|
||||||
@@ -67,21 +66,20 @@ class Bin(Document):
|
|||||||
materials_transferred = (
|
materials_transferred = (
|
||||||
frappe.qb.from_(se)
|
frappe.qb.from_(se)
|
||||||
.from_(se_item)
|
.from_(se_item)
|
||||||
.from_(po)
|
.from_(sco)
|
||||||
.select(
|
.select(
|
||||||
Sum(Case().when(se.is_return == 1, se_item.transfer_qty * -1).else_(se_item.transfer_qty))
|
Sum(Case().when(se.is_return == 1, se_item.transfer_qty * -1).else_(se_item.transfer_qty))
|
||||||
)
|
)
|
||||||
.where(
|
.where(
|
||||||
(se.docstatus == 1)
|
(se.docstatus == 1)
|
||||||
& (se.purpose == "Send to Subcontractor")
|
& (se.purpose == "Send to Subcontractor")
|
||||||
& (Coalesce(se.purchase_order, "") != "")
|
& (Coalesce(se.subcontracting_order, "") != "")
|
||||||
& ((se_item.item_code == self.item_code) | (se_item.original_item == self.item_code))
|
& ((se_item.item_code == self.item_code) | (se_item.original_item == self.item_code))
|
||||||
& (se.name == se_item.parent)
|
& (se.name == se_item.parent)
|
||||||
& (po.name == se.purchase_order)
|
& (sco.name == se.subcontracting_order)
|
||||||
& (po.docstatus == 1)
|
& (sco.docstatus == 1)
|
||||||
& (po.is_subcontracted == "Yes")
|
& (sco.status != "Closed")
|
||||||
& (po.status != "Closed")
|
& (sco.per_received < 100)
|
||||||
& (po.per_received < 100)
|
|
||||||
)
|
)
|
||||||
).run()[0][0] or 0.0
|
).run()[0][0] or 0.0
|
||||||
|
|
||||||
|
|||||||
@@ -134,8 +134,8 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
update_serial_nos_after_submit(self, "items")
|
update_serial_nos_after_submit(self, "items")
|
||||||
self.update_work_order()
|
self.update_work_order()
|
||||||
self.validate_purchase_order()
|
self.validate_subcontracting_order()
|
||||||
self.update_purchase_order_supplied_items()
|
self.update_subcontracting_order_supplied_items()
|
||||||
|
|
||||||
self.make_gl_entries()
|
self.make_gl_entries()
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ class StockEntry(StockController):
|
|||||||
self.set_material_request_transfer_status("Completed")
|
self.set_material_request_transfer_status("Completed")
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
self.update_purchase_order_supplied_items()
|
self.update_subcontracting_order_supplied_items()
|
||||||
|
|
||||||
if self.work_order and self.purpose == "Material Consumption for Manufacture":
|
if self.work_order and self.purpose == "Material Consumption for Manufacture":
|
||||||
self.validate_work_order_status()
|
self.validate_work_order_status()
|
||||||
@@ -810,8 +810,8 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
serial_nos.append(sn)
|
serial_nos.append(sn)
|
||||||
|
|
||||||
def validate_purchase_order(self):
|
def validate_subcontracting_order(self):
|
||||||
"""Throw exception if more raw material is transferred against Purchase Order than in
|
"""Throw exception if more raw material is transferred against Subcontracting Order than in
|
||||||
the raw materials supplied table"""
|
the raw materials supplied table"""
|
||||||
backflush_raw_materials_based_on = frappe.db.get_single_value(
|
backflush_raw_materials_based_on = frappe.db.get_single_value(
|
||||||
"Buying Settings", "backflush_raw_materials_of_subcontract_based_on"
|
"Buying Settings", "backflush_raw_materials_of_subcontract_based_on"
|
||||||
@@ -819,24 +819,28 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
qty_allowance = flt(frappe.db.get_single_value("Buying Settings", "over_transfer_allowance"))
|
qty_allowance = flt(frappe.db.get_single_value("Buying Settings", "over_transfer_allowance"))
|
||||||
|
|
||||||
if not (self.purpose == "Send to Subcontractor" and self.purchase_order):
|
if not (self.purpose == "Send to Subcontractor" and self.subcontracting_order):
|
||||||
return
|
return
|
||||||
|
|
||||||
if backflush_raw_materials_based_on == "BOM":
|
if backflush_raw_materials_based_on == "BOM":
|
||||||
purchase_order = frappe.get_doc("Purchase Order", self.purchase_order)
|
subcontracting_order = frappe.get_doc("Subcontracting Order", self.subcontracting_order)
|
||||||
for se_item in self.items:
|
for se_item in self.items:
|
||||||
item_code = se_item.original_item or se_item.item_code
|
item_code = se_item.original_item or se_item.item_code
|
||||||
precision = cint(frappe.db.get_default("float_precision")) or 3
|
precision = cint(frappe.db.get_default("float_precision")) or 3
|
||||||
required_qty = sum(
|
required_qty = sum(
|
||||||
[flt(d.required_qty) for d in purchase_order.supplied_items if d.rm_item_code == item_code]
|
[
|
||||||
|
flt(d.required_qty)
|
||||||
|
for d in subcontracting_order.supplied_items
|
||||||
|
if d.rm_item_code == item_code
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
total_allowed = required_qty + (required_qty * (qty_allowance / 100))
|
total_allowed = required_qty + (required_qty * (qty_allowance / 100))
|
||||||
|
|
||||||
if not required_qty:
|
if not required_qty:
|
||||||
bom_no = frappe.db.get_value(
|
bom_no = frappe.db.get_value(
|
||||||
"Purchase Order Item",
|
"Subcontracting Order Item",
|
||||||
{"parent": self.purchase_order, "item_code": se_item.subcontracted_item},
|
{"parent": self.subcontracting_order, "item_code": se_item.subcontracted_item},
|
||||||
"bom",
|
"bom",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -848,7 +852,7 @@ class StockEntry(StockController):
|
|||||||
required_qty = sum(
|
required_qty = sum(
|
||||||
[
|
[
|
||||||
flt(d.required_qty)
|
flt(d.required_qty)
|
||||||
for d in purchase_order.supplied_items
|
for d in subcontracting_order.supplied_items
|
||||||
if d.rm_item_code == original_item_code
|
if d.rm_item_code == original_item_code
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@@ -857,26 +861,39 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
if not required_qty:
|
if not required_qty:
|
||||||
frappe.throw(
|
frappe.throw(
|
||||||
_("Item {0} not found in 'Raw Materials Supplied' table in Purchase Order {1}").format(
|
_("Item {0} not found in 'Raw Materials Supplied' table in Subcontracting Order {1}").format(
|
||||||
se_item.item_code, self.purchase_order
|
se_item.item_code, self.subcontracting_order
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
total_supplied = frappe.db.sql(
|
total_supplied = frappe.db.sql(
|
||||||
"""select sum(transfer_qty)
|
"""select sum(transfer_qty)
|
||||||
from `tabStock Entry Detail`, `tabStock Entry`
|
from `tabStock Entry Detail`, `tabStock Entry`
|
||||||
where `tabStock Entry`.purchase_order = %s
|
where `tabStock Entry`.subcontracting_order = %s
|
||||||
and `tabStock Entry`.docstatus = 1
|
and `tabStock Entry`.docstatus = 1
|
||||||
and `tabStock Entry Detail`.item_code = %s
|
and `tabStock Entry Detail`.item_code = %s
|
||||||
and `tabStock Entry Detail`.parent = `tabStock Entry`.name""",
|
and `tabStock Entry Detail`.parent = `tabStock Entry`.name""",
|
||||||
(self.purchase_order, se_item.item_code),
|
(self.subcontracting_order, se_item.item_code),
|
||||||
)[0][0]
|
)[0][0]
|
||||||
|
|
||||||
if flt(total_supplied, precision) > flt(total_allowed, precision):
|
if flt(total_supplied, precision) > flt(total_allowed, precision):
|
||||||
frappe.throw(
|
frappe.throw(
|
||||||
_("Row {0}# Item {1} cannot be transferred more than {2} against Purchase Order {3}").format(
|
_(
|
||||||
se_item.idx, se_item.item_code, total_allowed, self.purchase_order
|
"Row {0}# Item {1} cannot be transferred more than {2} against Subcontracting Order {3}"
|
||||||
|
).format(
|
||||||
|
se_item.idx, se_item.item_code, total_allowed, self.subcontracting_order
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
elif not se_item.sco_rm_detail:
|
||||||
|
filters = {
|
||||||
|
"parent": self.subcontracting_order,
|
||||||
|
"docstatus": 1,
|
||||||
|
"rm_item_code": se_item.item_code,
|
||||||
|
"main_item_code": se_item.subcontracted_item,
|
||||||
|
}
|
||||||
|
|
||||||
|
sco_rm_detail = frappe.db.get_value("Subcontracting Order Supplied Item", filters, "name")
|
||||||
|
if sco_rm_detail:
|
||||||
|
se_item.db_set("sco_rm_detail", sco_rm_detail)
|
||||||
elif backflush_raw_materials_based_on == "Material Transferred for Subcontract":
|
elif backflush_raw_materials_based_on == "Material Transferred for Subcontract":
|
||||||
for row in self.items:
|
for row in self.items:
|
||||||
if not row.subcontracted_item:
|
if not row.subcontracted_item:
|
||||||
@@ -885,17 +902,17 @@ class StockEntry(StockController):
|
|||||||
row.idx, frappe.bold(row.item_code)
|
row.idx, frappe.bold(row.item_code)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif not row.po_detail:
|
elif not row.sco_rm_detail:
|
||||||
filters = {
|
filters = {
|
||||||
"parent": self.purchase_order,
|
"parent": self.subcontracting_order,
|
||||||
"docstatus": 1,
|
"docstatus": 1,
|
||||||
"rm_item_code": row.item_code,
|
"rm_item_code": row.item_code,
|
||||||
"main_item_code": row.subcontracted_item,
|
"main_item_code": row.subcontracted_item,
|
||||||
}
|
}
|
||||||
|
|
||||||
po_detail = frappe.db.get_value("Purchase Order Item Supplied", filters, "name")
|
sco_rm_detail = frappe.db.get_value("Subcontracting Order Supplied Item", filters, "name")
|
||||||
if po_detail:
|
if sco_rm_detail:
|
||||||
row.db_set("po_detail", po_detail)
|
row.db_set("sco_rm_detail", sco_rm_detail)
|
||||||
|
|
||||||
def validate_bom(self):
|
def validate_bom(self):
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
@@ -1901,7 +1918,7 @@ class StockEntry(StockController):
|
|||||||
se_child.is_process_loss = item_row.get("is_process_loss", 0)
|
se_child.is_process_loss = item_row.get("is_process_loss", 0)
|
||||||
|
|
||||||
for field in [
|
for field in [
|
||||||
"po_detail",
|
"sco_rm_detail",
|
||||||
"original_item",
|
"original_item",
|
||||||
"expense_account",
|
"expense_account",
|
||||||
"description",
|
"description",
|
||||||
@@ -1975,26 +1992,26 @@ class StockEntry(StockController):
|
|||||||
else:
|
else:
|
||||||
frappe.throw(_("Batch {0} of Item {1} is disabled.").format(item.batch_no, item.item_code))
|
frappe.throw(_("Batch {0} of Item {1} is disabled.").format(item.batch_no, item.item_code))
|
||||||
|
|
||||||
def update_purchase_order_supplied_items(self):
|
def update_subcontracting_order_supplied_items(self):
|
||||||
if self.purchase_order and (
|
if self.subcontracting_order and (
|
||||||
self.purpose in ["Send to Subcontractor", "Material Transfer"] or self.is_return
|
self.purpose in ["Send to Subcontractor", "Material Transfer"] or self.is_return
|
||||||
):
|
):
|
||||||
|
|
||||||
# Get PO Supplied Items Details
|
# Get SCO Supplied Items Details
|
||||||
item_wh = frappe._dict(
|
item_wh = frappe._dict(
|
||||||
frappe.db.sql(
|
frappe.db.sql(
|
||||||
"""
|
"""
|
||||||
select rm_item_code, reserve_warehouse
|
select rm_item_code, reserve_warehouse
|
||||||
from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup
|
from `tabSubcontracting Order` sco, `tabSubcontracting Order Supplied Item` scoitemsup
|
||||||
where po.name = poitemsup.parent
|
where sco.name = scoitemsup.parent
|
||||||
and po.name = %s""",
|
and sco.name = %s""",
|
||||||
self.purchase_order,
|
self.subcontracting_order,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
supplied_items = get_supplied_items(self.purchase_order)
|
supplied_items = get_supplied_items(self.subcontracting_order)
|
||||||
for name, item in supplied_items.items():
|
for name, item in supplied_items.items():
|
||||||
frappe.db.set_value("Purchase Order Item Supplied", name, item)
|
frappe.db.set_value("Subcontracting Order Supplied Item", name, item)
|
||||||
|
|
||||||
# Update reserved sub contracted quantity in bin based on Supplied Item Details and
|
# Update reserved sub contracted quantity in bin based on Supplied Item Details and
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
@@ -2479,25 +2496,25 @@ def validate_sample_quantity(item_code, sample_quantity, qty, batch_no=None):
|
|||||||
return sample_quantity
|
return sample_quantity
|
||||||
|
|
||||||
|
|
||||||
def get_supplied_items(purchase_order):
|
def get_supplied_items(subcontracting_order):
|
||||||
fields = [
|
fields = [
|
||||||
"`tabStock Entry Detail`.`transfer_qty`",
|
"`tabStock Entry Detail`.`transfer_qty`",
|
||||||
"`tabStock Entry`.`is_return`",
|
"`tabStock Entry`.`is_return`",
|
||||||
"`tabStock Entry Detail`.`po_detail`",
|
"`tabStock Entry Detail`.`sco_rm_detail`",
|
||||||
"`tabStock Entry Detail`.`item_code`",
|
"`tabStock Entry Detail`.`item_code`",
|
||||||
]
|
]
|
||||||
|
|
||||||
filters = [
|
filters = [
|
||||||
["Stock Entry", "docstatus", "=", 1],
|
["Stock Entry", "docstatus", "=", 1],
|
||||||
["Stock Entry", "purchase_order", "=", purchase_order],
|
["Stock Entry", "subcontracting_order", "=", subcontracting_order],
|
||||||
]
|
]
|
||||||
|
|
||||||
supplied_item_details = {}
|
supplied_item_details = {}
|
||||||
for row in frappe.get_all("Stock Entry", fields=fields, filters=filters):
|
for row in frappe.get_all("Stock Entry", fields=fields, filters=filters):
|
||||||
if not row.po_detail:
|
if not row.sco_rm_detail:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
key = row.po_detail
|
key = row.sco_rm_detail
|
||||||
if key not in supplied_item_details:
|
if key not in supplied_item_details:
|
||||||
supplied_item_details.setdefault(
|
supplied_item_details.setdefault(
|
||||||
key, frappe._dict({"supplied_qty": 0, "returned_qty": 0, "total_supplied_qty": 0})
|
key, frappe._dict({"supplied_qty": 0, "returned_qty": 0, "total_supplied_qty": 0})
|
||||||
|
|||||||
@@ -237,8 +237,8 @@ def validate_item_details(args, item):
|
|||||||
throw(_("Item {0} is a template, please select one of its variants").format(item.name))
|
throw(_("Item {0} is a template, please select one of its variants").format(item.name))
|
||||||
|
|
||||||
elif args.transaction_type == "buying" and args.doctype != "Material Request":
|
elif args.transaction_type == "buying" and args.doctype != "Material Request":
|
||||||
if args.get("is_subcontracted") == "Yes" and item.is_sub_contracted_item != 1:
|
if args.get("is_subcontracted") == "Yes" and item.is_stock_item:
|
||||||
throw(_("Item {0} must be a Sub-contracted Item").format(item.name))
|
throw(_("Item {0} must be a Non-Stock Item").format(item.name))
|
||||||
|
|
||||||
|
|
||||||
def get_basic_details(args, item, overwrite_warehouse=True):
|
def get_basic_details(args, item, overwrite_warehouse=True):
|
||||||
|
|||||||
Reference in New Issue
Block a user