[Fixes] Drop Shipping

This commit is contained in:
Saurabh 2015-10-19 14:17:52 +05:30
parent 556536615e
commit c6dbe70256
12 changed files with 337 additions and 95 deletions

View File

@ -50,6 +50,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
if(doc.update_stock) this.show_stock_ledger();
if(doc.docstatus==1 && !doc.is_return) {
var flag_delivery_note = false;
flag_delivery_note = cur_frm.doc.items.some(function(item){
return item.is_drop_ship ? true : false;
})
cur_frm.add_custom_button(doc.update_stock ? __('Sales Return') : __('Credit Note'),
this.make_sales_return);
@ -61,7 +68,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
return item.delivery_note ? true : false;
});
if(!from_delivery_note) {
if(!from_delivery_note && flag_delivery_note) {
cur_frm.add_custom_button(__('Delivery'), cur_frm.cscript['Make Delivery Note']).addClass("btn-primary");
}
}

View File

@ -667,7 +667,8 @@ def make_delivery_note(source_name, target_doc=None):
"sales_order": "against_sales_order",
"so_detail": "so_detail"
},
"postprocess": update_item
"postprocess": update_item,
"condition": lambda doc: doc.is_drop_ship!=1
},
"Sales Taxes and Charges": {
"doctype": "Sales Taxes and Charges",

View File

@ -680,6 +680,94 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "drop_ship",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Drop Ship",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "is_drop_ship",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Is Drop Ship Item",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break_33",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "supplier",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Supplier",
"no_copy": 0,
"options": "Supplier",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,

View File

@ -37,6 +37,7 @@ status_map = {
["Completed", "eval:self.order_type == 'Maintenance' and self.per_billed == 100 and self.docstatus == 1"],
["Stopped", "eval:self.status=='Stopped'"],
["Cancelled", "eval:self.docstatus==2"],
["Closed", "eval:self.status=='Closed'"],
],
"Purchase Order": [
["Draft", None],
@ -210,6 +211,16 @@ class StatusUpdater(Document):
def _update_percent_field(self, args):
"""Update percent field in parent transaction"""
unique_transactions = set([d.get(args['percent_join_field']) for d in self.get_all_children(args['source_dt'])])
args["drop_ship_cond"] = ''
if getattr(self, "drop_ship", None):
if self.drop_ship == 1:
args["drop_ship_cond"] = " and is_drop_ship=1 "
else:
if self.doctype=="Delivery Note":
args["drop_ship_cond"] = " and is_drop_ship!=1 "
for name in unique_transactions:
if not name:
@ -223,7 +234,7 @@ class StatusUpdater(Document):
set %(target_parent_field)s = round((select sum(if(%(target_ref_field)s >
ifnull(%(target_field)s, 0), %(target_field)s,
%(target_ref_field)s))/sum(%(target_ref_field)s)*100
from `tab%(target_dt)s` where parent="%(name)s"), 2) %(set_modified)s
from `tab%(target_dt)s` where parent="%(name)s" %(drop_ship_cond)s), 2) %(set_modified)s
where name='%(name)s'""" % args)
# update field

View File

@ -15,9 +15,20 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
refresh: function(doc, dt, dn) {
this._super();
this.frm.dashboard.reset();
var flag_drop_ship = false;
var flag_delivery_note = false;
if(doc.docstatus==1) {
if(doc.status != 'Stopped') {
if(doc.status != 'Stopped' && doc.status != 'Closed') {
$.each(cur_frm.doc.items, function(i, item){
if(item.is_drop_ship == 1){
flag_drop_ship = true;
}
else{
flag_delivery_note = true;
}
})
// cur_frm.dashboard.add_progress(cint(doc.per_delivered) + __("% Delivered"),
// doc.per_delivered);
@ -25,7 +36,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
// doc.per_billed);
// indent
if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && doc.drop_ship!=1)
if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1)
cur_frm.add_custom_button(__('Material Request'), this.make_material_request);
if(flt(doc.per_billed)==0) {
@ -33,30 +44,36 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
}
// stop
if(flt(doc.per_delivered, 2) < 100 || doc.per_billed < 100)
cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Sales Order'])
// maintenance
if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1 && doc.drop_ship!=1) {
cur_frm.add_custom_button(__('Maint. Visit'), this.make_maintenance_visit);
cur_frm.add_custom_button(__('Maint. Schedule'), this.make_maintenance_schedule);
if((flt(doc.per_delivered, 2) < 100 && flag_delivery_note) || doc.per_billed < 100
|| (flt(doc.per_ordered,2) < 100 && flag_drop_ship)){
cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Sales Order'])
}
cur_frm.add_custom_button(__('Close'), cur_frm.cscript['Close Sales Order'])
// delivery note
if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && doc.drop_ship!=1)
cur_frm.add_custom_button(__('Delivery'), this.make_delivery_note).addClass("btn-primary");
// maintenance
if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1) {
cur_frm.add_custom_button(__('Maint. Visit'), this.make_maintenance_visit);
cur_frm.add_custom_button(__('Maint. Schedule'), this.make_maintenance_schedule);
}
// sales invoice
if(flt(doc.per_billed, 2) < 100) {
cur_frm.add_custom_button(__('Invoice'), this.make_sales_invoice).addClass("btn-primary");
}
if(doc.drop_ship==1 && flt(doc.per_ordered, 2) < 100)
cur_frm.add_custom_button(__('Make Shipment'), cur_frm.cscript.make_drop_shipment);
// delivery note
if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && flag_delivery_note)
cur_frm.add_custom_button(__('Delivery'), this.make_delivery_note).addClass("btn-primary");
// sales invoice
if(flt(doc.per_billed, 2) < 100) {
cur_frm.add_custom_button(__('Invoice'), this.make_sales_invoice).addClass("btn-primary");
}
if(flt(doc.per_ordered, 2) < 100 && flag_drop_ship)
cur_frm.add_custom_button(__('Make Shipment'), cur_frm.cscript.make_drop_shipment).addClass("btn-primary");
} else {
// un-stop
cur_frm.add_custom_button(__('Unstop'), cur_frm.cscript['Unstop Sales Order']);
if( doc.status != 'Closed')
cur_frm.add_custom_button(__('Unstop'), cur_frm.cscript['Unstop Sales Order']);
}
}
@ -150,10 +167,36 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
});
},
make_drop_shipment: function(){
frappe.model.open_mapped_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_drop_shipment",
frm: cur_frm
})
var dialog = new frappe.ui.Dialog({
title: __("For Supplier"),
fields: [
{"fieldtype": "Link", "label": __("Supplier"), "fieldname": "supplier", "options":"Supplier",
"reqd": 1 },
{"fieldtype": "Button", "label": __("Proceed"), "fieldname": "proceed"},
]
});
dialog.fields_dict.proceed.$input.click(function() {
args = dialog.get_values();
if(!args) return;
dialog.hide();
return frappe.call({
type: "GET",
method: "erpnext.selling.doctype.sales_order.sales_order.make_drop_shipment",
args: {
"source_name": cur_frm.doc.name,
"for_supplier": args.supplier
},
freeze: true,
callback: function(r) {
if(!r.exc) {
var doc = frappe.model.sync(r.message);
frappe.set_route("Form", r.message.doctype, r.message.name);
}
}
})
});
dialog.show();
}
});
@ -185,7 +228,24 @@ cur_frm.cscript['Stop Sales Order'] = function() {
if (check) {
return $c('runserverobj', {
'method':'stop_sales_order',
'docs': doc
'docs': doc,
'arg': "Stopped"
}, function(r,rt) {
cur_frm.refresh();
});
}
}
cur_frm.cscript['Close Sales Order'] = function(){
var doc = cur_frm.doc;
var check = confirm(__("Are you sure you want to CLOSE ") + doc.name);
if (check) {
return $c('runserverobj', {
'method':'stop_sales_order',
'docs': doc,
'arg': "Closed"
}, function(r,rt) {
cur_frm.refresh();
});

View File

@ -234,7 +234,7 @@
"bold": 0,
"collapsible": 0,
"default": "Sales",
"depends_on": "eval:doc.drop_ship!=1",
"depends_on": "",
"fieldname": "order_type",
"fieldtype": "Select",
"hidden": 0,
@ -255,28 +255,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "drop_ship",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Drop Ship",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -404,7 +382,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "eval:doc.drop_ship!=1",
"depends_on": "",
"description": "",
"fieldname": "po_no",
"fieldtype": "Data",
@ -2001,7 +1979,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
"options": "\nDraft\nTo Deliver and Bill\nTo Bill\nTo Deliver\nCompleted\nStopped\nCancelled",
"options": "\nDraft\nTo Deliver and Bill\nTo Bill\nTo Deliver\nCompleted\nStopped\nCancelled\nClosed",
"permlevel": 0,
"print_hide": 1,
"read_only": 1,
@ -2600,7 +2578,7 @@
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"modified": "2015-10-15 15:27:34.592276",
"modified": "2015-10-19 11:34:16.668148",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",

View File

@ -214,9 +214,9 @@ class SalesOrder(SellingController):
if date_diff and date_diff[0][0]:
frappe.throw(_("{0} {1} has been modified. Please refresh.").format(self.doctype, self.name))
def stop_sales_order(self):
def stop_sales_order(self, status):
self.check_modified_date()
self.db_set('status', 'Stopped')
self.db_set('status', status)
self.update_reserved_qty()
self.notify_update()
clear_doctype_notifications(self)
@ -350,7 +350,7 @@ def make_delivery_note(source_name, target_doc=None):
"parent": "against_sales_order",
},
"postprocess": update_item,
"condition": lambda doc: doc.delivered_qty < doc.qty
"condition": lambda doc: doc.delivered_qty < doc.qty and doc.is_drop_ship!=1
},
"Sales Taxes and Charges": {
"doctype": "Sales Taxes and Charges",
@ -490,7 +490,7 @@ def get_events(start, end, filters=None):
return data
@frappe.whitelist()
def make_drop_shipment(source_name, target_doc=None):
def make_drop_shipment(source_name, for_supplier, target_doc=None):
def postprocess(source, target):
set_missing_values(source, target)
@ -500,7 +500,7 @@ def make_drop_shipment(source_name, target_doc=None):
target.contact_mobile = ""
target.contact_email = ""
target.contact_person = ""
target.ignore_pricing_rule = 1
target.drop_ship = 1
target.run_method("set_missing_values")
target.run_method("calculate_taxes_and_totals")
@ -529,10 +529,11 @@ def make_drop_shipment(source_name, target_doc=None):
["name", "prevdoc_detail_docname"],
["parent", "prevdoc_docname"],
["parenttype", "prevdoc_doctype"],
["uom", "stock_uom"]
["uom", "stock_uom"],
["delivery_date", "schedule_date"]
],
"postprocess": update_item,
"condition": lambda doc: doc.delivered_qty < doc.qty
"condition": lambda doc: doc.ordered_qty < doc.qty and doc.is_drop_ship==1 and doc.supplier == for_supplier
},
"Sales Taxes and Charges": {
"doctype": "Purchase Taxes and Charges",

View File

@ -1,16 +1,19 @@
frappe.listview_settings['Sales Order'] = {
add_fields: ["base_grand_total", "customer_name", "currency", "delivery_date", "per_delivered", "per_billed",
"status", "order_type", "per_ordered", "drop_ship"],
"status", "order_type"],
get_indicator: function(doc) {
if(doc.status==="Stopped") {
return [__("Stopped"), "darkgrey", "status,=,Stopped"];
} else if (doc.order_type !== "Maintenance" && doc.drop_ship !=1
} else if(doc.status==="Closed"){
return [__("Closed"), "green", "status,=,Closed"];
} else if (doc.order_type !== "Maintenance"
&& flt(doc.per_delivered, 2) < 100 && frappe.datetime.get_diff(doc.delivery_date) < 0) {
// to bill & overdue
return [__("Overdue"), "red", "per_delivered,<,100|delivery_date,<,Today|status,!=,Stopped"];
} else if (doc.order_type !== "Maintenance" && doc.drop_ship !=1
} else if (doc.order_type !== "Maintenance"
&& flt(doc.per_delivered, 2) < 100 && doc.status!=="Stopped") {
// not delivered
@ -20,43 +23,22 @@ frappe.listview_settings['Sales Order'] = {
return [__("To Deliver and Bill"), "orange",
"per_delivered,<,100|per_billed,<,100|status,!=,Stopped"];
} else {
// not delivered
// not billed
return [__("To Deliver"), "orange",
"per_delivered,<,100|per_billed,=,100|status,!=,Stopped"];
}
} else if ((doc.order_type === "Maintenance" || flt(doc.per_delivered, 2) == 100 ||
(doc.drop_ship == 1 && flt(doc.per_ordered, 2) == 100 ) ) && flt(doc.per_billed, 2) < 100
&& doc.status!=="Stopped") {
} else if ((doc.order_type === "Maintenance" || flt(doc.per_delivered, 2) == 100)
&& flt(doc.per_billed, 2) < 100 && doc.status!=="Stopped") {
// to bill
return [__("To Bill"), "orange", "per_delivered,=,100|per_billed,<,100|status,!=,Stopped|per_ordered,<,100"];
return [__("To Bill"), "orange", "per_delivered,=,100|per_billed,<,100|status,!=,Stopped"];
} else if((doc.order_type === "Maintenance" || flt(doc.per_delivered, 2) == 100)
&& flt(doc.per_billed, 2) == 100 && doc.status!=="Stopped") {
return [__("Completed"), "green", "per_delivered,=,100|per_billed,=,100|status,!=,Stopped"];
} else if ( doc.drop_ship == 1 && flt(doc.per_delivered, 2) < 100
&& frappe.datetime.get_diff(doc.delivery_date) < 0) {
// to bill & overdue
return [__("Overdue"), "red", "per_ordered,<,100|delivery_date,<,Today|status,!=,Stopped"];
} else if ( doc.drop_ship == 1 && flt(doc.per_ordered, 2) < 100 && doc.status!=="Stopped") {
// not ordered
if(flt(doc.per_billed, 2) < 100) {
// not delivered & not billed
return [__("To Order and Bill"), "orange",
"per_ordered,<,100|per_billed,<,100|status,!=,Stopped"];
} else {
// not ordered
return [__("To Order"), "orange",
"per_ordered,<,100|per_billed,=,100|status,!=,Stopped"];
}
}
},
onload: function(listview) {
@ -71,4 +53,4 @@ frappe.listview_settings['Sales Order'] = {
});
}
};
};

View File

@ -683,6 +683,95 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"collapsible_depends_on": "eval:doc.is_drop_ship==1",
"fieldname": "drop_ship",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Drop Ship",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"fieldname": "is_drop_ship",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Is Drop Ship Item",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break_32",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"fieldname": "supplier",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Supplier",
"no_copy": 0,
"options": "Supplier",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,

View File

@ -246,6 +246,28 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "is_drop_ship",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Is Drop Ship",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,

View File

@ -31,6 +31,7 @@ def get_item_details(args):
"transaction_type": "selling",
"ignore_pricing_rule": 0/1
"project_name": "",
"default_supplier":""
}
"""
args = process_args(args)
@ -69,7 +70,7 @@ def get_item_details(args):
if args.get("is_subcontracted") == "Yes":
out.bom = get_default_bom(args.item_code)
return out
def process_args(args):
@ -172,7 +173,9 @@ def get_basic_details(args, item):
"base_amount": 0.0,
"net_rate": 0.0,
"net_amount": 0.0,
"discount_percentage": 0.0
"discount_percentage": 0.0,
"supplier": item.default_supplier,
"is_drop_ship": item.is_drop_ship,
})
# if default specified in item is for another company, fetch from company

View File

@ -90,7 +90,7 @@ def get_reserved_qty(item_code, warehouse):
and parenttype="Sales Order"
and item_code != parent_item
and exists (select * from `tabSales Order` so
where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped')
where name = dnpi_in.parent and docstatus = 1 and status not in ('Stopped','Closed'))
) dnpi)
union
(select qty as dnpi_qty, qty as so_item_qty,
@ -99,7 +99,7 @@ def get_reserved_qty(item_code, warehouse):
where item_code = %s and warehouse = %s
and exists(select * from `tabSales Order` so
where so.name = so_item.parent and so.docstatus = 1
and so.status != 'Stopped'))
and so.status not in ('Stopped','Closed')))
) tab
where
so_item_qty >= so_item_delivered_qty