diff --git a/accounts/page/accounts_home/accounts_home.js b/accounts/page/accounts_home/accounts_home.js index b920bfdbab1..07c8b669d81 100644 --- a/accounts/page/accounts_home/accounts_home.js +++ b/accounts/page/accounts_home/accounts_home.js @@ -252,6 +252,21 @@ wn.module_page["Accounts"] = [ route: "query-report/Item-wise Purchase Register", doctype: "Purchase Invoice" }, + { + "label":wn._("Budget Variance Report"), + route: "query-report/Budget Variance Report", + doctype: "Cost Center" + }, + { + "label":wn._("Purchase Invoice Trends"), + route: "query-report/Purchase Invoice Trends", + doctype: "Purchase Invoice" + }, + { + "label":wn._("Sales Invoice Trends"), + route: "query-report/Sales Invoice Trends", + doctype: "Sales Invoice" + }, ] } ] diff --git a/accounts/report/budget_variance_report/__init__.py b/accounts/report/budget_variance_report/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/accounts/report/budget_variance_report/budget_variance_report.js b/accounts/report/budget_variance_report/budget_variance_report.js new file mode 100644 index 00000000000..a0516050ce7 --- /dev/null +++ b/accounts/report/budget_variance_report/budget_variance_report.js @@ -0,0 +1,25 @@ +wn.query_reports["Budget Variance Report"] = { + "filters": [ + { + fieldname: "fiscal_year", + label: "Fiscal Year", + fieldtype: "Link", + options: "Fiscal Year", + default: sys_defaults.fiscal_year + }, + { + fieldname: "period", + label: "Period", + fieldtype: "Select", + options: "Monthly\nQuarterly\nHalf-Yearly\nYearly", + default: "Monthly" + }, + { + fieldname: "company", + label: "Company", + fieldtype: "Link", + options: "Company", + default: sys_defaults.company + }, + ] +} \ No newline at end of file diff --git a/accounts/report/budget_variance_report/budget_variance_report.py b/accounts/report/budget_variance_report/budget_variance_report.py new file mode 100644 index 00000000000..99e303bd204 --- /dev/null +++ b/accounts/report/budget_variance_report/budget_variance_report.py @@ -0,0 +1,168 @@ +# 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 +import calendar +from webnotes import _, msgprint +from webnotes.utils import flt +import time + +def execute(filters=None): + if not filters: filters = {} + + columns = get_columns(filters) + period_month_ranges = get_period_month_ranges(filters) + cam_map = get_costcenter_account_month_map(filters) + + data = [] + + for cost_center, cost_center_items in cam_map.items(): + for account, monthwise_data in cost_center_items.items(): + row = [cost_center, account] + totals = [0, 0, 0] + for relevant_months in period_month_ranges: + period_data = [0, 0, 0] + for month in relevant_months: + month_data = monthwise_data.get(month, {}) + for i, fieldname in enumerate(["target", "actual", "variance"]): + value = flt(month_data.get(fieldname)) + period_data[i] += value + totals[i] += value + period_data[2] = period_data[0] - period_data[1] + row += period_data + totals[2] = totals[0] - totals[1] + row += totals + data.append(row) + + return columns, sorted(data, key=lambda x: (x[0], x[1])) + +def get_columns(filters): + for fieldname in ["fiscal_year", "period", "company"]: + if not filters.get(fieldname): + label = (" ".join(fieldname.split("_"))).title() + msgprint(_("Please specify") + ": " + label, + raise_exception=True) + + columns = ["Cost Center:Link/Cost Center:100", "Account:Link/Account:100"] + + group_months = False if filters["period"] == "Monthly" else True + + for from_date, to_date in get_period_date_ranges(filters): + for label in ["Target (%s)", "Actual (%s)", "Variance (%s)"]: + if group_months: + columns.append(label % (from_date.strftime("%b") + " - " + to_date.strftime("%b"))) + else: + columns.append(label % from_date.strftime("%b")) + + return columns + ["Total Target::80", "Total Actual::80", "Total Variance::80"] + +def get_period_date_ranges(filters): + from dateutil.relativedelta import relativedelta + + year_start_date, year_end_date = get_year_start_end_date(filters) + + increment = { + "Monthly": 1, + "Quarterly": 3, + "Half-Yearly": 6, + "Yearly": 12 + }.get(filters["period"]) + + period_date_ranges = [] + for i in xrange(1, 13, increment): + period_end_date = year_start_date + relativedelta(months=increment, + days=-1) + period_date_ranges.append([year_start_date, period_end_date]) + year_start_date = period_end_date + relativedelta(days=1) + + return period_date_ranges + +def get_period_month_ranges(filters): + from dateutil.relativedelta import relativedelta + period_month_ranges = [] + + for start_date, end_date in get_period_date_ranges(filters): + months_in_this_period = [] + while start_date <= end_date: + months_in_this_period.append(start_date.strftime("%B")) + start_date += relativedelta(months=1) + period_month_ranges.append(months_in_this_period) + + return period_month_ranges + + +#Get cost center & target details +def get_costcenter_target_details(filters): + return webnotes.conn.sql("""select cc.name, cc.distribution_id, + cc.parent_cost_center, bd.account, bd.budget_allocated + from `tabCost Center` cc, `tabBudget Detail` bd + where bd.parent=cc.name and bd.fiscal_year=%s and + cc.company_name=%s and ifnull(cc.distribution_id, '')!='' + order by cc.name""" % ('%s', '%s'), + (filters.get("fiscal_year"), filters.get("company")), as_dict=1) + +#Get target distribution details of accounts of cost center +def get_target_distribution_details(filters): + target_details = {} + + for d in webnotes.conn.sql("""select bdd.month, bdd.percentage_allocation \ + from `tabBudget Distribution Detail` bdd, `tabBudget Distribution` bd, \ + `tabCost Center` cc where bdd.parent=bd.name and cc.distribution_id=bd.name and \ + bd.fiscal_year=%s""" % ('%s'), (filters.get("fiscal_year")), as_dict=1): + target_details.setdefault(d.month, d) + + return target_details + +#Get actual details from gl entry +def get_actual_details(filters): + return webnotes.conn.sql("""select gl.account, gl.debit, gl.credit, + gl.cost_center, MONTHNAME(gl.posting_date) as month_name + from `tabGL Entry` gl, `tabBudget Detail` bd + where gl.fiscal_year=%s and company=%s and is_cancelled='No' + and bd.account=gl.account""" % ('%s', '%s'), + (filters.get("fiscal_year"), filters.get("company")), as_dict=1) + +def get_costcenter_account_month_map(filters): + costcenter_target_details = get_costcenter_target_details(filters) + tdd = get_target_distribution_details(filters) + actual_details = get_actual_details(filters) + + cam_map = {} + + for ccd in costcenter_target_details: + for month in tdd: + cam_map.setdefault(ccd.name, {}).setdefault(ccd.account, {})\ + .setdefault(month, webnotes._dict({ + "target": 0.0, "actual": 0.0, "variance": 0.0 + })) + + tav_dict = cam_map[ccd.name][ccd.account][month] + tav_dict.target = ccd.budget_allocated*(tdd[month]["percentage_allocation"]/100) + + for ad in actual_details: + if ad.month_name == month and ad.account == ccd.account \ + and ad.cost_center == ccd.name: + tav_dict.actual += ad.debit - ad.credit + + return cam_map + +def get_year_start_end_date(filters): + return webnotes.conn.sql("""select year_start_date, + subdate(adddate(year_start_date, interval 1 year), interval 1 day) + as year_end_date + from `tabFiscal Year` + where name=%s""", filters["fiscal_year"])[0] \ No newline at end of file diff --git a/accounts/report/budget_variance_report/budget_variance_report.txt b/accounts/report/budget_variance_report/budget_variance_report.txt new file mode 100644 index 00000000000..b89cb4545fe --- /dev/null +++ b/accounts/report/budget_variance_report/budget_variance_report.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-18 12:56:36", + "docstatus": 0, + "modified": "2013-06-18 12:56:36", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Cost Center", + "report_name": "Budget Variance Report", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Budget Variance Report" + } +] \ 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 index ad9d79504b1..f7afb3dfb64 100644 --- a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -23,7 +23,6 @@ def execute(filters=None): 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) diff --git a/accounts/report/purchase_invoice_trends/__init__.py b/accounts/report/purchase_invoice_trends/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/accounts/report/purchase_invoice_trends/purchase_invoice_trends.js b/accounts/report/purchase_invoice_trends/purchase_invoice_trends.js new file mode 100644 index 00000000000..bb18ce4cbe2 --- /dev/null +++ b/accounts/report/purchase_invoice_trends/purchase_invoice_trends.js @@ -0,0 +1,5 @@ +wn.require("app/js/purchase_trends_filters.js"); + +wn.query_reports["Purchase Invoice Trends"] = { + filters: get_filters() + } \ No newline at end of file diff --git a/accounts/report/purchase_invoice_trends/purchase_invoice_trends.py b/accounts/report/purchase_invoice_trends/purchase_invoice_trends.py new file mode 100644 index 00000000000..b2f376b4715 --- /dev/null +++ b/accounts/report/purchase_invoice_trends/purchase_invoice_trends.py @@ -0,0 +1,34 @@ +# 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 controllers.trends import get_columns,get_data + +def execute(filters=None): + if not filters: filters ={} + data = [] + + trans = "Purchase Invoice" + tab = ["tabPurchase Invoice","tabPurchase Invoice Item"] + + details = get_columns(filters, trans) + data = get_data(filters, tab, details) + + if not data : + webnotes.msgprint("Data not found for selected criterias") + + return details["columns"], data \ No newline at end of file diff --git a/accounts/report/purchase_invoice_trends/purchase_invoice_trends.txt b/accounts/report/purchase_invoice_trends/purchase_invoice_trends.txt new file mode 100644 index 00000000000..1d5c2d5f45e --- /dev/null +++ b/accounts/report/purchase_invoice_trends/purchase_invoice_trends.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-13 18:46:55", + "docstatus": 0, + "modified": "2013-06-13 18:46:55", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Purchase Invoice", + "report_name": "Purchase Invoice Trends", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Purchase Invoice Trends" + } +] \ No newline at end of file diff --git a/accounts/report/purchase_register/purchase_register.py b/accounts/report/purchase_register/purchase_register.py index 7c4b38671d7..548b5613440 100644 --- a/accounts/report/purchase_register/purchase_register.py +++ b/accounts/report/purchase_register/purchase_register.py @@ -107,6 +107,7 @@ def get_invoices(filters): from `tabPurchase Invoice` where docstatus = 1 %s order by posting_date desc, name desc""" % conditions, filters, as_dict=1) + def get_invoice_expense_map(invoice_list): expense_details = webnotes.conn.sql("""select parent, expense_head, sum(amount) as amount from `tabPurchase Invoice Item` where parent in (%s) group by parent, expense_head""" % diff --git a/accounts/report/sales_invoice_trends/__init__.py b/accounts/report/sales_invoice_trends/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/accounts/report/sales_invoice_trends/sales_invoice_trends.js b/accounts/report/sales_invoice_trends/sales_invoice_trends.js new file mode 100644 index 00000000000..6f20015d21f --- /dev/null +++ b/accounts/report/sales_invoice_trends/sales_invoice_trends.js @@ -0,0 +1,5 @@ +wn.require("app/js/sales_trends_filters.js"); + +wn.query_reports["Sales Invoice Trends"] = { + filters: get_filters() + } \ No newline at end of file diff --git a/accounts/report/sales_invoice_trends/sales_invoice_trends.py b/accounts/report/sales_invoice_trends/sales_invoice_trends.py new file mode 100644 index 00000000000..11d6665ff3f --- /dev/null +++ b/accounts/report/sales_invoice_trends/sales_invoice_trends.py @@ -0,0 +1,34 @@ +# 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 controllers.trends import get_columns,get_data + +def execute(filters=None): + if not filters: filters ={} + data = [] + + trans = "Sales Invoice" + tab = ["tabSales Invoice","tabSales Invoice Item"] + + details = get_columns(filters, trans) + data = get_data(filters, tab, details) + + if not data : + webnotes.msgprint("Data not found for selected criterias") + + return details["columns"], data \ No newline at end of file diff --git a/accounts/report/sales_invoice_trends/sales_invoice_trends.txt b/accounts/report/sales_invoice_trends/sales_invoice_trends.txt new file mode 100644 index 00000000000..279ac1269f1 --- /dev/null +++ b/accounts/report/sales_invoice_trends/sales_invoice_trends.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-13 18:44:21", + "docstatus": 0, + "modified": "2013-06-13 18:44:21", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Sales Invoice", + "report_name": "Sales Invoice Trends", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Sales Invoice Trends" + } +] \ No newline at end of file diff --git a/accounts/utils.py b/accounts/utils.py index eb240e796c0..fa93cb06286 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -26,17 +26,23 @@ from utilities import build_filter_conditions class FiscalYearError(webnotes.ValidationError): pass -def get_fiscal_year(date, verbose=1): - return get_fiscal_years(date, verbose=1)[0] +def get_fiscal_year(date=None, fiscal_year=None, verbose=1): + return get_fiscal_years(date, fiscal_year, verbose=1)[0] -def get_fiscal_years(date, verbose=1): +def get_fiscal_years(date=None, fiscal_year=None, verbose=1): # if year start date is 2012-04-01, year end date should be 2013-03-31 (hence subdate) + cond = "" + if fiscal_year: + cond = "name = '%s'" % fiscal_year + else: + cond = "'%s' >= year_start_date and '%s' < adddate(year_start_date, interval 1 year)" % \ + (date, date) fy = webnotes.conn.sql("""select name, year_start_date, subdate(adddate(year_start_date, interval 1 year), interval 1 day) as year_end_date from `tabFiscal Year` - where %s >= year_start_date and %s < adddate(year_start_date, interval 1 year) - order by year_start_date desc""", (date, date)) + where %s + order by year_start_date desc""" % cond) if not fy: error_msg = """%s not in any Fiscal Year""" % formatdate(date) diff --git a/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js index 54d80268731..d3a1a60e470 100644 --- a/buying/doctype/purchase_common/purchase_common.js +++ b/buying/doctype/purchase_common/purchase_common.js @@ -445,7 +445,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ $.each(field_label_map, function(fname, label) { $wrapper.find('[data-grid-fieldname="'+fname+'"]').text(label); }); - }, + } }); // to save previous state of cur_frm.cscript @@ -459,4 +459,4 @@ $.extend(cur_frm.cscript, prev_cscript); var tname = cur_frm.cscript.tname; -var fname = cur_frm.cscript.fname; \ No newline at end of file +var fname = cur_frm.cscript.fname; diff --git a/buying/page/buying_home/buying_home.js b/buying/page/buying_home/buying_home.js index e45e73d2918..bda2eb90158 100644 --- a/buying/page/buying_home/buying_home.js +++ b/buying/page/buying_home/buying_home.js @@ -115,6 +115,15 @@ wn.module_page["Buying"] = [ "label":wn._("Requested Items To Be Ordered"), route: "query-report/Requested Items To Be Ordered", }, + { + "label":wn._("Purchase Order Trends"), + route: "query-report/Purchase Order Trends", + doctype: "Purchase Order" + }, + { + "label":wn._("Item-wise Last Purchase Rate"), + route: "query-report/Item-wise Last Purchase Rate", + } ] } ] diff --git a/buying/report/item_wise_last_purchase_rate/__init__.py b/buying/report/item_wise_last_purchase_rate/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/buying/report/item_wise_last_purchase_rate/item_wise_last_purchase_rate.txt b/buying/report/item_wise_last_purchase_rate/item_wise_last_purchase_rate.txt new file mode 100644 index 00000000000..db99e724ced --- /dev/null +++ b/buying/report/item_wise_last_purchase_rate/item_wise_last_purchase_rate.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-06-18 11:24:36", + "docstatus": 0, + "modified": "2013-06-18 15:28:57", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "query": "select * from (select \n result.item_code as \"Item Code:Link/Item:120\",\n result.item_name as \"Item Name::120\",\n result.description as \"Description::150\",\n result.posting_date as \"Date::150\",\n result.purchase_ref_rate as \"Price List Rate::180\", \n result.discount_rate as \"Discount::120\", \n result.purchase_rate as \"Rate::120\"\nfrom (\n (select \n po_item.item_code,\n po_item.item_name,\n po_item.description,\n po.transaction_date as posting_date,\n po_item.purchase_ref_rate, \n po_item.discount_rate, \n po_item.purchase_rate\n from `tabPurchase Order` po, `tabPurchase Order Item` po_item\n where po.name = po_item.parent and po.docstatus = 1)\n union\n (select \n pr_item.item_code,\n pr_item.item_name,\n pr_item.description,\n pr.posting_date,\n pr_item.purchase_ref_rate,\n pr_item.discount_rate,\n pr_item.purchase_rate\n from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item\n where pr.name = pr_item.parent and pr.docstatus = 1)\n) result\norder by result.item_code asc, result.posting_date desc) result_wrapper\ngroup by `Item Code:Link/Item:120`\n", + "ref_doctype": "Purchase Order", + "report_name": "Item-wise Last Purchase Rate", + "report_type": "Query Report" + }, + { + "doctype": "Report", + "name": "Item-wise Last Purchase Rate" + } +] \ No newline at end of file diff --git a/buying/report/purchase_order_trends/__init__.py b/buying/report/purchase_order_trends/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/buying/report/purchase_order_trends/purchase_order_trends.js b/buying/report/purchase_order_trends/purchase_order_trends.js new file mode 100644 index 00000000000..c6373db6c2a --- /dev/null +++ b/buying/report/purchase_order_trends/purchase_order_trends.js @@ -0,0 +1,5 @@ +wn.require("app/js/purchase_trends_filters.js"); + +wn.query_reports["Purchase Order Trends"] = { + filters: get_filters() + } \ No newline at end of file diff --git a/buying/report/purchase_order_trends/purchase_order_trends.py b/buying/report/purchase_order_trends/purchase_order_trends.py new file mode 100644 index 00000000000..301124fd3b9 --- /dev/null +++ b/buying/report/purchase_order_trends/purchase_order_trends.py @@ -0,0 +1,34 @@ +# 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 controllers.trends import get_columns,get_data + +def execute(filters=None): + if not filters: filters ={} + data = [] + + trans = "Purchase Order" + tab = ["tabPurchase Order","tabPurchase Order Item"] + + details = get_columns(filters, trans) + data = get_data(filters, tab, details) + + if not data : + webnotes.msgprint("Data not found for selected criterias") + + return details["columns"], data \ No newline at end of file diff --git a/buying/report/purchase_order_trends/purchase_order_trends.txt b/buying/report/purchase_order_trends/purchase_order_trends.txt new file mode 100644 index 00000000000..658dd4aab11 --- /dev/null +++ b/buying/report/purchase_order_trends/purchase_order_trends.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-13 18:45:01", + "docstatus": 0, + "modified": "2013-06-13 18:45:01", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Purchase Order", + "report_name": "Purchase Order Trends", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Purchase Order Trends" + } +] \ No newline at end of file diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 52dc3a88580..885f9e54e6d 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -65,16 +65,7 @@ class BuyingController(StockController): raise_exception=WrongWarehouseCompany) def validate_stock_or_nonstock_items(self): - items = [d.item_code for d in self.doclist.get({"parentfield": self.fname})] - if self.stock_items: - nonstock_items = list(set(items) - set(self.stock_items)) - if nonstock_items: - webnotes.msgprint(_("Stock and non-stock items can not be entered in the same ") + - self.doc.doctype + _(""". You should make separate documents for them. - Stock Items: """) + ", ".join(self.stock_items) + _(""" - Non-stock Items: """) + ", ".join(nonstock_items), raise_exception=1) - - elif items and not self.stock_items: + if not self.stock_items: tax_for_valuation = [d.account_head for d in self.doclist.get({"parentfield": "purchase_tax_details"}) if d.category in ["Valuation", "Valuation and Total"]] @@ -288,4 +279,4 @@ class BuyingController(StockController): from `tabItem` where name in (%s) and is_purchase_item='Yes'""" % \ (", ".join((["%s"]*len(item_codes))),), item_codes)] - return self._purchase_items \ No newline at end of file + return self._purchase_items diff --git a/controllers/trends.py b/controllers/trends.py new file mode 100644 index 00000000000..c0636cba459 --- /dev/null +++ b/controllers/trends.py @@ -0,0 +1,258 @@ +# 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 add_days, add_months, cstr, getdate +from webnotes import _ + +def get_columns(filters, trans): + validate_filters(filters) + + # based_on_cols, based_on_select, based_on_group_by, addl_tables + bonc, query_bon, based, sup_tab = basedon_wise_colums_query(filters.get("based_on"), trans) + # period_cols, period_select + pwc, query_pwc = period_wise_colums_query(filters, trans) + + # group_by_cols + grbc = group_wise_column(filters.get("group_by")) + + columns = bonc + pwc + ["TOTAL(Qty):Float:120", "TOTAL(Amt):Currency:120"] + if grbc: + columns = bonc + grbc + pwc +["TOTAL(Qty):Float:120", "TOTAL(Amt):Currency:120"] + + # conditions + details = {"query_bon": query_bon, "query_pwc": query_pwc, "columns": columns, + "basedon": based, "grbc": grbc, "sup_tab": sup_tab} + + return details + +def validate_filters(filters): + for f in ["Fiscal Year", "Based On", "Period", "Company"]: + if not filters.get(f.lower().replace(" ", "_")): + webnotes.msgprint(f + _(" is mandatory"), raise_exception=1) + + if filters.get("based_on") == filters.get("group_by"): + webnotes.msgprint("'Based On' and 'Group By' can not be same", raise_exception=1) + +def get_data(filters, tab, details): + data = [] + inc, cond= '','' + query_details = details["query_bon"] + details["query_pwc"] + + if details["query_bon"] in ["t1.project_name,", "t2.project_name,"]: + cond = 'and '+ details["query_bon"][:-1] +' IS Not NULL' + + if filters.get("group_by"): + sel_col = '' + ind = details["columns"].index(details["grbc"][0]) + + if filters.get("group_by") == 'Item': + sel_col = 't2.item_code' + elif filters.get("group_by") == 'Customer': + sel_col = 't1.customer' + elif filters.get("group_by") == 'Supplier': + sel_col = 't1.supplier' + + if filters.get('based_on') in ['Item','Customer','Supplier']: + inc = 2 + else : + inc = 1 + + data1 = webnotes.conn.sql(""" select %s from `%s` t1, `%s` t2 %s + where t2.parent = t1.name and t1.company = %s + and t1.fiscal_year = %s and t1.docstatus = 1 %s + group by %s + """ % (query_details, tab[0], tab[1], details["sup_tab"], "%s", + "%s", cond, details["basedon"]), (filters.get("company"), + filters["fiscal_year"]), + as_list=1) + + for d in range(len(data1)): + #to add blanck column + dt = data1[d] + dt.insert(ind,'') + data.append(dt) + + #to get distinct value of col specified by group_by in filter + row = webnotes.conn.sql("""select DISTINCT(%s) from `%s` t1, `%s` t2 %s + where t2.parent = t1.name and t1.company = %s and t1.fiscal_year = %s + and t1.docstatus = 1 and %s = %s + """%(sel_col, tab[0], tab[1], details["sup_tab"], "%s", "%s", details["basedon"], "%s"), + (filters.get("company"), filters.get("fiscal_year"), data1[d][0]), + as_list=1) + + for i in range(len(row)): + des = ['' for q in range(len(details["columns"]))] + + #get data for each group_by filter + row1 = webnotes.conn.sql(""" select %s , %s from `%s` t1, `%s` t2 %s + where t2.parent = t1.name and t1.company = %s and t1.fiscal_year = %s + and t1.docstatus = 1 and %s = %s and %s = %s + """ % (sel_col, details["query_pwc"], tab[0], tab[1], details["sup_tab"], + "%s", "%s", sel_col, "%s", details["basedon"], "%s"), + (filters.get("company"), filters.get("fiscal_year"), + row[i][0], data1[d][0]), as_list=1) + + des[ind] = row[i] + for j in range(1,len(details["columns"])-inc): + des[j+inc] = row1[0][j] + + data.append(des) + else: + data = webnotes.conn.sql(""" select %s from `%s` t1, `%s` t2 %s + where t2.parent = t1.name and t1.company = %s + and t1.fiscal_year = %s and t1.docstatus = 1 %s + group by %s + """%(query_details, tab[0], tab[1], details["sup_tab"], "%s", + "%s", cond,details["basedon"]), (filters.get("company"), + filters.get("fiscal_year")), + as_list=1) + + return data + +def get_mon(dt): + return getdate(dt).strftime("%b") + +def period_wise_colums_query(filters, trans): + query_details = '' + pwc = [] + ysd = webnotes.conn.get_value("Fiscal year", filters.get("fiscal_year"), "year_start_date") + + if trans in ['Purchase Receipt', 'Delivery Note', 'Purchase Invoice', 'Sales Invoice']: + trans_date = 'posting_date' + else: + trans_date = 'transaction_date' + + if filters.get("period") == "Monthly": + month_name = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] + + for month_idx in range(ysd.month-1,len(month_name)) + range(0, ysd.month-1): + query_details = get_monthly_conditions(month_name, month_idx, trans_date, + pwc, query_details) + + elif filters.get("period") == "Quarterly": + + first_qsd, second_qsd, third_qsd, fourth_qsd = ysd, add_months(ysd,3), add_months(ysd,6), add_months(ysd,9) + first_qed, second_qed, third_qed, fourth_qed = add_days(add_months(first_qsd,3),-1), add_days(add_months(second_qsd,3),-1), add_days(add_months(third_qsd,3),-1), add_days(add_months(fourth_qsd,3),-1) + bet_dates = [[first_qsd,first_qed],[second_qsd,second_qed],[third_qsd,third_qed],[fourth_qsd,fourth_qed]] + + pwc = [get_mon(first_qsd)+"-"+get_mon(first_qed)+" (Qty):Float:120", get_mon(first_qsd)+"-"+get_mon(first_qed)+"(Amt):Currency:120", + get_mon(second_qsd)+"-"+get_mon(second_qed)+" (Qty):Float:120", get_mon(second_qsd)+"-"+get_mon(second_qed)+" (Amt):Currency:120", + get_mon(third_qsd)+"-"+get_mon(third_qed)+" (Qty):Float:120", get_mon(third_qsd)+"-"+get_mon(third_qed)+" (Amt):Currency:120", + get_mon(fourth_qsd)+"-"+get_mon(fourth_qed)+" (Qty):Float:120", get_mon(fourth_qsd)+"-"+get_mon(fourth_qed)+" (Amt):Currency:120"] + + for d in bet_dates: + query_details += """ + SUM(IF(t1.%(trans)s BETWEEN '%(sd)s' AND '%(ed)s', t2.qty, NULL)), + SUM(IF(t1.%(trans)s BETWEEN '%(sd)s' AND '%(ed)s', t1.grand_total, NULL)), + """%{"trans": trans_date, "sd": d[0],"ed": d[1]} + + elif filters.get("period") == "Half-yearly": + + first_half_start = ysd + first_half_end = add_days(add_months(first_half_start,6),-1) + second_half_start = add_days(first_half_end,1) + second_half_end = add_days(add_months(second_half_start,6),-1) + + pwc = [get_mon(first_half_start)+"-"+get_mon(first_half_end)+"(Qty):Float:120", get_mon(first_half_start)+"-"+get_mon(first_half_end)+" (Amt):Currency:120", + get_mon(second_half_start)+"-"+get_mon(second_half_end)+" (Qty):Float:120", get_mon(second_half_start)+"-"+get_mon(second_half_end)+" (Amt):Currency:120"] + + query_details = """ + SUM(IF(t1.%(trans)s BETWEEN '%(fhs)s' AND '%(fhe)s', t2.qty, NULL)), + SUM(IF(t1.%(trans)s BETWEEN '%(fhs)s' AND '%(fhe)s', t1.grand_total, NULL)), + SUM(IF(t1.%(trans)s BETWEEN '%(shs)s' AND '%(she)s', t2.qty, NULL)), + SUM(IF(t1.%(trans)s BETWEEN '%(shs)s' AND '%(she)s', t1.grand_total, NULL)), + """%{"trans": trans_date, "fhs": first_half_start, "fhe": first_half_end,"shs": second_half_start, + "she": second_half_end} + + else: + pwc = [filters.get("fiscal_year")+" (Qty):Float:120", filters.get("fiscal_year")+" (Amt):Currency:120"] + query_details = " SUM(t2.qty), SUM(t1.grand_total)," + + query_details += 'SUM(t2.qty), SUM(t1.grand_total)' + return pwc, query_details + +def get_monthly_conditions(month_list, month_idx, trans_date, pwc, query_details): + pwc += [month_list[month_idx] + ' (Qty):Float:120', + month_list[month_idx] + ' (Amt):Currency:120'] + + query_details += """ + Sum(IF(MONTH(t1.%(trans_date)s)= %(mon_num)s, t2.qty, NULL)), + SUM(IF(MONTH(t1.%(trans_date)s)= %(mon_num)s, t1.grand_total, NULL)), + """ % {"trans_date": trans_date, "mon_num": cstr(month_idx+1)} + + return query_details + +def basedon_wise_colums_query(based_on, trans): + sup_tab = '' + + if based_on == "Item": + bon = ["Item:Link/Item:120", "Item Name:Data:120"] + query_details = "t2.item_code, t2.item_name," + based = 't2.item_code' + + elif based_on == "Item Group": + bon = ["Item Group:Link/Item Group:120"] + query_details = "t2.item_group," + based = 't2.item_group' + + elif based_on == "Customer": + bon = ["Customer:Link/Customer:120", "Territory:Link/Territory:120"] + query_details = "t1.customer_name, t1.territory, " + based = 't1.customer_name' + + elif based_on == "Customer Group": + bon = ["Customer Group:Link/Customer Group"] + query_details = "t1.customer_group," + based = 't1.customer_group' + + elif based_on == 'Supplier': + bon = ["Supplier:Link/Supplier:120", "Supplier Type:Link/Supplier Type:120"] + query_details = "t1.supplier, t3.supplier_type," + based = 't1.supplier' + sup_tab = '`tabSupplier` t3', + + elif based_on == 'Supplier Type': + bon = ["Supplier Type:Link/Supplier Type:120"] + query_details = "t3.supplier_type," + based = 't3.supplier_type' + sup_tab ='`tabSupplier` t3', + + elif based_on == "Territory": + bon = ["Territory:Link/Territory:120"] + query_details = "t1.territory," + based = 't1.territory' + + elif based_on == "Project": + if trans in ['Sales Invoice', 'Delivery Note', 'Sales Order']: + bon = ["Project:Link/Project:120"] + query_details = "t1.project_name," + based = 't1.project_name' + elif trans in ['Purchase Order', 'Purchase Invoice', 'Purchase Receipt']: + bon = ["Project:Link/Project:120"] + query_details = "t2.project_name," + based = 't2.project_name' + else: + webnotes.msgprint("Project-wise data is not available for Quotation", raise_exception=1) + + return bon, query_details, based, sup_tab + +def group_wise_column(group_by): + if group_by: + return [group_by+":Link/"+group_by+":120"] + else: + return [] \ No newline at end of file diff --git a/public/js/purchase_trends_filters.js b/public/js/purchase_trends_filters.js new file mode 100644 index 00000000000..e994a47ebde --- /dev/null +++ b/public/js/purchase_trends_filters.js @@ -0,0 +1,39 @@ +var get_filters = function(){ + return [ + { + "fieldname":"period", + "label": "Period", + "fieldtype": "Select", + "options": ["Monthly", "Quarterly", "Half-yearly", "Yearly"].join("\n"), + "default": "Monthly" + }, + { + "fieldname":"based_on", + "label": "Based On", + "fieldtype": "Select", + "options": ["Item", "Item Group", "Supplier", "Supplier Type", "Project"].join("\n"), + "default": "Item" + }, + { + "fieldname":"group_by", + "label": "Group By", + "fieldtype": "Select", + "options": ["Item", "Supplier"].join("\n"), + "default": "" + }, + { + "fieldname":"fiscal_year", + "label": "Fiscal Year", + "fieldtype": "Link", + "options":'Fiscal Year', + "default": sys_defaults.fiscal_year + }, + { + "fieldname":"company", + "label": "Company", + "fieldtype": "Link", + "options": "Company", + "default": sys_defaults.company + }, + ]; +} \ No newline at end of file diff --git a/public/js/sales_trends_filters.js b/public/js/sales_trends_filters.js new file mode 100644 index 00000000000..14dcbe3cf6f --- /dev/null +++ b/public/js/sales_trends_filters.js @@ -0,0 +1,39 @@ +var get_filters = function(){ + return[ + { + "fieldname":"period", + "label": "Period", + "fieldtype": "Select", + "options": ["Monthly", "Quarterly", "Half-yearly", "Yearly"].join("\n"), + "default": "Monthly" + }, + { + "fieldname":"based_on", + "label": "Based On", + "fieldtype": "Select", + "options": ["Item", "Item Group", "Customer", "Customer Group", "Territory", "Project"].join("\n"), + "default": "Item" + }, + { + "fieldname":"group_by", + "label": "Group By", + "fieldtype": "Select", + "options": ["Item", "Customer"].join("\n"), + "default": "" + }, + { + "fieldname":"fiscal_year", + "label": "Fiscal Year", + "fieldtype": "Link", + "options":'Fiscal Year', + "default": sys_defaults.fiscal_year + }, + { + "fieldname":"company", + "label": "Company", + "fieldtype": "Link", + "options": "Company", + "default": sys_defaults.company + }, + ]; +} \ No newline at end of file diff --git a/public/js/transaction.js b/public/js/transaction.js index a7e8c10a24b..9df01478514 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -70,7 +70,7 @@ erpnext.TransactionController = wn.ui.form.Controller.extend({ }, company: function() { - if(this.frm.doc.company) { + if(this.frm.doc.company && this.frm.fields_dict.currency) { var me = this; var company_currency = this.get_company_currency(); $.each(["currency", "price_list_currency"], function(i, fieldname) { @@ -87,6 +87,9 @@ erpnext.TransactionController = wn.ui.form.Controller.extend({ }, currency: function() { + if(this.frm.doc.currency === this.get_company_currency()) + this.frm.set_value("conversion_rate", 1.0); + this.price_list_currency(); }, diff --git a/selling/page/selling_home/selling_home.js b/selling/page/selling_home/selling_home.js index 9c18fda6818..87e12db904a 100644 --- a/selling/page/selling_home/selling_home.js +++ b/selling/page/selling_home/selling_home.js @@ -159,18 +159,37 @@ wn.module_page["Selling"] = [ }, { "label":wn._("Sales Person-wise Transaction Summary"), - route: "query-report/Sales Person-wise Transaction Summary", + route: "query-report/Sales Person-wise Transaction Summary" }, { "label":wn._("Item-wise Sales History"), - route: "query-report/Item-wise Sales History", + route: "query-report/Item-wise Sales History" + }, + { + "label":wn._("Territory Target Variance (Item Group-Wise)"), + route: "query-report/Territory Target Variance (Item Group-Wise)", + doctype: "Sales Order" + }, + { + "label":wn._("Sales Person Target Variance (Item Group-Wise)"), + route: "query-report/Sales Person Target Variance (Item Group-Wise)", + doctype: "Sales Order" }, { "label":wn._("Customers Not Buying Since Long Time"), route: "query-report/Customers Not Buying Since Long Time", doctype: "Sales Order" }, - + { + "label":wn._("Quotation Trend"), + route: "query-report/Quotation Trends", + doctype: "Quotation" + }, + { + "label":wn._("Sales Order Trend"), + route: "query-report/Sales Order Trends", + doctype: "Sales Order" + }, ] } ] diff --git a/selling/report/quotation_trends/__init__.py b/selling/report/quotation_trends/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/selling/report/quotation_trends/quotation_trends.js b/selling/report/quotation_trends/quotation_trends.js new file mode 100644 index 00000000000..2f9f23666c2 --- /dev/null +++ b/selling/report/quotation_trends/quotation_trends.js @@ -0,0 +1,5 @@ +wn.require("app/js/sales_trends_filters.js"); + +wn.query_reports["Quotation Trends"] = { + filters: get_filters() + } \ No newline at end of file diff --git a/selling/report/quotation_trends/quotation_trends.py b/selling/report/quotation_trends/quotation_trends.py new file mode 100644 index 00000000000..c6a54c75886 --- /dev/null +++ b/selling/report/quotation_trends/quotation_trends.py @@ -0,0 +1,31 @@ +# 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 controllers.trends import get_columns, get_data + +def execute(filters=None): + if not filters: filters ={} + data = [] + + trans = "Quotation" + tab = ["tabQuotation","tabQuotation Item"] + + details = get_columns(filters, trans) + data = get_data(filters, tab, details) + + return details["columns"], data \ No newline at end of file diff --git a/selling/report/quotation_trends/quotation_trends.txt b/selling/report/quotation_trends/quotation_trends.txt new file mode 100644 index 00000000000..eebffcf84b7 --- /dev/null +++ b/selling/report/quotation_trends/quotation_trends.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-06-07 16:01:16", + "docstatus": 0, + "modified": "2013-06-12 16:31:23", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "add_total_row": 0, + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Quotation", + "report_name": "Quotation Trends", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Quotation Trends" + } +] \ No newline at end of file diff --git a/selling/report/sales_order_trends/__init__.py b/selling/report/sales_order_trends/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/selling/report/sales_order_trends/sales_order_trends.js b/selling/report/sales_order_trends/sales_order_trends.js new file mode 100644 index 00000000000..458fee6ed3b --- /dev/null +++ b/selling/report/sales_order_trends/sales_order_trends.js @@ -0,0 +1,5 @@ +wn.require("app/js/sales_trends_filters.js"); + +wn.query_reports["Sales Order Trends"] = { + filters: get_filters() + } \ No newline at end of file diff --git a/selling/report/sales_order_trends/sales_order_trends.py b/selling/report/sales_order_trends/sales_order_trends.py new file mode 100644 index 00000000000..d556a58d37a --- /dev/null +++ b/selling/report/sales_order_trends/sales_order_trends.py @@ -0,0 +1,34 @@ +# 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 controllers.trends import get_columns,get_data + +def execute(filters=None): + if not filters: filters ={} + data = [] + + trans = "Sales Order" + tab = ["tabSales Order","tabSales Order Item"] + + details = get_columns(filters, trans) + data = get_data(filters, tab, details) + + if not data : + webnotes.msgprint("Data not found for selected criterias") + + return details["columns"], data \ No newline at end of file diff --git a/selling/report/sales_order_trends/sales_order_trends.txt b/selling/report/sales_order_trends/sales_order_trends.txt new file mode 100644 index 00000000000..16ee9ca46b3 --- /dev/null +++ b/selling/report/sales_order_trends/sales_order_trends.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-13 18:43:30", + "docstatus": 0, + "modified": "2013-06-13 18:43:30", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Sales Order", + "report_name": "Sales Order Trends", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Sales Order Trends" + } +] \ No newline at end of file diff --git a/selling/report/sales_person_target_variance_(item_group_wise)/__init__.py b/selling/report/sales_person_target_variance_(item_group_wise)/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/selling/report/sales_person_target_variance_(item_group_wise)/sales_person_target_variance_(item_group_wise).js b/selling/report/sales_person_target_variance_(item_group_wise)/sales_person_target_variance_(item_group_wise).js new file mode 100644 index 00000000000..09f0d55aedc --- /dev/null +++ b/selling/report/sales_person_target_variance_(item_group_wise)/sales_person_target_variance_(item_group_wise).js @@ -0,0 +1,25 @@ +wn.query_reports["Sales Person Target Variance (Item Group-Wise)"] = { + "filters": [ + { + fieldname: "fiscal_year", + label: "Fiscal Year", + fieldtype: "Link", + options: "Fiscal Year", + default: sys_defaults.fiscal_year + }, + { + fieldname: "period", + label: "Period", + fieldtype: "Select", + options: "Monthly\nQuarterly\nHalf-Yearly\nYearly", + default: "Monthly" + }, + { + fieldname: "target_on", + label: "Target On", + fieldtype: "Select", + options: "Quantity\nAmount", + default: "Quantity" + }, + ] +} \ No newline at end of file diff --git a/selling/report/sales_person_target_variance_(item_group_wise)/sales_person_target_variance_(item_group_wise).py b/selling/report/sales_person_target_variance_(item_group_wise)/sales_person_target_variance_(item_group_wise).py new file mode 100644 index 00000000000..8f5931d826b --- /dev/null +++ b/selling/report/sales_person_target_variance_(item_group_wise)/sales_person_target_variance_(item_group_wise).py @@ -0,0 +1,183 @@ +# 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 +import calendar +from webnotes import _, msgprint +from webnotes.utils import flt +import time + +def execute(filters=None): + if not filters: filters = {} + + columns = get_columns(filters) + period_month_ranges = get_period_month_ranges(filters) + sim_map = get_salesperson_item_month_map(filters) + + data = [] + + for salesperson, salesperson_items in sim_map.items(): + for item_group, monthwise_data in salesperson_items.items(): + row = [salesperson, item_group] + totals = [0, 0, 0] + for relevant_months in period_month_ranges: + period_data = [0, 0, 0] + for month in relevant_months: + month_data = monthwise_data.get(month, {}) + for i, fieldname in enumerate(["target", "achieved", "variance"]): + value = flt(month_data.get(fieldname)) + period_data[i] += value + totals[i] += value + period_data[2] = period_data[0] - period_data[1] + row += period_data + totals[2] = totals[0] - totals[1] + row += totals + data.append(row) + + return columns, sorted(data, key=lambda x: (x[0], x[1])) + +def get_columns(filters): + for fieldname in ["fiscal_year", "period", "target_on"]: + if not filters.get(fieldname): + label = (" ".join(fieldname.split("_"))).title() + msgprint(_("Please specify") + ": " + label, + raise_exception=True) + + columns = ["Sales Person:Link/Sales Person:80", "Item Group:Link/Item Group:80"] + + group_months = False if filters["period"] == "Monthly" else True + + for from_date, to_date in get_period_date_ranges(filters): + for label in ["Target (%s)", "Achieved (%s)", "Variance (%s)"]: + if group_months: + columns.append(label % (from_date.strftime("%b") + " - " + to_date.strftime("%b"))) + else: + columns.append(label % from_date.strftime("%b")) + + return columns + ["Total Target::80", "Total Achieved::80", "Total Variance::80"] + +def get_period_date_ranges(filters): + from dateutil.relativedelta import relativedelta + + year_start_date, year_end_date = get_year_start_end_date(filters) + + increment = { + "Monthly": 1, + "Quarterly": 3, + "Half-Yearly": 6, + "Yearly": 12 + }.get(filters["period"]) + + period_date_ranges = [] + for i in xrange(1, 13, increment): + period_end_date = year_start_date + relativedelta(months=increment, + days=-1) + period_date_ranges.append([year_start_date, period_end_date]) + year_start_date = period_end_date + relativedelta(days=1) + + return period_date_ranges + +def get_period_month_ranges(filters): + from dateutil.relativedelta import relativedelta + period_month_ranges = [] + + for start_date, end_date in get_period_date_ranges(filters): + months_in_this_period = [] + while start_date <= end_date: + months_in_this_period.append(start_date.strftime("%B")) + start_date += relativedelta(months=1) + period_month_ranges.append(months_in_this_period) + + return period_month_ranges + + +#Get sales person & item group details +def get_salesperson_details(filters): + return webnotes.conn.sql("""select sp.name, td.item_group, td.target_qty, + td.target_amount, sp.distribution_id + from `tabSales Person` sp, `tabTarget Detail` td + where td.parent=sp.name and td.fiscal_year=%s and + ifnull(sp.distribution_id, '')!='' order by sp.name""" % + ('%s'), (filters.get("fiscal_year")), as_dict=1) + +#Get target distribution details of item group +def get_target_distribution_details(filters): + target_details = {} + + for d in webnotes.conn.sql("""select bdd.month, bdd.percentage_allocation \ + from `tabBudget Distribution Detail` bdd, `tabBudget Distribution` bd, \ + `tabTerritory` t where bdd.parent=bd.name and t.distribution_id=bd.name and \ + bd.fiscal_year=%s """ % ('%s'), (filters.get("fiscal_year")), as_dict=1): + target_details.setdefault(d.month, d) + + return target_details + +#Get achieved details from sales order +def get_achieved_details(filters): + start_date, end_date = get_year_start_end_date(filters) + + return webnotes.conn.sql("""select soi.item_code, soi.qty, soi.amount, so.transaction_date, + st.sales_person, MONTHNAME(so.transaction_date) as month_name + from `tabSales Order Item` soi, `tabSales Order` so, `tabSales Team` st + where soi.parent=so.name and so.docstatus=1 and + st.parent=so.name and so.transaction_date>=%s and + so.transaction_date<=%s""" % ('%s', '%s'), + (start_date, end_date), as_dict=1) + +def get_salesperson_item_month_map(filters): + salesperson_details = get_salesperson_details(filters) + tdd = get_target_distribution_details(filters) + achieved_details = get_achieved_details(filters) + + sim_map = {} + + for sd in salesperson_details: + for month in tdd: + sim_map.setdefault(sd.name, {}).setdefault(sd.item_group, {})\ + .setdefault(month, webnotes._dict({ + "target": 0.0, "achieved": 0.0, "variance": 0.0 + })) + + tav_dict = sim_map[sd.name][sd.item_group][month] + + for ad in achieved_details: + if (filters["target_on"] == "Quantity"): + tav_dict.target = sd.target_qty*(tdd[month]["percentage_allocation"]/100) + if ad.month_name == month and ''.join(get_item_group(ad.item_code)) == sd.item_group \ + and ad.sales_person == sd.name: + tav_dict.achieved += ad.qty + + if (filters["target_on"] == "Amount"): + tav_dict.target = sd.target_amount*(tdd[month]["percentage_allocation"]/100) + if ad.month_name == month and ''.join(get_item_group(ad.item_code)) == sd.item_group \ + and ad.sales_person == sd.name: + tav_dict.achieved += ad.amount + + return sim_map + +def get_year_start_end_date(filters): + return webnotes.conn.sql("""select year_start_date, + subdate(adddate(year_start_date, interval 1 year), interval 1 day) + as year_end_date + from `tabFiscal Year` + where name=%s""", filters["fiscal_year"])[0] + +def get_item_group(item_name): + """Get Item Group of an item""" + + return webnotes.conn.sql_list("select item_group from `tabItem` where name=%s""" % + ('%s'), (item_name)) \ No newline at end of file diff --git a/selling/report/sales_person_target_variance_(item_group_wise)/sales_person_target_variance_(item_group_wise).txt b/selling/report/sales_person_target_variance_(item_group_wise)/sales_person_target_variance_(item_group_wise).txt new file mode 100644 index 00000000000..955cdec4775 --- /dev/null +++ b/selling/report/sales_person_target_variance_(item_group_wise)/sales_person_target_variance_(item_group_wise).txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-18 12:09:40", + "docstatus": 0, + "modified": "2013-06-18 12:09:40", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Sales Order", + "report_name": "Sales Person Target Variance (Item Group-Wise)", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Sales Person Target Variance (Item Group-Wise)" + } +] \ No newline at end of file diff --git a/selling/report/territory_target_variance_(item_group_wise)/__init__.py b/selling/report/territory_target_variance_(item_group_wise)/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/selling/report/territory_target_variance_(item_group_wise)/territory_target_variance_(item_group_wise).js b/selling/report/territory_target_variance_(item_group_wise)/territory_target_variance_(item_group_wise).js new file mode 100644 index 00000000000..58718a4e0b2 --- /dev/null +++ b/selling/report/territory_target_variance_(item_group_wise)/territory_target_variance_(item_group_wise).js @@ -0,0 +1,25 @@ +wn.query_reports["Territory Target Variance (Item Group-Wise)"] = { + "filters": [ + { + fieldname: "fiscal_year", + label: "Fiscal Year", + fieldtype: "Link", + options: "Fiscal Year", + default: sys_defaults.fiscal_year + }, + { + fieldname: "period", + label: "Period", + fieldtype: "Select", + options: "Monthly\nQuarterly\nHalf-Yearly\nYearly", + default: "Monthly" + }, + { + fieldname: "target_on", + label: "Target On", + fieldtype: "Select", + options: "Quantity\nAmount", + default: "Quantity" + }, + ] +} \ No newline at end of file diff --git a/selling/report/territory_target_variance_(item_group_wise)/territory_target_variance_(item_group_wise).py b/selling/report/territory_target_variance_(item_group_wise)/territory_target_variance_(item_group_wise).py new file mode 100644 index 00000000000..022d19ecf64 --- /dev/null +++ b/selling/report/territory_target_variance_(item_group_wise)/territory_target_variance_(item_group_wise).py @@ -0,0 +1,173 @@ +# 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 +import calendar +from webnotes import _, msgprint +from webnotes.utils import flt +import time +from accounts.utils import get_fiscal_year + +def execute(filters=None): + if not filters: filters = {} + + columns = get_columns(filters) + period_month_ranges = get_period_month_ranges(filters) + tim_map = get_territory_item_month_map(filters) + + data = [] + + for territory, territory_items in tim_map.items(): + for item_group, monthwise_data in territory_items.items(): + row = [territory, item_group] + totals = [0, 0, 0] + for relevant_months in period_month_ranges: + period_data = [0, 0, 0] + for month in relevant_months: + month_data = monthwise_data.get(month, {}) + for i, fieldname in enumerate(["target", "achieved", "variance"]): + value = flt(month_data.get(fieldname)) + period_data[i] += value + totals[i] += value + period_data[2] = period_data[0] - period_data[1] + row += period_data + totals[2] = totals[0] - totals[1] + row += totals + data.append(row) + + return columns, sorted(data, key=lambda x: (x[0], x[1])) + +def get_columns(filters): + for fieldname in ["fiscal_year", "period", "target_on"]: + if not filters.get(fieldname): + label = (" ".join(fieldname.split("_"))).title() + msgprint(_("Please specify") + ": " + label, raise_exception=True) + + columns = ["Territory:Link/Territory:80", "Item Group:Link/Item Group:80"] + + group_months = False if filters["period"] == "Monthly" else True + + for from_date, to_date in get_period_date_ranges(filters): + for label in ["Target (%s)", "Achieved (%s)", "Variance (%s)"]: + if group_months: + columns.append(label % (from_date.strftime("%b") + " - " + to_date.strftime("%b"))) + else: + columns.append(label % from_date.strftime("%b")) + + return columns + ["Total Target::80", "Total Achieved::80", "Total Variance::80"] + +def get_period_date_ranges(filters): + from dateutil.relativedelta import relativedelta + year_start_date, year_end_date = get_fiscal_year(fiscal_year = filters["fiscal_year"])[1:] + + + increment = { + "Monthly": 1, + "Quarterly": 3, + "Half-Yearly": 6, + "Yearly": 12 + }.get(filters["period"]) + + period_date_ranges = [] + for i in xrange(1, 13, increment): + period_end_date = year_start_date + relativedelta(months=increment, + days=-1) + period_date_ranges.append([year_start_date, period_end_date]) + year_start_date = period_end_date + relativedelta(days=1) + + return period_date_ranges + +def get_period_month_ranges(filters): + from dateutil.relativedelta import relativedelta + period_month_ranges = [] + + for start_date, end_date in get_period_date_ranges(filters): + months_in_this_period = [] + while start_date <= end_date: + months_in_this_period.append(start_date.strftime("%B")) + start_date += relativedelta(months=1) + period_month_ranges.append(months_in_this_period) + + return period_month_ranges + + +#Get territory & item group details +def get_territory_details(filters): + return webnotes.conn.sql("""select t.name, td.item_group, td.target_qty, + td.target_amount, t.distribution_id + from `tabTerritory` t, `tabTarget Detail` td + where td.parent=t.name and td.fiscal_year=%s and + ifnull(t.distribution_id, '')!='' order by t.name""", + filters.get("fiscal_year"), as_dict=1) + +#Get target distribution details of item group +def get_target_distribution_details(filters): + target_details = {} + + for d in webnotes.conn.sql("""select bdd.month, bdd.percentage_allocation \ + from `tabBudget Distribution Detail` bdd, `tabBudget Distribution` bd, \ + `tabTerritory` t where bdd.parent=bd.name and t.distribution_id=bd.name and \ + bd.fiscal_year=%s""" % ('%s'), (filters.get("fiscal_year")), as_dict=1): + target_details.setdefault(d.month, d) + + return target_details + +#Get achieved details from sales order +def get_achieved_details(filters): + start_date, end_date = get_fiscal_year(fiscal_year = filters["fiscal_year"])[1:] + + return webnotes.conn.sql("""select soi.item_code, soi.qty, soi.amount, so.transaction_date, + so.territory, MONTHNAME(so.transaction_date) as month_name + from `tabSales Order Item` soi, `tabSales Order` so + where soi.parent=so.name and so.docstatus=1 and so.transaction_date>=%s and + so.transaction_date<=%s""" % ('%s', '%s'), + (start_date, end_date), as_dict=1) + +def get_territory_item_month_map(filters): + territory_details = get_territory_details(filters) + tdd = get_target_distribution_details(filters) + achieved_details = get_achieved_details(filters) + + tim_map = {} + + for td in territory_details: + for month in tdd: + tim_map.setdefault(td.name, {}).setdefault(td.item_group, {})\ + .setdefault(month, webnotes._dict({ + "target": 0.0, "achieved": 0.0 + })) + + tav_dict = tim_map[td.name][td.item_group][month] + + for ad in achieved_details: + if (filters["target_on"] == "Quantity"): + tav_dict.target = flt(td.target_qty) * (tdd[month]["percentage_allocation"]/100) + if ad.month_name == month and get_item_group(ad.item_code) == td.item_group \ + and ad.territory == td.name: + tav_dict.achieved += ad.qty + + if (filters["target_on"] == "Amount"): + tav_dict.target = flt(td.target_amount) * \ + (tdd[month]["percentage_allocation"]/100) + if ad.month_name == month and get_item_group(ad.item_code) == td.item_group \ + and ad.territory == td.name: + tav_dict.achieved += ad.amount + + return tim_map + +def get_item_group(item_name): + return webnotes.conn.get_value("Item", item_name, "item_group") \ No newline at end of file diff --git a/selling/report/territory_target_variance_(item_group_wise)/territory_target_variance_(item_group_wise).txt b/selling/report/territory_target_variance_(item_group_wise)/territory_target_variance_(item_group_wise).txt new file mode 100644 index 00000000000..7fff64a861f --- /dev/null +++ b/selling/report/territory_target_variance_(item_group_wise)/territory_target_variance_(item_group_wise).txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-07 15:13:13", + "docstatus": 0, + "modified": "2013-06-07 15:13:13", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Sales Order", + "report_name": "Territory Target Variance (Item Group-Wise)", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Territory Target Variance (Item Group-Wise)" + } +] \ No newline at end of file diff --git a/stock/doctype/serial_no/serial_no.txt b/stock/doctype/serial_no/serial_no.txt index 8e891b81724..33160c785fe 100644 --- a/stock/doctype/serial_no/serial_no.txt +++ b/stock/doctype/serial_no/serial_no.txt @@ -1,14 +1,14 @@ [ { - "creation": "2013-01-29 19:25:41", + "creation": "2013-05-16 10:59:15", "docstatus": 0, - "modified": "2013-01-29 16:27:57", + "modified": "2013-06-20 11:23:01", "modified_by": "Administrator", "owner": "Administrator" }, { "allow_attach": 1, - "allow_rename": 1, + "allow_rename": 0, "autoname": "field:serial_no", "description": "Distinct unit of an Item", "doctype": "DocType", @@ -31,7 +31,9 @@ "parent": "Serial No", "parentfield": "permissions", "parenttype": "DocType", + "permlevel": 0, "read": 1, + "report": 1, "submit": 0 }, { @@ -43,12 +45,14 @@ "fieldname": "details", "fieldtype": "Section Break", "label": "Details", - "oldfieldtype": "Section Break" + "oldfieldtype": "Section Break", + "read_only": 0 }, { "doctype": "DocField", "fieldname": "column_break0", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "read_only": 0 }, { "default": "In Store", @@ -75,6 +79,7 @@ "no_copy": 1, "oldfieldname": "serial_no", "oldfieldtype": "Data", + "read_only": 0, "reqd": 1, "search_index": 1 }, @@ -88,13 +93,15 @@ "oldfieldname": "item_code", "oldfieldtype": "Link", "options": "Item", + "read_only": 0, "reqd": 1, "search_index": 0 }, { "doctype": "DocField", "fieldname": "column_break1", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "read_only": 0 }, { "doctype": "DocField", @@ -146,12 +153,14 @@ "doctype": "DocField", "fieldname": "purchase_details", "fieldtype": "Section Break", - "label": "Purchase Details" + "label": "Purchase Details", + "read_only": 0 }, { "doctype": "DocField", "fieldname": "column_break2", "fieldtype": "Column Break", + "read_only": 0, "width": "50%" }, { @@ -160,7 +169,8 @@ "fieldtype": "Select", "label": "Purchase Document Type", "no_copy": 1, - "options": "\nPurchase Receipt\nStock Entry" + "options": "\nPurchase Receipt\nStock Entry", + "read_only": 0 }, { "doctype": "DocField", @@ -168,7 +178,8 @@ "fieldtype": "Data", "hidden": 0, "label": "Purchase Document No", - "no_copy": 1 + "no_copy": 1, + "read_only": 0 }, { "doctype": "DocField", @@ -179,6 +190,7 @@ "no_copy": 1, "oldfieldname": "purchase_date", "oldfieldtype": "Date", + "read_only": 0, "reqd": 0, "search_index": 0 }, @@ -188,6 +200,7 @@ "fieldtype": "Time", "label": "Incoming Time", "no_copy": 1, + "read_only": 0, "reqd": 1 }, { @@ -200,6 +213,7 @@ "oldfieldname": "purchase_rate", "oldfieldtype": "Currency", "options": "Company:company:default_currency", + "read_only": 0, "reqd": 1, "search_index": 0 }, @@ -207,6 +221,7 @@ "doctype": "DocField", "fieldname": "column_break3", "fieldtype": "Column Break", + "read_only": 0, "width": "50%" }, { @@ -220,6 +235,7 @@ "oldfieldname": "warehouse", "oldfieldtype": "Link", "options": "Warehouse", + "read_only": 0, "reqd": 0, "search_index": 1 }, @@ -230,7 +246,8 @@ "in_filter": 1, "label": "Supplier", "no_copy": 1, - "options": "Supplier" + "options": "Supplier", + "read_only": 0 }, { "doctype": "DocField", @@ -254,12 +271,14 @@ "fieldname": "delivery_details", "fieldtype": "Section Break", "label": "Delivery Details", - "oldfieldtype": "Column Break" + "oldfieldtype": "Column Break", + "read_only": 0 }, { "doctype": "DocField", "fieldname": "column_break4", "fieldtype": "Column Break", + "read_only": 0, "width": "50%" }, { @@ -318,12 +337,14 @@ "oldfieldname": "is_cancelled", "oldfieldtype": "Select", "options": "\nYes\nNo", + "read_only": 0, "report_hide": 1 }, { "doctype": "DocField", "fieldname": "column_break5", "fieldtype": "Column Break", + "read_only": 0, "width": "50%" }, { @@ -378,12 +399,14 @@ "doctype": "DocField", "fieldname": "warranty_amc_details", "fieldtype": "Section Break", - "label": "Warranty / AMC Details" + "label": "Warranty / AMC Details", + "read_only": 0 }, { "doctype": "DocField", "fieldname": "column_break6", "fieldtype": "Column Break", + "read_only": 0, "width": "50%" }, { @@ -396,6 +419,7 @@ "oldfieldname": "maintenance_status", "oldfieldtype": "Select", "options": "\nUnder Warranty\nOut of Warranty\nUnder AMC\nOut of AMC", + "read_only": 0, "search_index": 1, "width": "150px" }, @@ -406,12 +430,14 @@ "label": "Warranty Period (Days)", "oldfieldname": "warranty_period", "oldfieldtype": "Int", + "read_only": 0, "width": "150px" }, { "doctype": "DocField", "fieldname": "column_break7", "fieldtype": "Column Break", + "read_only": 0, "width": "50%" }, { @@ -422,6 +448,7 @@ "label": "Warranty Expiry Date", "oldfieldname": "warranty_expiry_date", "oldfieldtype": "Date", + "read_only": 0, "width": "150px" }, { @@ -432,6 +459,7 @@ "label": "AMC Expiry Date", "oldfieldname": "amc_expiry_date", "oldfieldtype": "Date", + "read_only": 0, "search_index": 0, "width": "150px" }, @@ -439,13 +467,15 @@ "doctype": "DocField", "fieldname": "more_info", "fieldtype": "Section Break", - "label": "More Info" + "label": "More Info", + "read_only": 0 }, { "doctype": "DocField", "fieldname": "serial_no_details", "fieldtype": "Text Editor", - "label": "Serial No Details" + "label": "Serial No Details", + "read_only": 0 }, { "doctype": "DocField", @@ -454,6 +484,7 @@ "in_filter": 1, "label": "Company", "options": "link:Company", + "read_only": 0, "reqd": 1, "search_index": 1 }, @@ -464,6 +495,7 @@ "in_filter": 1, "label": "Fiscal Year", "options": "link:Fiscal Year", + "read_only": 0, "reqd": 1, "search_index": 1 }, @@ -487,54 +519,10 @@ "read_only": 1, "report_hide": 1 }, - { - "amend": 0, - "cancel": 0, - "create": 0, - "doctype": "DocPerm", - "match": "", - "permlevel": 1, - "report": 0, - "role": "Material Manager", - "write": 0 - }, - { - "amend": 0, - "cancel": 0, - "create": 0, - "doctype": "DocPerm", - "permlevel": 0, - "report": 1, - "role": "Material Manager", - "write": 0 - }, - { - "amend": 0, - "cancel": 0, - "create": 0, - "doctype": "DocPerm", - "match": "", - "permlevel": 1, - "report": 0, - "role": "Material User", - "write": 0 - }, - { - "amend": 0, - "cancel": 0, - "create": 0, - "doctype": "DocPerm", - "permlevel": 0, - "report": 1, - "role": "Material User", - "write": 0 - }, { "cancel": 1, "create": 1, "doctype": "DocPerm", - "permlevel": 0, - "report": 1, "role": "System Manager", "write": 1 }, @@ -542,8 +530,6 @@ "cancel": 1, "create": 1, "doctype": "DocPerm", - "permlevel": 0, - "report": 1, "role": "Material Master Manager", "write": 1 }, @@ -552,17 +538,15 @@ "cancel": 0, "create": 0, "doctype": "DocPerm", - "match": "", - "permlevel": 1, - "role": "System Manager" + "role": "Material Manager", + "write": 0 }, { "amend": 0, "cancel": 0, "create": 0, "doctype": "DocPerm", - "match": "", - "permlevel": 1, - "role": "Sales Master Manager" + "role": "Material User", + "write": 0 } ] \ 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 511ddd7667e..1c0acd42b5f 100644 --- a/stock/page/stock_home/stock_home.js +++ b/stock/page/stock_home/stock_home.js @@ -223,6 +223,16 @@ wn.module_page["Stock"] = [ route: "query-report/Itemwise Recommended Reorder Level", doctype: "Item" }, + { + "label":wn._("Delivery Note Trends"), + route: "query-report/Delivery Note Trends", + doctype: "Delivery Note" + }, + { + "label":wn._("Purchase Receipt Trends"), + route: "query-report/Purchase Receipt Trends", + doctype: "Purchase Receipt" + }, ] } ] diff --git a/stock/report/delivery_note_trends/__init__.py b/stock/report/delivery_note_trends/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/stock/report/delivery_note_trends/delivery_note_trends.js b/stock/report/delivery_note_trends/delivery_note_trends.js new file mode 100644 index 00000000000..3ec5e594d7b --- /dev/null +++ b/stock/report/delivery_note_trends/delivery_note_trends.js @@ -0,0 +1,5 @@ +wn.require("app/js/sales_trends_filters.js"); + +wn.query_reports["Delivery Note Trends"] = { + filters: get_filters() + } \ No newline at end of file diff --git a/stock/report/delivery_note_trends/delivery_note_trends.py b/stock/report/delivery_note_trends/delivery_note_trends.py new file mode 100644 index 00000000000..369b6a36b1d --- /dev/null +++ b/stock/report/delivery_note_trends/delivery_note_trends.py @@ -0,0 +1,34 @@ +# 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 controllers.trends import get_columns,get_data + +def execute(filters=None): + if not filters: filters ={} + data = [] + + trans = "Delivery Note" + tab = ["tabDelivery Note","tabDelivery Note Item"] + + details = get_columns(filters, trans) + data = get_data(filters, tab, details) + + if not data : + webnotes.msgprint("Data not found for selected criterias") + + return details["columns"], data \ No newline at end of file diff --git a/stock/report/delivery_note_trends/delivery_note_trends.txt b/stock/report/delivery_note_trends/delivery_note_trends.txt new file mode 100644 index 00000000000..bb8720074a6 --- /dev/null +++ b/stock/report/delivery_note_trends/delivery_note_trends.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-13 18:42:11", + "docstatus": 0, + "modified": "2013-06-13 18:42:11", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Delivery Note", + "report_name": "Delivery Note Trends", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Delivery Note Trends" + } +] \ No newline at end of file diff --git a/stock/report/item_prices/item_prices.py b/stock/report/item_prices/item_prices.py index ea0be477df3..3bdb7465105 100644 --- a/stock/report/item_prices/item_prices.py +++ b/stock/report/item_prices/item_prices.py @@ -69,10 +69,11 @@ def get_price_list(): 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) + if j.price: + 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 = {} @@ -99,8 +100,9 @@ def get_valuation_rate(): 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): + for d in webnotes.conn.sql("""select item_code, + sum(actual_qty*valuation_rate)/sum(actual_qty) as val_rate + from tabBin where actual_qty > 0 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/purchase_receipt_trends/__init__.py b/stock/report/purchase_receipt_trends/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/stock/report/purchase_receipt_trends/purchase_receipt_trends.js b/stock/report/purchase_receipt_trends/purchase_receipt_trends.js new file mode 100644 index 00000000000..ecfa5a473e7 --- /dev/null +++ b/stock/report/purchase_receipt_trends/purchase_receipt_trends.js @@ -0,0 +1,5 @@ +wn.require("app/js/purchase_trends_filters.js"); + +wn.query_reports["Purchase Receipt Trends"] = { + filters: get_filters() + } \ No newline at end of file diff --git a/stock/report/purchase_receipt_trends/purchase_receipt_trends.py b/stock/report/purchase_receipt_trends/purchase_receipt_trends.py new file mode 100644 index 00000000000..bd089fafa21 --- /dev/null +++ b/stock/report/purchase_receipt_trends/purchase_receipt_trends.py @@ -0,0 +1,34 @@ +# 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 controllers.trends import get_columns,get_data + +def execute(filters=None): + if not filters: filters ={} + data = [] + + trans = "Purchase Receipt" + tab = ["tabPurchase Receipt","tabPurchase Receipt Item"] + + details = get_columns(filters, trans) + data = get_data(filters, tab, details) + + if not data : + webnotes.msgprint("Data not found for selected criterias") + + return details["columns"], data \ No newline at end of file diff --git a/stock/report/purchase_receipt_trends/purchase_receipt_trends.txt b/stock/report/purchase_receipt_trends/purchase_receipt_trends.txt new file mode 100644 index 00000000000..179c524f96f --- /dev/null +++ b/stock/report/purchase_receipt_trends/purchase_receipt_trends.txt @@ -0,0 +1,21 @@ +[ + { + "creation": "2013-06-13 18:45:44", + "docstatus": 0, + "modified": "2013-06-13 18:45:44", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "ref_doctype": "Purchase Receipt", + "report_name": "Purchase Receipt Trends", + "report_type": "Script Report" + }, + { + "doctype": "Report", + "name": "Purchase Receipt Trends" + } +] \ No newline at end of file