diff --git a/accounts/doctype/gl_entry/gl_entry.py b/accounts/doctype/gl_entry/gl_entry.py index 112e449f97..a2ef25a777 100644 --- a/accounts/doctype/gl_entry/gl_entry.py +++ b/accounts/doctype/gl_entry/gl_entry.py @@ -160,13 +160,13 @@ class DocType: def update_outstanding_amt(self): # get final outstanding amt bal = flt(sql("""select sum(debit) - sum(credit) from `tabGL Entry` - where against_voucher=%s and against_voucher_type=%s - and ifnull(is_cancelled,'No') = 'No'""", - (self.doc.against_voucher, self.doc.against_voucher_type))[0][0] or 0.0) - + where against_voucher=%s and against_voucher_type=%s and account = %s + and ifnull(is_cancelled,'No') = 'No'""", (self.doc.against_voucher, + self.doc.against_voucher_type, self.doc.account))[0][0] or 0.0) + if self.doc.against_voucher_type == 'Purchase Invoice': bal = -bal - + elif self.doc.against_voucher_type == "Journal Voucher": against_voucher_amount = flt(webnotes.conn.sql("""select sum(debit) - sum(credit) from `tabGL Entry` where voucher_type = 'Journal Voucher' and voucher_no = %s diff --git a/accounts/page/accounts_home/accounts_home.js b/accounts/page/accounts_home/accounts_home.js index 03009023c1..b920bfdbab 100644 --- a/accounts/page/accounts_home/accounts_home.js +++ b/accounts/page/accounts_home/accounts_home.js @@ -127,16 +127,6 @@ wn.module_page["Accounts"] = [ right: true, icon: "icon-table", items: [ - { - "label":wn._("Customer Account Head"), - route: "query-report/Customer Account Head", - doctype: "Account" - }, - { - "label":wn._("Supplier Account Head"), - route: "query-report/Supplier Account Head", - doctype: "Account" - }, { "label":wn._("General Ledger"), page: "general-ledger" @@ -247,11 +237,21 @@ wn.module_page["Accounts"] = [ route: "query-report/Customer Account Head", doctype: "Account" }, + { + "label":wn._("Supplier Account Head"), + route: "query-report/Supplier Account Head", + doctype: "Account" + }, { "label":wn._("Item-wise Sales Register"), route: "query-report/Item-wise Sales Register", doctype: "Sales Invoice" }, + { + "label":wn._("Item-wise Purchase Register"), + route: "query-report/Item-wise Purchase Register", + doctype: "Purchase Invoice" + }, ] } ] diff --git a/accounts/report/item_wise_purchase_register/__init__.py b/accounts/report/item_wise_purchase_register/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.js b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.js new file mode 100644 index 0000000000..8323a1af78 --- /dev/null +++ b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.js @@ -0,0 +1,39 @@ +wn.query_reports["Item-wise Purchase Register"] = { + "filters": [ + { + "fieldname":"from_date", + "label": "From Date", + "fieldtype": "Date", + "default": wn.defaults.get_user_default("year_start_date"), + "width": "80" + }, + { + "fieldname":"to_date", + "label": "To Date", + "fieldtype": "Date", + "default": get_today() + }, + { + "fieldname": "item_code", + "label": "Item", + "fieldtype": "Link", + "options": "Item", + }, + { + "fieldname":"account", + "label": "Account", + "fieldtype": "Link", + "options": "Account", + "get_query": function() { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "No", + "debit_or_credit": "Credit", + "master_type": "Supplier" + } + } + } + } + ] +} \ No newline at end of file diff --git a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py new file mode 100644 index 0000000000..ad9d79504b --- /dev/null +++ b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -0,0 +1,74 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals +import webnotes + +def execute(filters=None): + if not filters: filters = {} + + columns = get_columns() + item_list = get_items(filters) + aii_account_map = get_aii_accounts() + webnotes.errprint(aii_account_map) + data = [] + for d in item_list: + expense_head = d.expense_head or aii_account_map.get(d.company) + data.append([d.item_code, d.item_name, d.item_group, d.name, d.posting_date, d.supplier, + d.credit_to, d.project_name, d.company, d.purchase_order, d.purchase_receipt, + expense_head, d.qty, d.rate, d.amount]) + + return columns, data + + +def get_columns(): + return ["Item Code:Link/Item:120", "Item Name::120", "Item Group:Link/Item Group:100", + "Invoice:Link/Purchase Invoice:120", "Posting Date:Date:80", "Supplier:Link/Customer:120", + "Supplier Account:Link/Account:120", "Project:Link/Project:80", "Company:Link/Company:100", + "Purchase Order:Link/Purchase Order:100", "Purchase Receipt:Link/Purchase Receipt:100", + "Expense Account:Link/Account:140", "Qty:Float:120", "Rate:Currency:120", + "Amount:Currency:120"] + + +def get_conditions(filters): + conditions = "" + + if filters.get("account"): conditions += " and pi.credit_to = %(account)s" + + if filters.get("item_code"): conditions += " and pi_item.item_code = %(item_code)s" + + if filters.get("from_date"): conditions += " and pi.posting_date>=%(from_date)s" + if filters.get("to_date"): conditions += " and pi.posting_date<=%(to_date)s" + + return conditions + +def get_items(filters): + conditions = get_conditions(filters) + return webnotes.conn.sql("""select pi.name, pi.posting_date, pi.credit_to, pi.company, + pi.supplier, pi.remarks, pi_item.item_code, pi_item.item_name, pi_item.item_group, + pi_item.project_name, pi_item.purchase_order, pi_item.purchase_receipt, + pi_item.expense_head, pi_item.qty, pi_item.rate, pi_item.amount + from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item + where pi.name = pi_item.parent and pi.docstatus = 1 %s + order by pi.posting_date desc, pi_item.item_code desc""" % conditions, filters, as_dict=1) + +def get_aii_accounts(): + aii_account_map = {} + for d in webnotes.conn.sql("select name, stock_received_but_not_billed from tabCompany", + as_dict=1): + aii_account_map.setdefault(d.name, d.stock_received_but_not_billed) + + return aii_account_map \ No newline at end of file diff --git a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.txt b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.txt new file mode 100644 index 0000000000..7ded5ff583 --- /dev/null +++ b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-06-05 15:37:30", + "docstatus": 0, + "modified": "2013-06-05 15:37:30", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "add_total_row": 1, + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Purchase Invoice", + "report_name": "Item-wise Purchase Register", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Item-wise Purchase Register" + } +] \ No newline at end of file diff --git a/accounts/report/item_wise_sales_register/__init__.py b/accounts/report/item_wise_sales_register/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/accounts/report/item_wise_sales_register/item_wise_sales_register.js b/accounts/report/item_wise_sales_register/item_wise_sales_register.js new file mode 100644 index 0000000000..b9ce9595fe --- /dev/null +++ b/accounts/report/item_wise_sales_register/item_wise_sales_register.js @@ -0,0 +1,39 @@ +wn.query_reports["Item-wise Sales Register"] = { + "filters": [ + { + "fieldname":"from_date", + "label": "From Date", + "fieldtype": "Date", + "default": wn.defaults.get_user_default("year_start_date"), + "width": "80" + }, + { + "fieldname":"to_date", + "label": "To Date", + "fieldtype": "Date", + "default": get_today() + }, + { + "fieldname": "item_code", + "label": "Item", + "fieldtype": "Link", + "options": "Item", + }, + { + "fieldname":"account", + "label": "Account", + "fieldtype": "Link", + "options": "Account", + "get_query": function() { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "No", + "debit_or_credit": "Debit", + "master_type": "Customer" + } + } + } + } + ] +} \ No newline at end of file diff --git a/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/accounts/report/item_wise_sales_register/item_wise_sales_register.py new file mode 100644 index 0000000000..f3ed2a1242 --- /dev/null +++ b/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -0,0 +1,67 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import flt + +def execute(filters=None): + if not filters: filters = {} + + columns = get_columns() + item_list = get_items(filters) + + data = [] + for d in item_list: + data.append([d.item_code, d.item_name, d.item_group, d.name, d.posting_date, d.customer, + d.debit_to, d.territory, d.project_name, d.company, d.sales_order, d.delivery_note, + d.income_account, d.qty, d.basic_rate, d.amount]) + + return columns, data + + +def get_columns(): + return [ + "Item Code:Link/Item:120", "Item Name::120", "Item Group:Link/Item Group:100", + "Invoice:Link/Sales Invoice:120", "Posting Date:Date:80", "Customer:Link/Customer:120", + "Customer Account:Link/Account:120", "Territory:Link/Territory:80", + "Project:Link/Project:80", "Company:Link/Company:100", "Sales Order:Link/Sales Order:100", + "Delivery Note:Link/Delivery Note:100", "Income Account:Link/Account:140", + "Qty:Float:120", "Rate:Currency:120", "Amount:Currency:120" + ] + + +def get_conditions(filters): + conditions = "" + + if filters.get("account"): conditions += " and si.debit_to = %(account)s" + + if filters.get("item_code"): conditions += " and si_item.item_code = %(item_code)s" + + if filters.get("from_date"): conditions += " and si.posting_date>=%(from_date)s" + if filters.get("to_date"): conditions += " and si.posting_date<=%(to_date)s" + + return conditions + +def get_items(filters): + conditions = get_conditions(filters) + return webnotes.conn.sql("""select si.name, si.posting_date, si.debit_to, si.project_name, + si.customer, si.remarks, si.territory, si.company, si_item.item_code, si_item.item_name, + si_item.item_group, si_item.sales_order, si_item.delivery_note, si_item.income_account, + si_item.qty, si_item.basic_rate, si_item.amount + from `tabSales Invoice` si, `tabSales Invoice Item` si_item + where si.name = si_item.parent and si.docstatus = 1 %s + order by si.posting_date desc, si_item.item_code desc""" % conditions, filters, as_dict=1) \ No newline at end of file diff --git a/accounts/report/item_wise_sales_register/item_wise_sales_register.txt b/accounts/report/item_wise_sales_register/item_wise_sales_register.txt new file mode 100644 index 0000000000..fb0555d459 --- /dev/null +++ b/accounts/report/item_wise_sales_register/item_wise_sales_register.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-05-13 17:50:55", + "docstatus": 0, + "modified": "2013-05-13 17:50:55", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "add_total_row": 1, + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Sales Invoice", + "report_name": "Item-wise Sales Register", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Item-wise Sales Register" + } +] \ No newline at end of file diff --git a/patches/june_2013/p04_fix_event_for_lead_oppty_project.py b/patches/june_2013/p04_fix_event_for_lead_oppty_project.py new file mode 100644 index 0000000000..a6449c528a --- /dev/null +++ b/patches/june_2013/p04_fix_event_for_lead_oppty_project.py @@ -0,0 +1,21 @@ +import webnotes + +def execute(): + # delete orphaned Event User + webnotes.conn.sql("""delete from `tabEvent User` + where not exists(select name from `tabEvent` where `tabEvent`.name = `tabEvent User`.parent)""") + + for dt in ["Lead", "Opportunity", "Project"]: + for ref_name in webnotes.conn.sql_list("""select ref_name + from `tabEvent` where ref_type=%s and ifnull(starts_on, '')='' """, dt): + if webnotes.conn.exists(dt, ref_name): + controller = webnotes.get_obj(dt, ref_name) + if dt == "Project": + controller.add_calendar_event() + else: + controller.delete_events() + controller._add_calendar_event() + else: + # remove events where ref doc doesn't exist + webnotes.delete_doc("Event", webnotes.conn.sql_list("""select name from `tabEvent` + where ref_type=%s and ref_name=%s""", (dt, ref_name))) \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index cd3e9e7353..52b3e29b57 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -259,4 +259,6 @@ patch_list = [ "patches.may_2013.p08_change_item_wise_tax", "patches.june_2013.p01_update_bom_exploded_items", "patches.june_2013.p02_update_project_completed", + "execute:webnotes.delete_doc('DocType', 'System Console')", + "patches.june_2013.p04_fix_event_for_lead_oppty_project", ] \ No newline at end of file diff --git a/projects/doctype/project/project.py b/projects/doctype/project/project.py index 773cd4011c..f8ca43035f 100644 --- a/projects/doctype/project/project.py +++ b/projects/doctype/project/project.py @@ -18,11 +18,10 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import flt, getdate -from webnotes.model.doc import Document from webnotes import msgprint class DocType: - def __init__(self, doc, doclist=[]): + def __init__(self, doc, doclist=None): self.doc = doc self.doclist = doclist @@ -42,23 +41,7 @@ class DocType: raise Exception def on_update(self): - """add events for milestones""" - webnotes.conn.sql("""delete from tabEvent where ref_type='Project' and ref_name=%s""", - self.doc.name) - for d in self.doclist: - if d.doctype=='Project Milestone' and d.docstatus!=2: - self.add_calendar_event(d.milestone, d.milestone_date) - - def add_calendar_event(self, milestone, date): - """ Add calendar event for task in calendar of Allocated person""" - event = Document('Event') - event.description = milestone + ' for ' + self.doc.name - event.event_date = date - event.event_hour = '10:00' - event.event_type = 'Public' - event.ref_type = 'Project' - event.ref_name = self.doc.name - event.save(1) + self.add_calendar_event() def update_percent_complete(self): total = webnotes.conn.sql("""select count(*) from tabTask where project=%s""", @@ -69,3 +52,27 @@ class DocType: webnotes.conn.set_value("Project", self.doc.name, "percent_complete", int(float(completed) / total * 100)) + def add_calendar_event(self): + # delete any earlier event for this project + self.delete_events() + + # add events + for milestone in self.doclist.get({"parentfield": "project_milestones"}): + description = milestone.milestone + " for " + self.doc.name + webnotes.bean({ + "doctype": "Event", + "owner": self.doc.owner, + "subject": description, + "description": description, + "starts_on": milestone.milestone_date + " 10:00:00", + "event_type": "Private", + "ref_type": self.doc.doctype, + "ref_name": self.doc.name + }).insert() + + def on_trash(self): + self.delete_events() + + def delete_events(self): + webnotes.delete_doc("Event", webnotes.conn.sql_list("""select name from `tabEvent` + where ref_type=%s and ref_name=%s""", (self.doc.doctype, self.doc.name))) diff --git a/selling/doctype/lead/lead.py b/selling/doctype/lead/lead.py index 571cdfd516..0e27261a26 100644 --- a/selling/doctype/lead/lead.py +++ b/selling/doctype/lead/lead.py @@ -17,8 +17,7 @@ from __future__ import unicode_literals import webnotes from webnotes import _ -from webnotes.utils import cstr, validate_email_add -from webnotes.model.doc import Document, addchild +from webnotes.utils import cstr, validate_email_add, cint from webnotes import session, msgprint sql = webnotes.conn.sql @@ -30,6 +29,13 @@ class DocType(SellingController): self.doc = doc self.doclist = doclist + self._prev = webnotes._dict({ + "contact_date": webnotes.conn.get_value("Lead", self.doc.name, "contact_date") if \ + (not cint(self.doc.fields.get("__islocal"))) else None, + "contact_by": webnotes.conn.get_value("Lead", self.doc.name, "contact_by") if \ + (not cint(self.doc.fields.get("__islocal"))) else None, + }) + def onload(self): self.add_communication_list() @@ -55,12 +61,18 @@ class DocType(SellingController): msgprint('Please enter valid email id.') raise Exception - def on_update(self): - if self.doc.contact_date: - self.add_calendar_event() - self.check_email_id_is_unique() + self.add_calendar_event() + + def add_calendar_event(self, opts=None): + super(DocType, self).add_calendar_event({ + "owner": self.doc.lead_owner, + "subject": ('Contact ' + cstr(self.doc.lead_name)), + "description": ('Contact ' + cstr(self.doc.lead_name)) + \ + (self.doc.contact_by and ('. By : ' + cstr(self.doc.contact_by)) or '') + \ + (self.doc.remark and ('.To Discuss : ' + cstr(self.doc.remark)) or '') + }) def check_email_id_is_unique(self): if self.doc.email_id: @@ -71,27 +83,6 @@ class DocType(SellingController): items = [e[0] for e in email_list if e[0]!=self.doc.name] webnotes.msgprint(_("""Email Id must be unique, already exists for: """) + \ ", ".join(items), raise_exception=True) - - def add_calendar_event(self): - # delete any earlier event by this lead - sql("delete from tabEvent where ref_type='Lead' and ref_name=%s", self.doc.name) - - # create new event - ev = Document('Event') - ev.owner = self.doc.lead_owner - ev.description = ('Contact ' + cstr(self.doc.lead_name)) + \ - (self.doc.contact_by and ('. By : ' + cstr(self.doc.contact_by)) or '') + \ - (self.doc.remark and ('.To Discuss : ' + cstr(self.doc.remark)) or '') - ev.event_date = self.doc.contact_date - ev.event_hour = '10:00' - ev.event_type = 'Private' - ev.ref_type = 'Lead' - ev.ref_name = self.doc.name - ev.save(1) - - event_user = addchild(ev, 'event_individuals', 'Event User') - event_user.person = self.doc.contact_by - event_user.save() def get_sender(self, comm): return webnotes.conn.get_value('Sales Email Settings',None,'email_id') @@ -100,3 +91,5 @@ class DocType(SellingController): webnotes.conn.sql("""update tabCommunication set lead=null where lead=%s""", self.doc.name) webnotes.conn.sql("""update `tabSupport Ticket` set lead='' where lead=%s""", self.doc.name) + + self.delete_events() \ No newline at end of file diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index 75a7cd270d..0540ac9881 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -17,9 +17,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import add_days, cstr, getdate -from webnotes.model import db_exists -from webnotes.model.doc import Document, addchild +from webnotes.utils import add_days, cstr, getdate, cint from webnotes.model.bean import getlist from webnotes import msgprint @@ -34,6 +32,13 @@ class DocType(TransactionBase): self.fname = 'enq_details' self.tname = 'Opportunity Item' + self._prev = webnotes._dict({ + "contact_date": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_date") if \ + (not cint(self.doc.fields.get("__islocal"))) else None, + "contact_by": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_by") if \ + (not cint(self.doc.fields.get("__islocal"))) else None, + }) + def onload(self): self.add_communication_list() @@ -84,48 +89,34 @@ class DocType(TransactionBase): def on_update(self): # Add to calendar if self.doc.contact_date and self.doc.contact_date_ref != self.doc.contact_date: - if self.doc.contact_by: - self.add_calendar_event() webnotes.conn.set(self.doc, 'contact_date_ref',self.doc.contact_date) - webnotes.conn.set(self.doc, 'status', 'Draft') - def add_calendar_event(self): - desc='' - user_lst =[] + self.add_calendar_event() + + def add_calendar_event(self, opts=None): + if not opts: + opts = webnotes._dict() + + opts.description = "" + if self.doc.customer: if self.doc.contact_person: - desc = 'Contact '+cstr(self.doc.contact_person) + opts.description = 'Contact '+cstr(self.doc.contact_person) else: - desc = 'Contact customer '+cstr(self.doc.customer) + opts.description = 'Contact customer '+cstr(self.doc.customer) elif self.doc.lead: if self.doc.contact_display: - desc = 'Contact '+cstr(self.doc.contact_display) + opts.description = 'Contact '+cstr(self.doc.contact_display) else: - desc = 'Contact lead '+cstr(self.doc.lead) - desc = desc+ '. By : ' + cstr(self.doc.contact_by) + opts.description = 'Contact lead '+cstr(self.doc.lead) + + opts.subject = opts.description + opts.description += '. By : ' + cstr(self.doc.contact_by) if self.doc.to_discuss: - desc = desc+' To Discuss : ' + cstr(self.doc.to_discuss) + opts.description += ' To Discuss : ' + cstr(self.doc.to_discuss) - ev = Document('Event') - ev.description = desc - ev.event_date = self.doc.contact_date - ev.event_hour = '10:00' - ev.event_type = 'Private' - ev.ref_type = 'Opportunity' - ev.ref_name = self.doc.name - ev.save(1) - - user_lst.append(self.doc.owner) - - chk = sql("select t1.name from `tabProfile` t1, `tabSales Person` t2 where t2.email_id = t1.name and t2.name=%s",self.doc.contact_by) - if chk: - user_lst.append(chk[0][0]) - - for d in user_lst: - ch = addchild(ev, 'event_individuals', 'Event User') - ch.person = d - ch.save(1) + super(DocType, self).add_calendar_event(opts) def set_last_contact_date(self): if self.doc.contact_date_ref and self.doc.contact_date_ref != self.doc.contact_date: @@ -159,6 +150,9 @@ class DocType(TransactionBase): self.set_last_contact_date() self.validate_item_details() self.validate_lead_cust() + + if not self.doc.status: + self.doc.status = "Draft" def on_submit(self): webnotes.conn.set(self.doc, 'status', 'Submitted') @@ -180,3 +174,6 @@ class DocType(TransactionBase): webnotes.conn.set(self.doc, 'status', 'Opportunity Lost') webnotes.conn.set(self.doc, 'order_lost_reason', arg) return 'true' + + def on_trash(self): + self.delete_events() \ No newline at end of file diff --git a/selling/page/selling_home/selling_home.js b/selling/page/selling_home/selling_home.js index 682978bd17..9c18fda681 100644 --- a/selling/page/selling_home/selling_home.js +++ b/selling/page/selling_home/selling_home.js @@ -165,6 +165,12 @@ wn.module_page["Selling"] = [ "label":wn._("Item-wise Sales History"), route: "query-report/Item-wise Sales History", }, + { + "label":wn._("Customers Not Buying Since Long Time"), + route: "query-report/Customers Not Buying Since Long Time", + doctype: "Sales Order" + }, + ] } ] diff --git a/selling/report/customers_not_buying_since_long_time/__init__.py b/selling/report/customers_not_buying_since_long_time/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/selling/report/customers_not_buying_since_long_time/customers_not_buying_since_long_time.js b/selling/report/customers_not_buying_since_long_time/customers_not_buying_since_long_time.js new file mode 100644 index 0000000000..65d63484a5 --- /dev/null +++ b/selling/report/customers_not_buying_since_long_time/customers_not_buying_since_long_time.js @@ -0,0 +1,10 @@ +wn.query_reports["Customers Not Buying Since Long Time"] = { + "filters": [ + { + "fieldname":"days_since_last_order", + "label": "Days Since Last Order", + "fieldtype": "Int", + "default": 60 + } + ] +} \ No newline at end of file diff --git a/selling/report/customers_not_buying_since_long_time/customers_not_buying_since_long_time.py b/selling/report/customers_not_buying_since_long_time/customers_not_buying_since_long_time.py new file mode 100644 index 0000000000..08809a7619 --- /dev/null +++ b/selling/report/customers_not_buying_since_long_time/customers_not_buying_since_long_time.py @@ -0,0 +1,75 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import getdate, cint + +def execute(filters=None): + if not filters: filters ={} + + days_since_last_order = filters.get("days_since_last_order") + if cint(days_since_last_order) <= 0: + webnotes.msgprint("Please mention positive value in 'Days Since Last Order' field",raise_exception=1) + + columns = get_columns() + customers = get_so_details() + + data = [] + for cust in customers: + if cust[8] >= days_since_last_order: + cust.insert(7,get_last_so_amt(cust[0])) + data.append(cust) + return columns, data + +def get_so_details(): + return webnotes.conn.sql("""select + cust.name, + cust.customer_name, + cust.territory, + cust.customer_group, + count(distinct(so.name)) as 'num_of_order', + sum(net_total) as 'total_order_value', + sum(if(so.status = "Stopped", + so.net_total * so.per_delivered/100, + so.net_total)) as 'total_order_considered', + max(so.transaction_date) as 'last_sales_order_date', + DATEDIFF(CURDATE(), max(so.transaction_date)) as 'days_since_last_order' + from `tabCustomer` cust, `tabSales Order` so + where cust.name = so.customer and so.docstatus = 1 + group by cust.name + order by 'days_since_last_order' desc """,as_list=1) + +def get_last_so_amt(customer): + res = webnotes.conn.sql("""select net_total from `tabSales Order` + where customer ='%(customer)s' and docstatus = 1 order by transaction_date desc + limit 1""" % {'customer':customer}) + + return res and res[0][0] or 0 + +def get_columns(): + return [ + "Customer:Link/Customer:120", + "Customer Name:Data:120", + "Territory::120", + "Customer Group::120", + "Number of Order::120", + "Total Order Value:Currency:120", + "Total Order Considered:Currency:160", + "Last Order Amount:Currency:160", + "Last Sales Order Date:Date:160", + "Days Since Last Order::160" + ] \ No newline at end of file diff --git a/selling/report/customers_not_buying_since_long_time/customers_not_buying_since_long_time.txt b/selling/report/customers_not_buying_since_long_time/customers_not_buying_since_long_time.txt new file mode 100644 index 0000000000..4d94377aa9 --- /dev/null +++ b/selling/report/customers_not_buying_since_long_time/customers_not_buying_since_long_time.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-07 12:27:07", + "docstatus": 0, + "modified": "2013-06-07 12:27:07", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Sales Order", + "report_name": "Customers Not Buying Since Long Time ", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Customers Not Buying Since Long Time" + } +] \ No newline at end of file diff --git a/stock/page/stock_home/stock_home.js b/stock/page/stock_home/stock_home.js index fd1f977be7..511ddd7667 100644 --- a/stock/page/stock_home/stock_home.js +++ b/stock/page/stock_home/stock_home.js @@ -205,6 +205,24 @@ wn.module_page["Stock"] = [ "label":wn._("Requested Items To Be Transferred"), route: "query-report/Requested Items To Be Transferred", }, + { + "label":wn._("Batch-Wise Balance History"), + route: "query-report/Batch-Wise Balance History", + }, + { + "label":wn._("Warehouse-Wise Stock Balance"), + route: "query-report/Warehouse-Wise Stock Balance", + }, + { + "label":wn._("Item Prices"), + route: "query-report/Item Prices", + + }, + { + "label":wn._("Itemwise Recommended Reorder Level"), + route: "query-report/Itemwise Recommended Reorder Level", + doctype: "Item" + }, ] } ] diff --git a/stock/report/item_prices/__init__.py b/stock/report/item_prices/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/stock/report/item_prices/item_prices.py b/stock/report/item_prices/item_prices.py new file mode 100644 index 0000000000..ea0be477df --- /dev/null +++ b/stock/report/item_prices/item_prices.py @@ -0,0 +1,106 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import flt + +def execute(filters=None): + if not filters: filters = {} + + columns = get_columns(filters) + item_map = get_item_details() + pl = get_price_list() + bom_rate = get_item_bom_rate() + val_rate_map = get_valuation_rate() + + data = [] + for item in sorted(item_map): + data.append([item, item_map[item]["item_name"], + item_map[item]["description"], item_map[item]["stock_uom"], + flt(item_map[item]["last_purchase_rate"]), val_rate_map.get(item, 0), + pl.get(item, {}).get("selling"), pl.get(item, {}).get("buying"), + bom_rate.get(item, 0), flt(item_map[item]["standard_rate"]) + ]) + + return columns, data + +def get_columns(filters): + """return columns based on filters""" + + columns = ["Item:Link/Item:100", "Item Name::150", "Description::150", "UOM:Link/UOM:80", + "Last Purchase Rate:Currency:90", "Valuation Rate:Currency:80", "Sales Price List::80", + "Purchase Price List::80", "BOM Rate:Currency:90", "Standard Rate:Currency:100"] + + return columns + +def get_item_details(): + """returns all items details""" + + item_map = {} + + for i in webnotes.conn.sql("select name, item_name, description, \ + stock_uom, standard_rate, last_purchase_rate from tabItem \ + order by item_code", as_dict=1): + item_map.setdefault(i.name, i) + + return item_map + +def get_price_list(): + """Get selling & buying price list of every item""" + + rate = {} + + price_list = webnotes.conn.sql("""select parent, selling, buying, + concat(price_list_name, " - ", ref_currency, " ", ref_rate) as price + from `tabItem Price` where docstatus<2""", as_dict=1) + + for j in price_list: + if j.selling: + rate.setdefault(j.parent, {}).setdefault("selling", []).append(j.price) + if j.buying: + rate.setdefault(j.parent, {}).setdefault("buying", []).append(j.price) + + item_rate_map = {} + + for item in rate: + item_rate_map.setdefault(item, {}).setdefault("selling", + ", ".join(rate[item].get("selling", []))) + item_rate_map[item]["buying"] = ", ".join(rate[item].get("buying", [])) + + return item_rate_map + +def get_item_bom_rate(): + """Get BOM rate of an item from BOM""" + + bom_map = {} + + for b in webnotes.conn.sql("""select item, (total_cost/quantity) as bom_rate + from `tabBOM` where is_active=1 and is_default=1""", as_dict=1): + bom_map.setdefault(b.item, flt(b.bom_rate)) + + return bom_map + +def get_valuation_rate(): + """Get an average valuation rate of an item from all warehouses""" + + val_rate_map = {} + + for d in webnotes.conn.sql("""select item_code, avg(valuation_rate) as val_rate + from tabBin group by item_code""", as_dict=1): + val_rate_map.setdefault(d.item_code, d.val_rate) + + return val_rate_map \ No newline at end of file diff --git a/stock/report/item_prices/item_prices.txt b/stock/report/item_prices/item_prices.txt new file mode 100644 index 0000000000..4c49ca1748 --- /dev/null +++ b/stock/report/item_prices/item_prices.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-05 11:43:30", + "docstatus": 0, + "modified": "2013-06-05 11:43:30", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Stock Ledger Entry", + "report_name": "Item Prices", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Item Prices" + } +] \ No newline at end of file diff --git a/stock/report/itemwise_recommended_reorder_level/__init__.py b/stock/report/itemwise_recommended_reorder_level/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js b/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js new file mode 100644 index 0000000000..b8aa378828 --- /dev/null +++ b/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.js @@ -0,0 +1,16 @@ +wn.query_reports["Itemwise Recommended Reorder Level"] = { + "filters": [ + { + "fieldname":"from_date", + "label": "From Date", + "fieldtype": "Date", + "default": sys_defaults.year_start_date + }, + { + "fieldname":"to_date", + "label": "To Date", + "fieldtype": "Date", + "default": get_today() + } + ] +} \ No newline at end of file diff --git a/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py b/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py new file mode 100644 index 0000000000..588132f961 --- /dev/null +++ b/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py @@ -0,0 +1,104 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import webnotes +from webnotes.utils import getdate, flt + +def execute(filters=None): + if not filters: filters = {} + float_preceision = webnotes.conn.get_default("float_preceision") + + condition =get_condition(filters) + + avg_daily_outgoing = 0 + diff = ((getdate(filters.get("to_date")) - getdate(filters.get("from_date"))).days)+1 + if diff <= 0: + webnotes.msgprint("To Date should not be less than eual to From Date",raise_exception=1) + + columns = get_columns() + items = get_item_info() + consumed_item_map = get_consumed_items(condition) + delivered_item_map = get_delivered_items(condition) + + data = [] + for item in items: + + total_outgoing = consumed_item_map.get(item.name, 0)+delivered_item_map.get(item.name,0) + avg_daily_outgoing = flt(total_outgoing/diff, float_preceision) + reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt(item.min_order_qty) + + data.append([item.name, item.item_name, item.description, item.min_order_qty, item.lead_time_days, + consumed_item_map.get(item.name, 0), delivered_item_map.get(item.name,0), total_outgoing, + avg_daily_outgoing, reorder_level]) + + return columns , data + +def get_columns(): + return[ + "Item:Link/Item:120", "Item name:Data:120", "Description::160", + "Minimum Inventory Level:Float:160", "Lead Time Days:Float:120", "Consumed:Float:120", + "Delivered:Float:120", "Total Outgoing:Float:120", "Avg Daily Outgoing:Float:160", + "Reorder Level:Float:120" + ] + +def get_item_info(): + return webnotes.conn.sql("""select name, item_name, description, min_order_qty, + lead_time_days from tabItem""", as_dict=1) + +def get_consumed_items(condition): + + cn_items = webnotes.conn.sql("""select se_item.item_code, + sum(se_item.actual_qty) as 'consume_qty' + from `tabStock Entry` se, `tabStock Entry Detail` se_item + where se.name = se_item.parent and se.docstatus = 1 + and ifnull(se_item.t_warehouse, '') = '' %s + group by se_item.item_code""" % (condition), as_dict=1) + + cn_items_map = {} + for item in cn_items: + cn_items_map.setdefault(item.item_code, item.consume_qty) + + return cn_items_map + +def get_delivered_items(condition): + + dn_items = webnotes.conn.sql("""select dn_item.item_code, sum(dn_item.qty) as dn_qty + from `tabDelivery Note` dn, `tabDelivery Note Item` dn_item + where dn.name = dn_item.parent and dn.docstatus = 1 %s + group by dn_item.item_code""" % (condition), as_dict=1) + + si_items = webnotes.conn.sql("""select si_item.item_name, sum(si_item.qty) as si_qty + from `tabSales Invoice` si, `tabSales Invoice Item` si_item + where si.name = si_item.parent and si.docstatus = 1 and + ifnull(si.update_stock, 0) = 1 and ifnull(si.is_pos, 0) = 1 %s + group by si_item.item_name""" % (condition), as_dict=1) + + dn_item_map = {} + for item in dn_items: + dn_item_map.setdefault(item.item_code, item.dn_qty) + + for item in si_items: + dn_item_map.setdefault(item.item_code, item.si_qty) + + return dn_item_map + +def get_condition(filters): + conditions = "" + if filters.get("from_date") and filters.get("to_date"): + conditions += " and posting_date between '%s' and '%s'" % (filters["from_date"],filters["to_date"]) + else: + webnotes.msgprint("Please set date in from date field",raise_exception=1) + return conditions \ No newline at end of file diff --git a/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.txt b/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.txt new file mode 100644 index 0000000000..2763f21dfe --- /dev/null +++ b/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-07 12:47:22", + "docstatus": 0, + "modified": "2013-06-07 13:03:54", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Item", + "report_name": "Itemwise Recommended Reorder Level", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Itemwise Recommended Reorder Level" + } +] \ No newline at end of file diff --git a/stock/report/warehouse_wise_stock_balance/__init__.py b/stock/report/warehouse_wise_stock_balance/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.js b/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.js new file mode 100644 index 0000000000..5e1eb3a7b2 --- /dev/null +++ b/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.js @@ -0,0 +1,32 @@ +wn.query_reports["Warehouse-Wise Stock Balance"] = { + "filters": [ + { + "fieldname":"item_code", + "label": "Item", + "fieldtype": "Link", + "options": "Item", + "width": "80" + }, + { + "fieldname":"warehouse", + "label": "Warehouse", + "fieldtype": "Link", + "options": "Warehouse", + "width": "80" + }, + { + "fieldname":"from_date", + "label": "From Date", + "fieldtype": "Date", + "width": "80", + "default": sys_defaults.year_start_date, + }, + { + "fieldname":"to_date", + "label": "To Date", + "fieldtype": "Date", + "width": "80", + "default": wn.datetime.get_today() + } + ] +} \ No newline at end of file diff --git a/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.py b/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.py new file mode 100644 index 0000000000..324bbe3e8c --- /dev/null +++ b/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.py @@ -0,0 +1,104 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import flt + +def execute(filters=None): + if not filters: filters = {} + + columns = get_columns(filters) + item_map = get_item_details(filters) + iwb_map = get_item_warehouse_map(filters) + + data = [] + for item in sorted(iwb_map): + for wh in sorted(iwb_map[item]): + qty_dict = iwb_map[item][wh] + data.append([item, item_map[item]["item_name"], + item_map[item]["description"], wh, + qty_dict.opening_qty, qty_dict.in_qty, + qty_dict.out_qty, qty_dict.bal_qty + ]) + + return columns, data + +def get_columns(filters): + """return columns based on filters""" + + columns = ["Item:Link/Item:100"] + ["Item Name::150"] + ["Description::150"] + \ + ["Warehouse:Link/Warehouse:100"] + ["Opening Qty::90"] + \ + ["In Qty::80"] + ["Out Qty::80"] + ["Balance Qty::90"] + + return columns + +def get_conditions(filters): + conditions = "" + if filters.get("item_code"): + conditions += " and item_code='%s'" % filters["item_code"] + + if filters.get("warehouse"): + conditions += " and warehouse='%s'" % filters["warehouse"] + + if not filters.get("from_date"): + webnotes.msgprint("Please enter From Date", raise_exception=1) + + if filters.get("to_date"): + conditions += " and posting_date <= '%s'" % filters["to_date"] + else: + webnotes.msgprint("Please enter To Date", raise_exception=1) + + return conditions + +#get all details +def get_stock_ledger_entries(filters): + conditions = get_conditions(filters) + return webnotes.conn.sql("""select item_code, warehouse, + posting_date, actual_qty + from `tabStock Ledger Entry` + where ifnull(is_cancelled, 'No') = 'No' %s order by item_code, warehouse""" % + conditions, as_dict=1) + +def get_item_warehouse_map(filters): + sle = get_stock_ledger_entries(filters) + iwb_map = {} + + for d in sle: + iwb_map.setdefault(d.item_code, {}).setdefault(d.warehouse, webnotes._dict({\ + "opening_qty": 0.0, "in_qty": 0.0, "out_qty": 0.0, "bal_qty": 0.0 + })) + qty_dict = iwb_map[d.item_code][d.warehouse] + if d.posting_date < filters["from_date"]: + qty_dict.opening_qty += flt(d.actual_qty) + elif d.posting_date >= filters["from_date"] and d.posting_date <= filters["to_date"]: + if flt(d.actual_qty) > 0: + qty_dict.in_qty += flt(d.actual_qty) + else: + qty_dict.out_qty += abs(flt(d.actual_qty)) + + qty_dict.bal_qty += flt(d.actual_qty) + + return iwb_map + +def get_item_details(filters): + if filters.get("item_code"): + conditions = " and name = '%s'" % filters["item_code"] + item_map = {} + for d in webnotes.conn.sql("select name, item_name, description from tabItem", as_dict=1): + item_map.setdefault(d.name, d) + + return item_map \ No newline at end of file diff --git a/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.txt b/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.txt new file mode 100644 index 0000000000..2513587632 --- /dev/null +++ b/stock/report/warehouse_wise_stock_balance/warehouse_wise_stock_balance.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-05 11:00:31", + "docstatus": 0, + "modified": "2013-06-05 11:00:31", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Stock Ledger Entry", + "report_name": "Warehouse-Wise Stock Balance", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Warehouse-Wise Stock Balance" + } +] \ No newline at end of file diff --git a/support/doctype/maintenance_schedule/maintenance_schedule.py b/support/doctype/maintenance_schedule/maintenance_schedule.py index 60962b1d52..06c5a47aff 100644 --- a/support/doctype/maintenance_schedule/maintenance_schedule.py +++ b/support/doctype/maintenance_schedule/maintenance_schedule.py @@ -18,7 +18,7 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import add_days, cstr, getdate -from webnotes.model.doc import Document, addchild +from webnotes.model.doc import addchild from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import msgprint @@ -100,23 +100,21 @@ class DocType(TransactionBase): for key in scheduled_date: if email_map[d.incharge_name]: - self.add_calender_event(key["scheduled_date"],email_map[d.incharge_name],d.item_code) + description = "Reference: %s, Item Code: %s and Customer: %s" % \ + (self.doc.name, d.item_code, self.doc.customer) + webnotes.bean({ + "doctype": "Event", + "owner": email_map[d.incharge_name] or self.doc.owner, + "subject": description, + "description": description, + "starts_on": key["scheduled_date"] + " 10:00:00", + "event_type": "Private", + "ref_type": self.doc.doctype, + "ref_name": self.doc.name + }).insert() + webnotes.conn.set(self.doc, 'status', 'Submitted') - - def add_calender_event(self,scheduled_date,incharge_email,item_code): - """ Add calendar event for Maintenece Schedule in calendar of Allocated person""" - event = Document('Event') - event.owner = incharge_email - event.description = "Reference:%s, Item Code:%s and Customer: %s" %(self.doc.name, item_code, self.doc.customer) - event.event_date = scheduled_date - event.event_hour = '10:00' - event.event_type = 'Private' - event.ref_type = 'Maintenance Schedule' - event.ref_name = self.doc.name - event.save(1) - - #get schedule dates #---------------------- def create_schedule_list(self, start_date, end_date, no_of_visit): @@ -329,8 +327,13 @@ class DocType(TransactionBase): if d.serial_no: self.update_amc_date(d.serial_no, '') webnotes.conn.set(self.doc, 'status', 'Cancelled') - sql("delete from `tabEvent` where ref_type='Maintenance Schedule' and ref_name='%s' " %(self.doc.name)) + self.delete_events() + def on_trash(self): - sql("delete from `tabEvent` where ref_type='Maintenance Schedule' and ref_name='%s' " %(self.doc.name)) + self.delete_events() + + def delete_events(self): + webnotes.delete_doc("Event", webnotes.conn.sql_list("""select name from `tabEvent` + where ref_type=%s and ref_name=%s""", (self.doc.doctype, self.doc.name))) diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py index 29e74a9e63..011986debc 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -270,6 +270,41 @@ class TransactionBase(StatusUpdater): def validate_posting_time(self): if not self.doc.posting_time: self.doc.posting_time = now_datetime().strftime('%H:%M:%S') + + def add_calendar_event(self, opts): + if self.doc.contact_by != cstr(self._prev.contact_by) or \ + self.doc.contact_date != cstr(self._prev.contact_date): + + self.delete_events() + self._add_calendar_event(opts) + + def delete_events(self): + webnotes.delete_doc("Event", webnotes.conn.sql_list("""select name from `tabEvent` + where ref_type=%s and ref_name=%s""", (self.doc.doctype, self.doc.name))) + + def _add_calendar_event(self, opts): + opts = webnotes._dict(opts) + + if self.doc.contact_date: + event_doclist = [{ + "doctype": "Event", + "owner": opts.owner or self.doc.owner, + "subject": opts.subject, + "description": opts.description, + "starts_on": self.doc.contact_date + " 10:00:00", + "event_type": "Private", + "ref_type": self.doc.doctype, + "ref_name": self.doc.name + }] + + if webnotes.conn.exists("Profile", self.doc.contact_by): + event_doclist.append({ + "doctype": "Event User", + "parentfield": "event_individuals", + "person": self.doc.contact_by + }) + + webnotes.bean(event_doclist).insert() def validate_conversion_rate(currency, conversion_rate, conversion_rate_label, company): """common validation for currency and price list currency""" @@ -323,5 +358,4 @@ def validate_currency(args, item, meta=None): args.plc_conversion_rate = flt(args.plc_conversion_rate, get_field_precision(meta.get_field("plc_conversion_rate"), webnotes._dict({"fields": args}))) - \ No newline at end of file