feat: purchase order against sales order (#17975)
* feat: purchase order against sales order
* fix: remove unwanted checks
* fix:Related tests
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index f4bb070..26ca7c6 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -107,7 +107,6 @@
refresh: function(doc, dt, dn) {
var me = this;
this._super();
- var allow_purchase = false;
var allow_delivery = false;
if(doc.docstatus==1) {
@@ -129,28 +128,9 @@
me.frm.cscript.update_status('Re-open', 'Draft')
}, __("Status"));
}
- }
+ }
if(doc.status !== 'Closed') {
if(doc.status !== 'On Hold') {
- for (var i in this.frm.doc.items) {
- var item = this.frm.doc.items[i];
- if(item.delivered_by_supplier === 1 || item.supplier){
- if(item.qty > flt(item.ordered_qty)
- && item.qty > flt(item.delivered_qty)) {
- allow_purchase = true;
- }
- }
-
- if (item.delivered_by_supplier===0) {
- if(item.qty > flt(item.delivered_qty)) {
- allow_delivery = true;
- }
- }
-
- if (allow_delivery && allow_purchase) {
- break;
- }
- }
if (this.frm.has_perm("submit")) {
if(flt(doc.per_delivered, 6) < 100 || flt(doc.per_billed) < 100) {
@@ -180,9 +160,8 @@
}
// make purchase order
- if(flt(doc.per_delivered, 6) < 100 && allow_purchase) {
this.frm.add_custom_button(__('Purchase Order'), () => this.make_purchase_order(), __('Create'));
- }
+
// maintenance
if(flt(doc.per_delivered, 2) < 100 &&
["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1) {
@@ -543,6 +522,42 @@
filters: {'parent': me.frm.doc.name}
}
}},
+ {fieldname: 'items_for_po', fieldtype: 'Table', label: 'Select Items',
+ fields: [
+ {
+ fieldtype:'Data',
+ fieldname:'item_code',
+ label: __('Item'),
+ read_only:1,
+ in_list_view:1
+ },
+ {
+ fieldtype:'Data',
+ fieldname:'item_name',
+ label: __('Item name'),
+ read_only:1,
+ in_list_view:1
+ },
+ {
+ fieldtype:'Float',
+ fieldname:'qty',
+ label: __('Quantity'),
+ read_only: 1,
+ in_list_view:1
+ },
+ {
+ fieldtype:'Link',
+ read_only:1,
+ fieldname:'uom',
+ label: __('UOM'),
+ in_list_view:1
+ }
+ ],
+ data: cur_frm.doc.items,
+ get_data: function() {
+ return cur_frm.doc.items
+ }
+ },
{"fieldtype": "Button", "label": __('Create Purchase Order'), "fieldname": "make_purchase_order", "cssClass": "btn-primary"},
]
@@ -550,13 +565,22 @@
dialog.fields_dict.make_purchase_order.$input.click(function() {
var args = dialog.get_values();
+ let selected_items = dialog.fields_dict.items_for_po.grid.get_selected_children()
+ if(selected_items.length == 0) {
+ frappe.throw({message: 'Please select Item form Table', title: __('Message'), indicator:'blue'})
+ }
+ let selected_items_list = []
+ for(let i in selected_items){
+ selected_items_list.push(selected_items[i].item_code)
+ }
dialog.hide();
return frappe.call({
type: "GET",
- method: "erpnext.selling.doctype.sales_order.sales_order.make_purchase_order_for_drop_shipment",
+ method: "erpnext.selling.doctype.sales_order.sales_order.make_purchase_order",
args: {
"source_name": me.frm.doc.name,
- "for_supplier": args.supplier
+ "for_supplier": args.supplier,
+ "selected_items": selected_items_list
},
freeze: true,
callback: function(r) {
@@ -576,6 +600,8 @@
}
})
});
+ dialog.get_field("items_for_po").grid.only_sortable()
+ dialog.get_field("items_for_po").refresh()
dialog.show();
},
hold_sales_order: function(){
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 493da99..8ad3bf0 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -764,7 +764,10 @@
return data
@frappe.whitelist()
-def make_purchase_order_for_drop_shipment(source_name, for_supplier=None, target_doc=None):
+def make_purchase_order(source_name, for_supplier=None, selected_items=[], target_doc=None):
+ if isinstance(selected_items, string_types):
+ selected_items = json.loads(selected_items)
+
def set_missing_values(source, target):
target.supplier = supplier
target.apply_discount_on = ""
@@ -843,7 +846,7 @@
"price_list_rate"
],
"postprocess": update_item,
- "condition": lambda doc: doc.ordered_qty < doc.qty and doc.supplier == supplier
+ "condition": lambda doc: doc.ordered_qty < doc.qty and doc.supplier == supplier and doc.item_code in selected_items
}
}, target_doc, set_missing_values)
if not for_supplier:
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index e7697e2..569c53f 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -449,7 +449,7 @@
frappe.db.set_value("Stock Settings", None, "auto_insert_price_list_rate_if_missing", 1)
def test_drop_shipping(self):
- from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_drop_shipment
+ from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order
from erpnext.buying.doctype.purchase_order.purchase_order import update_status
make_stock_entry(target="_Test Warehouse - _TC", qty=10, rate=100)
@@ -495,7 +495,7 @@
so = make_sales_order(item_list=so_items, do_not_submit=True)
so.submit()
- po = make_purchase_order_for_drop_shipment(so.name, '_Test Supplier')
+ po = make_purchase_order(so.name, '_Test Supplier', selected_items=[so_items[0]['item_code']])
po.submit()
dn = create_dn_against_so(so.name, delivered_qty=1)