mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-28 17:34:47 +00:00
refactor!: Purchase Order
This commit is contained in:
@@ -7,17 +7,6 @@ frappe.provide("erpnext.accounts.dimensions");
|
|||||||
|
|
||||||
frappe.ui.form.on("Purchase Order", {
|
frappe.ui.form.on("Purchase Order", {
|
||||||
setup: function(frm) {
|
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',
|
frm.set_indicator_formatter('item_code',
|
||||||
function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
|
function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
|
||||||
|
|
||||||
@@ -59,39 +48,6 @@ frappe.ui.form.on("Purchase Order", {
|
|||||||
frm.set_value("tax_withholding_category", frm.supplier_tds);
|
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", {
|
frappe.ui.form.on("Purchase Order Item", {
|
||||||
@@ -112,13 +68,11 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
|
|||||||
this.frm.custom_make_buttons = {
|
this.frm.custom_make_buttons = {
|
||||||
'Purchase Receipt': 'Purchase Receipt',
|
'Purchase Receipt': 'Purchase Receipt',
|
||||||
'Purchase Invoice': 'Purchase Invoice',
|
'Purchase Invoice': 'Purchase Invoice',
|
||||||
'Stock Entry': 'Material to Supplier',
|
|
||||||
'Payment Entry': 'Payment',
|
'Payment Entry': 'Payment',
|
||||||
'Subcontracting Order': 'Subcontracting Order'
|
'Subcontracting Order': 'Subcontracting Order'
|
||||||
}
|
}
|
||||||
|
|
||||||
super.setup();
|
super.setup();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh(doc, cdt, cdn) {
|
refresh(doc, cdt, cdn) {
|
||||||
@@ -185,10 +139,6 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
|
|||||||
if (doc.status != "On Hold") {
|
if (doc.status != "On Hold") {
|
||||||
if(flt(doc.per_received) < 100 && allow_receipt) {
|
if(flt(doc.per_received) < 100 && allow_receipt) {
|
||||||
cur_frm.add_custom_button(__('Purchase Receipt'), this.make_purchase_receipt, __('Create'));
|
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) {
|
if (doc.is_subcontracted) {
|
||||||
cur_frm.add_custom_button(__('Subcontracting Order'), this.make_subcontracting_order, __('Create'));
|
cur_frm.add_custom_button(__('Subcontracting Order'), this.make_subcontracting_order, __('Create'));
|
||||||
}
|
}
|
||||||
@@ -258,142 +208,6 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
|
|||||||
set_schedule_date(this.frm);
|
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) {
|
make_inter_company_order(frm) {
|
||||||
frappe.model.open_mapped_doc({
|
frappe.model.open_mapped_doc({
|
||||||
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_inter_company_sales_order",
|
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('project').get_query = function(doc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
function set_schedule_date(frm) {
|
||||||
if(frm.doc.schedule_date){
|
if(frm.doc.schedule_date){
|
||||||
erpnext.utils.copy_value_in_all_rows(frm.doc, frm.doc.doctype, frm.doc.name, "items", "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.provide("erpnext.buying");
|
||||||
|
|
||||||
frappe.ui.form.on("Purchase Order", "is_subcontracted", function(frm) {
|
|
||||||
if (frm.doc.is_subcontracted) {
|
|
||||||
erpnext.buying.get_default_bom(frm);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -24,7 +24,6 @@ from erpnext.controllers.buying_controller import BuyingController
|
|||||||
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
|
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.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.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"}
|
form_grid_templates = {"items": "templates/form_grid/item_grid.html"}
|
||||||
|
|
||||||
@@ -70,7 +69,6 @@ class PurchaseOrder(BuyingController):
|
|||||||
self.validate_for_subcontracting()
|
self.validate_for_subcontracting()
|
||||||
self.validate_minimum_order_qty()
|
self.validate_minimum_order_qty()
|
||||||
self.validate_fg_item_for_subcontracting()
|
self.validate_fg_item_for_subcontracting()
|
||||||
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(
|
||||||
self.doctype, self.supplier, self.company, self.inter_company_order_reference
|
self.doctype, self.supplier, self.company, self.inter_company_order_reference
|
||||||
@@ -307,9 +305,6 @@ class PurchaseOrder(BuyingController):
|
|||||||
self.set_status(update=True, status=status)
|
self.set_status(update=True, status=status)
|
||||||
self.update_requested_qty()
|
self.update_requested_qty()
|
||||||
self.update_ordered_qty()
|
self.update_ordered_qty()
|
||||||
if self.is_subcontracted:
|
|
||||||
self.update_reserved_qty_for_subcontract()
|
|
||||||
|
|
||||||
self.notify_update()
|
self.notify_update()
|
||||||
clear_doctype_notifications(self)
|
clear_doctype_notifications(self)
|
||||||
|
|
||||||
@@ -324,9 +319,6 @@ class PurchaseOrder(BuyingController):
|
|||||||
self.update_ordered_qty()
|
self.update_ordered_qty()
|
||||||
self.validate_budget()
|
self.validate_budget()
|
||||||
|
|
||||||
if self.is_subcontracted:
|
|
||||||
self.update_reserved_qty_for_subcontract()
|
|
||||||
|
|
||||||
frappe.get_doc("Authorization Control").validate_approving_authority(
|
frappe.get_doc("Authorization Control").validate_approving_authority(
|
||||||
self.doctype, self.company, self.base_grand_total
|
self.doctype, self.company, self.base_grand_total
|
||||||
)
|
)
|
||||||
@@ -344,9 +336,6 @@ class PurchaseOrder(BuyingController):
|
|||||||
if self.has_drop_ship_item():
|
if self.has_drop_ship_item():
|
||||||
self.update_delivered_qty_in_sales_order()
|
self.update_delivered_qty_in_sales_order()
|
||||||
|
|
||||||
if self.is_subcontracted:
|
|
||||||
self.update_reserved_qty_for_subcontract()
|
|
||||||
|
|
||||||
self.check_on_hold_or_closed_status()
|
self.check_on_hold_or_closed_status()
|
||||||
|
|
||||||
frappe.db.set(self, "status", "Cancelled")
|
frappe.db.set(self, "status", "Cancelled")
|
||||||
@@ -416,12 +405,6 @@ class PurchaseOrder(BuyingController):
|
|||||||
if item.delivered_by_supplier == 1:
|
if item.delivered_by_supplier == 1:
|
||||||
item.received_qty = item.qty
|
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):
|
def update_receiving_percentage(self):
|
||||||
total_qty, received_qty = 0.0, 0.0
|
total_qty, received_qty = 0.0, 0.0
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
@@ -599,78 +582,6 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions
|
|||||||
return doc
|
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):
|
def get_list_context(context=None):
|
||||||
from erpnext.controllers.website_list_for_contact import get_list_context
|
from erpnext.controllers.website_list_for_contact import get_list_context
|
||||||
|
|
||||||
@@ -700,67 +611,6 @@ def make_inter_company_sales_order(source_name, target_doc=None):
|
|||||||
return make_inter_company_transaction("Purchase Order", source_name, target_doc)
|
return make_inter_company_transaction("Purchase Order", source_name, target_doc)
|
||||||
|
|
||||||
|
|
||||||
@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()
|
@frappe.whitelist()
|
||||||
def make_subcontracting_order(source_name, target_doc=None):
|
def make_subcontracting_order(source_name, target_doc=None):
|
||||||
return get_mapped_subcontracting_order(source_name, target_doc)
|
return get_mapped_subcontracting_order(source_name, target_doc)
|
||||||
|
|||||||
@@ -13,9 +13,6 @@ from erpnext.buying.doctype.purchase_order.purchase_order import (
|
|||||||
make_purchase_invoice as make_pi_from_po,
|
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_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.controllers.accounts_controller import update_child_qty_rate
|
||||||
from erpnext.manufacturing.doctype.blanket_order.test_blanket_order import make_blanket_order
|
from erpnext.manufacturing.doctype.blanket_order.test_blanket_order import make_blanket_order
|
||||||
from erpnext.stock.doctype.item.test_item import make_item
|
from erpnext.stock.doctype.item.test_item import make_item
|
||||||
@@ -24,7 +21,6 @@ from erpnext.stock.doctype.material_request.test_material_request import make_ma
|
|||||||
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
|
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
|
||||||
make_purchase_invoice as make_pi_from_pr,
|
make_purchase_invoice as make_pi_from_pr,
|
||||||
)
|
)
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
|
||||||
|
|
||||||
|
|
||||||
class TestPurchaseOrder(FrappeTestCase):
|
class TestPurchaseOrder(FrappeTestCase):
|
||||||
@@ -389,31 +385,6 @@ class TestPurchaseOrder(FrappeTestCase):
|
|||||||
new_item_with_tax.delete()
|
new_item_with_tax.delete()
|
||||||
frappe.get_doc("Item Tax Template", "Test Update Items Template - _TC").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):
|
def test_update_qty(self):
|
||||||
po = create_purchase_order()
|
po = create_purchase_order()
|
||||||
|
|
||||||
@@ -572,10 +543,6 @@ class TestPurchaseOrder(FrappeTestCase):
|
|||||||
)
|
)
|
||||||
automatically_fetch_payment_terms(enable=0)
|
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):
|
def test_warehouse_company_validation(self):
|
||||||
from erpnext.stock.utils import InvalidWarehouseCompany
|
from erpnext.stock.utils import InvalidWarehouseCompany
|
||||||
|
|
||||||
@@ -740,379 +707,6 @@ class TestPurchaseOrder(FrappeTestCase):
|
|||||||
pi.insert()
|
pi.insert()
|
||||||
self.assertTrue(pi.get("payment_schedule"))
|
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):
|
def test_advance_payment_entry_unlink_against_purchase_order(self):
|
||||||
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
|
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
|
||||||
|
|
||||||
@@ -1211,50 +805,6 @@ def make_pr_against_po(po, received_qty=0):
|
|||||||
return pr
|
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():
|
def get_same_items():
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -1341,4 +891,4 @@ def get_requested_qty(item_code="_Test Item", warehouse="_Test Warehouse - _TC")
|
|||||||
|
|
||||||
test_dependencies = ["BOM", "Item Price"]
|
test_dependencies = ["BOM", "Item Price"]
|
||||||
|
|
||||||
test_records = frappe.get_test_records("Purchase Order")
|
test_records = frappe.get_test_records("Purchase Order")
|
||||||
@@ -1,38 +1,4 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
"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": 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,
|
"advance_paid": 0.0,
|
||||||
"buying_price_list": "_Test Price List",
|
"buying_price_list": "_Test Price List",
|
||||||
|
|||||||
@@ -574,7 +574,6 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:parent.is_subcontracted",
|
|
||||||
"fieldname": "bom",
|
"fieldname": "bom",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "BOM",
|
"label": "BOM",
|
||||||
@@ -584,7 +583,6 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"depends_on": "eval:parent.is_subcontracted",
|
|
||||||
"fieldname": "include_exploded_items",
|
"fieldname": "include_exploded_items",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
|
|||||||
Reference in New Issue
Block a user