From c306b214150639f15683af6bf8415c69e1f94f77 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 19 Oct 2015 16:32:24 +0530 Subject: [PATCH 01/29] [merge fixes] --- .../purchase_order/purchase_order.json | 204 ++++++++++++++++++ .../doctype/purchase_order/purchase_order.py | 16 ++ .../purchase_order_item.json | 9 +- erpnext/controllers/selling_controller.py | 2 +- erpnext/public/js/utils/party.js | 2 +- .../doctype/sales_order/sales_order.js | 15 +- .../doctype/sales_order/sales_order.json | 65 +++++- .../doctype/sales_order/sales_order.py | 54 +++++ .../doctype/sales_order/sales_order_list.js | 35 ++- .../sales_order_item/sales_order_item.json | 22 ++ 10 files changed, 399 insertions(+), 25 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 904b762e1d..d0b454ef1c 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -147,6 +147,52 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "customer", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer", + "no_copy": 0, + "options": "Customer", + "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, + "depends_on": "eval:doc.order_type==\"Drop Shipment\"", + "fieldname": "customer_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Name", + "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, @@ -168,6 +214,28 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "customer_address_display", + "fieldtype": "Small Text", + "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Address", + "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, @@ -189,6 +257,28 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "customer_contact_display", + "fieldtype": "Small Text", + "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Contact", + "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, @@ -210,6 +300,28 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "customer_contact_mobile", + "fieldtype": "Small Text", + "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Mobile No", + "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, @@ -231,6 +343,28 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "customer_contact_email", + "fieldtype": "Small Text", + "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Contact Email", + "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, @@ -326,6 +460,28 @@ "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, @@ -1400,6 +1556,30 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "depends_on": "eval:doc.drop_ship==1", + "fieldname": "customer_address", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Address", + "no_copy": 0, + "options": "Address", + "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, @@ -1442,6 +1622,30 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "depends_on": "eval:doc.drop_ship==1", + "fieldname": "customer_contact_person", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Contact Person", + "no_copy": 0, + "options": "Contact", + "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, diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 0affd78f9b..234c643642 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -162,6 +162,14 @@ class PurchaseOrder(BuyingController): clear_doctype_notifications(self) def on_submit(self): + if self.drop_ship == 1: + self.status_updater[0].update({ + "target_parent_dt": "Sales Order", + "target_parent_field": "per_ordered", + "target_dt": "Sales Order Item", + 'target_field': 'ordered_qty' + }) + super(PurchaseOrder, self).on_submit() purchase_controller = frappe.get_doc("Purchase Common") @@ -176,6 +184,14 @@ class PurchaseOrder(BuyingController): purchase_controller.update_last_purchase_rate(self, is_submit = 1) def on_cancel(self): + if self.drop_ship == 1: + self.status_updater[0].update({ + "target_parent_dt": "Sales Order", + "target_parent_field": "per_ordered", + "target_dt": "Sales Order Item", + 'target_field': 'ordered_qty' + }) + pc_obj = frappe.get_doc('Purchase Common') self.check_for_stopped_status(pc_obj) 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 ecc41d2059..70e08e5d26 100755 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -848,7 +848,7 @@ "bold": 0, "collapsible": 0, "fieldname": "prevdoc_doctype", - "fieldtype": "Data", + "fieldtype": "Link", "hidden": 1, "ignore_user_permissions": 0, "in_filter": 0, @@ -857,6 +857,7 @@ "no_copy": 1, "oldfieldname": "prevdoc_doctype", "oldfieldtype": "Data", + "options": "DocType", "permlevel": 0, "print_hide": 1, "read_only": 1, @@ -871,16 +872,16 @@ "bold": 0, "collapsible": 0, "fieldname": "prevdoc_docname", - "fieldtype": "Link", + "fieldtype": "Dynamic Link", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 1, "in_list_view": 0, - "label": "Material Request No", + "label": "Reference Name", "no_copy": 1, "oldfieldname": "prevdoc_docname", "oldfieldtype": "Link", - "options": "Material Request", + "options": "prevdoc_doctype", "permlevel": 0, "print_hide": 1, "print_width": "120px", diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index b087b8a884..d7f287be49 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -143,7 +143,7 @@ class SellingController(StockController): throw(_("Total allocated percentage for sales team should be 100")) def validate_order_type(self): - valid_types = ["Sales", "Maintenance", "Shopping Cart"] + valid_types = ["Sales", "Maintenance", "Shopping Cart", "Drop Shipment"] if not self.order_type: self.order_type = "Sales" elif self.order_type not in valid_types: diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 427cd89c22..510938a9d1 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -7,7 +7,7 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { method = "erpnext.accounts.party.get_party_details"; } if(!args) { - if(frm.doc.customer) { + if(frm.doctype != "Purchase Order" && frm.doc.customer) { args = { party: frm.doc.customer, party_type: "Customer", diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 4a047e41ae..f46c16a510 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -25,7 +25,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( // doc.per_billed); // indent - if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1) + if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && doc.drop_ship!=1) cur_frm.add_custom_button(__('Material Request'), this.make_material_request); if(flt(doc.per_billed)==0) { @@ -37,19 +37,22 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( 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) { + 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); } // delivery note - if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1) + 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"); // 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); } else { // un-stop @@ -145,6 +148,12 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( frappe.set_route("Form", doclist[0].doctype, doclist[0].name); } }); + }, + make_drop_shipment: function(){ + frappe.model.open_mapped_doc({ + method: "erpnext.selling.doctype.sales_order.sales_order.make_drop_shipment", + frm: cur_frm + }) } }); diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 5bc8ef4727..97f5d36989 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -86,7 +86,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Series", + "label": "Series", "no_copy": 1, "oldfieldname": "naming_series", "oldfieldtype": "Select", @@ -234,13 +234,14 @@ "bold": 0, "collapsible": 0, "default": "Sales", + "depends_on": "eval:doc.drop_ship!=1", "fieldname": "order_type", "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Order Type", + "label": "Order Type", "no_copy": 0, "oldfieldname": "order_type", "oldfieldtype": "Select", @@ -254,6 +255,28 @@ "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, @@ -381,6 +404,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "depends_on": "eval:doc.drop_ship!=1", "description": "", "fieldname": "po_no", "fieldtype": "Data", @@ -1134,7 +1158,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Apply Additional Discount On", + "label": "Apply Additional Discount On", "no_copy": 0, "options": "\nGrand Total\nNet Total", "permlevel": 0, @@ -1808,7 +1832,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Source", + "label": "Source", "no_copy": 0, "oldfieldname": "source", "oldfieldtype": "Select", @@ -1973,7 +1997,7 @@ "ignore_user_permissions": 0, "in_filter": 1, "in_list_view": 1, - "label": "Status", + "label": "Status", "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", @@ -1998,7 +2022,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Delivery Status", + "label": "Delivery Status", "no_copy": 1, "options": "Not Delivered\nFully Delivered\nPartly Delivered\nClosed\nNot Applicable", "permlevel": 0, @@ -2036,6 +2060,29 @@ "unique": 0, "width": "100px" }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "per_ordered", + "fieldtype": "Percent", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 1, + "in_list_view": 1, + "label": "% Ordered", + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, + "width": "100px" + }, { "allow_on_submit": 0, "bold": 0, @@ -2092,7 +2139,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Billing Status", + "label": "Billing Status", "no_copy": 1, "options": "Not Billed\nFully Billed\nPartly Billed\nClosed", "permlevel": 0, @@ -2326,7 +2373,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Recurring Type", + "label": "Recurring Type", "no_copy": 1, "options": "\nMonthly\nQuarterly\nHalf-yearly\nYearly", "permlevel": 0, @@ -2553,7 +2600,7 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-10-03 07:39:10.525609", + "modified": "2015-10-15 15:27:34.592276", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 6cc12c53a9..25c8182649 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -488,3 +488,57 @@ def get_events(start, end, filters=None): "end": end }, as_dict=True, update={"allDay": 0}) return data + +@frappe.whitelist() +def make_drop_shipment(source_name, target_doc=None): + def postprocess(source, target): + set_missing_values(source, target) + + def set_missing_values(source, target): + target.address_display = "" + target.contact_display = "" + target.contact_mobile = "" + target.contact_email = "" + target.ignore_pricing_rule = 1 + target.run_method("set_missing_values") + target.run_method("calculate_taxes_and_totals") + + def update_item(source, target, source_parent): + target.base_amount = (flt(source.qty) - flt(source.ordered_qty)) * flt(source.base_rate) + target.amount = (flt(source.qty) - flt(source.ordered_qty)) * flt(source.rate) + target.qty = flt(source.qty) - flt(source.ordered_qty) + + doclist = get_mapped_doc("Sales Order", source_name, { + "Sales Order": { + "doctype": "Purchase Order", + "field_map": { + "address_display": "customer_address_display", + "contact_display": "customer_contact_display", + "contact_mobile": "customer_contact_mobile", + "contact_email": "customer_contact_email", + "contact_person": "customer_contact_person" + }, + "validation": { + "docstatus": ["=", 1] + } + }, + "Sales Order Item": { + "doctype": "Purchase Order Item", + "field_map": [ + ["name", "prevdoc_detail_docname"], + ["parent", "prevdoc_docname"], + ["parenttype", "prevdoc_doctype"], + ["uom", "stock_uom"] + ], + "postprocess": update_item, + "condition": lambda doc: doc.delivered_qty < doc.qty + }, + "Sales Taxes and Charges": { + "doctype": "Purchase Taxes and Charges", + "add_if_empty": True + } + }, target_doc, postprocess) + + + + return doclist diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js index aab168eb98..312f8785e1 100644 --- a/erpnext/selling/doctype/sales_order/sales_order_list.js +++ b/erpnext/selling/doctype/sales_order/sales_order_list.js @@ -1,16 +1,16 @@ frappe.listview_settings['Sales Order'] = { add_fields: ["base_grand_total", "customer_name", "currency", "delivery_date", "per_delivered", "per_billed", - "status", "order_type"], + "status", "order_type", "per_ordered", "drop_ship"], get_indicator: function(doc) { if(doc.status==="Stopped") { return [__("Stopped"), "darkgrey", "status,=,Stopped"]; - } else if (doc.order_type !== "Maintenance" + } else if (doc.order_type !== "Maintenance" && 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_delivered,<,100|delivery_date,<,Today|status,!=,Stopped"]; - } else if (doc.order_type !== "Maintenance" + } else if (doc.order_type !== "Maintenance" && doc.drop_ship !=1 && flt(doc.per_delivered, 2) < 100 && doc.status!=="Stopped") { // not delivered @@ -20,22 +20,43 @@ frappe.listview_settings['Sales Order'] = { return [__("To Deliver and Bill"), "orange", "per_delivered,<,100|per_billed,<,100|status,!=,Stopped"]; } else { - // not billed + // not delivered return [__("To Deliver"), "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") { + } 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") { // to bill - return [__("To Bill"), "orange", "per_delivered,=,100|per_billed,<,100|status,!=,Stopped"]; + return [__("To Bill"), "orange", "per_delivered,=,100|per_billed,<,100|status,!=,Stopped|per_ordered,<,100"]; } 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 Deliver"), "orange", + "per_ordered,<,100|per_billed,=,100|status,!=,Stopped"]; + } + } }, onload: function(listview) { diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index c7e9e2f78c..4192100510 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -917,6 +917,28 @@ "unique": 0, "width": "70px" }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "ordered_qty", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Ordered Qty", + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, From 5b7e9a1c944b2d3f0c365c86f1fa2137a599ebf3 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 15 Oct 2015 17:27:46 +0530 Subject: [PATCH 02/29] [minor fixes] --- erpnext/buying/doctype/purchase_order/purchase_order.json | 3 ++- erpnext/controllers/selling_controller.py | 2 +- erpnext/selling/doctype/sales_order/sales_order.py | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index d0b454ef1c..98dbfbe116 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -151,6 +151,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "depends_on": "eval:doc.drop_ship==1", "fieldname": "customer", "fieldtype": "Link", "hidden": 0, @@ -174,7 +175,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval:doc.order_type==\"Drop Shipment\"", + "depends_on": "eval:doc.drop_ship==1", "fieldname": "customer_name", "fieldtype": "Data", "hidden": 0, diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index d7f287be49..b087b8a884 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -143,7 +143,7 @@ class SellingController(StockController): throw(_("Total allocated percentage for sales team should be 100")) def validate_order_type(self): - valid_types = ["Sales", "Maintenance", "Shopping Cart", "Drop Shipment"] + valid_types = ["Sales", "Maintenance", "Shopping Cart"] if not self.order_type: self.order_type = "Sales" elif self.order_type not in valid_types: diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 25c8182649..c9cda38756 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -499,6 +499,7 @@ def make_drop_shipment(source_name, target_doc=None): target.contact_display = "" target.contact_mobile = "" target.contact_email = "" + target.contact_person = "" target.ignore_pricing_rule = 1 target.run_method("set_missing_values") target.run_method("calculate_taxes_and_totals") From 8bd96f1c08885769ef73b4edbb7394358bef600c Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 15 Oct 2015 17:58:05 +0530 Subject: [PATCH 03/29] [Test Case] Test case to check drop shipping --- .../doctype/sales_order/test_sales_order.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 4fa88d42b0..d4819a5e09 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -295,12 +295,29 @@ class TestSalesOrder(unittest.TestCase): {"price_list": "_Test Price List", "item_code": "_Test Item for Auto Price List"}, "price_list_rate"), None) 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_drop_shipment + from erpnext.stock.doctype.item.test_item import make_item + + item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 0, "is_sales_item": 1, + "is_purchase_item": 1}) + + so = make_sales_order(drop_ship=1, item_code=item.item_code) + po = make_drop_shipment(so.name) + + self.assertEquals(so.customer, po.customer) + self.assertEquals(po.items[0].prevdoc_doctype, "Sales Order") + self.assertEquals(po.items[0].prevdoc_docname, so.name) def make_sales_order(**args): so = frappe.new_doc("Sales Order") args = frappe._dict(args) if args.transaction_date: so.transaction_date = args.transaction_date + + if args.drop_ship: + so.drop_ship = 1 so.company = args.company or "_Test Company" so.customer = args.customer or "_Test Customer" From 556536615e37447f7b8f2e1d9404ef5ed09cf4b0 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 15 Oct 2015 18:08:56 +0530 Subject: [PATCH 04/29] [minor fix] Status fix in listview --- erpnext/selling/doctype/sales_order/sales_order_list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js index 312f8785e1..f9842a1b98 100644 --- a/erpnext/selling/doctype/sales_order/sales_order_list.js +++ b/erpnext/selling/doctype/sales_order/sales_order_list.js @@ -53,7 +53,7 @@ frappe.listview_settings['Sales Order'] = { } else { // not ordered - return [__("To Deliver"), "orange", + return [__("To Order"), "orange", "per_ordered,<,100|per_billed,=,100|status,!=,Stopped"]; } From c6dbe702562702e8bfb0889c7e5965e4781977a1 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 19 Oct 2015 14:17:52 +0530 Subject: [PATCH 05/29] [Fixes] Drop Shipping --- .../doctype/sales_invoice/sales_invoice.js | 9 +- .../doctype/sales_invoice/sales_invoice.py | 3 +- .../sales_invoice_item.json | 88 ++++++++++++++ erpnext/controllers/status_updater.py | 13 +- .../doctype/sales_order/sales_order.js | 112 ++++++++++++++---- .../doctype/sales_order/sales_order.json | 30 +---- .../doctype/sales_order/sales_order.py | 15 +-- .../doctype/sales_order/sales_order_list.js | 40 ++----- .../sales_order_item/sales_order_item.json | 89 ++++++++++++++ erpnext/stock/doctype/item/item.json | 22 ++++ erpnext/stock/get_item_details.py | 7 +- erpnext/stock/stock_balance.py | 4 +- 12 files changed, 337 insertions(+), 95 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 95e5a1c340..d89a39eb6b 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -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"); } } diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index a0b0c4eaca..dee2b7b0b8 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -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", diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 32b2ccd3c6..c8a65f5995 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -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, diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 94cddeeac3..f666eedf4e 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -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 diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index f46c16a510..57162a1edb 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -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(); }); diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 97f5d36989..b8680b8428 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -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", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index c9cda38756..ab5ddbda60 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -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", diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js index f9842a1b98..6c6254b3bc 100644 --- a/erpnext/selling/doctype/sales_order/sales_order_list.js +++ b/erpnext/selling/doctype/sales_order/sales_order_list.js @@ -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'] = { }); } -}; +}; \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 4192100510..8acb16ae8e 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -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, diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index bef4e25739..bd812a062a 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -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, diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 1f0b63727c..8f47ebc68b 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -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 diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py index efc604bd91..b0654e28ae 100644 --- a/erpnext/stock/stock_balance.py +++ b/erpnext/stock/stock_balance.py @@ -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 From 98b287565a5781a1d4dfc8c7a22eb9e1b269d261 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 19 Oct 2015 15:16:17 +0530 Subject: [PATCH 06/29] [enhance] close purchase order --- .../doctype/purchase_order/purchase_order.js | 16 +++++++++- .../purchase_order/purchase_order.json | 4 +-- .../purchase_order/purchase_order_list.js | 2 ++ erpnext/controllers/status_updater.py | 1 + .../doctype/sales_order/sales_order.js | 30 +++++++++---------- erpnext/stock/stock_balance.py | 2 +- 6 files changed, 36 insertions(+), 19 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 6ae83d0f00..9a701595c5 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -19,11 +19,13 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( this._super(); // this.frm.dashboard.reset(); - if(doc.docstatus == 1 && doc.status != 'Stopped') { + if(doc.docstatus == 1 && doc.status != 'Stopped' && doc.status != 'Closed') { if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100) cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order']); + cur_frm.add_custom_button(__('Close'), cur_frm.cscript['Close Purchase Order']); + if(flt(doc.per_billed)==0) { cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry); } @@ -223,6 +225,18 @@ cur_frm.cscript['Unstop Purchase Order'] = function() { } } +cur_frm.cscript['Close Purchase Order'] = function() { + var doc = cur_frm.doc; + var check = confirm(__("Do you really want to Close ") + doc.name); + + if (check) { + return $c('runserverobj', args={'method':'update_status', 'arg': 'Closed', 'docs':doc}, function(r,rt) { + cur_frm.refresh(); + }); + } +} + + cur_frm.pformat.indent_no = function(doc, cdt, cdn){ //function to make row of table diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 98dbfbe116..5f15675de7 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -1684,7 +1684,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "\nDraft\nTo Receive and Bill\nTo Bill\nTo Receive\nCompleted\nStopped\nCancelled", + "options": "\nDraft\nTo Receive and Bill\nTo Bill\nTo Receive\nCompleted\nStopped\nCancelled\nClosed", "permlevel": 0, "print_hide": 1, "read_only": 1, @@ -2238,7 +2238,7 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-10-16 06:13:50.058318", + "modified": "2015-10-19 14:23:14.190768", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_list.js b/erpnext/buying/doctype/purchase_order/purchase_order_list.js index 7f0ab658ef..ad83fb2f27 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order_list.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order_list.js @@ -4,6 +4,8 @@ frappe.listview_settings['Purchase Order'] = { get_indicator: function(doc) { if(doc.status==="Stopped") { return [__("Stopped"), "darkgrey", "status,=,Stopped"]; + } else if(doc.status==="Closed"){ + return [__("Closed"), "green", "status,=,Closed"]; } else if(flt(doc.per_received, 2) < 100 && doc.status!=="Stopped") { if(flt(doc.per_billed, 2) < 100) { return [__("To Receive and Bill"), "orange", diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index f666eedf4e..69e2d3e7b2 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -47,6 +47,7 @@ status_map = { ["Completed", "eval:self.per_received == 100 and self.per_billed == 100 and self.docstatus == 1"], ["Stopped", "eval:self.status=='Stopped'"], ["Cancelled", "eval:self.docstatus==2"], + ["Closed", "eval:self.status=='Closed'"], ], "Delivery Note": [ ["Draft", None], diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 57162a1edb..7a2bdb0fa0 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -236,6 +236,21 @@ cur_frm.cscript['Stop Sales Order'] = function() { } } +cur_frm.cscript['Unstop Sales Order'] = function() { + var doc = cur_frm.doc; + + var check = confirm(__("Are you sure you want to UNSTOP ") + doc.name); + + if (check) { + return $c('runserverobj', { + 'method':'unstop_sales_order', + 'docs': doc + }, function(r,rt) { + cur_frm.refresh(); + }); + } +} + cur_frm.cscript['Close Sales Order'] = function(){ var doc = cur_frm.doc; @@ -252,21 +267,6 @@ cur_frm.cscript['Close Sales Order'] = function(){ } } -cur_frm.cscript['Unstop Sales Order'] = function() { - var doc = cur_frm.doc; - - var check = confirm(__("Are you sure you want to UNSTOP ") + doc.name); - - if (check) { - return $c('runserverobj', { - 'method':'unstop_sales_order', - 'docs': doc - }, function(r,rt) { - cur_frm.refresh(); - }); - } -} - cur_frm.cscript.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); diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py index b0654e28ae..b1e8b22063 100644 --- a/erpnext/stock/stock_balance.py +++ b/erpnext/stock/stock_balance.py @@ -122,7 +122,7 @@ def get_ordered_qty(item_code, warehouse): from `tabPurchase Order Item` po_item, `tabPurchase Order` po where po_item.item_code=%s and po_item.warehouse=%s and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name - and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse)) + and po.status not in ('Stopped', 'Closed') and po.docstatus=1""", (item_code, warehouse)) return flt(ordered_qty[0][0]) if ordered_qty else 0 From bd65cb88170c599c0a0f31f1c36607b59de0195d Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 19 Oct 2015 16:29:16 +0530 Subject: [PATCH 07/29] [fixes] field rename and test case for drop ship --- .../purchase_order/purchase_order.json | 14 ++-- .../doctype/sales_order/sales_order.py | 3 + .../doctype/sales_order/test_sales_order.py | 76 +++++++++++++------ 3 files changed, 61 insertions(+), 32 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 5f15675de7..3d74f247dd 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -151,7 +151,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval:doc.drop_ship==1", + "depends_on": "eval:doc.is_drop_ship==1", "fieldname": "customer", "fieldtype": "Link", "hidden": 0, @@ -175,7 +175,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval:doc.drop_ship==1", + "depends_on": "eval:doc.is_drop_ship==1", "fieldname": "customer_name", "fieldtype": "Data", "hidden": 0, @@ -465,13 +465,13 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "drop_ship", + "fieldname": "is_drop_ship", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Drop Ship", + "label": "Is Drop Ship", "no_copy": 0, "permlevel": 0, "precision": "", @@ -1561,7 +1561,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval:doc.drop_ship==1", + "depends_on": "eval:doc.is_drop_ship==1", "fieldname": "customer_address", "fieldtype": "Link", "hidden": 0, @@ -1627,7 +1627,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval:doc.drop_ship==1", + "depends_on": "eval:doc.is_drop_ship==1", "fieldname": "customer_contact_person", "fieldtype": "Link", "hidden": 0, @@ -2238,7 +2238,7 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-10-19 14:23:14.190768", + "modified": "2015-10-19 15:58:28.388829", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index ab5ddbda60..911f4b7f75 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -505,6 +505,9 @@ def make_drop_shipment(source_name, for_supplier, target_doc=None): target.run_method("calculate_taxes_and_totals") def update_item(source, target, source_parent): + target.schedule_date = source_parent.delivery_date + target.rate = '' + target.price_list_rate = '' target.base_amount = (flt(source.qty) - flt(source.ordered_qty)) * flt(source.base_rate) target.amount = (flt(source.qty) - flt(source.ordered_qty)) * flt(source.rate) target.qty = flt(source.qty) - flt(source.ordered_qty) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index d4819a5e09..281ba28ec8 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -296,28 +296,50 @@ class TestSalesOrder(unittest.TestCase): 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_drop_shipment - from erpnext.stock.doctype.item.test_item import make_item - - item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 0, "is_sales_item": 1, - "is_purchase_item": 1}) - - so = make_sales_order(drop_ship=1, item_code=item.item_code) - po = make_drop_shipment(so.name) - - self.assertEquals(so.customer, po.customer) - self.assertEquals(po.items[0].prevdoc_doctype, "Sales Order") - self.assertEquals(po.items[0].prevdoc_docname, so.name) + # def test_drop_shipping(self): + # from erpnext.selling.doctype.sales_order.sales_order import make_drop_shipment, make_delivery_note + # from erpnext.stock.doctype.item.test_item import make_item + # + # po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 0, "is_sales_item": 1, + # "is_purchase_item": 1, "is_drop_ship": 1, 'default_supplier': '_Test Supplier'}) + # + # dn_item = make_item("_Test Regular Item", {"is_stock_item": 0, "is_sales_item": 1, + # "is_purchase_item": 1}) + # + # so_items = [ + # { + # "item_code": po_item.item_code, + # "warehouse": "_Test Warehouse - _TC", + # "qty": 1, + # "rate": 400, + # "conversion_factor": 1.0, + # "is_drop_ship": 1, + # "supplier": '_Test Supplier' + # }, + # { + # "item_code": dn_item.item_code, + # "warehouse": "_Test Warehouse - _TC", + # "qty": 1, + # "rate": 300, + # "conversion_factor": 1.0 + # } + # ] + # + # so = make_sales_order(items=so_items) + # po = make_drop_shipment(so.name, '_Test Supplier') + # dn = make_delivery_note(so.name) + # + # self.assertEquals(so.customer, po.customer) + # self.assertEquals(po.items[0].prevdoc_doctype, "Sales Order") + # self.assertEquals(po.items[0].prevdoc_docname, so.name) + # self.assertEquals(po.items[0].item_code, po_item.item_code) + # self.assertEquals(dn.items[0].item_code, dn.item_code) def make_sales_order(**args): so = frappe.new_doc("Sales Order") args = frappe._dict(args) if args.transaction_date: so.transaction_date = args.transaction_date - - if args.drop_ship: - so.drop_ship = 1 so.company = args.company or "_Test Company" so.customer = args.customer or "_Test Customer" @@ -328,15 +350,19 @@ def make_sales_order(**args): if "warehouse" not in args: args.warehouse = "_Test Warehouse - _TC" - - so.append("items", { - "item_code": args.item or args.item_code or "_Test Item", - "warehouse": args.warehouse, - "qty": args.qty or 10, - "rate": args.rate or 100, - "conversion_factor": 1.0, - }) - + + if args.items: + so.items = args.items + + else: + so.append("items", { + "item_code": args.item or args.item_code or "_Test Item", + "warehouse": args.warehouse, + "qty": args.qty or 10, + "rate": args.rate or 100, + "conversion_factor": 1.0, + }) + if not args.do_not_save: so.insert() if not args.do_not_submit: From 1a9646739a97595ee13f64364f0f44e24aeb687c Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 19 Oct 2015 16:45:46 +0530 Subject: [PATCH 08/29] [fixes][rename-field-name] drop_ship to is_drop_ship --- erpnext/buying/doctype/purchase_order/purchase_order.py | 4 ++-- erpnext/controllers/status_updater.py | 4 ++-- erpnext/selling/doctype/sales_order/sales_order.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 234c643642..8f5c63d138 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -162,7 +162,7 @@ class PurchaseOrder(BuyingController): clear_doctype_notifications(self) def on_submit(self): - if self.drop_ship == 1: + if self.is_drop_ship == 1: self.status_updater[0].update({ "target_parent_dt": "Sales Order", "target_parent_field": "per_ordered", @@ -184,7 +184,7 @@ class PurchaseOrder(BuyingController): purchase_controller.update_last_purchase_rate(self, is_submit = 1) def on_cancel(self): - if self.drop_ship == 1: + if self.is_drop_ship == 1: self.status_updater[0].update({ "target_parent_dt": "Sales Order", "target_parent_field": "per_ordered", diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 69e2d3e7b2..0861f37f5b 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -215,8 +215,8 @@ class StatusUpdater(Document): args["drop_ship_cond"] = '' - if getattr(self, "drop_ship", None): - if self.drop_ship == 1: + if getattr(self, "is_drop_ship", None): + if self.is_drop_ship == 1: args["drop_ship_cond"] = " and is_drop_ship=1 " else: diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 911f4b7f75..0e7ca96335 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -500,7 +500,7 @@ def make_drop_shipment(source_name, for_supplier, target_doc=None): target.contact_mobile = "" target.contact_email = "" target.contact_person = "" - target.drop_ship = 1 + target.is_drop_ship = 1 target.run_method("set_missing_values") target.run_method("calculate_taxes_and_totals") From 99543f72d8f72eed9cf850a78c5798c7aecac89b Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 19 Oct 2015 17:12:21 +0530 Subject: [PATCH 09/29] [fixes] test case for drop shipping and minor fixes for test_reserved_qty_for_partial_delivery & test_reserved_qty_for_partial_delivery_with_packing_list --- .../doctype/sales_order/test_sales_order.py | 85 ++++++++++--------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 281ba28ec8..9d08899906 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -97,7 +97,7 @@ class TestSalesOrder(unittest.TestCase): # stop so so.load_from_db() - so.stop_sales_order() + so.stop_sales_order("Stopped") self.assertEqual(get_reserved_qty(), existing_reserved_qty) # unstop so @@ -147,7 +147,7 @@ class TestSalesOrder(unittest.TestCase): # stop so so.load_from_db() - so.stop_sales_order() + so.stop_sales_order("Stopped") self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1) self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"), existing_reserved_qty_item2) @@ -296,44 +296,44 @@ class TestSalesOrder(unittest.TestCase): 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_drop_shipment, make_delivery_note - # from erpnext.stock.doctype.item.test_item import make_item - # - # po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 0, "is_sales_item": 1, - # "is_purchase_item": 1, "is_drop_ship": 1, 'default_supplier': '_Test Supplier'}) - # - # dn_item = make_item("_Test Regular Item", {"is_stock_item": 0, "is_sales_item": 1, - # "is_purchase_item": 1}) - # - # so_items = [ - # { - # "item_code": po_item.item_code, - # "warehouse": "_Test Warehouse - _TC", - # "qty": 1, - # "rate": 400, - # "conversion_factor": 1.0, - # "is_drop_ship": 1, - # "supplier": '_Test Supplier' - # }, - # { - # "item_code": dn_item.item_code, - # "warehouse": "_Test Warehouse - _TC", - # "qty": 1, - # "rate": 300, - # "conversion_factor": 1.0 - # } - # ] - # - # so = make_sales_order(items=so_items) - # po = make_drop_shipment(so.name, '_Test Supplier') - # dn = make_delivery_note(so.name) - # - # self.assertEquals(so.customer, po.customer) - # self.assertEquals(po.items[0].prevdoc_doctype, "Sales Order") - # self.assertEquals(po.items[0].prevdoc_docname, so.name) - # self.assertEquals(po.items[0].item_code, po_item.item_code) - # self.assertEquals(dn.items[0].item_code, dn.item_code) + def test_drop_shipping(self): + from erpnext.selling.doctype.sales_order.sales_order import make_drop_shipment, make_delivery_note + from erpnext.stock.doctype.item.test_item import make_item + + po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 0, "is_sales_item": 1, + "is_purchase_item": 1, "is_drop_ship": 1, 'default_supplier': '_Test Supplier'}) + + dn_item = make_item("_Test Regular Item", {"is_stock_item": 0, "is_sales_item": 1, + "is_purchase_item": 1}) + + so_items = [ + { + "item_code": po_item.item_code, + "warehouse": "_Test Warehouse - _TC", + "qty": 1, + "rate": 400, + "conversion_factor": 1.0, + "is_drop_ship": 1, + "supplier": '_Test Supplier' + }, + { + "item_code": dn_item.item_code, + "warehouse": "_Test Warehouse - _TC", + "qty": 1, + "rate": 300, + "conversion_factor": 1.0 + } + ] + + so = make_sales_order(item_list=so_items) + po = make_drop_shipment(so.name, '_Test Supplier') + dn = make_delivery_note(so.name) + + self.assertEquals(so.customer, po.customer) + self.assertEquals(po.items[0].prevdoc_doctype, "Sales Order") + self.assertEquals(po.items[0].prevdoc_docname, so.name) + self.assertEquals(po.items[0].item_code, po_item.item_code) + self.assertEquals(dn.items[0].item_code, dn_item.item_code) def make_sales_order(**args): so = frappe.new_doc("Sales Order") @@ -351,8 +351,9 @@ def make_sales_order(**args): if "warehouse" not in args: args.warehouse = "_Test Warehouse - _TC" - if args.items: - so.items = args.items + if args.item_list: + for item in args.item_list: + so.append("items", item) else: so.append("items", { From e930f0f74e8ec023e3c68be1cc59ecf98974ff4a Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 20 Oct 2015 13:34:21 +0530 Subject: [PATCH 10/29] [fixes] filter on supplier list for DropShip, checking closed status --- .../doctype/sales_invoice/sales_invoice.py | 4 +-- erpnext/controllers/selling_controller.py | 4 ++- .../doctype/sales_order/sales_order.js | 13 +++++--- .../doctype/sales_order/sales_order.py | 31 +++++++++++++++++++ .../doctype/delivery_note/delivery_note.py | 4 +-- 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index dee2b7b0b8..60fdc1a710 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -52,7 +52,7 @@ class SalesInvoice(SellingController): self.validate_proj_cust() self.validate_with_previous_doc() self.validate_uom_is_integer("stock_uom", "qty") - self.check_stop_sales_order("sales_order") + self.check_stop_or_close_sales_order("sales_order") self.validate_debit_to_acc() self.validate_fixed_asset_account() self.clear_unallocated_advances("Sales Invoice Advance", "advances") @@ -117,7 +117,7 @@ class SalesInvoice(SellingController): if cint(self.update_stock) == 1: self.update_stock_ledger() - self.check_stop_sales_order("sales_order") + self.check_stop_or_close_sales_order("sales_order") from erpnext.accounts.utils import remove_against_link_from_jv remove_against_link_from_jv(self.doctype, self.name) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index b087b8a884..7135baf02a 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -219,12 +219,14 @@ class SellingController(StockController): so_warehouse = so_item and so_item[0]["warehouse"] or "" return so_qty, so_warehouse - def check_stop_sales_order(self, ref_fieldname): + def check_stop_or_close_sales_order(self, ref_fieldname): for d in self.get("items"): if d.get(ref_fieldname): status = frappe.db.get_value("Sales Order", d.get(ref_fieldname), "status") if status == "Stopped": frappe.throw(_("Sales Order {0} is stopped").format(d.get(ref_fieldname))) + if status == "Closed": + frappe.throw(_("Sales Order {0} is closed").format(d.get(ref_fieldname))) def check_active_sales_items(obj): for d in obj.get("items"): diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 7a2bdb0fa0..71e52150fb 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -22,7 +22,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( if(doc.status != 'Stopped' && doc.status != 'Closed') { $.each(cur_frm.doc.items, function(i, item){ - if(item.is_drop_ship == 1){ + if(item.is_drop_ship == 1 || item.supplier){ flag_drop_ship = true; } else{ @@ -68,7 +68,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( } 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"); + cur_frm.add_custom_button(__('Make Purchase Order'), cur_frm.cscript.make_purchase_order).addClass("btn-primary"); } else { // un-stop @@ -166,12 +166,17 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( } }); }, - make_drop_shipment: function(){ + make_purchase_order: function(){ var dialog = new frappe.ui.Dialog({ title: __("For Supplier"), fields: [ {"fieldtype": "Link", "label": __("Supplier"), "fieldname": "supplier", "options":"Supplier", - "reqd": 1 }, + "get_query": function () { + return { + query:"erpnext.selling.doctype.sales_order.sales_order.get_supplier", + filters: {'parent': cur_frm.doc.name} + } + }, "reqd": 1 }, {"fieldtype": "Button", "label": __("Proceed"), "fieldname": "proceed"}, ] }); diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 0e7ca96335..69ec248dd9 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -495,6 +495,8 @@ def make_drop_shipment(source_name, for_supplier, target_doc=None): set_missing_values(source, target) def set_missing_values(source, target): + target.supplier = for_supplier + target.buying_price_list = frappe.get_value("Supplier", for_supplier, "default_price_list") or 'Standard Buying' target.address_display = "" target.contact_display = "" target.contact_mobile = "" @@ -547,3 +549,32 @@ def make_drop_shipment(source_name, for_supplier, target_doc=None): return doclist + +@frappe.whitelist() +def get_supplier(doctype, txt, searchfield, start, page_len, filters): + supp_master_name = frappe.defaults.get_user_default("supp_master_name") + if supp_master_name == "Supplier Name": + fields = ["name", "supplier_type"] + else: + fields = ["name", "supplier_name", "supplier_type"] + fields = ", ".join(fields) + + return frappe.db.sql("""select {field} from `tabSupplier` + where docstatus < 2 + and ({key} like %(txt)s + or supplier_name like %(txt)s) + and name in (select supplier from `tabSales Order Item` where parent = %(parent)s) + order by + if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), + if(locate(%(_txt)s, supplier_name), locate(%(_txt)s, supplier_name), 99999), + name, supplier_name + limit %(start)s, %(page_len)s """.format(**{ + 'field': fields, + 'key': searchfield + }), { + 'txt': "%%%s%%" % txt, + '_txt': txt.replace("%", ""), + 'start': start, + 'page_len': page_len, + 'parent': filters.get('parent') + }) \ No newline at end of file diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 6339752634..70f28c6f64 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -106,7 +106,7 @@ class DeliveryNote(SellingController): self.set_status() self.so_required() self.validate_proj_cust() - self.check_stop_sales_order("against_sales_order") + self.check_stop_or_close_sales_order("against_sales_order") self.validate_for_items() self.validate_warehouse() self.validate_uom_is_integer("stock_uom", "qty") @@ -203,7 +203,7 @@ class DeliveryNote(SellingController): def on_cancel(self): - self.check_stop_sales_order("against_sales_order") + self.check_stop_or_close_sales_order("against_sales_order") self.check_next_docstatus() self.update_prevdoc_status() From a4efbf0db703071c5b6b31fdc7baf63d49c9f344 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 20 Oct 2015 14:24:33 +0530 Subject: [PATCH 11/29] [fixes] check for close status --- .../doctype/purchase_invoice/purchase_invoice.py | 12 +++++++----- .../doctype/purchase_common/purchase_common.py | 12 +++++++----- .../buying/doctype/purchase_order/purchase_order.py | 8 ++++---- .../doctype/material_request/material_request.py | 2 +- .../doctype/purchase_receipt/purchase_receipt.py | 8 ++++---- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index af41ef5bd4..91b01d5103 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -48,7 +48,7 @@ class PurchaseInvoice(BuyingController): self.check_conversion_rate() self.validate_credit_to_acc() self.clear_unallocated_advances("Purchase Invoice Advance", "advances") - self.check_for_stopped_status() + self.check_for_stopped_or_closed_status() self.validate_with_previous_doc() self.validate_uom_is_integer("uom", "qty") self.set_against_expense_account() @@ -103,14 +103,14 @@ class PurchaseInvoice(BuyingController): self.party_account_currency = account.account_currency - def check_for_stopped_status(self): + def check_for_stopped_or_closed_status(self): check_list = [] + pc_obj = frappe.get_doc('Purchase Common') + for d in self.get('items'): if d.purchase_order and not d.purchase_order in check_list and not d.purchase_receipt: check_list.append(d.purchase_order) - stopped = frappe.db.sql("select name from `tabPurchase Order` where status = 'Stopped' and name = %s", d.purchase_order) - if stopped: - throw(_("Purchase Order {0} is 'Stopped'").format(d.purchase_order)) + pc_obj.check_for_stopped_or_closed_status('Purchase Order', d.purchase_order) def validate_with_previous_doc(self): super(PurchaseInvoice, self).validate_with_previous_doc({ @@ -394,6 +394,8 @@ class PurchaseInvoice(BuyingController): make_gl_entries(gl_entries, cancel=(self.docstatus == 2)) def on_cancel(self): + self.check_for_stopped_or_closed_status() + if not self.is_return: from erpnext.accounts.utils import remove_against_link_from_jv remove_against_link_from_jv(self.doctype, self.name) diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.py b/erpnext/buying/doctype/purchase_common/purchase_common.py index 030d6a276e..3cdb5a064b 100644 --- a/erpnext/buying/doctype/purchase_common/purchase_common.py +++ b/erpnext/buying/doctype/purchase_common/purchase_common.py @@ -80,11 +80,13 @@ class PurchaseCommon(BuyingController): frappe.msgprint(_("Warning: Same item has been entered multiple times.")) - def check_for_stopped_status(self, doctype, docname): - stopped = frappe.db.sql("""select name from `tab%s` where name = %s and - status = 'Stopped'""" % (doctype, '%s'), docname) - if stopped: - frappe.throw(_("{0} {1} status is 'Stopped'").format(doctype, docname), frappe.InvalidStatusError) + def check_for_stopped_or_closed_status(self, doctype, docname): + status = frappe.db.get_value(doctype, docname, "status") + + if status == "Stopped": + frappe.throw(_("{0} {1} status is Stopped").format(doctype, docname), frappe.InvalidStatusError) + if status == "Closed": + frappe.throw(_("{0} {1} status is Closed").format(doctype, docname), frappe.InvalidStatusError) def check_docstatus(self, check, doctype, docname, detail_doctype = ''): if check == 'Next': diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 8f5c63d138..9e0649ba34 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -39,7 +39,7 @@ class PurchaseOrder(BuyingController): self.set_status() pc_obj = frappe.get_doc('Purchase Common') pc_obj.validate_for_items(self) - self.check_for_stopped_status(pc_obj) + self.check_for_stopped_or_closed_status(pc_obj) self.validate_uom_is_integer("uom", "qty") self.validate_uom_is_integer("stock_uom", ["qty", "required_qty"]) @@ -108,12 +108,12 @@ class PurchaseOrder(BuyingController): = d.rate = item_last_purchase_rate # Check for Stopped status - def check_for_stopped_status(self, pc_obj): + def check_for_stopped_or_closed_status(self, pc_obj): check_list =[] for d in self.get('items'): if d.meta.get_field('prevdoc_docname') and d.prevdoc_docname and d.prevdoc_docname not in check_list: check_list.append(d.prevdoc_docname) - pc_obj.check_for_stopped_status( d.prevdoc_doctype, d.prevdoc_docname) + pc_obj.check_for_stopped_or_closed_status( d.prevdoc_doctype, d.prevdoc_docname) def update_requested_qty(self): material_request_map = {} @@ -193,7 +193,7 @@ class PurchaseOrder(BuyingController): }) pc_obj = frappe.get_doc('Purchase Common') - self.check_for_stopped_status(pc_obj) + self.check_for_stopped_or_closed_status(pc_obj) # Check if Purchase Receipt has been submitted against current Purchase Order pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Receipt', docname = self.name, detail_doctype = 'Purchase Receipt Item') diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 38238c7ded..9ca4758854 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -103,7 +103,7 @@ class MaterialRequest(BuyingController): def on_cancel(self): pc_obj = frappe.get_doc('Purchase Common') - pc_obj.check_for_stopped_status(self.doctype, self.name) + pc_obj.check_for_stopped_or_closed_status(self.doctype, self.name) pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Order', docname = self.name, detail_doctype = 'Purchase Order Item') self.update_requested_qty() diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 1ca81b66d9..e4d32ea9d0 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -67,7 +67,7 @@ class PurchaseReceipt(BuyingController): pc_obj = frappe.get_doc('Purchase Common') pc_obj.validate_for_items(self) - self.check_for_stopped_status(pc_obj) + self.check_for_stopped_or_closed_status(pc_obj) # sub-contracting self.validate_for_subcontracting() @@ -219,12 +219,12 @@ class PurchaseReceipt(BuyingController): raise frappe.ValidationError # Check for Stopped status - def check_for_stopped_status(self, pc_obj): + def check_for_stopped_or_closed_status(self, pc_obj): check_list =[] for d in self.get('items'): if d.meta.get_field('prevdoc_docname') and d.prevdoc_docname and d.prevdoc_docname not in check_list: check_list.append(d.prevdoc_docname) - pc_obj.check_for_stopped_status(d.prevdoc_doctype, d.prevdoc_docname) + pc_obj.check_for_stopped_or_closed_status(d.prevdoc_doctype, d.prevdoc_docname) # on submit def on_submit(self): @@ -260,7 +260,7 @@ class PurchaseReceipt(BuyingController): def on_cancel(self): pc_obj = frappe.get_doc('Purchase Common') - self.check_for_stopped_status(pc_obj) + self.check_for_stopped_or_closed_status(pc_obj) # Check if Purchase Invoice has been submitted against current Purchase Order submitted = frappe.db.sql("""select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 From 5e0b0b4b971e692efd35f9fb866f0599ab404698 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 20 Oct 2015 16:27:16 +0530 Subject: [PATCH 12/29] [enhance] make PO from SO if supplier is specified --- .../doctype/sales_invoice/sales_invoice.py | 2 +- .../sales_invoice_item/sales_invoice_item.json | 7 ++++--- erpnext/controllers/status_updater.py | 2 +- erpnext/selling/doctype/sales_order/sales_order.py | 14 ++++++++++++-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 60fdc1a710..11cd5d8073 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -668,7 +668,7 @@ def make_delivery_note(source_name, target_doc=None): "so_detail": "so_detail" }, "postprocess": update_item, - "condition": lambda doc: doc.is_drop_ship!=1 + "condition": lambda doc: (doc.is_drop_ship!=1 and not doc.supplier) }, "Sales Taxes and Charges": { "doctype": "Sales Taxes and Charges", diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index c8a65f5995..44f69cb923 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -683,7 +683,8 @@ { "allow_on_submit": 0, "bold": 0, - "collapsible": 0, + "collapsible": 1, + "collapsible_depends_on": "eval:doc.is_drop_ship==1", "fieldname": "drop_ship", "fieldtype": "Section Break", "hidden": 0, @@ -1370,8 +1371,8 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-10-19 03:04:52.093181", - "modified_by": "Administrator", + "modified": "2015-10-20 15:54:03.318846", + "modified_by": "saurabh6790@gmail.com", "module": "Accounts", "name": "Sales Invoice Item", "owner": "Administrator", diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 0861f37f5b..f7a0939444 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -221,7 +221,7 @@ class StatusUpdater(Document): else: if self.doctype=="Delivery Note": - args["drop_ship_cond"] = " and is_drop_ship!=1 " + args["drop_ship_cond"] = " and is_drop_ship!=1 and supplier = '' " for name in unique_transactions: if not name: diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 69ec248dd9..630494a6cf 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -31,6 +31,7 @@ class SalesOrder(SellingController): self.validate_uom_is_integer("stock_uom", "qty") self.validate_for_items() self.validate_warehouse() + self.validate_drop_ship() from erpnext.stock.doctype.packed_item.packed_item import make_packing_list make_packing_list(self) @@ -147,6 +148,11 @@ class SalesOrder(SellingController): doc.set_status(update=True) doc.update_opportunity() + def validate_drop_ship(self): + for d in self.get('items'): + if d.is_drop_ship and not d.supplier: + frappe.throw(_("#{0} Set Supplier for item {1}").format(d.idx, d.item_code)) + def on_submit(self): super(SalesOrder, self).on_submit() @@ -252,6 +258,9 @@ class SalesOrder(SellingController): def on_update(self): pass + + def before_update_after_submit(self): + self.validate_drop_ship() def get_list_context(context=None): from erpnext.controllers.website_list_for_contact import get_list_context @@ -350,7 +359,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 and doc.is_drop_ship!=1 + "condition": lambda doc: doc.delivered_qty < doc.qty and (doc.is_drop_ship!=1 and not doc.supplier) }, "Sales Taxes and Charges": { "doctype": "Sales Taxes and Charges", @@ -378,6 +387,7 @@ def make_sales_invoice(source_name, target_doc=None): target.run_method("calculate_taxes_and_totals") def update_item(source, target, source_parent): + target.supplier = source.supplier target.amount = flt(source.amount) - flt(source.billed_amt) target.base_amount = target.amount * flt(source_parent.conversion_rate) target.qty = target.amount / flt(source.rate) if (source.rate and source.billed_amt) else source.qty @@ -538,7 +548,7 @@ def make_drop_shipment(source_name, for_supplier, target_doc=None): ["delivery_date", "schedule_date"] ], "postprocess": update_item, - "condition": lambda doc: doc.ordered_qty < doc.qty and doc.is_drop_ship==1 and doc.supplier == for_supplier + "condition": lambda doc: doc.ordered_qty < doc.qty and doc.supplier == for_supplier or (doc.is_drop_ship==1 and doc.supplier == for_supplier) }, "Sales Taxes and Charges": { "doctype": "Purchase Taxes and Charges", From b705798ccb1c89d0b289bedc3955fca07c4c58fb Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 20 Oct 2015 17:53:50 +0530 Subject: [PATCH 13/29] [enhance & fixes] Print Format on PO for Drop Shipping --- .../purchase_order/purchase_order.json | 20 +++++++++---------- erpnext/buying/print_format/__init__.py | 0 .../print_format/drop_shipping/__init__.py | 0 .../drop_shipping/drop_shipping.json | 17 ++++++++++++++++ 4 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 erpnext/buying/print_format/__init__.py create mode 100644 erpnext/buying/print_format/drop_shipping/__init__.py create mode 100644 erpnext/buying/print_format/drop_shipping/drop_shipping.json diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 3d74f247dd..8f6ac5c440 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -186,7 +186,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 1, "report_hide": 0, "reqd": 0, @@ -229,7 +229,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -272,7 +272,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -315,7 +315,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -358,7 +358,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -475,7 +475,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -1573,7 +1573,7 @@ "options": "Address", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -1644,7 +1644,7 @@ "report_hide": 0, "reqd": 0, "search_index": 0, - "set_only_once": 0, + "set_only_once": 1, "unique": 0 }, { @@ -2238,8 +2238,8 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-10-19 15:58:28.388829", - "modified_by": "Administrator", + "modified": "2015-10-20 17:52:42.822372", + "modified_by": "saurabh@erpnext.com", "module": "Buying", "name": "Purchase Order", "owner": "Administrator", diff --git a/erpnext/buying/print_format/__init__.py b/erpnext/buying/print_format/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/buying/print_format/drop_shipping/__init__.py b/erpnext/buying/print_format/drop_shipping/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/buying/print_format/drop_shipping/drop_shipping.json b/erpnext/buying/print_format/drop_shipping/drop_shipping.json new file mode 100644 index 0000000000..0af9a2425c --- /dev/null +++ b/erpnext/buying/print_format/drop_shipping/drop_shipping.json @@ -0,0 +1,17 @@ +{ + "creation": "2015-10-20 16:46:39.382799", + "custom_format": 0, + "disabled": 0, + "doc_type": "Purchase Order", + "docstatus": 0, + "doctype": "Print Format", + "font": "Default", + "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"HTML\", \"options\": \"

Purchase Order

{{doc.name}}

\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"title\"}, {\"print_hide\": 0, \"fieldname\": \"supplier\"}, {\"print_hide\": 0, \"fieldname\": \"supplier_name\"}, {\"print_hide\": 0, \"fieldname\": \"address_display\"}, {\"print_hide\": 0, \"fieldname\": \"contact_display\"}, {\"print_hide\": 0, \"fieldname\": \"contact_mobile\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"transaction_date\"}, {\"print_hide\": 0, \"fieldname\": \"customer\"}, {\"print_hide\": 0, \"fieldname\": \"customer_name\"}, {\"print_hide\": 0, \"fieldname\": \"customer_address_display\"}, {\"print_hide\": 0, \"fieldname\": \"customer_contact_display\"}, {\"print_hide\": 0, \"fieldname\": \"customer_contact_mobile\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"item_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"300px\"}, {\"print_hide\": 0, \"fieldname\": \"image\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"qty\", \"print_width\": \"60px\"}, {\"print_hide\": 0, \"fieldname\": \"uom\", \"print_width\": \"100px\"}, {\"print_hide\": 0, \"fieldname\": \"discount_percentage\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"pricing_rule\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"supplier_quotation\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"supplier_quotation_item\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"items\"}, {\"print_hide\": 0, \"fieldname\": \"get_last_purchase_rate\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"total\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"category\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"add_deduct_tax\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"charge_type\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"row_id\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"included_in_print_rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"account_head\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"cost_center\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"300px\"}, {\"print_hide\": 0, \"fieldname\": \"rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"tax_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"total\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"taxes\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"grand_total\"}, {\"print_hide\": 0, \"fieldname\": \"in_words\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"terms\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"customer_contact_person\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"recurring_print_format\"}]", + "modified": "2015-10-20 17:21:45.810640", + "modified_by": "saurabh@erpnext.com", + "name": "Drop Shipping", + "owner": "Administrator", + "print_format_builder": 1, + "print_format_type": "Server", + "standard": "No" +} \ No newline at end of file From edba048c1436d0f668db0a66c3c6fa58272dd2a2 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 20 Oct 2015 18:20:16 +0530 Subject: [PATCH 14/29] [fixes] set is_stock_item for test items --- erpnext/selling/doctype/sales_order/test_sales_order.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 9d08899906..cd669afa73 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -300,10 +300,10 @@ class TestSalesOrder(unittest.TestCase): from erpnext.selling.doctype.sales_order.sales_order import make_drop_shipment, make_delivery_note from erpnext.stock.doctype.item.test_item import make_item - po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 0, "is_sales_item": 1, + po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 1, "is_sales_item": 1, "is_purchase_item": 1, "is_drop_ship": 1, 'default_supplier': '_Test Supplier'}) - dn_item = make_item("_Test Regular Item", {"is_stock_item": 0, "is_sales_item": 1, + dn_item = make_item("_Test Regular Item", {"is_stock_item": 1, "is_sales_item": 1, "is_purchase_item": 1}) so_items = [ From 8a8ef85174135b6888f73b907f59110592c1d1b1 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 21 Oct 2015 19:28:53 +0530 Subject: [PATCH 15/29] [fixes] reviwe fixes --- .../doctype/sales_invoice/sales_invoice.js | 6 +- .../doctype/sales_invoice/sales_invoice.py | 2 +- .../sales_invoice_item.json | 48 +------------- .../purchase_common/purchase_common.py | 8 +-- .../doctype/purchase_order/purchase_order.js | 64 ++++++++---------- .../doctype/purchase_order/purchase_order.py | 28 ++++---- erpnext/controllers/selling_controller.py | 6 +- erpnext/public/js/controllers/transaction.js | 2 +- .../doctype/sales_order/sales_order.js | 65 ++++++++----------- .../doctype/sales_order/sales_order.json | 4 +- .../doctype/sales_order/sales_order.py | 48 ++++++++------ .../sales_order_item/sales_order_item.json | 6 +- erpnext/stock/get_item_details.py | 3 +- 13 files changed, 116 insertions(+), 174 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index d89a39eb6b..8c5097466e 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -51,9 +51,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte if(doc.docstatus==1 && !doc.is_return) { - var flag_delivery_note = false; + var is_drop_ship = false; - flag_delivery_note = cur_frm.doc.items.some(function(item){ + is_drop_ship = cur_frm.doc.items.some(function(item){ return item.is_drop_ship ? true : false; }) @@ -68,7 +68,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte return item.delivery_note ? true : false; }); - if(!from_delivery_note && flag_delivery_note) { + if(!from_delivery_note && !is_drop_ship) { cur_frm.add_custom_button(__('Delivery'), cur_frm.cscript['Make Delivery Note']).addClass("btn-primary"); } } diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 11cd5d8073..60fdc1a710 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -668,7 +668,7 @@ def make_delivery_note(source_name, target_doc=None): "so_detail": "so_detail" }, "postprocess": update_item, - "condition": lambda doc: (doc.is_drop_ship!=1 and not doc.supplier) + "condition": lambda doc: doc.is_drop_ship!=1 }, "Sales Taxes and Charges": { "doctype": "Sales Taxes and Charges", diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 44f69cb923..37b60d1bf6 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -725,50 +725,6 @@ "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, @@ -1371,8 +1327,8 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-10-20 15:54:03.318846", - "modified_by": "saurabh6790@gmail.com", + "modified": "2015-10-21 19:06:40.313900", + "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", "owner": "Administrator", diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.py b/erpnext/buying/doctype/purchase_common/purchase_common.py index 3cdb5a064b..a86b330630 100644 --- a/erpnext/buying/doctype/purchase_common/purchase_common.py +++ b/erpnext/buying/doctype/purchase_common/purchase_common.py @@ -83,11 +83,9 @@ class PurchaseCommon(BuyingController): def check_for_stopped_or_closed_status(self, doctype, docname): status = frappe.db.get_value(doctype, docname, "status") - if status == "Stopped": - frappe.throw(_("{0} {1} status is Stopped").format(doctype, docname), frappe.InvalidStatusError) - if status == "Closed": - frappe.throw(_("{0} {1} status is Closed").format(doctype, docname), frappe.InvalidStatusError) - + if status in ("Stopped", "Closed"): + frappe.throw(_("{0} {1} status is {2}").format(doctype, docname, status), frappe.InvalidStatusError) + def check_docstatus(self, check, doctype, docname, detail_doctype = ''): if check == 'Next': submitted = frappe.db.sql("""select t1.name from `tab%s` t1,`tab%s` t2 diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 9a701595c5..94ec770b5d 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -22,9 +22,9 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( if(doc.docstatus == 1 && doc.status != 'Stopped' && doc.status != 'Closed') { if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100) - cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order']); + cur_frm.add_custom_button(__('Stop'), this.stop_purchase_order); - cur_frm.add_custom_button(__('Close'), cur_frm.cscript['Close Purchase Order']); + cur_frm.add_custom_button(__('Close'), this.close_purchase_order); if(flt(doc.per_billed)==0) { cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry); @@ -48,7 +48,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( } if(doc.docstatus == 1 && doc.status == 'Stopped') - cur_frm.add_custom_button(__('Unstop'), cur_frm.cscript['Unstop Purchase Order']); + cur_frm.add_custom_button(__('Unstop'), this.unstop_purchase_order); }, make_stock_entry: function() { @@ -157,6 +157,15 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( frappe.set_route("Form", doclist[0].doctype, doclist[0].name); } }); + }, + stop_purchase_order: function(){ + cur_frm.cscript.update_status('Stop', 'Stopped') + }, + unstop_purchase_order: function(){ + cur_frm.cscript.update_status('UNSTOP', 'Submitted') + }, + close_purchase_order: function(){ + cur_frm.cscript.update_status('Close', 'Closed') } }); @@ -164,6 +173,21 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( // for backward compatibility: combine new and previous states $.extend(cur_frm.cscript, new erpnext.buying.PurchaseOrderController({frm: cur_frm})); +cur_frm.cscript.update_status= function(label, status){ + var doc = cur_frm.doc; + var check = confirm(__("Do you really want to {0} {1}",[label, doc.name])); + + if (check) { + frappe.call({ + method: "erpnext.buying.doctype.purchase_order.purchase_order.update_status", + args:{status: status, name: doc.name}, + callback:function(r){ + cur_frm.refresh(); + } + }) + } +} + cur_frm.fields_dict['supplier_address'].get_query = function(doc, cdt, cdn) { return { filters: {'supplier': doc.supplier} @@ -203,40 +227,6 @@ cur_frm.cscript.get_last_purchase_rate = function(doc, cdt, cdn){ }); } -cur_frm.cscript['Stop Purchase Order'] = function() { - var doc = cur_frm.doc; - var check = confirm(__("Do you really want to STOP ") + doc.name); - - if (check) { - return $c('runserverobj', args={'method':'update_status', 'arg': 'Stopped', 'docs':doc}, function(r,rt) { - cur_frm.refresh(); - }); - } -} - -cur_frm.cscript['Unstop Purchase Order'] = function() { - var doc = cur_frm.doc; - var check = confirm(__("Do you really want to UNSTOP ") + doc.name); - - if (check) { - return $c('runserverobj', args={'method':'update_status', 'arg': 'Submitted', 'docs':doc}, function(r,rt) { - cur_frm.refresh(); - }); - } -} - -cur_frm.cscript['Close Purchase Order'] = function() { - var doc = cur_frm.doc; - var check = confirm(__("Do you really want to Close ") + doc.name); - - if (check) { - return $c('runserverobj', args={'method':'update_status', 'arg': 'Closed', 'docs':doc}, function(r,rt) { - cur_frm.refresh(); - }); - } -} - - cur_frm.pformat.indent_no = function(doc, cdt, cdn){ //function to make row of table diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 9e0649ba34..d73f793c42 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -163,12 +163,7 @@ class PurchaseOrder(BuyingController): def on_submit(self): if self.is_drop_ship == 1: - self.status_updater[0].update({ - "target_parent_dt": "Sales Order", - "target_parent_field": "per_ordered", - "target_dt": "Sales Order Item", - 'target_field': 'ordered_qty' - }) + self.update_status_updater() super(PurchaseOrder, self).on_submit() @@ -185,12 +180,7 @@ class PurchaseOrder(BuyingController): def on_cancel(self): if self.is_drop_ship == 1: - self.status_updater[0].update({ - "target_parent_dt": "Sales Order", - "target_parent_field": "per_ordered", - "target_dt": "Sales Order Item", - 'target_field': 'ordered_qty' - }) + self.update_status_updater() pc_obj = frappe.get_doc('Purchase Common') self.check_for_stopped_or_closed_status(pc_obj) @@ -229,6 +219,14 @@ class PurchaseOrder(BuyingController): for field in ("received_qty", "billed_amt", "prevdoc_doctype", "prevdoc_docname", "prevdoc_detail_docname", "supplier_quotation", "supplier_quotation_item"): d.set(field, None) + + def update_status_updater(self): + self.status_updater[0].update({ + "target_parent_dt": "Sales Order", + "target_parent_field": "per_ordered", + "target_dt": "Sales Order Item", + 'target_field': 'ordered_qty' + }) @frappe.whitelist() def stop_or_unstop_purchase_orders(names, status): @@ -341,3 +339,9 @@ def make_stock_entry(purchase_order, item_code): stock_entry.bom_no = po_item.bom stock_entry.get_items() return stock_entry.as_dict() + +@frappe.whitelist() +def update_status(status, name): + po = frappe.get_doc("Purchase Order", name) + po.update_status(status) + return \ No newline at end of file diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 7135baf02a..1ed8b8abe1 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -223,10 +223,8 @@ class SellingController(StockController): for d in self.get("items"): if d.get(ref_fieldname): status = frappe.db.get_value("Sales Order", d.get(ref_fieldname), "status") - if status == "Stopped": - frappe.throw(_("Sales Order {0} is stopped").format(d.get(ref_fieldname))) - if status == "Closed": - frappe.throw(_("Sales Order {0} is closed").format(d.get(ref_fieldname))) + if status in ("Stopped", "Closed"): + frappe.throw(_("Sales Order {0} is {1}").format(d.get(ref_fieldname), status)) def check_active_sales_items(obj): for d in obj.get("items"): diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index f518e9c53d..87cc2f6591 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -735,7 +735,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ var valid = true; $.each(["company", "customer"], function(i, fieldname) { - if(frappe.meta.has_field(me.frm.doc.doctype, fieldname)) { + if(frappe.meta.has_field(me.frm.doc.doctype, fieldname && me.frm.doc.doctype != "Purchase Order")) { if (!me.frm.doc[fieldname]) { msgprint(__("Please specify") + ": " + frappe.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name) + diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 71e52150fb..c354242353 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -15,18 +15,18 @@ 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; + var is_drop_ship = false; + var is_delivery_note = false; if(doc.docstatus==1) { if(doc.status != 'Stopped' && doc.status != 'Closed') { $.each(cur_frm.doc.items, function(i, item){ if(item.is_drop_ship == 1 || item.supplier){ - flag_drop_ship = true; + is_drop_ship = true; } else{ - flag_delivery_note = true; + is_delivery_note = true; } }) @@ -44,13 +44,13 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( } // stop - 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']) + if((flt(doc.per_delivered, 2) < 100 && is_delivery_note) || doc.per_billed < 100 + || (flt(doc.per_ordered,2) < 100 && is_drop_ship)){ + cur_frm.add_custom_button(__('Stop'), this.stop_sales_order) } - cur_frm.add_custom_button(__('Close'), cur_frm.cscript['Close Sales Order']) + cur_frm.add_custom_button(__('Close'), this.close_sales_order) // maintenance if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1) { @@ -59,7 +59,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( } // delivery note - if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && flag_delivery_note) + if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && is_delivery_note) cur_frm.add_custom_button(__('Delivery'), this.make_delivery_note).addClass("btn-primary"); // sales invoice @@ -67,7 +67,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( cur_frm.add_custom_button(__('Invoice'), this.make_sales_invoice).addClass("btn-primary"); } - if(flt(doc.per_ordered, 2) < 100 && flag_drop_ship) + if(flt(doc.per_ordered, 2) < 100 && is_drop_ship) cur_frm.add_custom_button(__('Make Purchase Order'), cur_frm.cscript.make_purchase_order).addClass("btn-primary"); } else { @@ -187,7 +187,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( dialog.hide(); return frappe.call({ type: "GET", - method: "erpnext.selling.doctype.sales_order.sales_order.make_drop_shipment", + method: "erpnext.selling.doctype.sales_order.sales_order.make_purchase_order_for_drop_shipment", args: { "source_name": cur_frm.doc.name, "for_supplier": args.supplier @@ -202,6 +202,12 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( }) }); dialog.show(); + }, + stop_sales_order: function(){ + cur_frm.cscript.update_status("Stop", "Stopped") + }, + close_sales_order: function(){ + cur_frm.cscript.update_status("Close", "Closed") } }); @@ -225,19 +231,18 @@ cur_frm.fields_dict['project_name'].get_query = function(doc, cdt, cdn) { } } -cur_frm.cscript['Stop Sales Order'] = function() { +cur_frm.cscript.update_status = function(label, status){ var doc = cur_frm.doc; - - var check = confirm(__("Are you sure you want to STOP ") + doc.name); - + var check = confirm(__("Do you really want to {0} {1}",[label, doc.name])); + if (check) { - return $c('runserverobj', { - 'method':'stop_sales_order', - 'docs': doc, - 'arg': "Stopped" - }, function(r,rt) { - cur_frm.refresh(); - }); + frappe.call({ + method: "erpnext.selling.doctype.sales_order.sales_order.update_status", + args:{status: status, name: doc.name}, + callback:function(r){ + cur_frm.refresh(); + } + }) } } @@ -256,22 +261,6 @@ cur_frm.cscript['Unstop Sales Order'] = function() { } } -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(); - }); - } -} - cur_frm.cscript.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); diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index b8680b8428..63f60f933c 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -2048,7 +2048,7 @@ "ignore_user_permissions": 0, "in_filter": 1, "in_list_view": 1, - "label": "% Ordered", + "label": "% Ordered", "no_copy": 1, "permlevel": 0, "precision": "", @@ -2578,7 +2578,7 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-10-19 11:34:16.668148", + "modified": "2015-10-21 19:02:58.591057", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 630494a6cf..8c5cf59829 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -151,7 +151,7 @@ class SalesOrder(SellingController): def validate_drop_ship(self): for d in self.get('items'): if d.is_drop_ship and not d.supplier: - frappe.throw(_("#{0} Set Supplier for item {1}").format(d.idx, d.item_code)) + frappe.throw(_("Row #{0}: Set Supplier for item {1}").format(d.idx, d.item_code)) def on_submit(self): super(SalesOrder, self).on_submit() @@ -359,7 +359,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 and (doc.is_drop_ship!=1 and not doc.supplier) + "condition": lambda doc: doc.delivered_qty < doc.qty and doc.is_drop_ship!=1 }, "Sales Taxes and Charges": { "doctype": "Sales Taxes and Charges", @@ -387,7 +387,6 @@ def make_sales_invoice(source_name, target_doc=None): target.run_method("calculate_taxes_and_totals") def update_item(source, target, source_parent): - target.supplier = source.supplier target.amount = flt(source.amount) - flt(source.billed_amt) target.base_amount = target.amount * flt(source_parent.conversion_rate) target.qty = target.amount / flt(source.rate) if (source.rate and source.billed_amt) else source.qty @@ -500,28 +499,20 @@ def get_events(start, end, filters=None): return data @frappe.whitelist() -def make_drop_shipment(source_name, for_supplier, target_doc=None): - def postprocess(source, target): - set_missing_values(source, target) - +def make_purchase_order_for_drop_shipment(source_name, for_supplier, target_doc=None): def set_missing_values(source, target): target.supplier = for_supplier - target.buying_price_list = frappe.get_value("Supplier", for_supplier, "default_price_list") or 'Standard Buying' - target.address_display = "" - target.contact_display = "" - target.contact_mobile = "" - target.contact_email = "" - target.contact_person = "" + + default_price_list = frappe.get_value("Supplier", for_supplier, "default_price_list") + if default_price_list: + target.buying_price_list = default_price_list + target.is_drop_ship = 1 target.run_method("set_missing_values") target.run_method("calculate_taxes_and_totals") def update_item(source, target, source_parent): target.schedule_date = source_parent.delivery_date - target.rate = '' - target.price_list_rate = '' - target.base_amount = (flt(source.qty) - flt(source.ordered_qty)) * flt(source.base_rate) - target.amount = (flt(source.qty) - flt(source.ordered_qty)) * flt(source.rate) target.qty = flt(source.qty) - flt(source.ordered_qty) doclist = get_mapped_doc("Sales Order", source_name, { @@ -534,6 +525,13 @@ def make_drop_shipment(source_name, for_supplier, target_doc=None): "contact_email": "customer_contact_email", "contact_person": "customer_contact_person" }, + "field_no_map": [ + "address_display", + "contact_display", + "contact_mobile", + "contact_email", + "contact_person" + ], "validation": { "docstatus": ["=", 1] } @@ -547,14 +545,18 @@ def make_drop_shipment(source_name, for_supplier, target_doc=None): ["uom", "stock_uom"], ["delivery_date", "schedule_date"] ], + "field_no_map": [ + "rate", + "price_list_rate" + ], "postprocess": update_item, - "condition": lambda doc: doc.ordered_qty < doc.qty and doc.supplier == for_supplier or (doc.is_drop_ship==1 and doc.supplier == for_supplier) + "condition": lambda doc: doc.ordered_qty < doc.qty and doc.supplier == for_supplier }, "Sales Taxes and Charges": { "doctype": "Purchase Taxes and Charges", "add_if_empty": True } - }, target_doc, postprocess) + }, target_doc, set_missing_values) @@ -587,4 +589,10 @@ def get_supplier(doctype, txt, searchfield, start, page_len, filters): 'start': start, 'page_len': page_len, 'parent': filters.get('parent') - }) \ No newline at end of file + }) + +@frappe.whitelist() +def update_status(status, name): + so = frappe.get_doc("Sales Order", name) + so.stop_sales_order(status) + return \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 8acb16ae8e..cd56cc5f87 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -720,7 +720,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -764,7 +764,7 @@ "options": "Supplier", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -1206,7 +1206,7 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-10-19 03:04:51.257808", + "modified": "2015-10-21 19:25:21.712515", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 8f47ebc68b..0c5f7c7eae 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -30,8 +30,7 @@ def get_item_details(args): "is_subcontracted": "Yes" / "No", "transaction_type": "selling", "ignore_pricing_rule": 0/1 - "project_name": "", - "default_supplier":"" + "project_name": "" } """ args = process_args(args) From d8930a776d6c40f3c23ecb8bf018aa41bc4cc6bc Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 22 Oct 2015 10:43:29 +0530 Subject: [PATCH 16/29] [fixes] test case import fix --- erpnext/selling/doctype/sales_order/test_sales_order.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index cd669afa73..71c78bbcb2 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -297,7 +297,7 @@ class TestSalesOrder(unittest.TestCase): 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_drop_shipment, make_delivery_note + from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_drop_shipment, make_delivery_note from erpnext.stock.doctype.item.test_item import make_item po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 1, "is_sales_item": 1, @@ -326,7 +326,7 @@ class TestSalesOrder(unittest.TestCase): ] so = make_sales_order(item_list=so_items) - po = make_drop_shipment(so.name, '_Test Supplier') + po = make_purchase_order_for_drop_shipment(so.name, '_Test Supplier') dn = make_delivery_note(so.name) self.assertEquals(so.customer, po.customer) From a1f2aec918e51a72fba136b7b646bfa87a2237e4 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 22 Oct 2015 12:17:54 +0530 Subject: [PATCH 17/29] [fixes] check ordered and reserved qrt, check closed status for so and po --- .../purchase_order/test_purchase_order.py | 14 ++++++++ .../doctype/sales_order/test_sales_order.py | 35 +++++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 66d50ba89d..0c8fba62b5 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -70,6 +70,20 @@ class TestPurchaseOrder(unittest.TestCase): from erpnext.utilities.transaction_base import UOMMustBeIntegerError po = create_purchase_order(qty=3.4, do_not_save=True) self.assertRaises(UOMMustBeIntegerError, po.insert) + + def test_ordered_qty_for_closing_po(self): + from erpnext.stock.doctype.item.test_item import make_item + + item = make_item("_Test Close Item", {"is_stock_item": 1, "is_sales_item": 1, + "is_purchase_item": 1}) + + po = create_purchase_order(item_code=item.item_code, qty=1) + + self.assertEquals(get_ordered_qty(item_code=item.item_code, warehouse="_Test Warehouse - _TC"), 1) + + po.update_status("Closed") + + self.assertEquals(get_ordered_qty(item_code=item.item_code, warehouse="_Test Warehouse - _TC"), 0) def create_purchase_order(**args): po = frappe.new_doc("Purchase Order") diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 71c78bbcb2..459b35fb1b 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -324,17 +324,48 @@ class TestSalesOrder(unittest.TestCase): "conversion_factor": 1.0 } ] - + + existing_ordered_qty, existing_reserved_qty = frappe.db.get_value("Bin", {"item_code": po_item.item_code, + "Warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) + so = make_sales_order(item_list=so_items) po = make_purchase_order_for_drop_shipment(so.name, '_Test Supplier') + po.submit() + dn = make_delivery_note(so.name) + self.assertEquals(so.customer, po.customer) self.assertEquals(po.items[0].prevdoc_doctype, "Sales Order") self.assertEquals(po.items[0].prevdoc_docname, so.name) self.assertEquals(po.items[0].item_code, po_item.item_code) self.assertEquals(dn.items[0].item_code, dn_item.item_code) - + + #test ordered_qty and reserved_qty + ordered_qty, reserved_qty = frappe.db.get_value("Bin", {"item_code": po_item.item_code, + "Warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) + + self.assertEquals(abs(ordered_qty), (existing_ordered_qty + so_items[0]['qty'])) + self.assertEquals(abs(reserved_qty), (existing_reserved_qty + so_items[0]['qty'])) + + #test po_item length + self.assertEquals(len(po.items), 1) + + def test_reserved_qty_for_closing_so(self): + from erpnext.stock.doctype.item.test_item import make_item + + item = make_item("_Test Close Item", {"is_stock_item": 1, "is_sales_item": 1, + "is_purchase_item": 1}) + + so = make_sales_order(item_code=item.item_code, qty=1) + + self.assertEquals(get_reserved_qty(item_code=item.item_code, warehouse="_Test Warehouse - _TC"), 1) + + so.stop_sales_order("Closed") + + self.assertEquals(get_reserved_qty(item_code=item.item_code, warehouse="_Test Warehouse - _TC"), 0) + + def make_sales_order(**args): so = frappe.new_doc("Sales Order") args = frappe._dict(args) From df1c1a573fa38c550c7985cebae2aef65cc89e13 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 22 Oct 2015 12:44:23 +0530 Subject: [PATCH 18/29] [fixes] test case for per_ordered --- erpnext/selling/doctype/sales_order/test_sales_order.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 459b35fb1b..43e08946c6 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -328,7 +328,9 @@ class TestSalesOrder(unittest.TestCase): existing_ordered_qty, existing_reserved_qty = frappe.db.get_value("Bin", {"item_code": po_item.item_code, "Warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) - so = make_sales_order(item_list=so_items) + 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.submit() @@ -351,6 +353,10 @@ class TestSalesOrder(unittest.TestCase): #test po_item length self.assertEquals(len(po.items), 1) + #test per_ordered status + per_ordered = frappe.db.get_value("Sales Order", so.name, "per_ordered") + self.assertEquals(per_ordered, 100.0) + def test_reserved_qty_for_closing_so(self): from erpnext.stock.doctype.item.test_item import make_item From b0ab93f7793d831f0d18049b007af8f461fdaad7 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 22 Oct 2015 14:41:52 +0530 Subject: [PATCH 19/29] [fixes] typo error --- erpnext/selling/doctype/sales_order/test_sales_order.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 43e08946c6..57954ddcb8 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -326,7 +326,7 @@ class TestSalesOrder(unittest.TestCase): ] existing_ordered_qty, existing_reserved_qty = frappe.db.get_value("Bin", {"item_code": po_item.item_code, - "Warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) + "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) so = make_sales_order(item_list=so_items, do_not_submit=True) so.submit() @@ -345,7 +345,7 @@ class TestSalesOrder(unittest.TestCase): #test ordered_qty and reserved_qty ordered_qty, reserved_qty = frappe.db.get_value("Bin", {"item_code": po_item.item_code, - "Warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) + "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) self.assertEquals(abs(ordered_qty), (existing_ordered_qty + so_items[0]['qty'])) self.assertEquals(abs(reserved_qty), (existing_reserved_qty + so_items[0]['qty'])) From 6d64fe378d95d9c81b3b1b1f85abcd225192dc9b Mon Sep 17 00:00:00 2001 From: Saurabh Date: Fri, 23 Oct 2015 10:40:32 +0530 Subject: [PATCH 20/29] [fixes] remover per_ordered field and update delivered qty from perchase order via delivered by supplier -1 --- .../doctype/purchase_order/purchase_order.js | 18 ++++++++- .../purchase_order/purchase_order.json | 6 +-- .../doctype/purchase_order/purchase_order.py | 37 +++++++++++++++++-- .../purchase_order/purchase_order_list.js | 4 +- erpnext/controllers/status_updater.py | 18 +++------ .../doctype/sales_order/sales_order.json | 25 +------------ .../doctype/sales_order/test_sales_order.py | 8 ++-- 7 files changed, 67 insertions(+), 49 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 94ec770b5d..a9ca76f7bd 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -25,7 +25,11 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( cur_frm.add_custom_button(__('Stop'), this.stop_purchase_order); cur_frm.add_custom_button(__('Close'), this.close_purchase_order); - + + if(doc.is_drop_ship && doc.status!="Delivered"){ + cur_frm.add_custom_button(__('Delivered By Supplier'), this.delivered_by_supplier); + } + if(flt(doc.per_billed)==0) { cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry); } @@ -166,6 +170,18 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( }, close_purchase_order: function(){ cur_frm.cscript.update_status('Close', 'Closed') + }, + delivered_by_supplier: function(){ + return frappe.call({ + method: "erpnext.buying.doctype.purchase_order.purchase_order.delivered_by_supplier", + freez: true, + args:{ + purchase_order: cur_frm.doc.name + }, + callback:function(r){ + cur_frm.refresh(); + } + }) } }); diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 8f6ac5c440..318813c6d3 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -1684,7 +1684,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "\nDraft\nTo Receive and Bill\nTo Bill\nTo Receive\nCompleted\nStopped\nCancelled\nClosed", + "options": "\nDraft\nTo Receive and Bill\nTo Bill\nTo Receive\nCompleted\nStopped\nCancelled\nClosed\nDelivered", "permlevel": 0, "print_hide": 1, "read_only": 1, @@ -2238,8 +2238,8 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-10-20 17:52:42.822372", - "modified_by": "saurabh@erpnext.com", + "modified": "2015-10-22 19:03:10.932738", + "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", "owner": "Administrator", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index d73f793c42..a416663e9e 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -223,11 +223,10 @@ class PurchaseOrder(BuyingController): def update_status_updater(self): self.status_updater[0].update({ "target_parent_dt": "Sales Order", - "target_parent_field": "per_ordered", "target_dt": "Sales Order Item", 'target_field': 'ordered_qty' }) - + @frappe.whitelist() def stop_or_unstop_purchase_orders(names, status): if not frappe.has_permission("Purchase Order", "write"): @@ -344,4 +343,36 @@ def make_stock_entry(purchase_order, item_code): def update_status(status, name): po = frappe.get_doc("Purchase Order", name) po.update_status(status) - return \ No newline at end of file + return + +@frappe.whitelist() +def delivered_by_supplier(purchase_order): + po = frappe.get_doc("Purchase Order", purchase_order) + update_delivered_qty(po) + po.update_status("Delivered") + return po.as_dict() + +def update_delivered_qty(purchase_order): + sales_order_list = [] + for item in purchase_order.items: + if item.prevdoc_doctype == "Sales Order": + frappe.db.sql(""" update `tabSales Order Item` + set delivered_qty = (ifnull(delivered_qty, 0) + %(qty)s) + where item_code='%(item_code)s' and parent = '%(name)s' + """%{"qty": item.qty, "item_code": item.item_code, "name": item.prevdoc_docname}) + + sales_order_list.append(item.prevdoc_docname) + + update_per_delivery(sales_order_list) + +def update_per_delivery(sales_order_list): + for so in sales_order_list: + frappe.db.sql("""update `tabSales Order` + set per_delivered = (select + sum(if(qty > ifnull(delivered_qty, 0), delivered_qty, qty))/ sum(qty)*100 + from `tabSales Order Item` where parent="%(name)s") where name = "%(name)s" """%{"name":so}) + + so = frappe.get_doc("Sales Order", so) + so.set_status(update=True) + so.notify_update() + \ No newline at end of file diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_list.js b/erpnext/buying/doctype/purchase_order/purchase_order_list.js index ad83fb2f27..82231b84a1 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order_list.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order_list.js @@ -6,7 +6,9 @@ frappe.listview_settings['Purchase Order'] = { return [__("Stopped"), "darkgrey", "status,=,Stopped"]; } else if(doc.status==="Closed"){ return [__("Closed"), "green", "status,=,Closed"]; - } else if(flt(doc.per_received, 2) < 100 && doc.status!=="Stopped") { + } else if (doc.status==="Delivered") { + return [__("Delivered"), "green", "status,=,Closed"]; + }else if(flt(doc.per_received, 2) < 100 && doc.status!=="Stopped") { if(flt(doc.per_billed, 2) < 100) { return [__("To Receive and Bill"), "orange", "per_received,<,100|per_billed,<,100|status,!=,Stopped"]; diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index f7a0939444..2de6777fef 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -45,6 +45,7 @@ status_map = { ["To Bill", "eval:self.per_received == 100 and self.per_billed < 100 and self.docstatus == 1"], ["To Receive", "eval:self.per_received < 100 and self.per_billed == 100 and self.docstatus == 1"], ["Completed", "eval:self.per_received == 100 and self.per_billed == 100 and self.docstatus == 1"], + ["Delivered", "eval:self.status=='Delivered'"], ["Stopped", "eval:self.status=='Stopped'"], ["Cancelled", "eval:self.docstatus==2"], ["Closed", "eval:self.status=='Closed'"], @@ -170,11 +171,12 @@ class StatusUpdater(Document): else: args['cond'] = ' and parent!="%s"' % self.name.replace('"', '\"') - args['set_modified'] = '' if change_modified: args['set_modified'] = ', modified = now(), modified_by = "{0}"'\ .format(frappe.db.escape(frappe.session.user)) - + + args["drop_ship_cond"] = '' + self._update_children(args) if "percent_join_field" in args: @@ -212,16 +214,6 @@ 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, "is_drop_ship", None): - if self.is_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 and supplier = '' " for name in unique_transactions: if not name: @@ -235,7 +227,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" %(drop_ship_cond)s), 2) %(set_modified)s + from `tab%(target_dt)s` where parent="%(name)s"), 2) %(set_modified)s where name='%(name)s'""" % args) # update field diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 63f60f933c..ed661f8767 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -2038,29 +2038,6 @@ "unique": 0, "width": "100px" }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "per_ordered", - "fieldtype": "Percent", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 1, - "in_list_view": 1, - "label": "% Ordered", - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "read_only": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, - "width": "100px" - }, { "allow_on_submit": 0, "bold": 0, @@ -2578,7 +2555,7 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-10-21 19:02:58.591057", + "modified": "2015-10-22 16:32:34.339835", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 57954ddcb8..acccd69957 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -325,8 +325,8 @@ class TestSalesOrder(unittest.TestCase): } ] - existing_ordered_qty, existing_reserved_qty = frappe.db.get_value("Bin", {"item_code": po_item.item_code, - "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) + existing_ordered_qty, existing_reserved_qty = frappe.db.get_value("Bin", + {"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) so = make_sales_order(item_list=so_items, do_not_submit=True) so.submit() @@ -344,8 +344,8 @@ class TestSalesOrder(unittest.TestCase): self.assertEquals(dn.items[0].item_code, dn_item.item_code) #test ordered_qty and reserved_qty - ordered_qty, reserved_qty = frappe.db.get_value("Bin", {"item_code": po_item.item_code, - "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) + ordered_qty, reserved_qty = frappe.db.get_value("Bin", + {"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) self.assertEquals(abs(ordered_qty), (existing_ordered_qty + so_items[0]['qty'])) self.assertEquals(abs(reserved_qty), (existing_reserved_qty + so_items[0]['qty'])) From f857d81f353514ad9639bb3c182ac8b63cb2ac34 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 26 Oct 2015 13:59:12 +0530 Subject: [PATCH 21/29] [fixes]test case to check updated delivered qty --- .../doctype/sales_invoice/sales_invoice.json | 14 +++++++------- .../doctype/sales_order/test_sales_order.py | 13 +++++++------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 6194a6069d..a6a47d546f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -65,7 +65,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Series", + "label": "Series", "no_copy": 1, "oldfieldname": "naming_series", "oldfieldtype": "Select", @@ -1168,7 +1168,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Apply Additional Discount On", + "label": "Apply Additional Discount On", "no_copy": 0, "options": "\nGrand Total\nNet Total", "permlevel": 0, @@ -2211,7 +2211,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Source", + "label": "Source", "no_copy": 0, "oldfieldname": "source", "oldfieldtype": "Select", @@ -2308,7 +2308,7 @@ "ignore_user_permissions": 0, "in_filter": 1, "in_list_view": 0, - "label": "Is Opening Entry", + "label": "Is Opening Entry", "no_copy": 0, "oldfieldname": "is_opening", "oldfieldtype": "Select", @@ -2332,7 +2332,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "C-Form Applicable", + "label": "C-Form Applicable", "no_copy": 1, "options": "No\nYes", "permlevel": 0, @@ -2700,7 +2700,7 @@ "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Recurring Type", + "label": "Recurring Type", "no_copy": 1, "options": "\nMonthly\nQuarterly\nHalf-yearly\nYearly", "permlevel": 0, @@ -2951,7 +2951,7 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-10-02 07:39:09.123982", + "modified": "2015-10-26 12:12:40.616546", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index acccd69957..367be5ef77 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -299,6 +299,7 @@ class TestSalesOrder(unittest.TestCase): def test_drop_shipping(self): from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_drop_shipment, make_delivery_note from erpnext.stock.doctype.item.test_item import make_item + from erpnext.buying.doctype.purchase_order.purchase_order import delivered_by_supplier po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 1, "is_sales_item": 1, "is_purchase_item": 1, "is_drop_ship": 1, 'default_supplier': '_Test Supplier'}) @@ -310,7 +311,7 @@ class TestSalesOrder(unittest.TestCase): { "item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC", - "qty": 1, + "qty": 2, "rate": 400, "conversion_factor": 1.0, "is_drop_ship": 1, @@ -319,7 +320,7 @@ class TestSalesOrder(unittest.TestCase): { "item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC", - "qty": 1, + "qty": 2, "rate": 300, "conversion_factor": 1.0 } @@ -334,9 +335,8 @@ class TestSalesOrder(unittest.TestCase): po = make_purchase_order_for_drop_shipment(so.name, '_Test Supplier') po.submit() - dn = make_delivery_note(so.name) + dn = create_dn_against_so(so, delivered_qty=1) - self.assertEquals(so.customer, po.customer) self.assertEquals(po.items[0].prevdoc_doctype, "Sales Order") self.assertEquals(po.items[0].prevdoc_docname, so.name) @@ -354,8 +354,9 @@ class TestSalesOrder(unittest.TestCase): self.assertEquals(len(po.items), 1) #test per_ordered status - per_ordered = frappe.db.get_value("Sales Order", so.name, "per_ordered") - self.assertEquals(per_ordered, 100.0) + delivered_by_supplier(po.name) + per_delivered = frappe.db.get_value("Sales Order", so.name, "per_delivered") + self.assertEquals(per_delivered, ) def test_reserved_qty_for_closing_so(self): from erpnext.stock.doctype.item.test_item import make_item From 2f702dcb3225b544c757ddf0fccf3d0a948a9d62 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 26 Oct 2015 17:28:17 +0530 Subject: [PATCH 22/29] [fixes] bulk close facility, rename Drop Ship to Delivered By Supplier --- .../doctype/sales_invoice/sales_invoice.js | 8 ++++---- .../doctype/sales_invoice/sales_invoice.py | 2 +- .../sales_invoice_item/sales_invoice_item.json | 14 +++++++------- .../doctype/purchase_order/purchase_order.js | 2 +- .../doctype/purchase_order/purchase_order.py | 10 +++++----- .../purchase_order/purchase_order_list.js | 5 ++++- .../selling/doctype/sales_order/sales_order.js | 10 +++++----- .../selling/doctype/sales_order/sales_order.py | 12 ++++++------ .../doctype/sales_order/sales_order_list.js | 6 +++++- .../doctype/sales_order/test_sales_order.py | 4 ++-- .../sales_order_item/sales_order_item.json | 16 ++++++++-------- erpnext/stock/doctype/item/item.json | 8 ++++++-- erpnext/stock/get_item_details.py | 2 +- 13 files changed, 55 insertions(+), 44 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 8c5097466e..9b9ab24811 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -51,10 +51,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte if(doc.docstatus==1 && !doc.is_return) { - var is_drop_ship = false; + var is_delivered_by_supplier = false; - is_drop_ship = cur_frm.doc.items.some(function(item){ - return item.is_drop_ship ? true : false; + is_delivered_by_supplier = cur_frm.doc.items.some(function(item){ + return item.is_delivered_by_supplier ? true : false; }) cur_frm.add_custom_button(doc.update_stock ? __('Sales Return') : __('Credit Note'), @@ -68,7 +68,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte return item.delivery_note ? true : false; }); - if(!from_delivery_note && !is_drop_ship) { + if(!from_delivery_note && !is_delivered_by_supplier) { cur_frm.add_custom_button(__('Delivery'), cur_frm.cscript['Make Delivery Note']).addClass("btn-primary"); } } diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 60fdc1a710..6abf1ba96d 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -668,7 +668,7 @@ def make_delivery_note(source_name, target_doc=None): "so_detail": "so_detail" }, "postprocess": update_item, - "condition": lambda doc: doc.is_drop_ship!=1 + "condition": lambda doc: doc.delivered_by_supplier!=1 }, "Sales Taxes and Charges": { "doctype": "Sales Taxes and Charges", diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 37b60d1bf6..0a98d87dc7 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -684,14 +684,14 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 1, - "collapsible_depends_on": "eval:doc.is_drop_ship==1", - "fieldname": "drop_ship", + "collapsible_depends_on": "eval:doc.delivered_by_supplier==1", + "fieldname": "by_supplier", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Drop Ship", + "label": "Delivered By Sypplier", "no_copy": 0, "permlevel": 0, "precision": "", @@ -707,18 +707,18 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "is_drop_ship", + "fieldname": "delivered_by_supplier", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Is Drop Ship Item", + "label": "Delivered By Supplier", "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, - "read_only": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -1327,7 +1327,7 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-10-21 19:06:40.313900", + "modified": "2015-10-26 17:22:23.631195", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index a9ca76f7bd..b6a785c348 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -26,7 +26,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( cur_frm.add_custom_button(__('Close'), this.close_purchase_order); - if(doc.is_drop_ship && doc.status!="Delivered"){ + if(doc.delivered_by_supplier && doc.status!="Delivered"){ cur_frm.add_custom_button(__('Delivered By Supplier'), this.delivered_by_supplier); } diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index a416663e9e..45444b98a1 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -162,7 +162,7 @@ class PurchaseOrder(BuyingController): clear_doctype_notifications(self) def on_submit(self): - if self.is_drop_ship == 1: + if self.delivered_by_supplier == 1: self.update_status_updater() super(PurchaseOrder, self).on_submit() @@ -179,7 +179,7 @@ class PurchaseOrder(BuyingController): purchase_controller.update_last_purchase_rate(self, is_submit = 1) def on_cancel(self): - if self.is_drop_ship == 1: + if self.delivered_by_supplier == 1: self.update_status_updater() pc_obj = frappe.get_doc('Purchase Common') @@ -236,9 +236,9 @@ def stop_or_unstop_purchase_orders(names, status): for name in names: po = frappe.get_doc("Purchase Order", name) if po.docstatus == 1: - if status=="Stopped": - if po.status not in ("Stopped", "Cancelled") and (po.per_received < 100 or po.per_billed < 100): - po.update_status("Stopped") + if status in ("Stopped", "Closed"): + if po.status not in ("Stopped", "Cancelled", "Closed") and (po.per_received < 100 or po.per_billed < 100): + po.update_status(status) else: if po.status == "Stopped": po.update_status("Draft") diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_list.js b/erpnext/buying/doctype/purchase_order/purchase_order_list.js index 82231b84a1..0f1581dfb4 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order_list.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order_list.js @@ -32,6 +32,9 @@ frappe.listview_settings['Purchase Order'] = { listview.page.add_menu_item(__("Set as Unstopped"), function() { listview.call_for_selected_items(method, {"status": "Submitted"}); }); - + + listview.page.add_menu_item(__("Set as Closed"), function() { + listview.call_for_selected_items(method, {"status": "Closed"}); + }); } }; diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index c354242353..2951d288a7 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -15,15 +15,15 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( refresh: function(doc, dt, dn) { this._super(); this.frm.dashboard.reset(); - var is_drop_ship = false; + var is_delivered_by_supplier = false; var is_delivery_note = false; if(doc.docstatus==1) { if(doc.status != 'Stopped' && doc.status != 'Closed') { $.each(cur_frm.doc.items, function(i, item){ - if(item.is_drop_ship == 1 || item.supplier){ - is_drop_ship = true; + if(item.is_delivered_by_supplier == 1 || item.supplier){ + is_delivered_by_supplier = true; } else{ is_delivery_note = true; @@ -45,7 +45,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( // stop if((flt(doc.per_delivered, 2) < 100 && is_delivery_note) || doc.per_billed < 100 - || (flt(doc.per_ordered,2) < 100 && is_drop_ship)){ + || (flt(doc.per_ordered,2) < 100 && is_delivered_by_supplier)){ cur_frm.add_custom_button(__('Stop'), this.stop_sales_order) } @@ -67,7 +67,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( cur_frm.add_custom_button(__('Invoice'), this.make_sales_invoice).addClass("btn-primary"); } - if(flt(doc.per_ordered, 2) < 100 && is_drop_ship) + if(flt(doc.per_ordered, 2) < 100 && is_delivered_by_supplier) cur_frm.add_custom_button(__('Make Purchase Order'), cur_frm.cscript.make_purchase_order).addClass("btn-primary"); } else { diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 8c5cf59829..f452fa9841 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -150,7 +150,7 @@ class SalesOrder(SellingController): def validate_drop_ship(self): for d in self.get('items'): - if d.is_drop_ship and not d.supplier: + if d.delivered_by_supplier and not d.supplier: frappe.throw(_("Row #{0}: Set Supplier for item {1}").format(d.idx, d.item_code)) def on_submit(self): @@ -277,9 +277,9 @@ def stop_or_unstop_sales_orders(names, status): for name in names: so = frappe.get_doc("Sales Order", name) if so.docstatus == 1: - if status=="Stop": - if so.status not in ("Stopped", "Cancelled") and (so.per_delivered < 100 or so.per_billed < 100): - so.stop_sales_order() + if status in ("Stopped", "Closed"): + if so.status not in ("Stopped", "Cancelled", "Closed") and (so.per_delivered < 100 or so.per_billed < 100): + so.stop_sales_order(status) else: if so.status == "Stopped": so.unstop_sales_order() @@ -359,7 +359,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 and doc.is_drop_ship!=1 + "condition": lambda doc: doc.delivered_qty < doc.qty and doc.delivered_by_supplier!=1 }, "Sales Taxes and Charges": { "doctype": "Sales Taxes and Charges", @@ -507,7 +507,7 @@ def make_purchase_order_for_drop_shipment(source_name, for_supplier, target_doc= if default_price_list: target.buying_price_list = default_price_list - target.is_drop_ship = 1 + target.delivered_by_supplier = 1 target.run_method("set_missing_values") target.run_method("calculate_taxes_and_totals") diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js index 6c6254b3bc..8030ff80e4 100644 --- a/erpnext/selling/doctype/sales_order/sales_order_list.js +++ b/erpnext/selling/doctype/sales_order/sales_order_list.js @@ -45,12 +45,16 @@ frappe.listview_settings['Sales Order'] = { var method = "erpnext.selling.doctype.sales_order.sales_order.stop_or_unstop_sales_orders"; listview.page.add_menu_item(__("Set as Stopped"), function() { - listview.call_for_selected_items(method, {"status": "Stop"}); + listview.call_for_selected_items(method, {"status": "Stoped"}); }); listview.page.add_menu_item(__("Set as Unstopped"), function() { listview.call_for_selected_items(method, {"status": "Unstop"}); }); + + listview.page.add_menu_item(__("Set as Closed"), function() { + listview.call_for_selected_items(method, {"status": "Closed"}); + }); } }; \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 367be5ef77..667f21b617 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -302,7 +302,7 @@ class TestSalesOrder(unittest.TestCase): from erpnext.buying.doctype.purchase_order.purchase_order import delivered_by_supplier po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 1, "is_sales_item": 1, - "is_purchase_item": 1, "is_drop_ship": 1, 'default_supplier': '_Test Supplier'}) + "is_purchase_item": 1, "delivered_by_supplier": 1, 'default_supplier': '_Test Supplier'}) dn_item = make_item("_Test Regular Item", {"is_stock_item": 1, "is_sales_item": 1, "is_purchase_item": 1}) @@ -314,7 +314,7 @@ class TestSalesOrder(unittest.TestCase): "qty": 2, "rate": 400, "conversion_factor": 1.0, - "is_drop_ship": 1, + "delivered_by_supplier": 1, "supplier": '_Test Supplier' }, { diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index cd56cc5f87..11181574e1 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -687,14 +687,14 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 1, - "collapsible_depends_on": "eval:doc.is_drop_ship==1", - "fieldname": "drop_ship", + "collapsible_depends_on": "eval:doc.delivered_by_supplier==1||doc.supplier", + "fieldname": "by_supplier", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Drop Ship", + "label": "Delivered by Supplier", "no_copy": 0, "permlevel": 0, "precision": "", @@ -707,20 +707,20 @@ "unique": 0 }, { - "allow_on_submit": 1, + "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "is_drop_ship", + "fieldname": "delivered_by_supplier", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Is Drop Ship Item", + "label": "Delivered By Supplier", "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 1, + "print_hide": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -1206,7 +1206,7 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-10-21 19:25:21.712515", + "modified": "2015-10-26 17:17:04.378067", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index bd812a062a..0f076f49f8 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -250,13 +250,13 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "is_drop_ship", + "fieldname": "delivered_by_supplier", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Is Drop Ship", + "label": "Delivered By Supplier", "no_copy": 0, "permlevel": 0, "precision": "", @@ -2157,7 +2157,11 @@ "issingle": 0, "istable": 0, "max_attachments": 1, +<<<<<<< ac7a1da680daa876b9f107cec87150cf7a195138 "modified": "2015-10-29 02:25:26.256373", +======= + "modified": "2015-10-26 17:18:54.615802", +>>>>>>> [fixes] bulk close facility, rename Drop Ship to Delivered By Supplier "modified_by": "Administrator", "module": "Stock", "name": "Item", diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 0c5f7c7eae..6c6f84ba38 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -174,7 +174,7 @@ def get_basic_details(args, item): "net_amount": 0.0, "discount_percentage": 0.0, "supplier": item.default_supplier, - "is_drop_ship": item.is_drop_ship, + "delivered_by_supplier": item.delivered_by_supplier, }) # if default specified in item is for another company, fetch from company From cc8f1afa568514247669f54f0ef8cf483348c971 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 26 Oct 2015 19:12:05 +0530 Subject: [PATCH 23/29] [fixes] test case fixes for drop shipping --- .../purchase_order/purchase_order.json | 8 ++-- .../doctype/purchase_order/purchase_order.py | 3 +- .../doctype/sales_order/sales_order.js | 9 +++-- .../doctype/sales_order/test_sales_order.py | 38 +++++++++++++------ erpnext/stock/stock_balance.py | 2 +- 5 files changed, 38 insertions(+), 22 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 318813c6d3..a866e81a99 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -465,17 +465,17 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "is_drop_ship", + "fieldname": "delivered_by_supplier", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Is Drop Ship", + "label": "Delivered By Supplier", "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 1, + "print_hide": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -2238,7 +2238,7 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-10-22 19:03:10.932738", + "modified": "2015-10-26 09:09:06.796558", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 45444b98a1..3fe833f36e 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -224,7 +224,8 @@ class PurchaseOrder(BuyingController): self.status_updater[0].update({ "target_parent_dt": "Sales Order", "target_dt": "Sales Order Item", - 'target_field': 'ordered_qty' + 'target_field': 'ordered_qty', + "target_parent_field": '' }) @frappe.whitelist() diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 2951d288a7..af300f662f 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -22,11 +22,12 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( if(doc.status != 'Stopped' && doc.status != 'Closed') { $.each(cur_frm.doc.items, function(i, item){ - if(item.is_delivered_by_supplier == 1 || item.supplier){ + if((item.delivered_by_supplier == 1 || item.supplier) && (item.qty > item.ordered_qty)){ is_delivered_by_supplier = true; } else{ - is_delivery_note = true; + if(item.qty > item.delivered_qty) + is_delivery_note = true; } }) @@ -177,11 +178,11 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( filters: {'parent': cur_frm.doc.name} } }, "reqd": 1 }, - {"fieldtype": "Button", "label": __("Proceed"), "fieldname": "proceed"}, + {"fieldtype": "Button", "label": __("Make Purchase Order"), "fieldname": "make_purchase_order"}, ] }); - dialog.fields_dict.proceed.$input.click(function() { + dialog.fields_dict.make_purchase_order.$input.click(function() { args = dialog.get_values(); if(!args) return; dialog.hide(); diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 667f21b617..3ef1a25bc5 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -302,10 +302,14 @@ class TestSalesOrder(unittest.TestCase): from erpnext.buying.doctype.purchase_order.purchase_order import delivered_by_supplier po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 1, "is_sales_item": 1, - "is_purchase_item": 1, "delivered_by_supplier": 1, 'default_supplier': '_Test Supplier'}) + "is_purchase_item": 1, "delivered_by_supplier": 1, 'default_supplier': '_Test Supplier', + "expense_account": "_Test Account Cost for Goods Sold - _TC", + "cost_center": "_Test Cost Center - _TC" + }) dn_item = make_item("_Test Regular Item", {"is_stock_item": 1, "is_sales_item": 1, - "is_purchase_item": 1}) + "is_purchase_item": 1, "expense_account": "_Test Account Cost for Goods Sold - _TC", + "cost_center": "_Test Cost Center - _TC"}) so_items = [ { @@ -326,8 +330,8 @@ class TestSalesOrder(unittest.TestCase): } ] - existing_ordered_qty, existing_reserved_qty = frappe.db.get_value("Bin", - {"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) + bin = frappe.get_all("Bin", filters={"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"}, + fields=["ordered_qty", "reserved_qty"]) so = make_sales_order(item_list=so_items, do_not_submit=True) so.submit() @@ -335,7 +339,7 @@ class TestSalesOrder(unittest.TestCase): po = make_purchase_order_for_drop_shipment(so.name, '_Test Supplier') po.submit() - dn = create_dn_against_so(so, delivered_qty=1) + dn = create_dn_against_so(so.name, delivered_qty=1) self.assertEquals(so.customer, po.customer) self.assertEquals(po.items[0].prevdoc_doctype, "Sales Order") @@ -344,19 +348,29 @@ class TestSalesOrder(unittest.TestCase): self.assertEquals(dn.items[0].item_code, dn_item.item_code) #test ordered_qty and reserved_qty - ordered_qty, reserved_qty = frappe.db.get_value("Bin", - {"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) + ordered_qty, reserved_qty = frappe.db.get_value("Bin", + {"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) + + existing_ordered_qty = bin[0].ordered_qty if bin else 0.0 + existing_reserved_qty = bin[0].reserved_qty if bin else 0.0 - self.assertEquals(abs(ordered_qty), (existing_ordered_qty + so_items[0]['qty'])) - self.assertEquals(abs(reserved_qty), (existing_reserved_qty + so_items[0]['qty'])) + self.assertEquals(abs(ordered_qty), existing_ordered_qty + so_items[0]['qty']) + self.assertEquals(abs(reserved_qty), existing_reserved_qty + so_items[0]['qty']) #test po_item length self.assertEquals(len(po.items), 1) - #test per_ordered status + #test per_delivered status delivered_by_supplier(po.name) - per_delivered = frappe.db.get_value("Sales Order", so.name, "per_delivered") - self.assertEquals(per_delivered, ) + per_delivered = frappe.db.sql("""select sum(if(qty > ifnull(delivered_qty, 0), delivered_qty, qty))/sum(qty)*100 as per_delivered + from `tabSales Order Item` where parent="{0}" """.format(so.name)) + + self.assertEquals(frappe.db.get_value("Sales Order", so.name, "per_delivered"), per_delivered[0][0]) + + dn = create_dn_against_so(so.name, delivered_qty=1) + + so.db_set('status', "Closed") + so.update_reserved_qty() def test_reserved_qty_for_closing_so(self): from erpnext.stock.doctype.item.test_item import make_item diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py index b1e8b22063..609c986c44 100644 --- a/erpnext/stock/stock_balance.py +++ b/erpnext/stock/stock_balance.py @@ -122,7 +122,7 @@ def get_ordered_qty(item_code, warehouse): from `tabPurchase Order Item` po_item, `tabPurchase Order` po where po_item.item_code=%s and po_item.warehouse=%s and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name - and po.status not in ('Stopped', 'Closed') and po.docstatus=1""", (item_code, warehouse)) + and po.status not in ('Stopped', 'Closed', 'Delivered') and po.docstatus=1""", (item_code, warehouse)) return flt(ordered_qty[0][0]) if ordered_qty else 0 From 653cffec1ecfe4113b46122e6800ab69c879c171 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 27 Oct 2015 17:07:56 +0530 Subject: [PATCH 24/29] [change_log and fixes] set print hide, add change_log --- .../doctype/sales_invoice_item/sales_invoice_item.json | 6 +++--- erpnext/buying/doctype/purchase_order/purchase_order.json | 6 +++--- erpnext/change_log/current/drop-ship.md | 1 + .../selling/doctype/sales_order_item/sales_order_item.json | 6 +++--- erpnext/stock/doctype/item/item.json | 6 +----- 5 files changed, 11 insertions(+), 14 deletions(-) create mode 100644 erpnext/change_log/current/drop-ship.md diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 0a98d87dc7..d4c40f2ade 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -717,7 +717,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -1327,8 +1327,8 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-10-26 17:22:23.631195", - "modified_by": "Administrator", + "modified": "2015-10-27 16:59:39.595490", + "modified_by": "saurabh@erpnext.com", "module": "Accounts", "name": "Sales Invoice Item", "owner": "Administrator", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index a866e81a99..121fc93fb9 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -475,7 +475,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -2238,8 +2238,8 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-10-26 09:09:06.796558", - "modified_by": "Administrator", + "modified": "2015-10-27 16:58:53.362949", + "modified_by": "saurabh@erpnext.com", "module": "Buying", "name": "Purchase Order", "owner": "Administrator", diff --git a/erpnext/change_log/current/drop-ship.md b/erpnext/change_log/current/drop-ship.md new file mode 100644 index 0000000000..d6758e77e6 --- /dev/null +++ b/erpnext/change_log/current/drop-ship.md @@ -0,0 +1 @@ +- **Drop Ship** You can now implement drop shipping by creating Purchase Order from Sales Order. \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 11181574e1..e8ad1e82f5 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -720,7 +720,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -1206,8 +1206,8 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-10-26 17:17:04.378067", - "modified_by": "Administrator", + "modified": "2015-10-27 17:00:01.005108", + "modified_by": "saurabh@erpnext.com", "module": "Selling", "name": "Sales Order Item", "owner": "Administrator", diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index 0f076f49f8..8632d124d3 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -260,7 +260,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -2157,11 +2157,7 @@ "issingle": 0, "istable": 0, "max_attachments": 1, -<<<<<<< ac7a1da680daa876b9f107cec87150cf7a195138 "modified": "2015-10-29 02:25:26.256373", -======= - "modified": "2015-10-26 17:18:54.615802", ->>>>>>> [fixes] bulk close facility, rename Drop Ship to Delivered By Supplier "modified_by": "Administrator", "module": "Stock", "name": "Item", From 2e65aadb1e36c26765e41e8df05ae6261815530a Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 28 Oct 2015 11:40:14 +0530 Subject: [PATCH 25/29] [fixes] reload doc after status update and supplier address fetching --- erpnext/buying/doctype/purchase_order/purchase_order.js | 7 +++++-- erpnext/buying/doctype/purchase_order/purchase_order.py | 2 -- erpnext/public/js/utils/party.js | 2 +- erpnext/selling/doctype/sales_order/sales_order.js | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index b6a785c348..146694e27d 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -179,7 +179,9 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( purchase_order: cur_frm.doc.name }, callback:function(r){ - cur_frm.refresh(); + if(!r.exc) { + cur_frm.reload_doc(); + } } }) } @@ -198,7 +200,8 @@ cur_frm.cscript.update_status= function(label, status){ method: "erpnext.buying.doctype.purchase_order.purchase_order.update_status", args:{status: status, name: doc.name}, callback:function(r){ - cur_frm.refresh(); + cur_frm.set_value("status", status); + cur_frm.reload_doc(); } }) } diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 3fe833f36e..26837f1a64 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -344,14 +344,12 @@ def make_stock_entry(purchase_order, item_code): def update_status(status, name): po = frappe.get_doc("Purchase Order", name) po.update_status(status) - return @frappe.whitelist() def delivered_by_supplier(purchase_order): po = frappe.get_doc("Purchase Order", purchase_order) update_delivered_qty(po) po.update_status("Delivered") - return po.as_dict() def update_delivered_qty(purchase_order): sales_order_list = [] diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 510938a9d1..93301fcb0b 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -53,7 +53,7 @@ erpnext.utils.get_address_display = function(frm, address_field, display_field) if(frm.updating_party_details) return; if(!address_field) { - if(frm.doc.customer) { + if(frm.doctype != "Purchase Order" && frm.doc.customer) { address_field = "customer_address"; } else if(frm.doc.supplier) { address_field = "supplier_address"; diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index af300f662f..9ad6d56301 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -37,7 +37,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( // doc.per_billed); // indent - if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1) + 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); if(flt(doc.per_billed)==0) { @@ -241,7 +241,7 @@ cur_frm.cscript.update_status = function(label, status){ method: "erpnext.selling.doctype.sales_order.sales_order.update_status", args:{status: status, name: doc.name}, callback:function(r){ - cur_frm.refresh(); + cur_frm.reload_doc(); } }) } From 6956eee790fbfd8d8b57850495ece0e33694d80f Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 29 Oct 2015 19:43:13 +0530 Subject: [PATCH 26/29] [fixes] test case and code rewrite --- .../purchase_order/purchase_order.json | 60 ++----------------- .../doctype/purchase_order/purchase_order.py | 24 ++------ .../purchase_order/test_purchase_order.py | 14 ++--- erpnext/controllers/status_updater.py | 4 +- .../doctype/sales_order/sales_order.js | 12 ++-- .../doctype/sales_order/sales_order.py | 36 ++++++++--- .../doctype/sales_order/test_sales_order.py | 57 +++++++++++++----- 7 files changed, 95 insertions(+), 112 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 121fc93fb9..cd4290134c 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -151,7 +151,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval:doc.is_drop_ship==1", + "depends_on": "eval:doc.delivered_by_supplier==1", "fieldname": "customer", "fieldtype": "Link", "hidden": 0, @@ -164,7 +164,7 @@ "permlevel": 0, "precision": "", "print_hide": 0, - "read_only": 0, + "read_only": 1, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -175,7 +175,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval:doc.is_drop_ship==1", + "depends_on": "eval:doc.delivered_by_supplier==1", "fieldname": "customer_name", "fieldtype": "Data", "hidden": 0, @@ -476,7 +476,7 @@ "permlevel": 0, "precision": "", "print_hide": 1, - "read_only": 0, + "read_only": 1, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -1557,30 +1557,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "depends_on": "eval:doc.is_drop_ship==1", - "fieldname": "customer_address", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Customer Address", - "no_copy": 0, - "options": "Address", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -1623,30 +1599,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "depends_on": "eval:doc.is_drop_ship==1", - "fieldname": "customer_contact_person", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Customer Contact Person", - "no_copy": 0, - "options": "Contact", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -2238,8 +2190,8 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-10-27 16:58:53.362949", - "modified_by": "saurabh@erpnext.com", + "modified": "2015-10-29 16:41:30.749753", + "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", "owner": "Administrator", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 26837f1a64..4f373e0eb2 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -353,25 +353,13 @@ def delivered_by_supplier(purchase_order): def update_delivered_qty(purchase_order): sales_order_list = [] + so_name = '' for item in purchase_order.items: if item.prevdoc_doctype == "Sales Order": - frappe.db.sql(""" update `tabSales Order Item` - set delivered_qty = (ifnull(delivered_qty, 0) + %(qty)s) - where item_code='%(item_code)s' and parent = '%(name)s' - """%{"qty": item.qty, "item_code": item.item_code, "name": item.prevdoc_docname}) - - sales_order_list.append(item.prevdoc_docname) + so_name = item.prevdoc_docname - update_per_delivery(sales_order_list) - -def update_per_delivery(sales_order_list): - for so in sales_order_list: - frappe.db.sql("""update `tabSales Order` - set per_delivered = (select - sum(if(qty > ifnull(delivered_qty, 0), delivered_qty, qty))/ sum(qty)*100 - from `tabSales Order Item` where parent="%(name)s") where name = "%(name)s" """%{"name":so}) - - so = frappe.get_doc("Sales Order", so) - so.set_status(update=True) - so.notify_update() + so = frappe.get_doc("Sales Order", so_name) + so.update_delivery_status(purchase_order.name) + so.set_status(update=True) + so.notify_update() \ No newline at end of file diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 0c8fba62b5..1988a6d8e1 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -71,19 +71,19 @@ class TestPurchaseOrder(unittest.TestCase): po = create_purchase_order(qty=3.4, do_not_save=True) self.assertRaises(UOMMustBeIntegerError, po.insert) - def test_ordered_qty_for_closing_po(self): - from erpnext.stock.doctype.item.test_item import make_item + def test_ordered_qty_for_closing_po(self): + bin = frappe.get_all("Bin", filters={"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"}, + fields=["ordered_qty"]) - item = make_item("_Test Close Item", {"is_stock_item": 1, "is_sales_item": 1, - "is_purchase_item": 1}) + existing_ordered_qty = bin[0].ordered_qty if bin else 0.0 - po = create_purchase_order(item_code=item.item_code, qty=1) + po = create_purchase_order(item_code= "_Test Item", qty=1) - self.assertEquals(get_ordered_qty(item_code=item.item_code, warehouse="_Test Warehouse - _TC"), 1) + self.assertEquals(get_ordered_qty(item_code= "_Test Item", warehouse="_Test Warehouse - _TC"), existing_ordered_qty+1) po.update_status("Closed") - self.assertEquals(get_ordered_qty(item_code=item.item_code, warehouse="_Test Warehouse - _TC"), 0) + self.assertEquals(get_ordered_qty(item_code="_Test Item", warehouse="_Test Warehouse - _TC"), existing_ordered_qty) def create_purchase_order(**args): po = frappe.new_doc("Purchase Order") diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 2de6777fef..b68339c351 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -174,9 +174,7 @@ class StatusUpdater(Document): if change_modified: args['set_modified'] = ', modified = now(), modified_by = "{0}"'\ .format(frappe.db.escape(frappe.session.user)) - - args["drop_ship_cond"] = '' - + self._update_children(args) if "percent_join_field" in args: diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 9ad6d56301..2022ffd80a 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -22,8 +22,9 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( if(doc.status != 'Stopped' && doc.status != 'Closed') { $.each(cur_frm.doc.items, function(i, item){ - if((item.delivered_by_supplier == 1 || item.supplier) && (item.qty > item.ordered_qty)){ - is_delivered_by_supplier = true; + if(item.delivered_by_supplier == 1 || item.supplier){ + if(item.qty > item.ordered_qty) + is_delivered_by_supplier = true; } else{ if(item.qty > item.delivered_qty) @@ -37,7 +38,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( // doc.per_billed); // indent - if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && flt(doc.per_delivered, 2) < 100) + if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && flt(doc.per_delivered, 2) < 100 && !is_delivered_by_supplier) cur_frm.add_custom_button(__('Material Request'), this.make_material_request); if(flt(doc.per_billed)==0) { @@ -45,8 +46,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( } // stop - if((flt(doc.per_delivered, 2) < 100 && is_delivery_note) || doc.per_billed < 100 - || (flt(doc.per_ordered,2) < 100 && is_delivered_by_supplier)){ + if(flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed) < 100) { cur_frm.add_custom_button(__('Stop'), this.stop_sales_order) } @@ -68,7 +68,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( cur_frm.add_custom_button(__('Invoice'), this.make_sales_invoice).addClass("btn-primary"); } - if(flt(doc.per_ordered, 2) < 100 && is_delivered_by_supplier) + if(flt(doc.per_delivered, 2) < 100 && is_delivered_by_supplier) cur_frm.add_custom_button(__('Make Purchase Order'), cur_frm.cscript.make_purchase_order).addClass("btn-primary"); } else { diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index f452fa9841..7ea796cc99 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -260,8 +260,34 @@ class SalesOrder(SellingController): pass def before_update_after_submit(self): - self.validate_drop_ship() + self.validate_drop_ship() + self.validate_po() + + def validate_po(self): + exc_list = [] + + for item in self.items: + supplier = frappe.db.get_value("Sales Order Item", {"parent": self.name, "item_code": item.item_code}, + "supplier") + if item.ordered_qty > 0.0 and item.supplier != supplier: + exc_list.append("Row #{0}: Not allowed to change supplier as Purchase Order already exists".format(item.idx)) + + if exc_list: + frappe.throw('\n'.join(exc_list)) + + def update_delivery_status(self, po_name): + tot_qty, delivered_qty = 0.0, 0.0 + for item in self.items: + if item.delivered_by_supplier: + delivered_qty = frappe.db.get_value("Purchase Order Item", {"parent": po_name, "item_code": item.item_code}, "qty") + frappe.db.set_value("Sales Order Item", item.name, "delivered_qty", delivered_qty) + + delivered_qty += item.delivered_qty + tot_qty += item.qty + + frappe.db.set_value("Sales Order", self.name, "per_delivered", flt(delivered_qty/tot_qty) * 100) + def get_list_context(context=None): from erpnext.controllers.website_list_for_contact import get_list_context list_context = get_list_context(context) @@ -551,15 +577,9 @@ def make_purchase_order_for_drop_shipment(source_name, for_supplier, target_doc= ], "postprocess": update_item, "condition": lambda doc: doc.ordered_qty < doc.qty and doc.supplier == for_supplier - }, - "Sales Taxes and Charges": { - "doctype": "Purchase Taxes and Charges", - "add_if_empty": True } }, target_doc, set_missing_values) - - return doclist @frappe.whitelist() @@ -595,4 +615,4 @@ def get_supplier(doctype, txt, searchfield, start, page_len, filters): def update_status(status, name): so = frappe.get_doc("Sales Order", name) so.stop_sales_order(status) - return \ No newline at end of file + \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 3ef1a25bc5..1d11a8bead 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -317,7 +317,6 @@ class TestSalesOrder(unittest.TestCase): "warehouse": "_Test Warehouse - _TC", "qty": 2, "rate": 400, - "conversion_factor": 1.0, "delivered_by_supplier": 1, "supplier": '_Test Supplier' }, @@ -330,9 +329,19 @@ class TestSalesOrder(unittest.TestCase): } ] + #setuo existing qty from bin bin = frappe.get_all("Bin", filters={"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"}, fields=["ordered_qty", "reserved_qty"]) - + + existing_ordered_qty = bin[0].ordered_qty if bin else 0.0 + existing_reserved_qty = bin[0].reserved_qty if bin else 0.0 + + bin = frappe.get_all("Bin", filters={"item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC"}, + fields=["reserved_qty"]) + + existing_reserved_qty_for_dn_item = bin[0].reserved_qty if bin else 0.0 + + #create so, po and partial dn so = make_sales_order(item_list=so_items, do_not_submit=True) so.submit() @@ -351,40 +360,56 @@ class TestSalesOrder(unittest.TestCase): ordered_qty, reserved_qty = frappe.db.get_value("Bin", {"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) - existing_ordered_qty = bin[0].ordered_qty if bin else 0.0 - existing_reserved_qty = bin[0].reserved_qty if bin else 0.0 - self.assertEquals(abs(ordered_qty), existing_ordered_qty + so_items[0]['qty']) - self.assertEquals(abs(reserved_qty), existing_reserved_qty + so_items[0]['qty']) + self.assertEquals(abs(reserved_qty), existing_reserved_qty + so_items[0]['qty']) + + reserved_qty = frappe.db.get_value("Bin", + {"item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC"}, "reserved_qty") + + self.assertEquals(abs(reserved_qty), existing_reserved_qty_for_dn_item + 1) #test po_item length self.assertEquals(len(po.items), 1) #test per_delivered status delivered_by_supplier(po.name) - per_delivered = frappe.db.sql("""select sum(if(qty > ifnull(delivered_qty, 0), delivered_qty, qty))/sum(qty)*100 as per_delivered - from `tabSales Order Item` where parent="{0}" """.format(so.name)) - - self.assertEquals(frappe.db.get_value("Sales Order", so.name, "per_delivered"), per_delivered[0][0]) + self.assertEquals(flt(frappe.db.get_value("Sales Order", so.name, "per_delivered"), 2), 75.00) + #test reserved qty after complete delivery dn = create_dn_against_so(so.name, delivered_qty=1) + reserved_qty = frappe.db.get_value("Bin", + {"item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC"}, "reserved_qty") + self.assertEquals(abs(reserved_qty), existing_reserved_qty_for_dn_item) + + #test after closing so so.db_set('status', "Closed") so.update_reserved_qty() + ordered_qty, reserved_qty = frappe.db.get_value("Bin", + {"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"]) + + self.assertEquals(abs(ordered_qty), existing_ordered_qty) + self.assertEquals(abs(reserved_qty), existing_reserved_qty) + + reserved_qty = frappe.db.get_value("Bin", + {"item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC"}, "reserved_qty") + + self.assertEquals(abs(reserved_qty), existing_reserved_qty) + def test_reserved_qty_for_closing_so(self): - from erpnext.stock.doctype.item.test_item import make_item + bin = frappe.get_all("Bin", filters={"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"}, + fields=["reserved_qty"]) - item = make_item("_Test Close Item", {"is_stock_item": 1, "is_sales_item": 1, - "is_purchase_item": 1}) + existing_reserved_qty = bin[0].reserved_qty if bin else 0.0 - so = make_sales_order(item_code=item.item_code, qty=1) + so = make_sales_order(item_code="_Test Item", qty=1) - self.assertEquals(get_reserved_qty(item_code=item.item_code, warehouse="_Test Warehouse - _TC"), 1) + self.assertEquals(get_reserved_qty(item_code="_Test Item", warehouse="_Test Warehouse - _TC"), existing_reserved_qty+1) so.stop_sales_order("Closed") - self.assertEquals(get_reserved_qty(item_code=item.item_code, warehouse="_Test Warehouse - _TC"), 0) + self.assertEquals(get_reserved_qty(item_code="_Test Item", warehouse="_Test Warehouse - _TC"), existing_reserved_qty) def make_sales_order(**args): From 61c9ea938d28de288287e4bdb4e3ef5d842744f2 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Fri, 30 Oct 2015 12:02:24 +0530 Subject: [PATCH 27/29] [Change Log] change log entry for drop shipment --- erpnext/change_log/current/drop-ship.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/change_log/current/drop-ship.md b/erpnext/change_log/current/drop-ship.md index d6758e77e6..daa06c2c39 100644 --- a/erpnext/change_log/current/drop-ship.md +++ b/erpnext/change_log/current/drop-ship.md @@ -1 +1,2 @@ -- **Drop Ship** You can now implement drop shipping by creating Purchase Order from Sales Order. \ No newline at end of file +- **Drop Ship** + - Make Sales Order with mrked item as **_Delivered By Supplier_** and submit SO and then make a Purchase Order. \ No newline at end of file From 381385d19a26c9bf368a44c4d0e26f5c430605b9 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 2 Nov 2015 11:30:51 +0530 Subject: [PATCH 28/29] [fixes] add status 'Closed' in filter creating PR, PI from PO and SI, DN from SO --- erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js | 2 +- erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 2 +- erpnext/stock/doctype/delivery_note/delivery_note.js | 2 +- erpnext/stock/doctype/purchase_receipt/purchase_receipt.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index 2e3794a238..3c2d3f6cb4 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -38,7 +38,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({ get_query_filters: { supplier: cur_frm.doc.supplier || undefined, docstatus: 1, - status: ["!=", "Stopped"], + status: ["not in", ["Stopped", "Closed"]], per_billed: ["<", 99.99], company: cur_frm.doc.company } diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 9b9ab24811..213c2491e4 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -111,7 +111,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte source_doctype: "Sales Order", get_query_filters: { docstatus: 1, - status: ["!=", "Stopped"], + status: ["not in", ["Stopped", "Closed"]], per_billed: ["<", 99.99], customer: cur_frm.doc.customer || undefined, company: cur_frm.doc.company diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js index 17194fdd4a..876e369946 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.js +++ b/erpnext/stock/doctype/delivery_note/delivery_note.js @@ -30,7 +30,7 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend( source_doctype: "Sales Order", get_query_filters: { docstatus: 1, - status: ["!=", "Stopped"], + status: ["not in", ["Stopped", "Closed"]], per_delivered: ["<", 99.99], project_name: cur_frm.doc.project_name || undefined, customer: cur_frm.doc.customer || undefined, diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js index 38b054cbfd..0ebd7538b0 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js @@ -43,7 +43,7 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend get_query_filters: { supplier: cur_frm.doc.supplier || undefined, docstatus: 1, - status: ["!=", "Stopped"], + status: ["not in", ["Stopped", "Closed"]], per_received: ["<", 99.99], company: cur_frm.doc.company } From 7cd0ba70d925694421c98962acc3b0f30f187e02 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 2 Nov 2015 15:18:23 +0530 Subject: [PATCH 29/29] [fixes] typo error --- .../doctype/sales_invoice_item/sales_invoice_item.json | 10 +++++----- .../buying/doctype/purchase_order/purchase_order.js | 4 ++-- .../doctype/sales_order_item/sales_order_item.json | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index d4c40f2ade..0dcf9f5d0a 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -685,13 +685,13 @@ "bold": 0, "collapsible": 1, "collapsible_depends_on": "eval:doc.delivered_by_supplier==1", - "fieldname": "by_supplier", + "fieldname": "drop_ship", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Delivered By Sypplier", + "label": "Drop Ship", "no_copy": 0, "permlevel": 0, "precision": "", @@ -718,7 +718,7 @@ "permlevel": 0, "precision": "", "print_hide": 1, - "read_only": 0, + "read_only": 1, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -1327,8 +1327,8 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-10-27 16:59:39.595490", - "modified_by": "saurabh@erpnext.com", + "modified": "2015-11-02 15:14:02.306067", + "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", "owner": "Administrator", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 146694e27d..463b5d9901 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -166,7 +166,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( cur_frm.cscript.update_status('Stop', 'Stopped') }, unstop_purchase_order: function(){ - cur_frm.cscript.update_status('UNSTOP', 'Submitted') + cur_frm.cscript.update_status('Resume', 'Submitted') }, close_purchase_order: function(){ cur_frm.cscript.update_status('Close', 'Closed') @@ -174,7 +174,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( delivered_by_supplier: function(){ return frappe.call({ method: "erpnext.buying.doctype.purchase_order.purchase_order.delivered_by_supplier", - freez: true, + freeze: true, args:{ purchase_order: cur_frm.doc.name }, diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index e8ad1e82f5..93ba3a5f94 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -688,17 +688,17 @@ "bold": 0, "collapsible": 1, "collapsible_depends_on": "eval:doc.delivered_by_supplier==1||doc.supplier", - "fieldname": "by_supplier", + "fieldname": "drop_ship", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, "in_filter": 0, "in_list_view": 0, - "label": "Delivered by Supplier", + "label": "Drop Ship", "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -1206,8 +1206,8 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-10-27 17:00:01.005108", - "modified_by": "saurabh@erpnext.com", + "modified": "2015-11-02 15:15:05.774529", + "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", "owner": "Administrator",