From d10ba853e68c7d30b6d49e1b3adba69003f951e3 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 2 Oct 2015 12:42:48 +0530 Subject: [PATCH] [fix] sales & purchase order status --- .../doctype/sales_invoice/sales_invoice.py | 4 +- .../purchase_order/purchase_order.json | 5 +- .../doctype/purchase_order/purchase_order.py | 18 ++---- erpnext/controllers/status_updater.py | 18 +++++- erpnext/patches.txt | 3 +- .../fix_status_in_sales_and_purchase_order.py | 7 +++ .../doctype/time_log/time_log_calendar.js | 1 + .../doctype/time_log_batch/time_log_batch.py | 2 +- .../doctype/sales_order/sales_order.json | 4 +- .../doctype/sales_order/sales_order.py | 58 ++++++++----------- erpnext/startup/notifications.py | 13 ++++- 11 files changed, 73 insertions(+), 60 deletions(-) create mode 100644 erpnext/patches/v6_4/fix_status_in_sales_and_purchase_order.py diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index dba7647a62..33fa4e340b 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -207,8 +207,8 @@ class SalesInvoice(SellingController): def validate_time_logs_are_submitted(self): for d in self.get("items"): if d.time_log_batch: - status = frappe.db.get_value("Time Log Batch", d.time_log_batch, "status") - if status!="Submitted": + docstatus = frappe.db.get_value("Time Log Batch", d.time_log_batch, "docstatus") + if docstatus!=1: frappe.throw(_("Time Log Batch {0} must be 'Submitted'").format(d.time_log_batch)) def set_pos_fields(self, for_validate=False): diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index e4d04eae06..6a7256ade2 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -1468,6 +1468,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "default": "Draft", "fieldname": "status", "fieldtype": "Select", "hidden": 0, @@ -1478,7 +1479,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "\nDraft\nSubmitted\nStopped\nCancelled", + "options": "\nDraft\nTo Receive and Bill\nTo Bill\nTo Receive\nCompleted\nStopped\nCancelled", "permlevel": 0, "print_hide": 1, "read_only": 1, @@ -2032,7 +2033,7 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-09-30 08:52:56.137185", + "modified": "2015-10-02 07:17:59.659036", "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 e8c79d8e7a..0affd78f9b 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -36,13 +36,7 @@ class PurchaseOrder(BuyingController): def validate(self): super(PurchaseOrder, self).validate() - if not self.status: - self.status = "Draft" - - from erpnext.controllers.status_updater import validate_status - validate_status(self.status, ["Draft", "Submitted", "Stopped", - "Cancelled"]) - + self.set_status() pc_obj = frappe.get_doc('Purchase Common') pc_obj.validate_for_items(self) self.check_for_stopped_status(pc_obj) @@ -160,12 +154,10 @@ class PurchaseOrder(BuyingController): def update_status(self, status): self.check_modified_date() - frappe.db.set(self,'status',cstr(status)) - + self.db_set('status', status) + self.set_status(update=True) self.update_requested_qty() self.update_ordered_qty() - - msgprint(_("Status of {0} {1} is now {2}").format(self.doctype, self.name, status)) self.notify_update() clear_doctype_notifications(self) @@ -183,8 +175,6 @@ class PurchaseOrder(BuyingController): purchase_controller.update_last_purchase_rate(self, is_submit = 1) - frappe.db.set(self,'status','Submitted') - def on_cancel(self): pc_obj = frappe.get_doc('Purchase Common') self.check_for_stopped_status(pc_obj) @@ -238,7 +228,7 @@ def stop_or_unstop_purchase_orders(names, status): po.update_status("Stopped") else: if po.status == "Stopped": - po.update_status("Submitted") + po.update_status("Draft") frappe.local.message_log = [] diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 42eaf4db59..7d18867869 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -30,7 +30,19 @@ status_map = { ], "Sales Order": [ ["Draft", None], - ["Submitted", "eval:self.docstatus==1"], + ["To Deliver and Bill", "eval:self.per_delivered < 100 and self.per_billed < 100 and self.docstatus == 1"], + ["To Bill", "eval:self.per_delivered == 100 and self.per_billed < 100 and self.docstatus == 1"], + ["To Deliver", "eval:self.per_delivered < 100 and self.per_billed == 100 and self.docstatus == 1"], + ["Completed", "eval:self.per_delivered == 100 and self.per_billed == 100 and self.docstatus == 1"], + ["Stopped", "eval:self.status=='Stopped'"], + ["Cancelled", "eval:self.docstatus==2"], + ], + "Purchase Order": [ + ["Draft", None], + ["To Receive and Bill", "eval:self.per_received < 100 and self.per_billed < 100 and self.docstatus == 1"], + ["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"], ["Stopped", "eval:self.status=='Stopped'"], ["Cancelled", "eval:self.docstatus==2"], ], @@ -222,7 +234,9 @@ class StatusUpdater(Document): where name='%(name)s'""" % args) if args.get("set_modified"): - frappe.get_doc(args["target_parent_dt"], name).notify_update() + target = frappe.get_doc(args["target_parent_dt"], name) + target.set_status(update=True) + target.notify_update() def update_billing_status_for_zero_amount_refdoc(self, ref_dt): ref_fieldname = ref_dt.lower().replace(" ", "_") diff --git a/erpnext/patches.txt b/erpnext/patches.txt index fe930c4f0c..9eaa0121da 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -213,4 +213,5 @@ erpnext.patches.v5_8.tax_rule erpnext.patches.v6_3.convert_applicable_territory erpnext.patches.v6_4.round_status_updater_percentages erpnext.patches.v6_4.repost_gle_for_journal_entries_where_reference_name_missing -erpnext.patches.v6_4.fix_journal_entries_due_to_reconciliation \ No newline at end of file +erpnext.patches.v6_4.fix_journal_entries_due_to_reconciliation +erpnext.patches.v6_4.fix_status_in_sales_and_purchase_order diff --git a/erpnext/patches/v6_4/fix_status_in_sales_and_purchase_order.py b/erpnext/patches/v6_4/fix_status_in_sales_and_purchase_order.py new file mode 100644 index 0000000000..867a5b2182 --- /dev/null +++ b/erpnext/patches/v6_4/fix_status_in_sales_and_purchase_order.py @@ -0,0 +1,7 @@ +import frappe + +def execute(): + for doctype in ("Sales Order", "Purchase Order"): + for doc in frappe.get_all(doctype, filters={"docstatus": 1}): + doc = frappe.get_doc(doctype, doc.name) + doc.set_status(update=True) diff --git a/erpnext/projects/doctype/time_log/time_log_calendar.js b/erpnext/projects/doctype/time_log/time_log_calendar.js index 61229d6a98..132355f38c 100644 --- a/erpnext/projects/doctype/time_log/time_log_calendar.js +++ b/erpnext/projects/doctype/time_log/time_log_calendar.js @@ -10,6 +10,7 @@ frappe.views.calendar["Time Log"] = { "allDay": "allDay" }, gantt: true, + gantt_scale: "hours", filters: [ { "fieldtype": "Link", diff --git a/erpnext/projects/doctype/time_log_batch/time_log_batch.py b/erpnext/projects/doctype/time_log_batch/time_log_batch.py index 55d593763d..03bd881602 100644 --- a/erpnext/projects/doctype/time_log_batch/time_log_batch.py +++ b/erpnext/projects/doctype/time_log_batch/time_log_batch.py @@ -34,7 +34,7 @@ class TimeLogBatch(Document): def validate_time_log_is_submitted(self, tl): if tl.status == "Batched for Billing": frappe.throw(_("Time Log {0} already billed").format(tl.name)) - elif tl.status != "Submitted": + elif tl.docstatus != 1: frappe.throw(_("Time Log {0} must be 'Submitted'").format(tl.name)) def set_status(self): diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index a7fa95451e..0e26727188 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -1977,7 +1977,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "\nDraft\nSubmitted\nStopped\nCancelled", + "options": "\nDraft\nTo Deliver and Bill\nTo Bill\nTo Deliver\nCompleted\nStopped\nCancelled", "permlevel": 0, "print_hide": 1, "read_only": 1, @@ -2553,7 +2553,7 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-09-30 08:52:52.211212", + "modified": "2015-10-02 07:17:43.178678", "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 3e689038a0..eda8c7323a 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -20,6 +20,27 @@ form_grid_templates = { class WarehouseRequired(frappe.ValidationError): pass class SalesOrder(SellingController): + def validate(self): + super(SalesOrder, self).validate() + + self.validate_order_type() + self.validate_delivery_date() + self.validate_mandatory() + self.validate_proj_cust() + self.validate_po() + self.validate_uom_is_integer("stock_uom", "qty") + self.validate_for_items() + self.validate_warehouse() + + from erpnext.stock.doctype.packed_item.packed_item import make_packing_list + make_packing_list(self,'items') + + self.validate_with_previous_doc() + self.set_status() + + if not self.billing_status: self.billing_status = 'Not Billed' + if not self.delivery_status: self.delivery_status = 'Not Delivered' + def validate_mandatory(self): # validate transaction date v/s delivery date if self.delivery_date: @@ -93,33 +114,6 @@ class SalesOrder(SellingController): if not res: frappe.throw(_("Customer {0} does not belong to project {1}").format(self.customer, self.project_name)) - def validate(self): - super(SalesOrder, self).validate() - - self.validate_order_type() - self.validate_delivery_date() - self.validate_mandatory() - self.validate_proj_cust() - self.validate_po() - self.validate_uom_is_integer("stock_uom", "qty") - self.validate_for_items() - self.validate_warehouse() - - from erpnext.stock.doctype.packed_item.packed_item import make_packing_list - make_packing_list(self,'items') - - self.validate_with_previous_doc() - - if not self.status: - self.status = "Draft" - - from erpnext.controllers.status_updater import validate_status - validate_status(self.status, ["Draft", "Submitted", "Stopped", - "Cancelled"]) - - if not self.billing_status: self.billing_status = 'Not Billed' - if not self.delivery_status: self.delivery_status = 'Not Delivered' - def validate_warehouse(self): from erpnext.stock.utils import validate_warehouse_company @@ -162,7 +156,6 @@ class SalesOrder(SellingController): frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, self.base_grand_total, self) self.update_prevdoc_status('submit') - frappe.db.set(self, 'status', 'Submitted') def on_cancel(self): # Cannot cancel stopped SO @@ -175,7 +168,7 @@ class SalesOrder(SellingController): self.update_prevdoc_status('cancel') frappe.db.set(self, 'status', 'Cancelled') - + def check_credit_limit(self): from erpnext.selling.doctype.customer.customer import check_credit_limit check_credit_limit(self.customer, self.company) @@ -223,17 +216,16 @@ class SalesOrder(SellingController): def stop_sales_order(self): self.check_modified_date() - frappe.db.set(self, 'status', 'Stopped') + self.db_set('status', 'Stopped') self.update_reserved_qty() - frappe.msgprint(_("{0} {1} status is Stopped").format(self.doctype, self.name)) self.notify_update() clear_doctype_notifications(self) def unstop_sales_order(self): self.check_modified_date() - frappe.db.set(self, 'status', 'Submitted') + self.db_set('status', 'Draft') + self.set_status(update=True) self.update_reserved_qty() - frappe.msgprint(_("{0} {1} status is Unstopped").format(self.doctype, self.name)) clear_doctype_notifications(self) def update_reserved_qty(self, so_item_rows=None): diff --git a/erpnext/startup/notifications.py b/erpnext/startup/notifications.py index c7e63f133c..12d0308ecd 100644 --- a/erpnext/startup/notifications.py +++ b/erpnext/startup/notifications.py @@ -2,7 +2,6 @@ # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals -import frappe def get_notification_config(): return { "for_doctype": @@ -15,7 +14,11 @@ def get_notification_config(): "Contact": {"status": "Open"}, "Opportunity": {"status": "Open"}, "Quotation": {"docstatus": 0}, - "Sales Order": { "per_billed": ("<", 100), "status": ("!=", "Stopped"), "docstatus": ("<", 2) }, + "Sales Order": { + "status": ("!=", "Stopped"), + "status": ("!=", "Completed"), + "docstatus": ("<", 2) + }, "Journal Entry": {"docstatus": 0}, "Sales Invoice": { "outstanding_amount": (">", 0), "docstatus": ("<", 2) }, "Purchase Invoice": {"docstatus": 0}, @@ -26,7 +29,11 @@ def get_notification_config(): "Delivery Note": {"docstatus": 0}, "Stock Entry": {"docstatus": 0}, "Material Request": {"docstatus": 0}, - "Purchase Order": { "per_billed": ("<", 100), "status": ("!=", "Stopped"), "docstatus": ("<", 2) }, + "Purchase Order": { + "status": ("!=", "Completed"), + "status": ("!=", "Stopped"), + "docstatus": ("<", 2) + }, "Production Order": { "status": "In Process" }, "BOM": {"docstatus": 0}, "Timesheet": {"docstatus": 0},