Merge pull request #7657 from rmehta/po-from-so
[enhance] production order from sales order
This commit is contained in:
commit
259489572d
File diff suppressed because it is too large
Load Diff
@ -4,11 +4,23 @@
|
||||
{% include 'erpnext/selling/sales_common.js' %}
|
||||
|
||||
frappe.ui.form.on("Sales Order", {
|
||||
setup: function(frm) {
|
||||
$.extend(frm.cscript, new erpnext.selling.SalesOrderController({frm: frm}));
|
||||
},
|
||||
onload: function(frm) {
|
||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||
return erpnext.queries.warehouse(frm.doc);
|
||||
});
|
||||
|
||||
frm.set_query('project', function(doc, cdt, cdn) {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.get_project_name",
|
||||
filters: {
|
||||
'customer': doc.customer
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// formatter for material request item
|
||||
frm.set_indicator_formatter('item_code',
|
||||
function(doc) { return (doc.qty<=doc.delivered_qty) ? "green" : "orange" })
|
||||
@ -17,6 +29,7 @@ frappe.ui.form.on("Sales Order", {
|
||||
|
||||
erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
|
||||
refresh: function(doc, dt, dn) {
|
||||
var me = this;
|
||||
this._super();
|
||||
var allow_purchase = false;
|
||||
var allow_delivery = false;
|
||||
@ -24,8 +37,8 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
if(doc.docstatus==1) {
|
||||
if(doc.status != 'Closed') {
|
||||
|
||||
for (var i in cur_frm.doc.items) {
|
||||
var item = cur_frm.doc.items[i];
|
||||
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)) {
|
||||
@ -47,55 +60,69 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
if (this.frm.has_perm("submit")) {
|
||||
// close
|
||||
if(flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed) < 100) {
|
||||
cur_frm.add_custom_button(__('Close'), this.close_sales_order, __("Status"))
|
||||
this.frm.add_custom_button(__('Close'),
|
||||
function() { me.close_sales_order() }, __("Status"))
|
||||
}
|
||||
}
|
||||
|
||||
// delivery note
|
||||
if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && allow_delivery) {
|
||||
cur_frm.add_custom_button(__('Delivery'), this.make_delivery_note, __("Make"));
|
||||
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
|
||||
this.frm.add_custom_button(__('Delivery'),
|
||||
function() { me.make_delivery_note() }, __("Make"));
|
||||
this.frm.add_custom_button(__('Production Order'),
|
||||
function() { me.make_production_order() }, __("Make"));
|
||||
|
||||
this.frm.page.set_inner_btn_group_as_primary(__("Make"));
|
||||
}
|
||||
|
||||
// sales invoice
|
||||
if(flt(doc.per_billed, 2) < 100) {
|
||||
cur_frm.add_custom_button(__('Invoice'), this.make_sales_invoice, __("Make"));
|
||||
this.frm.add_custom_button(__('Invoice'),
|
||||
function() { me.make_sales_invoice() }, __("Make"));
|
||||
}
|
||||
|
||||
// material request
|
||||
if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1
|
||||
&& flt(doc.per_delivered, 2) < 100) {
|
||||
cur_frm.add_custom_button(__('Material Request'), this.make_material_request, __("Make"));
|
||||
this.frm.add_custom_button(__('Material Request'),
|
||||
function() { me.make_material_request() }, __("Make"));
|
||||
}
|
||||
|
||||
// make purchase order
|
||||
if(flt(doc.per_delivered, 2) < 100 && allow_purchase) {
|
||||
cur_frm.add_custom_button(__('Purchase Order'), cur_frm.cscript.make_purchase_order, __("Make"));
|
||||
this.frm.add_custom_button(__('Purchase Order'),
|
||||
function() { me.make_purchase_order() }, __("Make"));
|
||||
}
|
||||
|
||||
// payment request
|
||||
if(flt(doc.per_billed)==0) {
|
||||
cur_frm.add_custom_button(__('Payment Request'), this.make_payment_request, __("Make"));
|
||||
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __("Make"));
|
||||
this.frm.add_custom_button(__('Payment Request'),
|
||||
function() { me.make_payment_request() }, __("Make"));
|
||||
this.frm.add_custom_button(__('Payment'),
|
||||
function() { me.make_payment_entry() }, __("Make"));
|
||||
}
|
||||
|
||||
// maintenance
|
||||
if(flt(doc.per_delivered, 2) < 100 &&
|
||||
["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1) {
|
||||
cur_frm.add_custom_button(__('Maintenance Visit'), this.make_maintenance_visit, __("Make"));
|
||||
cur_frm.add_custom_button(__('Maintenance Schedule'), this.make_maintenance_schedule, __("Make"));
|
||||
this.frm.add_custom_button(__('Maintenance Visit'),
|
||||
function() { me.make_maintenance_visit() }, __("Make"));
|
||||
this.frm.add_custom_button(__('Maintenance Schedule'),
|
||||
function() { me.make_maintenance_schedule() }, __("Make"));
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
if (this.frm.has_perm("submit")) {
|
||||
// un-close
|
||||
cur_frm.add_custom_button(__('Re-open'), cur_frm.cscript['Unclose Sales Order'], __("Status"));
|
||||
this.frm.add_custom_button(__('Re-open'), function() {
|
||||
me.frm.cscript.update_status('Re-open', 'Draft')
|
||||
}, __("Status"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.frm.doc.docstatus===0) {
|
||||
cur_frm.add_custom_button(__('Quotation'),
|
||||
this.frm.add_custom_button(__('Quotation'),
|
||||
function() {
|
||||
erpnext.utils.map_current_doc({
|
||||
method: "erpnext.selling.doctype.quotation.quotation.make_sales_order",
|
||||
@ -103,9 +130,9 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
get_query_filters: {
|
||||
docstatus: 1,
|
||||
status: ["!=", "Lost"],
|
||||
order_type: cur_frm.doc.order_type,
|
||||
customer: cur_frm.doc.customer || undefined,
|
||||
company: cur_frm.doc.company
|
||||
order_type: me.frm.doc.order_type,
|
||||
customer: me.frm.doc.customer || undefined,
|
||||
company: me.frm.doc.company
|
||||
}
|
||||
})
|
||||
}, __("Get items from"));
|
||||
@ -114,6 +141,82 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
this.order_type(doc);
|
||||
},
|
||||
|
||||
make_production_order() {
|
||||
var me = this;
|
||||
this.frm.call({
|
||||
doc: this.frm.doc,
|
||||
method: 'get_production_order_items',
|
||||
callback: function(r) {
|
||||
if(!r.message.every(function(d) { return !!d.bom })) {
|
||||
frappe.msgprint({
|
||||
title: __('Production Order not created'),
|
||||
message: __('No Items with Bill of Materials to Manufacture'),
|
||||
indicator: 'orange'
|
||||
});
|
||||
return;
|
||||
}
|
||||
else if(!r.message.every(function(d) { return !!d.pending_qty })) {
|
||||
frappe.msgprint({
|
||||
title: __('Production Order not created'),
|
||||
message: __('Production Order already created for all items with BOM'),
|
||||
indicator: 'orange'
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
var fields = [
|
||||
{fieldtype:'Table', fieldname: 'items',
|
||||
description: __('Select BOM and Qty for Production'),
|
||||
fields: [
|
||||
{fieldtype:'Read Only', fieldname:'item_code',
|
||||
label: __('Item Code'), in_list_view:1},
|
||||
{fieldtype:'Link', fieldname:'bom', options: 'BOM',
|
||||
label: __('Select BOM'), in_list_view:1, get_query: function(doc) {
|
||||
return {filters: {item: doc.item_code}};
|
||||
}},
|
||||
{fieldtype:'Float', fieldname:'pending_qty',
|
||||
label: __('Qty'), in_list_view:1},
|
||||
],
|
||||
get_data: function() {
|
||||
return r.message
|
||||
}
|
||||
}
|
||||
]
|
||||
var d = new frappe.ui.Dialog({
|
||||
title: __('Select Items to Manufacture'),
|
||||
fields: fields,
|
||||
primary_action: function() {
|
||||
data = d.get_values();
|
||||
me.frm.call({
|
||||
method: 'make_production_orders',
|
||||
args: {
|
||||
items: data,
|
||||
company: me.frm.doc.company,
|
||||
sales_order: me.frm.docname,
|
||||
project: me.frm.project
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
frappe.msgprint({
|
||||
message: __('Production Orders Created: {0}',
|
||||
[r.message.map(function(d) {
|
||||
return repl('<a href="#Form/Production Order/%(name)s">%(name)s</a>', {name:d})
|
||||
}).join(', ')]),
|
||||
indicator: 'green'
|
||||
})
|
||||
}
|
||||
d.hide();
|
||||
}
|
||||
});
|
||||
},
|
||||
primary_action_label: __('Make')
|
||||
});
|
||||
d.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
order_type: function() {
|
||||
this.frm.toggle_reqd("delivery_date", this.frm.doc.order_type == "Sales");
|
||||
},
|
||||
@ -125,39 +228,40 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
make_material_request: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_material_request",
|
||||
frm: cur_frm
|
||||
frm: this.frm
|
||||
})
|
||||
},
|
||||
|
||||
make_delivery_note: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
|
||||
frm: cur_frm
|
||||
frm: this.frm
|
||||
})
|
||||
},
|
||||
|
||||
make_sales_invoice: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice",
|
||||
frm: cur_frm
|
||||
frm: this.frm
|
||||
})
|
||||
},
|
||||
|
||||
make_maintenance_schedule: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_schedule",
|
||||
frm: cur_frm
|
||||
frm: this.frm
|
||||
})
|
||||
},
|
||||
|
||||
make_maintenance_visit: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit",
|
||||
frm: cur_frm
|
||||
frm: this.frm
|
||||
})
|
||||
},
|
||||
|
||||
make_purchase_order: function(){
|
||||
var me = this;
|
||||
var dialog = new frappe.ui.Dialog({
|
||||
title: __("For Supplier"),
|
||||
fields: [
|
||||
@ -165,7 +269,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
"get_query": function () {
|
||||
return {
|
||||
query:"erpnext.selling.doctype.sales_order.sales_order.get_supplier",
|
||||
filters: {'parent': cur_frm.doc.name}
|
||||
filters: {'parent': me.frm.doc.name}
|
||||
}
|
||||
}, "reqd": 1 },
|
||||
{"fieldtype": "Button", "label": __("Make Purchase Order"), "fieldname": "make_purchase_order", "cssClass": "btn-primary"},
|
||||
@ -180,7 +284,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
type: "GET",
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_purchase_order_for_drop_shipment",
|
||||
args: {
|
||||
"source_name": cur_frm.doc.name,
|
||||
"source_name": me.frm.doc.name,
|
||||
"for_supplier": args.supplier
|
||||
},
|
||||
freeze: true,
|
||||
@ -195,44 +299,25 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
dialog.show();
|
||||
},
|
||||
close_sales_order: function(){
|
||||
cur_frm.cscript.update_status("Close", "Closed")
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// for backward compatibility: combine new and previous states
|
||||
$.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm}));
|
||||
|
||||
cur_frm.fields_dict['project'].get_query = function(doc, cdt, cdn) {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.get_project_name",
|
||||
filters: {
|
||||
'customer': doc.customer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.update_status = function(label, status){
|
||||
var doc = cur_frm.doc;
|
||||
this.frm.cscript.update_status("Close", "Closed")
|
||||
},
|
||||
update_status: function(label, status){
|
||||
var doc = this.frm.doc;
|
||||
frappe.ui.form.is_saving = true;
|
||||
frappe.call({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.update_status",
|
||||
args: {status: status, name: doc.name},
|
||||
callback: function(r){
|
||||
cur_frm.reload_doc();
|
||||
this.frm.reload_doc();
|
||||
},
|
||||
always: function() {
|
||||
frappe.ui.form.is_saving = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.cscript['Unclose Sales Order'] = function() {
|
||||
cur_frm.cscript.update_status('Re-open', 'Draft')
|
||||
}
|
||||
|
||||
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
},
|
||||
on_submit: function(doc, cdt, cdn) {
|
||||
if(cint(frappe.boot.notification_settings.sales_order)) {
|
||||
cur_frm.email_doc(frappe.boot.notification_settings.sales_order_message);
|
||||
this.frm.email_doc(frappe.boot.notification_settings.sales_order_message);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@ -304,6 +304,24 @@ class SalesOrder(SellingController):
|
||||
self.indicator_color = "green"
|
||||
self.indicator_title = _("Paid")
|
||||
|
||||
def get_production_order_items(self):
|
||||
'''Returns items with BOM that already do not have a linked production order'''
|
||||
items = []
|
||||
for i in self.packed_items or self.items:
|
||||
bom = frappe.get_all('BOM', dict(item=i.item_code, is_active=True),
|
||||
order_by='is_default desc')
|
||||
bom = bom[0].name if bom else None
|
||||
items.append(dict(
|
||||
item_code= i.item_code,
|
||||
bom = bom,
|
||||
warehouse = i.warehouse,
|
||||
pending_qty= i.qty - flt(frappe.db.sql('''select sum(qty) from `tabProduction Order`
|
||||
where production_item=%s and sales_order=%s''', (i.item_code, self.name))[0][0])
|
||||
))
|
||||
|
||||
return items
|
||||
|
||||
|
||||
def on_recurring(self, reference_doc):
|
||||
mcount = month_map[reference_doc.recurring_type]
|
||||
self.set("delivery_date", get_next_date(reference_doc.delivery_date, mcount,
|
||||
@ -652,6 +670,27 @@ def get_supplier(doctype, txt, searchfield, start, page_len, filters):
|
||||
'parent': filters.get('parent')
|
||||
})
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_production_orders(items, sales_order, company, project=None):
|
||||
'''Make Production Orders against the given Sales Order for the given `items`'''
|
||||
items = json.loads(items).get('items')
|
||||
out = []
|
||||
|
||||
for i in items:
|
||||
production_order = frappe.get_doc(dict(
|
||||
doctype='Production Order',
|
||||
production_item=i['item_code'],
|
||||
bom_no=i['bom'],
|
||||
qty=i['pending_qty'],
|
||||
company=company,
|
||||
sales_order=sales_order,
|
||||
project=project,
|
||||
fg_warehouse=i['warehouse']
|
||||
)).insert()
|
||||
out.append(production_order)
|
||||
|
||||
return [p.name for p in out]
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_status(status, name):
|
||||
so = frappe.get_doc("Sales Order", name)
|
||||
|
||||
@ -41,6 +41,10 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.frm.set_indicator_formatter('item_code',
|
||||
function(doc) { return (doc.qty<=doc.actual_qty) ? "green" : "orange" })
|
||||
|
||||
},
|
||||
|
||||
onload_post_render: function() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user