refactor!: Make required changes to create SCO from PO

This commit is contained in:
Sagar Sharma
2022-05-05 19:41:05 +05:30
parent f94d607288
commit 77db843692
11 changed files with 182 additions and 86 deletions

View File

@@ -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'),

View File

@@ -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

View File

@@ -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

View File

@@ -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"]},
], ],
} }

View File

@@ -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",

View File

@@ -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):

View File

@@ -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 {

View File

@@ -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};
} }

View File

@@ -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

View File

@@ -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})

View File

@@ -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):