From d10ba853e68c7d30b6d49e1b3adba69003f951e3 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 2 Oct 2015 12:42:48 +0530 Subject: [PATCH 01/13] [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}, From 0bc3ca02f3067d589eccca36e839aa70c5965f1e Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Sat, 3 Oct 2015 12:08:32 +0530 Subject: [PATCH 02/13] [fix] default contact for website --- erpnext/controllers/website_list_for_contact.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/controllers/website_list_for_contact.py b/erpnext/controllers/website_list_for_contact.py index 51fb0a5889..c92538332a 100644 --- a/erpnext/controllers/website_list_for_contact.py +++ b/erpnext/controllers/website_list_for_contact.py @@ -35,6 +35,8 @@ def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_p key, parties = "customer", customers elif suppliers: key, parties = "supplier", suppliers + else: + key, parties = "customer", [] filters.append((doctype, key, "in", parties)) From ae92fc7f35575595d3b76ee532c71f9898c14135 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 3 Oct 2015 13:22:53 +0530 Subject: [PATCH 03/13] [fix] Create sample opportunity and quotation only if Customer exists --- .../setup/page/setup_wizard/sample_data.py | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/erpnext/setup/page/setup_wizard/sample_data.py b/erpnext/setup/page/setup_wizard/sample_data.py index 2cebc9148b..095264f44d 100644 --- a/erpnext/setup/page/setup_wizard/sample_data.py +++ b/erpnext/setup/page/setup_wizard/sample_data.py @@ -4,8 +4,9 @@ from __future__ import unicode_literals import frappe -from frappe.utils.make_random import add_random_children, get_random +from frappe.utils.make_random import add_random_children import frappe.utils +import random def make_sample_data(): """Create a few opportunities, quotes, material requests, issues, todos, projects @@ -13,11 +14,13 @@ def make_sample_data(): selling_items = frappe.get_all("Item", filters = {"is_sales_item": 1}) buying_items = frappe.get_all("Item", filters = {"is_purchase_item": 1}) - - if selling_items: + customers = frappe.get_all("Customer") + + if selling_items and customers: for i in range(3): - make_opportunity(selling_items) - make_quote(selling_items) + customer = random.choice(customers).name + make_opportunity(selling_items, customer) + make_quote(selling_items, customer) make_projects() @@ -26,11 +29,11 @@ def make_sample_data(): frappe.db.commit() -def make_opportunity(selling_items): +def make_opportunity(selling_items, customer): b = frappe.get_doc({ "doctype": "Opportunity", "enquiry_from": "Customer", - "customer": get_random("Customer"), + "customer": customer, "enquiry_type": "Sales", "with_items": 1 }) @@ -44,11 +47,11 @@ def make_opportunity(selling_items): b.add_comment("This is a dummy record") -def make_quote(selling_items): +def make_quote(selling_items, customer): qtn = frappe.get_doc({ "doctype": "Quotation", "quotation_to": "Customer", - "customer": get_random("Customer"), + "customer": customer, "order_type": "Sales" }) From 8954b24b221550e47d3d72ffaa627a14f5aad51c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sun, 4 Oct 2015 12:27:46 +0530 Subject: [PATCH 04/13] [fix] Return account currency only if account provided --- erpnext/accounts/doctype/account/account.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 7b6d0daeba..c3e4c393e4 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -210,6 +210,8 @@ def get_parent_account(doctype, txt, searchfield, start, page_len, filters): def get_account_currency(account): """Helper function to get account currency""" + if not account: + return def generator(): account_currency, company = frappe.db.get_value("Account", account, ["account_currency", "company"]) if not account_currency: From ebbd1639035ab451df4b48960dd9ac106d3395a5 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 5 Oct 2015 13:21:38 +0530 Subject: [PATCH 05/13] [fix] allowed more than 2 currencies in Journal Entry --- erpnext/accounts/doctype/journal_entry/journal_entry.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index e7773a6388..9f3c3373da 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -7,7 +7,6 @@ from frappe.utils import cstr, flt, fmt_money, formatdate from frappe import msgprint, _, scrub from erpnext.controllers.accounts_controller import AccountsController from erpnext.accounts.utils import get_balance_on, get_account_currency -from erpnext.accounts.party import get_party_account_currency from erpnext.setup.utils import get_company_currency @@ -278,9 +277,6 @@ class JournalEntry(AccountsController): if not self.multi_currency: frappe.throw(_("Please check Multi Currency option to allow accounts with other currency")) - if len(alternate_currency) > 1: - frappe.throw(_("Only one alternate currency can be used in a single Journal Entry")) - self.set_exchange_rate() for d in self.get("accounts"): From f4edaef48105d1d7210f860bc125dbe645b93d25 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 6 Oct 2015 12:48:04 +0530 Subject: [PATCH 06/13] [fix][report] Left join used in pending reports --- .../pending_so_items_for_purchase_request.json | 6 ++++-- .../ordered_items_to_be_delivered.json | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.json b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.json index 9c01fff550..6d431faa21 100644 --- a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.json +++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.json @@ -1,16 +1,18 @@ { + "add_total_row": 0, "apply_user_permissions": 1, "creation": "2013-06-21 16:46:45", + "disabled": 0, "docstatus": 0, "doctype": "Report", "idx": 1, "is_standard": "Yes", - "modified": "2015-03-30 05:45:40.146567", + "modified": "2015-10-06 12:43:48.259027", "modified_by": "Administrator", "module": "Selling", "name": "Pending SO Items For Purchase Request", "owner": "Administrator", - "query": "select \n so_item.item_code as \"Item Code:Link/Item:120\",\n so_item.item_name as \"Item Name::120\",\n so_item.description as \"Description::120\",\n so.`name` as \"S.O. No.:Link/Sales Order:120\",\n so.`transaction_date` as \"Date:Date:120\",\n mr.name as \"Material Request:Link/Material Request:120\",\n so.customer as \"Customer:Link/Customer:120\",\n so.territory as \"Terretory:Link/Territory:120\",\n sum(so_item.qty) as \"SO Qty:Float:100 \",\n sum(mr_item.qty) as \"Requested Qty:Float:100\",\n so.company as \"Company:Link/Company:\"\nfrom\n `tabSales Order` so, `tabSales Order Item` so_item, \n `tabMaterial Request` mr, `tabMaterial Request Item` mr_item\nwhere\n so_item.`parent` = so.`name` and mr_item.sales_order_no = so.name\n and mr_item.parent = mr.name \n and so.docstatus = 1 and so.status != \"Stopped\" \n and mr.docstatus = 1 and mr.status != \"Stopped\"\ngroup by so.name, so_item.item_code\norder by so.name desc, so_item.item_code asc", + "query": "select so_item.item_code as \"Item Code:Link/Item:120\",\n so_item.item_name as \"Item Name::120\",\n so_item.description as \"Description::120\",\n so.`name` as \"S.O. No.:Link/Sales Order:120\",\n so.`transaction_date` as \"Date:Date:120\",\n mr.name as \"Material Request:Link/Material Request:120\",\n so.customer as \"Customer:Link/Customer:120\",\n so.territory as \"Terretory:Link/Territory:120\",\n sum(so_item.qty) as \"SO Qty:Float:100 \",\n sum(mr_item.qty) as \"Requested Qty:Float:100\",\n sum(so_item.qty) - sum(mr_item.qty) as \"Pending Qty:Float:100 \", \n so.company as \"Company:Link/Company:\"\nfrom\n `tabSales Order` so, `tabSales Order Item` so_item, \n `tabMaterial Request` mr, `tabMaterial Request Item` mr_item\nwhere \n so_item.`parent` = so.`name` \n and mr_item.parent = mr.name\n and mr_item.sales_order_no = so.name\n and mr_item.item_code = so_item.item_code\n and so.docstatus = 1 and so.status != \"Stopped\" \n and mr.docstatus = 1 and mr.status != \"Stopped\"\ngroup by so.name, so_item.item_code\nhaving sum(so_item.qty) > sum(mr_item.qty)\norder by so.name desc, so_item.item_code asc", "ref_doctype": "Sales Order", "report_name": "Pending SO Items For Purchase Request", "report_type": "Query Report" diff --git a/erpnext/stock/report/ordered_items_to_be_delivered/ordered_items_to_be_delivered.json b/erpnext/stock/report/ordered_items_to_be_delivered/ordered_items_to_be_delivered.json index 3a18dafd8e..14af598b76 100644 --- a/erpnext/stock/report/ordered_items_to_be_delivered/ordered_items_to_be_delivered.json +++ b/erpnext/stock/report/ordered_items_to_be_delivered/ordered_items_to_be_delivered.json @@ -1,16 +1,18 @@ { + "add_total_row": 0, "apply_user_permissions": 1, "creation": "2013-02-22 18:01:55", + "disabled": 0, "docstatus": 0, "doctype": "Report", "idx": 1, "is_standard": "Yes", - "modified": "2015-06-10 15:52:49.492144", + "modified": "2015-10-06 12:43:37.547654", "modified_by": "Administrator", "module": "Stock", "name": "Ordered Items To Be Delivered", "owner": "Administrator", - "query": "select \n `tabSales Order`.`name` as \"Sales Order:Link/Sales Order:120\",\n `tabSales Order`.`customer` as \"Customer:Link/Customer:120\",\n `tabSales Order`.`transaction_date` as \"Date:Date\",\n `tabSales Order`.`project_name` as \"Project\",\n `tabSales Order Item`.item_code as \"Item:Link/Item:120\",\n `tabSales Order Item`.qty as \"Qty:Float:140\",\n `tabSales Order Item`.delivered_qty as \"Delivered Qty:Float:140\",\n (`tabSales Order Item`.qty - ifnull(`tabSales Order Item`.delivered_qty, 0)) as \"Qty to Deliver:Float:140\",\n `tabSales Order Item`.base_rate as \"Rate:Float:140\",\n `tabSales Order Item`.base_amount as \"Amount:Float:140\",\n ((`tabSales Order Item`.qty - ifnull(`tabSales Order Item`.delivered_qty, 0))*`tabSales Order Item`.base_rate) as \"Amount to Deliver:Float:140\",\n `tabBin`.actual_qty as \"Available Qty:Float:120\",\n `tabBin`.projected_qty as \"Projected Qty:Float:120\",\n `tabSales Order`.`delivery_date` as \"Expected Delivery Date:Date:120\",\n `tabSales Order Item`.item_name as \"Item Name::150\",\n `tabSales Order Item`.description as \"Description::200\",\n `tabSales Order Item`.item_group as \"Item Group:Link/Item Group:120\",\n `tabSales Order Item`.warehouse as \"Warehouse:Link/Warehouse:200\"\nfrom\n `tabSales Order`, `tabSales Order Item`, `tabBin`\nwhere\n `tabSales Order Item`.`parent` = `tabSales Order`.`name`\n and `tabSales Order`.docstatus = 1\n and `tabSales Order`.status != \"Stopped\"\n and ifnull(`tabSales Order Item`.delivered_qty,0) < ifnull(`tabSales Order Item`.qty,0)\n and `tabBin`.item_code = `tabSales Order Item`.item_code\n and `tabBin`.warehouse = `tabSales Order Item`.warehouse\norder by `tabSales Order`.transaction_date asc", + "query": "select \n `tabSales Order`.`name` as \"Sales Order:Link/Sales Order:120\",\n `tabSales Order`.`customer` as \"Customer:Link/Customer:120\",\n `tabSales Order`.`transaction_date` as \"Date:Date\",\n `tabSales Order`.`project_name` as \"Project\",\n `tabSales Order Item`.item_code as \"Item:Link/Item:120\",\n `tabSales Order Item`.qty as \"Qty:Float:140\",\n `tabSales Order Item`.delivered_qty as \"Delivered Qty:Float:140\",\n (`tabSales Order Item`.qty - ifnull(`tabSales Order Item`.delivered_qty, 0)) as \"Qty to Deliver:Float:140\",\n `tabSales Order Item`.base_rate as \"Rate:Float:140\",\n `tabSales Order Item`.base_amount as \"Amount:Float:140\",\n ((`tabSales Order Item`.qty - ifnull(`tabSales Order Item`.delivered_qty, 0))*`tabSales Order Item`.base_rate) as \"Amount to Deliver:Float:140\",\n `tabBin`.actual_qty as \"Available Qty:Float:120\",\n `tabBin`.projected_qty as \"Projected Qty:Float:120\",\n `tabSales Order`.`delivery_date` as \"Expected Delivery Date:Date:120\",\n `tabSales Order Item`.item_name as \"Item Name::150\",\n `tabSales Order Item`.description as \"Description::200\",\n `tabSales Order Item`.item_group as \"Item Group:Link/Item Group:120\",\n `tabSales Order Item`.warehouse as \"Warehouse:Link/Warehouse:200\"\nfrom\n `tabSales Order` JOIN `tabSales Order Item` \n LEFT JOIN `tabBin` ON (`tabBin`.item_code = `tabSales Order Item`.item_code\n and `tabBin`.warehouse = `tabSales Order Item`.warehouse)\nwhere\n `tabSales Order Item`.`parent` = `tabSales Order`.`name`\n and `tabSales Order`.docstatus = 1\n and `tabSales Order`.status != \"Stopped\"\n and ifnull(`tabSales Order Item`.delivered_qty,0) < ifnull(`tabSales Order Item`.qty,0)\norder by `tabSales Order`.transaction_date asc", "ref_doctype": "Delivery Note", "report_name": "Ordered Items To Be Delivered", "report_type": "Query Report" From 54ecc8ebba614d981dcb039dc429834a482108d2 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 6 Oct 2015 14:28:41 +0530 Subject: [PATCH 07/13] minor fix in credit limit --- erpnext/selling/doctype/customer/customer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 9e5e7bdc7e..21f6578df4 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -212,7 +212,7 @@ def get_customer_outstanding(customer, company): from `tabSales Invoice Item` where dn_detail = %s and docstatus = 1""", dn_item.name)[0][0] - if flt(dn_item.amount) > flt(si_amount): + if flt(dn_item.amount) > flt(si_amount) and dn_item.base_net_total: outstanding_based_on_dn += ((flt(dn_item.amount) - flt(si_amount)) \ / dn_item.base_net_total) * dn_item.base_grand_total From 1d753c92b1feb8528f1951d8e67e7d99dd4ee255 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 6 Oct 2015 15:21:23 +0530 Subject: [PATCH 08/13] Calendar view for holiday listing --- erpnext/hooks.py | 2 +- .../hr/doctype/holiday_list/holiday_list.py | 50 +++++++++++++++++-- .../holiday_list/holiday_list_calendar.js | 21 ++++++++ 3 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 erpnext/hr/doctype/holiday_list/holiday_list_calendar.js diff --git a/erpnext/hooks.py b/erpnext/hooks.py index a832315440..8ca62a8931 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -53,7 +53,7 @@ my_account_context = "erpnext.shopping_cart.utils.update_my_account_context" email_append_to = ["Job Applicant", "Opportunity", "Issue"] -calendars = ["Task", "Production Order", "Time Log", "Leave Application", "Sales Order"] +calendars = ["Task", "Production Order", "Time Log", "Leave Application", "Sales Order", "Holiday List"] website_generators = ["Item Group", "Item", "Sales Partner"] diff --git a/erpnext/hr/doctype/holiday_list/holiday_list.py b/erpnext/hr/doctype/holiday_list/holiday_list.py index b9a088a898..84499711a5 100644 --- a/erpnext/hr/doctype/holiday_list/holiday_list.py +++ b/erpnext/hr/doctype/holiday_list/holiday_list.py @@ -16,7 +16,8 @@ class HolidayList(Document): def get_weekly_off_dates(self): self.validate_values() - yr_start_date, yr_end_date = self.get_fy_start_end_dates() + self.validate_days() + yr_start_date, yr_end_date = get_fy_start_end_dates(self.fiscal_year) date_list = self.get_weekly_off_date_list(yr_start_date, yr_end_date) last_idx = max([cint(d.idx) for d in self.get("holidays")] or [0,]) for i, d in enumerate(date_list): @@ -30,10 +31,11 @@ class HolidayList(Document): throw(_("Please select Fiscal Year")) if not self.weekly_off: throw(_("Please select weekly off day")) - - def get_fy_start_end_dates(self): - return frappe.db.sql("""select year_start_date, year_end_date - from `tabFiscal Year` where name=%s""", (self.fiscal_year,))[0] + + def validate_days(self): + for day in self.get("holidays"): + if (self.weekly_off).upper() == (day.description).upper(): + frappe.throw("Records alredy exist for mentioned weekly off") def get_weekly_off_date_list(self, year_start_date, year_end_date): from frappe.utils import getdate @@ -59,3 +61,41 @@ class HolidayList(Document): def update_default_holiday_list(self): frappe.db.sql("""update `tabHoliday List` set is_default = 0 where ifnull(is_default, 0) = 1 and fiscal_year = %s""", (self.fiscal_year,)) + +@frappe.whitelist() +def get_events(start, end, filters=None): + import json + """Returns events for Gantt / Calendar view rendering. + + :param start: Start date-time. + :param end: End date-time. + :param filters: Filters (JSON). + """ + from frappe.desk.calendar import get_event_conditions + conditions = get_event_conditions("Holiday List", filters) + + fiscal_year = None + if filters: + fiscal_year = json.loads(filters).get("fiscal_year") + + yr_start_date, yr_end_date = get_fy_start_end_dates(fiscal_year) + + data = frappe.db.sql("""select hl.name, hld.holiday_date, hld.description + from `tabHoliday List` hl, tabHoliday hld + where hld.parent = hl.name + and (ifnull(hld.holiday_date, "0000-00-00") != "0000-00-00" + and hld.holiday_date between %(start)s and %(end)s) + {conditions}""".format(conditions=conditions), { + "start": yr_start_date, + "end": yr_end_date + }, as_dict=True, update={"allDay": 1}) + + return data + + +def get_fy_start_end_dates(fiscal_year=None): + if not fiscal_year: + fiscal_year = frappe.get_doc("Global Defaults").current_fiscal_year + + return frappe.db.sql("""select year_start_date, year_end_date + from `tabFiscal Year` where name=%s""", (fiscal_year,))[0] \ No newline at end of file diff --git a/erpnext/hr/doctype/holiday_list/holiday_list_calendar.js b/erpnext/hr/doctype/holiday_list/holiday_list_calendar.js new file mode 100644 index 0000000000..d7e9adc5fc --- /dev/null +++ b/erpnext/hr/doctype/holiday_list/holiday_list_calendar.js @@ -0,0 +1,21 @@ +// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +// License: GNU General Public License v3. See license.txt + +frappe.views.calendar["Holiday List"] = { + field_map: { + "start": "holiday_date", + "end": "holiday_date", + "id": "name", + "title": "description", + "allDay": "allDay" + }, + filters: [ + { + "fieldtype": "Link", + "fieldname": "fiscal_year", + "options": "Fiscal Year", + "label": __("Fiscal Year") + } + ], + get_events_method: "erpnext.hr.doctype.holiday_list.holiday_list.get_events" +} From 8a7bdd5a9282ab5fc6f9ca991c8085b1934165a6 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 6 Oct 2015 18:46:56 +0530 Subject: [PATCH 09/13] [fix] Valuation Rate in Stock Balance report --- erpnext/stock/report/stock_balance/stock_balance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py index 45f5ccc4cd..92e7adf50d 100644 --- a/erpnext/stock/report/stock_balance/stock_balance.py +++ b/erpnext/stock/report/stock_balance/stock_balance.py @@ -93,14 +93,14 @@ def get_item_warehouse_map(filters): qty_dict.opening_qty += qty_diff qty_dict.opening_val += value_diff elif d.posting_date >= getdate(filters["from_date"]) and d.posting_date <= getdate(filters["to_date"]): - qty_dict.val_rate = d.valuation_rate if qty_diff > 0: qty_dict.in_qty += qty_diff qty_dict.in_val += value_diff else: qty_dict.out_qty += abs(qty_diff) qty_dict.out_val += abs(value_diff) - + + qty_dict.val_rate = d.valuation_rate qty_dict.bal_qty += qty_diff qty_dict.bal_val += value_diff From 74eb8e34da9468e85d7e11bc6024a9b93a098bf9 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 7 Oct 2015 11:17:14 +0530 Subject: [PATCH 10/13] [Fixes] minor fix for fiscal year in holiday list --- erpnext/hr/doctype/holiday_list/holiday_list.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/hr/doctype/holiday_list/holiday_list.py b/erpnext/hr/doctype/holiday_list/holiday_list.py index 84499711a5..14135be795 100644 --- a/erpnext/hr/doctype/holiday_list/holiday_list.py +++ b/erpnext/hr/doctype/holiday_list/holiday_list.py @@ -77,6 +77,9 @@ def get_events(start, end, filters=None): fiscal_year = None if filters: fiscal_year = json.loads(filters).get("fiscal_year") + + if not fiscal_year: + fiscal_year = frappe.get_doc("Global Defaults").current_fiscal_year yr_start_date, yr_end_date = get_fy_start_end_dates(fiscal_year) @@ -93,9 +96,6 @@ def get_events(start, end, filters=None): return data -def get_fy_start_end_dates(fiscal_year=None): - if not fiscal_year: - fiscal_year = frappe.get_doc("Global Defaults").current_fiscal_year - +def get_fy_start_end_dates(fiscal_year): return frappe.db.sql("""select year_start_date, year_end_date from `tabFiscal Year` where name=%s""", (fiscal_year,))[0] \ No newline at end of file From b0dbdc143928466ca1d50223f6491442710ed2f1 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 7 Oct 2015 11:27:25 +0530 Subject: [PATCH 11/13] minor fixes --- erpnext/hr/doctype/holiday_list/holiday_list.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/hr/doctype/holiday_list/holiday_list.py b/erpnext/hr/doctype/holiday_list/holiday_list.py index 14135be795..c5d93ef617 100644 --- a/erpnext/hr/doctype/holiday_list/holiday_list.py +++ b/erpnext/hr/doctype/holiday_list/holiday_list.py @@ -79,7 +79,7 @@ def get_events(start, end, filters=None): fiscal_year = json.loads(filters).get("fiscal_year") if not fiscal_year: - fiscal_year = frappe.get_doc("Global Defaults").current_fiscal_year + fiscal_year = frappe.db.get_value("Global Defaults", None, "current_fiscal_year") yr_start_date, yr_end_date = get_fy_start_end_dates(fiscal_year) @@ -95,7 +95,5 @@ def get_events(start, end, filters=None): return data - def get_fy_start_end_dates(fiscal_year): - return frappe.db.sql("""select year_start_date, year_end_date - from `tabFiscal Year` where name=%s""", (fiscal_year,))[0] \ No newline at end of file + return frappe.db.get_value("Fiscal Year", fiscal_year, ["year_start_date", "year_end_date"]) \ No newline at end of file From 314086d6c05cd159aa94a84878bf160a8b7162bb Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 7 Oct 2015 11:55:01 +0530 Subject: [PATCH 12/13] [fix] Fetch UOM Conversion Factor from template if not specified in variants --- erpnext/stock/get_item_details.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index a626875cdf..fb661e13a8 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -346,8 +346,7 @@ def get_conversion_factor(item_code, uom): variant_of = frappe.db.get_value("Item", item_code, "variant_of") filters = {"parent": item_code, "uom": uom} if variant_of: - filters = {"parent": ("in", (item_code, variant_of))} - + filters["parent"] = ("in", (item_code, variant_of)) return {"conversion_factor": frappe.db.get_value("UOM Conversion Detail", filters, "conversion_factor")} From 4c502bcd2666c9a14a886d51a077a22291b01560 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 7 Oct 2015 15:10:32 +0600 Subject: [PATCH 13/13] bumped to version 6.4.5 --- erpnext/__version__.py | 2 +- erpnext/hooks.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/__version__.py b/erpnext/__version__.py index 4e607288d1..f863722c26 100644 --- a/erpnext/__version__.py +++ b/erpnext/__version__.py @@ -1,2 +1,2 @@ from __future__ import unicode_literals -__version__ = '6.4.4' +__version__ = '6.4.5' diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 8ca62a8931..ec8d4b5eae 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -29,7 +29,7 @@ blogs. """ app_icon = "icon-th" app_color = "#e74c3c" -app_version = "6.4.4" +app_version = "6.4.5" github_link = "https://github.com/frappe/erpnext" error_report_email = "support@erpnext.com" diff --git a/setup.py b/setup.py index 21f5b56df8..7670f39b05 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "6.4.4" +version = "6.4.5" with open("requirements.txt", "r") as f: install_requires = f.readlines()