refactor!: Purchase Order
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 2cad1fb..d347026 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -7,17 +7,6 @@
frappe.ui.form.on("Purchase Order", {
setup: function(frm) {
-
- frm.set_query("reserve_warehouse", "supplied_items", function() {
- return {
- filters: {
- "company": frm.doc.company,
- "name": ['!=', frm.doc.supplier_warehouse],
- "is_group": 0
- }
- }
- });
-
frm.set_indicator_formatter('item_code',
function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
@@ -59,39 +48,6 @@
frm.set_value("tax_withholding_category", frm.supplier_tds);
}
},
-
- refresh: function(frm) {
- frm.trigger('get_materials_from_supplier');
- },
-
- get_materials_from_supplier: function(frm) {
- let po_details = [];
-
- if (frm.doc.supplied_items && (frm.doc.per_received == 100 || frm.doc.status === 'Closed')) {
- frm.doc.supplied_items.forEach(d => {
- if (d.total_supplied_qty && d.total_supplied_qty != d.consumed_qty) {
- po_details.push(d.name)
- }
- });
- }
-
- if (po_details && po_details.length) {
- frm.add_custom_button(__('Return of Components'), () => {
- frm.call({
- method: 'erpnext.buying.doctype.purchase_order.purchase_order.get_materials_from_supplier',
- freeze: true,
- freeze_message: __('Creating Stock Entry'),
- args: { purchase_order: frm.doc.name, po_details: po_details },
- callback: function(r) {
- if (r && r.message) {
- const doc = frappe.model.sync(r.message);
- frappe.set_route("Form", doc[0].doctype, doc[0].name);
- }
- }
- });
- }, __('Create'));
- }
- }
});
frappe.ui.form.on("Purchase Order Item", {
@@ -112,13 +68,11 @@
this.frm.custom_make_buttons = {
'Purchase Receipt': 'Purchase Receipt',
'Purchase Invoice': 'Purchase Invoice',
- 'Stock Entry': 'Material to Supplier',
'Payment Entry': 'Payment',
'Subcontracting Order': 'Subcontracting Order'
}
super.setup();
-
}
refresh(doc, cdt, cdn) {
@@ -185,10 +139,6 @@
if (doc.status != "On Hold") {
if(flt(doc.per_received) < 100 && allow_receipt) {
cur_frm.add_custom_button(__('Purchase Receipt'), this.make_purchase_receipt, __('Create'));
- if(doc.is_subcontracted && me.has_unsupplied_items()) {
- cur_frm.add_custom_button(__('Material to Supplier'),
- function() { me.make_stock_entry(); }, __("Transfer"));
- }
if (doc.is_subcontracted) {
cur_frm.add_custom_button(__('Subcontracting Order'), this.make_subcontracting_order, __('Create'));
}
@@ -258,142 +208,6 @@
set_schedule_date(this.frm);
}
- has_unsupplied_items() {
- return this.frm.doc['supplied_items'].some(item => item.required_qty > item.supplied_qty);
- }
-
- make_stock_entry() {
- var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; });
- var me = this;
-
- if(items.length >= 1){
- me.raw_material_data = [];
- me.show_dialog = 1;
- let title = __('Transfer Material to Supplier');
- let fields = [
- {fieldtype:'Section Break', label: __('Raw Materials')},
- {fieldname: 'sub_con_rm_items', fieldtype: 'Table', label: __('Items'),
- fields: [
- {
- fieldtype:'Data',
- fieldname:'item_code',
- label: __('Item'),
- read_only:1,
- in_list_view:1
- },
- {
- fieldtype:'Data',
- fieldname:'rm_item_code',
- label: __('Raw Material'),
- read_only:1,
- in_list_view:1
- },
- {
- fieldtype:'Float',
- read_only:1,
- fieldname:'qty',
- label: __('Quantity'),
- read_only:1,
- in_list_view:1
- },
- {
- fieldtype:'Data',
- read_only:1,
- fieldname:'warehouse',
- label: __('Reserve Warehouse'),
- in_list_view:1
- },
- {
- fieldtype:'Float',
- read_only:1,
- fieldname:'rate',
- label: __('Rate'),
- hidden:1
- },
- {
- fieldtype:'Float',
- read_only:1,
- fieldname:'amount',
- label: __('Amount'),
- hidden:1
- },
- {
- fieldtype:'Link',
- read_only:1,
- fieldname:'uom',
- label: __('UOM'),
- hidden:1
- }
- ],
- data: me.raw_material_data,
- get_data: function() {
- return me.raw_material_data;
- }
- }
- ]
-
- me.dialog = new frappe.ui.Dialog({
- title: title, fields: fields
- });
-
- if (me.frm.doc['supplied_items']) {
- me.frm.doc['supplied_items'].forEach((item, index) => {
- if (item.rm_item_code && item.main_item_code && item.required_qty - item.supplied_qty != 0) {
- me.raw_material_data.push ({
- 'name':item.name,
- 'item_code': item.main_item_code,
- 'rm_item_code': item.rm_item_code,
- 'item_name': item.rm_item_code,
- 'qty': item.required_qty - item.supplied_qty,
- 'warehouse':item.reserve_warehouse,
- 'rate':item.rate,
- 'amount':item.amount,
- 'stock_uom':item.stock_uom
- });
- me.dialog.fields_dict.sub_con_rm_items.grid.refresh();
- }
- })
- }
-
- me.dialog.get_field('sub_con_rm_items').check_all_rows()
-
- me.dialog.show()
- this.dialog.set_primary_action(__('Transfer'), function() {
- me.values = me.dialog.get_values();
- if(me.values) {
- me.values.sub_con_rm_items.map((row,i) => {
- if (!row.item_code || !row.rm_item_code || !row.warehouse || !row.qty || row.qty === 0) {
- let row_id = i+1;
- frappe.throw(__("Item Code, warehouse and quantity are required on row {0}", [row_id]));
- }
- })
- me._make_rm_stock_entry(me.dialog.fields_dict.sub_con_rm_items.grid.get_selected_children())
- me.dialog.hide()
- }
- });
- }
-
- me.dialog.get_close_btn().on('click', () => {
- me.dialog.hide();
- });
-
- }
-
- _make_rm_stock_entry(rm_items) {
- frappe.call({
- method:"erpnext.buying.doctype.purchase_order.purchase_order.make_rm_stock_entry",
- args: {
- purchase_order: cur_frm.doc.name,
- rm_items: rm_items
- }
- ,
- callback: function(r) {
- var doclist = frappe.model.sync(r.message);
- frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
- });
- }
-
make_inter_company_order(frm) {
frappe.model.open_mapped_doc({
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_inter_company_sales_order",
@@ -632,28 +446,10 @@
}
}
-cur_frm.fields_dict['items'].grid.get_field('bom').get_query = function(doc, cdt, cdn) {
- var d = locals[cdt][cdn]
- return {
- filters: [
- ['BOM', 'item', '=', d.item_code],
- ['BOM', 'is_active', '=', '1'],
- ['BOM', 'docstatus', '=', '1'],
- ['BOM', 'company', '=', doc.company]
- ]
- }
-}
-
function set_schedule_date(frm) {
if(frm.doc.schedule_date){
erpnext.utils.copy_value_in_all_rows(frm.doc, frm.doc.doctype, frm.doc.name, "items", "schedule_date");
}
}
-frappe.provide("erpnext.buying");
-
-frappe.ui.form.on("Purchase Order", "is_subcontracted", function(frm) {
- if (frm.doc.is_subcontracted) {
- erpnext.buying.get_default_bom(frm);
- }
-});
+frappe.provide("erpnext.buying");
\ No newline at end of file
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 1945079..234bec1 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -24,7 +24,6 @@
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
from erpnext.stock.doctype.item.item import get_item_defaults, get_last_purchase_details
from erpnext.stock.stock_balance import get_ordered_qty, update_bin_qty
-from erpnext.stock.utils import get_bin
form_grid_templates = {"items": "templates/form_grid/item_grid.html"}
@@ -70,7 +69,6 @@
self.validate_for_subcontracting()
self.validate_minimum_order_qty()
self.validate_fg_item_for_subcontracting()
- self.create_raw_materials_supplied("supplied_items")
self.set_received_qty_for_drop_ship_items()
validate_inter_company_party(
self.doctype, self.supplier, self.company, self.inter_company_order_reference
@@ -307,9 +305,6 @@
self.set_status(update=True, status=status)
self.update_requested_qty()
self.update_ordered_qty()
- if self.is_subcontracted:
- self.update_reserved_qty_for_subcontract()
-
self.notify_update()
clear_doctype_notifications(self)
@@ -324,9 +319,6 @@
self.update_ordered_qty()
self.validate_budget()
- if self.is_subcontracted:
- self.update_reserved_qty_for_subcontract()
-
frappe.get_doc("Authorization Control").validate_approving_authority(
self.doctype, self.company, self.base_grand_total
)
@@ -344,9 +336,6 @@
if self.has_drop_ship_item():
self.update_delivered_qty_in_sales_order()
- if self.is_subcontracted:
- self.update_reserved_qty_for_subcontract()
-
self.check_on_hold_or_closed_status()
frappe.db.set(self, "status", "Cancelled")
@@ -416,12 +405,6 @@
if item.delivered_by_supplier == 1:
item.received_qty = item.qty
- def update_reserved_qty_for_subcontract(self):
- for d in self.supplied_items:
- if d.rm_item_code:
- stock_bin = get_bin(d.rm_item_code, d.reserve_warehouse)
- stock_bin.update_reserved_qty_for_sub_contracting()
-
def update_receiving_percentage(self):
total_qty, received_qty = 0.0, 0.0
for item in self.items:
@@ -599,78 +582,6 @@
return doc
-@frappe.whitelist()
-def make_rm_stock_entry(purchase_order, rm_items):
- rm_items_list = rm_items
-
- if isinstance(rm_items, str):
- rm_items_list = json.loads(rm_items)
- elif not rm_items:
- frappe.throw(_("No Items available for transfer"))
-
- if rm_items_list:
- fg_items = list(set(d["item_code"] for d in rm_items_list))
- else:
- frappe.throw(_("No Items selected for transfer"))
-
- if purchase_order:
- purchase_order = frappe.get_doc("Purchase Order", purchase_order)
-
- if fg_items:
- items = tuple(set(d["rm_item_code"] for d in rm_items_list))
- item_wh = get_item_details(items)
-
- stock_entry = frappe.new_doc("Stock Entry")
- stock_entry.purpose = "Send to Subcontractor"
- stock_entry.purchase_order = purchase_order.name
- stock_entry.supplier = purchase_order.supplier
- stock_entry.supplier_name = purchase_order.supplier_name
- stock_entry.supplier_address = purchase_order.supplier_address
- stock_entry.address_display = purchase_order.address_display
- stock_entry.company = purchase_order.company
- stock_entry.to_warehouse = purchase_order.supplier_warehouse
- stock_entry.set_stock_entry_type()
-
- for item_code in fg_items:
- for rm_item_data in rm_items_list:
- if rm_item_data["item_code"] == item_code:
- rm_item_code = rm_item_data["rm_item_code"]
- items_dict = {
- rm_item_code: {
- "po_detail": rm_item_data.get("name"),
- "item_name": rm_item_data["item_name"],
- "description": item_wh.get(rm_item_code, {}).get("description", ""),
- "qty": rm_item_data["qty"],
- "from_warehouse": rm_item_data["warehouse"],
- "stock_uom": rm_item_data["stock_uom"],
- "serial_no": rm_item_data.get("serial_no"),
- "batch_no": rm_item_data.get("batch_no"),
- "main_item_code": rm_item_data["item_code"],
- "allow_alternative_item": item_wh.get(rm_item_code, {}).get("allow_alternative_item"),
- }
- }
- stock_entry.add_to_stock_entry_detail(items_dict)
- return stock_entry.as_dict()
- else:
- frappe.throw(_("No Items selected for transfer"))
- return purchase_order.name
-
-
-def get_item_details(items):
- item_details = {}
- for d in frappe.db.sql(
- """select item_code, description, allow_alternative_item from `tabItem`
- where name in ({0})""".format(
- ", ".join(["%s"] * len(items))
- ),
- items,
- as_dict=1,
- ):
- item_details[d.item_code] = d
-
- return item_details
-
-
def get_list_context(context=None):
from erpnext.controllers.website_list_for_contact import get_list_context
@@ -701,67 +612,6 @@
@frappe.whitelist()
-def get_materials_from_supplier(purchase_order, po_details):
- if isinstance(po_details, str):
- po_details = json.loads(po_details)
-
- doc = frappe.get_cached_doc("Purchase Order", purchase_order)
- doc.initialized_fields()
- doc.purchase_orders = [doc.name]
- doc.get_available_materials()
-
- if not doc.available_materials:
- frappe.throw(
- _("Materials are already received against the purchase order {0}").format(purchase_order)
- )
-
- return make_return_stock_entry_for_subcontract(doc.available_materials, doc, po_details)
-
-
-def make_return_stock_entry_for_subcontract(available_materials, po_doc, po_details):
- ste_doc = frappe.new_doc("Stock Entry")
- ste_doc.purpose = "Material Transfer"
- ste_doc.purchase_order = po_doc.name
- ste_doc.company = po_doc.company
- ste_doc.is_return = 1
-
- for key, value in available_materials.items():
- if not value.qty:
- continue
-
- if value.batch_no:
- for batch_no, qty in value.batch_no.items():
- if qty > 0:
- add_items_in_ste(ste_doc, value, value.qty, po_details, batch_no)
- else:
- add_items_in_ste(ste_doc, value, value.qty, po_details)
-
- ste_doc.set_stock_entry_type()
- ste_doc.calculate_rate_and_amount()
-
- return ste_doc
-
-
-def add_items_in_ste(ste_doc, row, qty, po_details, batch_no=None):
- item = ste_doc.append("items", row.item_details)
-
- po_detail = list(set(row.po_details).intersection(po_details))
- item.update(
- {
- "qty": qty,
- "batch_no": batch_no,
- "basic_rate": row.item_details["rate"],
- "po_detail": po_detail[0] if po_detail else "",
- "s_warehouse": row.item_details["t_warehouse"],
- "t_warehouse": row.item_details["s_warehouse"],
- "item_code": row.item_details["rm_item_code"],
- "subcontracted_item": row.item_details["main_item_code"],
- "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)
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 1a7f2dd..e1da54e 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -13,9 +13,6 @@
make_purchase_invoice as make_pi_from_po,
)
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt
-from erpnext.buying.doctype.purchase_order.purchase_order import (
- make_rm_stock_entry as make_subcontract_transfer_entry,
-)
from erpnext.controllers.accounts_controller import update_child_qty_rate
from erpnext.manufacturing.doctype.blanket_order.test_blanket_order import make_blanket_order
from erpnext.stock.doctype.item.test_item import make_item
@@ -24,7 +21,6 @@
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
make_purchase_invoice as make_pi_from_pr,
)
-from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
class TestPurchaseOrder(FrappeTestCase):
@@ -389,31 +385,6 @@
new_item_with_tax.delete()
frappe.get_doc("Item Tax Template", "Test Update Items Template - _TC").delete()
- def test_update_child_uom_conv_factor_change(self):
- po = create_purchase_order(item_code="_Test FG Item", is_subcontracted=1)
- total_reqd_qty = sum([d.get("required_qty") for d in po.as_dict().get("supplied_items")])
-
- trans_item = json.dumps(
- [
- {
- "item_code": po.get("items")[0].item_code,
- "rate": po.get("items")[0].rate,
- "qty": po.get("items")[0].qty,
- "uom": "_Test UOM 1",
- "conversion_factor": 2,
- "docname": po.get("items")[0].name,
- }
- ]
- )
- update_child_qty_rate("Purchase Order", trans_item, po.name)
- po.reload()
-
- total_reqd_qty_after_change = sum(
- d.get("required_qty") for d in po.as_dict().get("supplied_items")
- )
-
- self.assertEqual(total_reqd_qty_after_change, 2 * total_reqd_qty)
-
def test_update_qty(self):
po = create_purchase_order()
@@ -572,10 +543,6 @@
)
automatically_fetch_payment_terms(enable=0)
- def test_subcontracting(self):
- po = create_purchase_order(item_code="_Test FG Item", is_subcontracted=1)
- self.assertEqual(len(po.get("supplied_items")), 2)
-
def test_warehouse_company_validation(self):
from erpnext.stock.utils import InvalidWarehouseCompany
@@ -740,379 +707,6 @@
pi.insert()
self.assertTrue(pi.get("payment_schedule"))
- def test_reserved_qty_subcontract_po(self):
- # Make stock available for raw materials
- make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100)
- make_stock_entry(
- target="_Test Warehouse - _TC", item_code="_Test Item Home Desktop 100", qty=20, basic_rate=100
- )
- make_stock_entry(
- target="_Test Warehouse 1 - _TC", item_code="_Test Item", qty=30, basic_rate=100
- )
- make_stock_entry(
- target="_Test Warehouse 1 - _TC",
- item_code="_Test Item Home Desktop 100",
- qty=30,
- basic_rate=100,
- )
-
- bin1 = frappe.db.get_value(
- "Bin",
- filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
- fieldname=["reserved_qty_for_sub_contract", "projected_qty", "modified"],
- as_dict=1,
- )
-
- # Submit PO
- po = create_purchase_order(item_code="_Test FG Item", is_subcontracted=1)
-
- bin2 = frappe.db.get_value(
- "Bin",
- filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
- fieldname=["reserved_qty_for_sub_contract", "projected_qty", "modified"],
- as_dict=1,
- )
-
- self.assertEqual(bin2.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
- self.assertEqual(bin2.projected_qty, bin1.projected_qty - 10)
- self.assertNotEqual(bin1.modified, bin2.modified)
-
- # Create stock transfer
- rm_item = [
- {
- "item_code": "_Test FG Item",
- "rm_item_code": "_Test Item",
- "item_name": "_Test Item",
- "qty": 6,
- "warehouse": "_Test Warehouse - _TC",
- "rate": 100,
- "amount": 600,
- "stock_uom": "Nos",
- }
- ]
- rm_item_string = json.dumps(rm_item)
- se = frappe.get_doc(make_subcontract_transfer_entry(po.name, rm_item_string))
- se.to_warehouse = "_Test Warehouse 1 - _TC"
- se.save()
- se.submit()
-
- bin3 = frappe.db.get_value(
- "Bin",
- filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
- fieldname="reserved_qty_for_sub_contract",
- as_dict=1,
- )
-
- self.assertEqual(bin3.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
-
- # close PO
- po.update_status("Closed")
- bin4 = frappe.db.get_value(
- "Bin",
- filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
- fieldname="reserved_qty_for_sub_contract",
- as_dict=1,
- )
-
- self.assertEqual(bin4.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
-
- # Re-open PO
- po.update_status("Submitted")
- bin5 = frappe.db.get_value(
- "Bin",
- filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
- fieldname="reserved_qty_for_sub_contract",
- as_dict=1,
- )
-
- self.assertEqual(bin5.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
-
- make_stock_entry(
- target="_Test Warehouse 1 - _TC", item_code="_Test Item", qty=40, basic_rate=100
- )
- make_stock_entry(
- target="_Test Warehouse 1 - _TC",
- item_code="_Test Item Home Desktop 100",
- qty=40,
- basic_rate=100,
- )
-
- # make Purchase Receipt against PO
- pr = make_purchase_receipt(po.name)
- pr.supplier_warehouse = "_Test Warehouse 1 - _TC"
- pr.save()
- pr.submit()
-
- bin6 = frappe.db.get_value(
- "Bin",
- filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
- fieldname="reserved_qty_for_sub_contract",
- as_dict=1,
- )
-
- self.assertEqual(bin6.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
-
- # Cancel PR
- pr.cancel()
- bin7 = frappe.db.get_value(
- "Bin",
- filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
- fieldname="reserved_qty_for_sub_contract",
- as_dict=1,
- )
-
- self.assertEqual(bin7.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
-
- # Make Purchase Invoice
- pi = make_pi_from_po(po.name)
- pi.update_stock = 1
- pi.supplier_warehouse = "_Test Warehouse 1 - _TC"
- pi.insert()
- pi.submit()
- bin8 = frappe.db.get_value(
- "Bin",
- filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
- fieldname="reserved_qty_for_sub_contract",
- as_dict=1,
- )
-
- self.assertEqual(bin8.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
-
- # Cancel PR
- pi.cancel()
- bin9 = frappe.db.get_value(
- "Bin",
- filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
- fieldname="reserved_qty_for_sub_contract",
- as_dict=1,
- )
-
- self.assertEqual(bin9.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
-
- # Cancel Stock Entry
- se.cancel()
- bin10 = frappe.db.get_value(
- "Bin",
- filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
- fieldname="reserved_qty_for_sub_contract",
- as_dict=1,
- )
-
- self.assertEqual(bin10.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
-
- # Cancel PO
- po.reload()
- po.cancel()
- bin11 = frappe.db.get_value(
- "Bin",
- filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
- fieldname="reserved_qty_for_sub_contract",
- as_dict=1,
- )
-
- self.assertEqual(bin11.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
-
- def test_exploded_items_in_subcontracted(self):
- item_code = "_Test Subcontracted FG Item 11"
- make_subcontracted_item(item_code=item_code)
-
- po = create_purchase_order(
- item_code=item_code,
- qty=1,
- is_subcontracted=1,
- supplier_warehouse="_Test Warehouse 1 - _TC",
- include_exploded_items=1,
- )
-
- name = frappe.db.get_value("BOM", {"item": item_code}, "name")
- bom = frappe.get_doc("BOM", name)
-
- exploded_items = sorted(
- [d.item_code for d in bom.exploded_items if not d.get("sourced_by_supplier")]
- )
- supplied_items = sorted([d.rm_item_code for d in po.supplied_items])
- self.assertEqual(exploded_items, supplied_items)
-
- po1 = create_purchase_order(
- item_code=item_code,
- qty=1,
- is_subcontracted=1,
- supplier_warehouse="_Test Warehouse 1 - _TC",
- include_exploded_items=0,
- )
-
- supplied_items1 = sorted([d.rm_item_code for d in po1.supplied_items])
- bom_items = sorted([d.item_code for d in bom.items if not d.get("sourced_by_supplier")])
-
- self.assertEqual(supplied_items1, bom_items)
-
- def test_backflush_based_on_stock_entry(self):
- item_code = "_Test Subcontracted FG Item 1"
- make_subcontracted_item(item_code=item_code)
- make_item("Sub Contracted Raw Material 1", {"is_stock_item": 1, "is_sub_contracted_item": 1})
-
- update_backflush_based_on("Material Transferred for Subcontract")
-
- order_qty = 5
- po = create_purchase_order(
- item_code=item_code,
- qty=order_qty,
- is_subcontracted=1,
- supplier_warehouse="_Test Warehouse 1 - _TC",
- )
-
- make_stock_entry(
- target="_Test Warehouse - _TC", item_code="_Test Item Home Desktop 100", qty=20, basic_rate=100
- )
- make_stock_entry(
- target="_Test Warehouse - _TC", item_code="Test Extra Item 1", qty=100, basic_rate=100
- )
- make_stock_entry(
- target="_Test Warehouse - _TC", item_code="Test Extra Item 2", qty=10, basic_rate=100
- )
- make_stock_entry(
- target="_Test Warehouse - _TC",
- item_code="Sub Contracted Raw Material 1",
- qty=10,
- basic_rate=100,
- )
-
- rm_items = [
- {
- "item_code": item_code,
- "rm_item_code": "Sub Contracted Raw Material 1",
- "item_name": "_Test Item",
- "qty": 10,
- "warehouse": "_Test Warehouse - _TC",
- "stock_uom": "Nos",
- },
- {
- "item_code": item_code,
- "rm_item_code": "_Test Item Home Desktop 100",
- "item_name": "_Test Item Home Desktop 100",
- "qty": 20,
- "warehouse": "_Test Warehouse - _TC",
- "stock_uom": "Nos",
- },
- {
- "item_code": item_code,
- "rm_item_code": "Test Extra Item 1",
- "item_name": "Test Extra Item 1",
- "qty": 10,
- "warehouse": "_Test Warehouse - _TC",
- "stock_uom": "Nos",
- },
- {
- "item_code": item_code,
- "rm_item_code": "Test Extra Item 2",
- "stock_uom": "Nos",
- "qty": 10,
- "warehouse": "_Test Warehouse - _TC",
- "item_name": "Test Extra Item 2",
- },
- ]
-
- rm_item_string = json.dumps(rm_items)
- se = frappe.get_doc(make_subcontract_transfer_entry(po.name, rm_item_string))
- se.submit()
-
- pr = make_purchase_receipt(po.name)
-
- received_qty = 2
- # partial receipt
- pr.get("items")[0].qty = received_qty
- pr.save()
- pr.submit()
-
- transferred_items = sorted(
- [d.item_code for d in se.get("items") if se.purchase_order == po.name]
- )
- issued_items = sorted([d.rm_item_code for d in pr.get("supplied_items")])
-
- self.assertEqual(transferred_items, issued_items)
- self.assertEqual(pr.get("items")[0].rm_supp_cost, 2000)
-
- transferred_rm_map = frappe._dict()
- for item in rm_items:
- transferred_rm_map[item.get("rm_item_code")] = item
-
- update_backflush_based_on("BOM")
-
- def test_supplied_qty_against_subcontracted_po(self):
- item_code = "_Test Subcontracted FG Item 5"
- make_item("Sub Contracted Raw Material 4", {"is_stock_item": 1, "is_sub_contracted_item": 1})
-
- make_subcontracted_item(item_code=item_code, raw_materials=["Sub Contracted Raw Material 4"])
-
- update_backflush_based_on("Material Transferred for Subcontract")
-
- order_qty = 250
- po = create_purchase_order(
- item_code=item_code,
- qty=order_qty,
- is_subcontracted=1,
- supplier_warehouse="_Test Warehouse 1 - _TC",
- do_not_save=True,
- )
-
- # Add same subcontracted items multiple times
- po.append(
- "items",
- {
- "item_code": item_code,
- "qty": order_qty,
- "schedule_date": add_days(nowdate(), 1),
- "warehouse": "_Test Warehouse - _TC",
- },
- )
-
- po.set_missing_values()
- po.submit()
-
- # Material receipt entry for the raw materials which will be send to supplier
- make_stock_entry(
- target="_Test Warehouse - _TC",
- item_code="Sub Contracted Raw Material 4",
- qty=500,
- basic_rate=100,
- )
-
- rm_items = [
- {
- "item_code": item_code,
- "rm_item_code": "Sub Contracted Raw Material 4",
- "item_name": "_Test Item",
- "qty": 250,
- "warehouse": "_Test Warehouse - _TC",
- "stock_uom": "Nos",
- "name": po.supplied_items[0].name,
- },
- {
- "item_code": item_code,
- "rm_item_code": "Sub Contracted Raw Material 4",
- "item_name": "_Test Item",
- "qty": 250,
- "warehouse": "_Test Warehouse - _TC",
- "stock_uom": "Nos",
- },
- ]
-
- # Raw Materials transfer entry from stores to supplier's warehouse
- rm_item_string = json.dumps(rm_items)
- se = frappe.get_doc(make_subcontract_transfer_entry(po.name, rm_item_string))
- se.submit()
-
- # Test po_detail field has value or not
- for item_row in se.items:
- self.assertEqual(item_row.po_detail, po.supplied_items[item_row.idx - 1].name)
-
- po_doc = frappe.get_doc("Purchase Order", po.name)
- for row in po_doc.supplied_items:
- # Valid that whether transferred quantity is matching with supplied qty or not in the purchase order
- self.assertEqual(row.supplied_qty, 250.0)
-
- update_backflush_based_on("BOM")
-
def test_advance_payment_entry_unlink_against_purchase_order(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
@@ -1211,50 +805,6 @@
return pr
-def make_subcontracted_item(**args):
- from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
-
- args = frappe._dict(args)
-
- if not frappe.db.exists("Item", args.item_code):
- make_item(
- args.item_code,
- {
- "is_stock_item": 1,
- "is_sub_contracted_item": 1,
- "has_batch_no": args.get("has_batch_no") or 0,
- },
- )
-
- if not args.raw_materials:
- if not frappe.db.exists("Item", "Test Extra Item 1"):
- make_item(
- "Test Extra Item 1",
- {
- "is_stock_item": 1,
- },
- )
-
- if not frappe.db.exists("Item", "Test Extra Item 2"):
- make_item(
- "Test Extra Item 2",
- {
- "is_stock_item": 1,
- },
- )
-
- args.raw_materials = ["_Test FG Item", "Test Extra Item 1"]
-
- if not frappe.db.get_value("BOM", {"item": args.item_code}, "name"):
- make_bom(item=args.item_code, raw_materials=args.get("raw_materials"))
-
-
-def update_backflush_based_on(based_on):
- doc = frappe.get_doc("Buying Settings")
- doc.backflush_raw_materials_of_subcontract_based_on = based_on
- doc.save()
-
-
def get_same_items():
return [
{
@@ -1341,4 +891,4 @@
test_dependencies = ["BOM", "Item Price"]
-test_records = frappe.get_test_records("Purchase Order")
+test_records = frappe.get_test_records("Purchase Order")
\ No newline at end of file
diff --git a/erpnext/buying/doctype/purchase_order/test_records.json b/erpnext/buying/doctype/purchase_order/test_records.json
index 896050c..4df994a 100644
--- a/erpnext/buying/doctype/purchase_order/test_records.json
+++ b/erpnext/buying/doctype/purchase_order/test_records.json
@@ -8,40 +8,6 @@
"doctype": "Purchase Order",
"base_grand_total": 5000.0,
"grand_total": 5000.0,
- "is_subcontracted": 1,
- "naming_series": "_T-Purchase Order-",
- "base_net_total": 5000.0,
- "items": [
- {
- "base_amount": 5000.0,
- "conversion_factor": 1.0,
- "description": "_Test FG Item",
- "doctype": "Purchase Order Item",
- "item_code": "_Test FG Item",
- "item_name": "_Test FG Item",
- "parentfield": "items",
- "qty": 10.0,
- "rate": 500.0,
- "schedule_date": "2013-03-01",
- "stock_uom": "_Test UOM",
- "uom": "_Test UOM",
- "warehouse": "_Test Warehouse - _TC"
- }
- ],
- "supplier": "_Test Supplier",
- "supplier_name": "_Test Supplier",
- "transaction_date": "2013-02-12",
- "schedule_date": "2013-02-13"
- },
- {
- "advance_paid": 0.0,
- "buying_price_list": "_Test Price List",
- "company": "_Test Company",
- "conversion_rate": 1.0,
- "currency": "INR",
- "doctype": "Purchase Order",
- "base_grand_total": 5000.0,
- "grand_total": 5000.0,
"is_subcontracted": 0,
"naming_series": "_T-Purchase Order-",
"base_net_total": 5000.0,
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
index 7f797cf..12eef79 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -574,7 +574,6 @@
"read_only": 1
},
{
- "depends_on": "eval:parent.is_subcontracted",
"fieldname": "bom",
"fieldtype": "Link",
"label": "BOM",
@@ -584,7 +583,6 @@
},
{
"default": "0",
- "depends_on": "eval:parent.is_subcontracted",
"fieldname": "include_exploded_items",
"fieldtype": "Check",
"hidden": 1,