diff --git a/erpnext/controllers/tests/test_recurring_document.py b/erpnext/controllers/tests/test_recurring_document.py index e218fa6c9b..d47c5c7701 100644 --- a/erpnext/controllers/tests/test_recurring_document.py +++ b/erpnext/controllers/tests/test_recurring_document.py @@ -27,8 +27,7 @@ def test_recurring_document(obj, test_records): base_doc.set(date_field, today) if base_doc.doctype == "Sales Order": - for d in base_doc.get("items"): - d.set("delivery_date", add_days(today, 15)) + base_doc.set("delivery_date", add_days(today, 15)) # monthly doc1 = frappe.copy_doc(base_doc) diff --git a/erpnext/demo/user/sales.py b/erpnext/demo/user/sales.py index 666e201716..ddd36efc36 100644 --- a/erpnext/demo/user/sales.py +++ b/erpnext/demo/user/sales.py @@ -118,8 +118,7 @@ def make_sales_order(): from erpnext.selling.doctype.quotation.quotation import make_sales_order so = frappe.get_doc(make_sales_order(q)) so.transaction_date = frappe.flags.current_date - for d in so.get("items"): - d.delivery_date = frappe.utils.add_days(frappe.flags.current_date, 10) + so.delivery_date = frappe.utils.add_days(frappe.flags.current_date, 10) so.insert() frappe.db.commit() so.submit() diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 6e2284f493..2923d6dc9d 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -422,7 +422,7 @@ erpnext.patches.v8_1.add_indexes_in_transaction_doctypes erpnext.patches.v8_3.set_restrict_to_domain_for_module_def erpnext.patches.v8_1.update_expense_claim_status erpnext.patches.v8_3.update_company_total_sales -erpnext.patches.v8_1.set_delivery_date_in_so_item +erpnext.patches.v8_1.set_delivery_date_in_so_item #2017-07-28 erpnext.patches.v8_5.fix_tax_breakup_for_non_invoice_docs erpnext.patches.v8_5.update_customer_group_in_POS_profile erpnext.patches.v8_6.update_timesheet_company_from_PO \ No newline at end of file diff --git a/erpnext/patches/v8_1/set_delivery_date_in_so_item.py b/erpnext/patches/v8_1/set_delivery_date_in_so_item.py index 6840424774..963b82a4de 100644 --- a/erpnext/patches/v8_1/set_delivery_date_in_so_item.py +++ b/erpnext/patches/v8_1/set_delivery_date_in_so_item.py @@ -4,10 +4,18 @@ def execute(): frappe.reload_doctype("Sales Order") frappe.reload_doctype("Sales Order Item") - frappe.db.sql("""update `tabSales Order` set final_delivery_date = delivery_date where docstatus=1""") + if "final_delivery_date" in frappe.db.get_table_columns("Sales Order"): + frappe.db.sql(""" + update `tabSales Order` + set delivery_date = final_delivery_date + where (delivery_date is null or delivery_date = '' or delivery_date = '0000-00-00') + and order_type = 'Sales'""") frappe.db.sql(""" update `tabSales Order` so, `tabSales Order Item` so_item set so_item.delivery_date = so.delivery_date where so.name = so_item.parent + and so.order_type = 'Sales' + and (so_item.delivery_date is null or so_item.delivery_date = '' + or so_item.delivery_date = '0000-00-00') """) \ No newline at end of file diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index 7fb40748f0..fa69df418a 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -27,8 +27,7 @@ class TestQuotation(unittest.TestCase): self.assertEquals(sales_order.get("items")[0].prevdoc_docname, quotation.name) self.assertEquals(sales_order.customer, "_Test Customer") - for d in sales_order.get("items"): - d.delivery_date = "2014-01-01" + sales_order.delivery_date = "2014-01-01" sales_order.naming_series = "_T-Quotation-" sales_order.transaction_date = "2013-05-12" sales_order.insert() @@ -54,8 +53,7 @@ class TestQuotation(unittest.TestCase): sales_order = make_sales_order(quotation.name) sales_order.naming_series = "_T-Quotation-" sales_order.transaction_date = "2016-01-01" - for d in sales_order.get("items"): - d.delivery_date = "2016-01-02" + sales_order.delivery_date = "2016-01-02" sales_order.insert() diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 2e01a08359..80dc4f23ec 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -34,11 +34,20 @@ frappe.ui.form.on("Sales Order", { erpnext.queries.setup_warehouse_query(frm); }, + + delivery_date: function(frm) { + $.each(frm.doc.items || [], function(i, d) { + if(!d.delivery_date) d.delivery_date = frm.doc.delivery_date; + }); + refresh_field("items"); + } }); frappe.ui.form.on("Sales Order Item", { delivery_date: function(frm, cdt, cdn) { - erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "delivery_date"); + if(!frm.doc.delivery_date) { + erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "delivery_date"); + } } }); @@ -416,8 +425,13 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( items_add: function(doc, cdt, cdn) { var row = frappe.get_doc(cdt, cdn); - this.frm.script_manager.copy_from_first_row("items", row, ["delivery_date"]); + if(doc.delivery_date) { + row.delivery_date = doc.delivery_date; + refresh_field("delivery_date", cdn, "items"); + } else { + this.frm.script_manager.copy_from_first_row("items", row, ["delivery_date"]); + } } }); -$.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm})); +$.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm})); \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 596bf2f9dd..bf2ccf78f8 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -367,23 +367,23 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "final_delivery_date", + "fieldname": "delivery_date", "fieldtype": "Date", - "hidden": 1, + "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 0, - "label": "Final Delivery Date", + "label": "Delivery Date", "length": 0, "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 1, + "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -3659,7 +3659,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-07-25 13:45:02.965353", + "modified": "2017-07-28 14:03:33.373347", "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 fd80dc8662..c6dbd7043b 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -101,20 +101,20 @@ class SalesOrder(SellingController): super(SalesOrder, self).validate_order_type() def validate_delivery_date(self): - self.final_delivery_date = None if self.order_type == 'Sales': - for d in self.get("items"): - if not d.delivery_date: - frappe.throw(_("Row #{0}: Please enter Delivery Date against item {1}") - .format(d.idx, d.item_code)) + if not self.delivery_date: + self.delivery_date = max([d.delivery_date for d in self.get("items")]) - if getdate(self.transaction_date) > getdate(d.delivery_date): - frappe.msgprint(_("Expected Delivery Date should be after Sales Order Date"), - indicator='orange', title=_('Warning')) - - if not self.final_delivery_date or \ - (d.delivery_date and getdate(d.delivery_date) > getdate(self.final_delivery_date)): - self.final_delivery_date = d.delivery_date + if self.delivery_date: + for d in self.get("items"): + if not d.delivery_date: + d.delivery_date = self.delivery_date + + if getdate(self.transaction_date) > getdate(d.delivery_date): + frappe.msgprint(_("Expected Delivery Date should be after Sales Order Date"), + indicator='orange', title=_('Warning')) + else: + frappe.throw(_("Please enter Delivery Date")) self.validate_sales_mntc_quotation() @@ -347,6 +347,9 @@ class SalesOrder(SellingController): def on_recurring(self, reference_doc): mcount = month_map[reference_doc.recurring_type] + self.set("delivery_date", get_next_date(reference_doc.delivery_date, mcount, + cint(reference_doc.repeat_on_day_of_month))) + for d in self.get("items"): reference_delivery_date = frappe.db.get_value("Sales Order Item", {"parent": reference_doc.name, "item_code": d.item_code, "idx": d.idx}, "delivery_date") diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js index 0ee9cf34f0..9751935183 100644 --- a/erpnext/selling/doctype/sales_order/sales_order_list.js +++ b/erpnext/selling/doctype/sales_order/sales_order_list.js @@ -1,14 +1,14 @@ frappe.listview_settings['Sales Order'] = { - add_fields: ["base_grand_total", "customer_name", "currency", "final_delivery_date", + add_fields: ["base_grand_total", "customer_name", "currency", "delivery_date", "per_delivered", "per_billed", "status", "order_type", "name"], get_indicator: function(doc) { 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.final_delivery_date) < 0) { + && flt(doc.per_delivered, 2) < 100 && frappe.datetime.get_diff(doc.delivery_date) < 0) { // to bill & overdue - return [__("Overdue"), "red", "per_delivered,<,100|final_delivery_date,<,Today|status,!=,Closed"]; + return [__("Overdue"), "red", "per_delivered,<,100|delivery_date,<,Today|status,!=,Closed"]; } else if (doc.order_type !== "Maintenance" && flt(doc.per_delivered, 2) < 100 && doc.status!=="Closed") { diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.js b/erpnext/selling/doctype/sales_order/test_sales_order.js new file mode 100644 index 0000000000..87f0e965c2 --- /dev/null +++ b/erpnext/selling/doctype/sales_order/test_sales_order.js @@ -0,0 +1,59 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Sales Order", function (assert) { + assert.expect(2); + let done = assert.async(); + let delivery_date = frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1); + + frappe.run_serially([ + // insert a new Sales Order + () => { + return frappe.tests.make('Sales Order', [ + {customer: "Test Customer 1"}, + {delivery_date: delivery_date}, + {order_type: 'Sales'}, + {items: [ + [ + {"item_code": "Test Product 1"}, + {"qty": 5}, + {'rate': 100}, + ]] + } + ]) + }, + () => { + assert.ok(cur_frm.doc.items[0].delivery_date == delivery_date); + }, + () => frappe.timeout(1), + // make SO without delivery date in parent, + // parent delivery date should be set based on final delivery date entered in item + () => { + return frappe.tests.make('Sales Order', [ + {customer: "Test Customer 1"}, + {order_type: 'Sales'}, + {items: [ + [ + {"item_code": "Test Product 1"}, + {"qty": 5}, + {'rate': 100}, + {'delivery_date': delivery_date} + ], + [ + {"item_code": "Test Product 2"}, + {"qty": 5}, + {'rate': 100}, + {'delivery_date': frappe.datetime.add_days(delivery_date, 5)} + ]] + } + ]) + }, + () => cur_frm.save(), + () => frappe.timeout(1), + () => { + assert.ok(cur_frm.doc.delivery_date == frappe.datetime.add_days(delivery_date, 5)); + }, + () => done() + ]); +}); \ 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 8c0711870b..ce8c18af41 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -532,8 +532,7 @@ def make_sales_order(**args): "rate": args.rate or 100 }) - for d in so.get("items"): - d.delivery_date = add_days(so.transaction_date, 10) + so.delivery_date = add_days(so.transaction_date, 10) if not args.do_not_save: so.insert() 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 f14f50dedd..47bc1b6077 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -220,7 +220,7 @@ "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, @@ -1963,7 +1963,7 @@ "istable": 1, "max_attachments": 0, "menu_index": 0, - "modified": "2017-07-18 18:26:36.870342", + "modified": "2017-07-28 14:04:04.289428", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/tests/ui/tests.txt b/erpnext/tests/ui/tests.txt index 42233dc800..40b1c590e0 100644 --- a/erpnext/tests/ui/tests.txt +++ b/erpnext/tests/ui/tests.txt @@ -2,4 +2,5 @@ erpnext/tests/ui/make_fixtures.js #long erpnext/accounts/doctype/account/test_account.js erpnext/crm/doctype/lead/test_lead.js erpnext/crm/doctype/opportunity/test_opportunity.js -erpnext/selling/doctype/quotation/test_quotation.js \ No newline at end of file +erpnext/selling/doctype/quotation/test_quotation.js +erpnext/selling/doctype/sales_order/test_sales_order.js \ No newline at end of file