diff --git a/erpnext/accounts/doctype/c_form/c_form.py b/erpnext/accounts/doctype/c_form/c_form.py index 11d05470aa..e0f008f8ad 100644 --- a/erpnext/accounts/doctype/c_form/c_form.py +++ b/erpnext/accounts/doctype/c_form/c_form.py @@ -64,13 +64,3 @@ class CForm(Document): 'net_total' : inv.net_total, 'grand_total' : inv.grand_total } - -def get_invoice_nos(doctype, txt, searchfield, start, page_len, filters): - from erpnext.utilities import build_filter_conditions - conditions, filter_values = build_filter_conditions(filters) - - return frappe.db.sql("""select name from `tabSales Invoice` where docstatus = 1 - and c_form_applicable = 'Yes' and ifnull(c_form_no, '') = '' %s - and %s like %s order by name limit %s, %s""" % - (conditions, searchfield, "%s", "%s", "%s"), - tuple(filter_values + ["%%%s%%" % txt, start, page_len])) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.js b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js new file mode 100644 index 0000000000..356cc0de9c --- /dev/null +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js @@ -0,0 +1,64 @@ +// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +// License: GNU General Public License v3. See license.txt + +frappe.ui.form.on("Pricing Rule", "refresh", function(frm) { + var help_content = ['', + '', + '', + '
', + '

', + __('Notes'), + ':

', + '
    ', + '
  • ', + __("Pricing Rule is made to overwrite Price List / define discount percentage, based on some criteria."), + '
  • ', + '
  • ', + __("If selected Pricing Rule is made for 'Price', it will overwrite Price List. Pricing Rule price is the final price, so no further discount should be applied. Hence, in transactions like Sales Order, Purchase Order etc, it will be fetched in 'Rate' field, rather than 'Price List Rate' field."), + '
  • ', + '
  • ', + __('Discount Percentage can be applied either against a Price List or for all Price List.'), + '
  • ', + '
  • ', + __('To not apply Pricing Rule in a particular transaction, all applicable Pricing Rules should be disabled.'), + '
  • ', + '
', + '
', + '

', + __('How Pricing Rule is applied?'), + '

', + '
    ', + '
  1. ', + __("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand."), + '
  2. ', + '
  3. ', + __("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc."), + '
  4. ', + '
  5. ', + __('Pricing Rules are further filtered based on quantity.'), + '
  6. ', + '
  7. ', + __('If two or more Pricing Rules are found based on the above conditions, Priority is applied. Priority is a number between 0 to 20 while default value is zero (blank). Higher number means it will take precedence if there are multiple Pricing Rules with same conditions.'), + '
  8. ', + '
  9. ', + __('Even if there are multiple Pricing Rules with highest priority, then following internal priorities are applied:'), + '
      ', + '
    • ', + __('Item Code > Item Group > Brand'), + '
    • ', + '
    • ', + __('Customer > Customer Group > Territory'), + '
    • ', + '
    • ', + __('Supplier > Supplier Type'), + '
    • ', + '
    ', + '
  10. ', + '
  11. ', + __('If multiple Pricing Rules continue to prevail, users are asked to set Priority manually to resolve conflict.'), + '
  12. ', + '
', + '
'].join("\n"); + + set_field_options("pricing_rule_help", help_content); +}); diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index baefde26ef..e023dd08c3 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -131,6 +131,13 @@ "fieldtype": "Column Break", "permlevel": 0 }, + { + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company", + "permlevel": 0 + }, { "default": "Today", "fieldname": "valid_from", @@ -198,12 +205,25 @@ "label": "For Price List", "options": "Price List", "permlevel": 0 + }, + { + "fieldname": "help_section", + "fieldtype": "Section Break", + "label": "", + "options": "Simple", + "permlevel": 0 + }, + { + "fieldname": "pricing_rule_help", + "fieldtype": "HTML", + "label": "Pricing Rule Help", + "permlevel": 0 } ], "icon": "icon-gift", "idx": 1, "istable": 0, - "modified": "2014-05-12 16:24:52.005162", + "modified": "2014-05-28 15:36:29.403659", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index 39260a2e9e..61e7ade441 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -15,7 +15,6 @@ class PricingRule(Document): self.validate_min_max_qty() self.cleanup_fields_value() - def validate_mandatory(self): for field in ["apply_on", "applicable_for", "price_or_discount"]: tocheck = frappe.scrub(self.get(field) or "") @@ -26,7 +25,6 @@ class PricingRule(Document): if self.min_qty and self.max_qty and flt(self.min_qty) > flt(self.max_qty): throw(_("Min Qty can not be greater than Max Qty")) - def cleanup_fields_value(self): for logic_field in ["apply_on", "applicable_for", "price_or_discount"]: fieldname = frappe.scrub(self.get(logic_field) or "") diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 003c6e66b4..b17c995298 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -20,6 +20,7 @@ class TestPricingRule(unittest.TestCase): "price_or_discount": "Discount Percentage", "price": 0, "discount_percentage": 10, + "company": "_Test Company" } frappe.get_doc(test_record.copy()).insert() @@ -36,7 +37,6 @@ class TestPricingRule(unittest.TestCase): "transaction_type": "selling", "customer": "_Test Customer", }) - details = get_item_details(args) self.assertEquals(details.get("discount_percentage"), 10) @@ -72,7 +72,7 @@ class TestPricingRule(unittest.TestCase): frappe.db.sql("update `tabPricing Rule` set priority=NULL where campaign='_Test Campaign'") from erpnext.stock.get_item_details import MultiplePricingRuleConflict - self.assertRaises (MultiplePricingRuleConflict, get_item_details, args) + self.assertRaises(MultiplePricingRuleConflict, get_item_details, args) args.item_code = "_Test Item 2" details = get_item_details(args) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index 158dec2046..d87456d260 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -77,16 +77,19 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({ }, supplier: function() { + var me = this; if(this.frm.updating_party_details) return; - erpnext.utils.get_party_details(this.frm, - "erpnext.accounts.party.get_party_details", { + erpnext.utils.get_party_details(this.frm, "erpnext.accounts.party.get_party_details", + { posting_date: this.frm.doc.posting_date, party: this.frm.doc.supplier, party_type: "Supplier", account: this.frm.doc.debit_to, price_list: this.frm.doc.buying_price_list, - }) + }, function() { + me.apply_pricing_rule(); + }) }, credit_to: function() { diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index 26f3be7889..d3b4606034 100755 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -1,6 +1,6 @@ { "autoname": "EVD.######", - "creation": "2013-05-22 12:43:10.000000", + "creation": "2013-05-22 12:43:10", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -193,17 +193,9 @@ "reqd": 1 }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -429,9 +421,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:27:53.000000", + "modified": "2014-05-28 12:43:40.647183", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index a5707bb222..21b42a5f3f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -155,8 +155,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }, customer: function() { - if(this.frm.updating_party_details) - return; + var me = this; + if(this.frm.updating_party_details) return; + erpnext.utils.get_party_details(this.frm, "erpnext.accounts.party.get_party_details", { posting_date: this.frm.doc.posting_date, @@ -164,7 +165,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte party_type: "Customer", account: this.frm.doc.debit_to, price_list: this.frm.doc.selling_price_list, - }) + }, function() { + me.apply_pricing_rule(); + }) }, debit_to: function() { diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 527213be01..5b3bd9d888 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -1,6 +1,6 @@ { "autoname": "INVD.######", - "creation": "2013-06-04 11:02:19.000000", + "creation": "2013-06-04 11:02:19", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -201,17 +201,9 @@ "reqd": 1 }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -456,9 +448,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:04:19.000000", + "modified": "2014-05-28 12:42:28.209942", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js index 09fbd3ef28..300c2285e7 100644 --- a/erpnext/accounts/report/accounts_payable/accounts_payable.js +++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js @@ -18,7 +18,7 @@ frappe.query_reports["Accounts Payable"] = { "get_query": function() { var company = frappe.query_report.filters_by_name.company.get_value(); return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": { "report_type": "Balance Sheet", "company": company, diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js index 1cf0941e0f..304c21bebb 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js @@ -18,7 +18,7 @@ frappe.query_reports["Accounts Receivable"] = { "get_query": function() { var company = frappe.query_report.filters_by_name.company.get_value(); return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": { "report_type": "Balance Sheet", "company": company, diff --git a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js index abeaba85e5..c28ba70a25 100644 --- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js +++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js @@ -23,7 +23,7 @@ frappe.query_reports["Bank Clearance Summary"] = { "options": "Account", "get_query": function() { return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": [ ['Account', 'account_type', 'in', 'Bank, Cash'], ['Account', 'group_or_ledger', '=', 'Ledger'], diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js index 5316b587e1..adc9ca2500 100644 --- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js +++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js @@ -11,7 +11,7 @@ frappe.query_reports["Bank Reconciliation Statement"] = { "reqd": 1, "get_query": function() { return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": [ ['Account', 'account_type', 'in', 'Bank, Cash'], ['Account', 'group_or_ledger', '=', 'Ledger'], @@ -27,4 +27,4 @@ frappe.query_reports["Bank Reconciliation Statement"] = { "reqd": 1 }, ] -} \ No newline at end of file +} diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py index 2b1923b11f..c1072a30ff 100644 --- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py +++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py @@ -7,10 +7,13 @@ from frappe.utils import flt def execute(filters=None): if not filters: filters = {} - + columns = get_columns() + + if not filters.get("account"): return columns, [] + data = get_entries(filters) - + from erpnext.accounts.utils import get_balance_on balance_as_per_company = get_balance_on(filters["account"], filters["report_date"]) @@ -20,33 +23,33 @@ def execute(filters=None): total_credit += flt(d[5]) bank_bal = flt(balance_as_per_company) + flt(total_debit) - flt(total_credit) - + data += [ get_balance_row("Balance as per company books", balance_as_per_company), - ["", "", "", "Amounts not reflected in bank", total_debit, total_credit], + ["", "", "", "Amounts not reflected in bank", total_debit, total_credit], get_balance_row("Balance as per bank", bank_bal) ] - + return columns, data - + def get_columns(): - return ["Journal Voucher:Link/Journal Voucher:140", "Posting Date:Date:100", - "Clearance Date:Date:110", "Against Account:Link/Account:200", + return ["Journal Voucher:Link/Journal Voucher:140", "Posting Date:Date:100", + "Clearance Date:Date:110", "Against Account:Link/Account:200", "Debit:Currency:120", "Credit:Currency:120" ] - + def get_entries(filters): - entries = frappe.db.sql("""select + entries = frappe.db.sql("""select jv.name, jv.posting_date, jv.clearance_date, jvd.against_account, jvd.debit, jvd.credit - from - `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv - where jvd.parent = jv.name and jv.docstatus=1 - and jvd.account = %(account)s and jv.posting_date <= %(report_date)s + from + `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv + where jvd.parent = jv.name and jv.docstatus=1 + and jvd.account = %(account)s and jv.posting_date <= %(report_date)s and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s order by jv.name DESC""", filters, as_list=1) - + return entries - + def get_balance_row(label, amount): if amount > 0: return ["", "", "", label, amount, 0] diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.js b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.js index 402f894d3f..13c0edc0a7 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.js +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.js @@ -30,7 +30,7 @@ frappe.query_reports["Item-wise Purchase Register"] = { "get_query": function() { var company = frappe.query_report.filters_by_name.company.get_value(); return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": { "report_type": "Balance Sheet", "company": company, diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js index 3264da7155..79b1785dec 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js @@ -24,7 +24,7 @@ frappe.query_reports["Item-wise Sales Register"] = frappe.query_reports["Sales R "get_query": function() { var company = frappe.query_report.filters_by_name.company.get_value(); return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": { "report_type": "Balance Sheet", "company": company, diff --git a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js index b0833b54a7..bff3f70a34 100644 --- a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js +++ b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js @@ -29,7 +29,7 @@ frappe.query_reports["Payment Period Based On Invoice Date"] = { options: "Account", get_query: function() { return { - query: "erpnext.accounts.utils.get_account_list", + query: "erpnext.controllers.queries.get_account_list", filters: { "report_type": "Balance Sheet", company: frappe.query_report.filters_by_name.company.get_value() diff --git a/erpnext/accounts/report/purchase_register/purchase_register.js b/erpnext/accounts/report/purchase_register/purchase_register.js index 7e999dee70..a1a41a5ee0 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.js +++ b/erpnext/accounts/report/purchase_register/purchase_register.js @@ -24,7 +24,7 @@ frappe.query_reports["Purchase Register"] = { "get_query": function() { var company = frappe.query_report.filters_by_name.company.get_value(); return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": { "report_type": "Balance Sheet", "company": company, diff --git a/erpnext/accounts/report/sales_register/sales_register.js b/erpnext/accounts/report/sales_register/sales_register.js index 0cc48a6489..ac30562fd7 100644 --- a/erpnext/accounts/report/sales_register/sales_register.js +++ b/erpnext/accounts/report/sales_register/sales_register.js @@ -24,7 +24,7 @@ frappe.query_reports["Sales Register"] = { "get_query": function() { var company = frappe.query_report.filters_by_name.company.get_value(); return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": { "report_type": "Balance Sheet", "company": company, diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 1a09d38bf7..160514bfe5 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -7,8 +7,7 @@ import frappe from frappe.utils import nowdate, cstr, flt, now, getdate, add_months from frappe import throw, _ from frappe.utils import formatdate -from erpnext.utilities import build_filter_conditions - +import frappe.widgets.reportview class FiscalYearError(frappe.ValidationError): pass class BudgetError(frappe.ValidationError): pass @@ -196,28 +195,6 @@ def update_against_doc(d, jv_obj): jv_obj.ignore_validate_update_after_submit = True jv_obj.save() -def get_account_list(doctype, txt, searchfield, start, page_len, filters): - if not filters.get("group_or_ledger"): - filters["group_or_ledger"] = "Ledger" - - conditions, filter_values = build_filter_conditions(filters) - - return frappe.db.sql("""select name, parent_account from `tabAccount` - where docstatus < 2 %s and %s like %s order by name limit %s, %s""" % - (conditions, searchfield, "%s", "%s", "%s"), - tuple(filter_values + ["%%%s%%" % txt, start, page_len])) - -def get_cost_center_list(doctype, txt, searchfield, start, page_len, filters): - if not filters.get("group_or_ledger"): - filters["group_or_ledger"] = "Ledger" - - conditions, filter_values = build_filter_conditions(filters) - - return frappe.db.sql("""select name, parent_cost_center from `tabCost Center` - where docstatus < 2 %s and %s like %s order by name limit %s, %s""" % - (conditions, searchfield, "%s", "%s", "%s"), - tuple(filter_values + ["%%%s%%" % txt, start, page_len])) - def remove_against_link_from_jv(ref_type, ref_no, against_field): linked_jv = frappe.db.sql_list("""select parent from `tabJournal Voucher Detail` where `%s`=%s and docstatus < 2""" % (against_field, "%s"), (ref_no)) diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.js b/erpnext/buying/doctype/purchase_common/purchase_common.js index c50dc3b664..032448f79f 100644 --- a/erpnext/buying/doctype/purchase_common/purchase_common.js +++ b/erpnext/buying/doctype/purchase_common/purchase_common.js @@ -62,7 +62,8 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ }, supplier: function() { - erpnext.utils.get_party_details(this.frm); + var me = this; + erpnext.utils.get_party_details(this.frm, null, null, function(){me.apply_pricing_rule()}); }, supplier_address: function() { diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 23fb1c0e95..224f784c69 100755 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -1,6 +1,6 @@ { "autoname": "POD/.#####", - "creation": "2013-05-24 19:29:06.000000", + "creation": "2013-05-24 19:29:06", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -252,17 +252,9 @@ "reqd": 1 }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -474,9 +466,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:26:25.000000", + "modified": "2014-05-28 12:42:53.018610", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json index 11cb9d9627..65dfe97af8 100644 --- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json +++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json @@ -1,6 +1,6 @@ { "autoname": "SQI-.#####", - "creation": "2013-05-22 12:43:10.000000", + "creation": "2013-05-22 12:43:10", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -195,17 +195,9 @@ "reqd": 1 }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -354,9 +346,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:25:38.000000", + "modified": "2014-05-28 12:44:17.347236", "modified_by": "Administrator", "module": "Buying", "name": "Supplier Quotation Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/buying/page/purchase_analytics/purchase_analytics.js b/erpnext/buying/page/purchase_analytics/purchase_analytics.js index f695a4982f..2e29d01a0a 100644 --- a/erpnext/buying/page/purchase_analytics/purchase_analytics.js +++ b/erpnext/buying/page/purchase_analytics/purchase_analytics.js @@ -1,18 +1,18 @@ // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -frappe.pages['purchase-analytics'].onload = function(wrapper) { +frappe.pages['purchase-analytics'].onload = function(wrapper) { frappe.ui.make_app_page({ parent: wrapper, title: __('Purchase Analytics'), single_column: true - }); - + }); + new erpnext.PurchaseAnalytics(wrapper); - + wrapper.appframe.add_module_icon("Buying") - + } erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ @@ -22,19 +22,19 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ page: wrapper, parent: $(wrapper).find('.layout-main'), appframe: wrapper.appframe, - doctypes: ["Item", "Item Group", "Supplier", "Supplier Type", "Company", "Fiscal Year", - "Purchase Invoice", "Purchase Invoice Item", - "Purchase Order", "Purchase Order Item[Purchase Analytics]", + doctypes: ["Item", "Item Group", "Supplier", "Supplier Type", "Company", "Fiscal Year", + "Purchase Invoice", "Purchase Invoice Item", + "Purchase Order", "Purchase Order Item[Purchase Analytics]", "Purchase Receipt", "Purchase Receipt Item[Purchase Analytics]"], tree_grid: { show: true } }); - + this.tree_grids = { "Supplier Type": { label: __("Supplier Type / Supplier"), - show: true, + show: true, item_key: "supplier", - parent_field: "parent_supplier_type", + parent_field: "parent_supplier_type", formatter: function(item) { // return repl('%(value)s', { // value: item.name, @@ -45,29 +45,29 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ }, "Supplier": { label: __("Supplier"), - show: false, + show: false, item_key: "supplier", formatter: function(item) { return item.name; } - }, + }, "Item Group": { label: "Item", - show: true, - parent_field: "parent_item_group", + show: true, + parent_field: "parent_item_group", item_key: "item_code", formatter: function(item) { return item.name; } - }, + }, "Item": { label: "Item", - show: false, + show: false, item_key: "item_code", formatter: function(item) { return item.name; } - }, + }, } }, setup_columns: function() { @@ -82,24 +82,24 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ formatter: this.currency_formatter} ]; - this.make_date_range_columns(); + this.make_date_range_columns(); this.columns = std_columns.concat(this.columns); }, filters: [ - {fieldtype:"Select", label: __("Tree Type"), options:["Supplier Type", "Supplier", + {fieldtype:"Select", label: __("Tree Type"), options:["Supplier Type", "Supplier", "Item Group", "Item"], filter: function(val, item, opts, me) { return me.apply_zero_filter(val, item, opts, me); }}, - {fieldtype:"Select", label: __("Based On"), options:["Purchase Invoice", + {fieldtype:"Select", label: __("Based On"), options:["Purchase Invoice", "Purchase Order", "Purchase Receipt"]}, {fieldtype:"Select", label: __("Value or Qty"), options:["Value", "Quantity"]}, - {fieldtype:"Select", label: __("Company"), link:"Company", + {fieldtype:"Select", label: __("Company"), link:"Company", default_value: "Select Company..."}, {fieldtype:"Date", label: __("From Date")}, {fieldtype:"Label", label: __("To")}, {fieldtype:"Date", label: __("To Date")}, - {fieldtype:"Select", label: __("Range"), + {fieldtype:"Select", label: __("Range"), options:["Daily", "Weekly", "Monthly", "Quarterly", "Yearly"]}, {fieldtype:"Button", label: __("Refresh"), icon:"icon-refresh icon-white"}, {fieldtype:"Button", label: __("Reset Filters"), icon: "icon-filter"} @@ -107,10 +107,10 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ setup_filters: function() { var me = this; this._super(); - + this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on", "company"]); - this.show_zero_check() + this.show_zero_check() this.setup_plot_check(); }, init_filter_values: function() { @@ -124,34 +124,34 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ // Add 'All Supplier Types' Supplier Type // (Supplier / Item are not mandatory!!) // Set parent supplier type for tree view - + $.each(frappe.report_dump.data["Supplier Type"], function(i, v) { v['parent_supplier_type'] = "All Supplier Types" }) - + frappe.report_dump.data["Supplier Type"] = [{ - name: __("All Supplier Types"), + name: __("All Supplier Types"), id: "All Supplier Types", }].concat(frappe.report_dump.data["Supplier Type"]); - + frappe.report_dump.data["Supplier"].push({ - name: __("Not Set"), + name: __("Not Set"), parent_supplier_type: "All Supplier Types", id: "Not Set", }); frappe.report_dump.data["Item"].push({ - name: __("Not Set"), + name: __("Not Set"), parent_item_group: "All Item Groups", id: "Not Set", }); } - + if (!this.tl || !this.tl[this.based_on]) { this.make_transaction_list(this.based_on, this.based_on + " Item"); } - - + + if(!this.data || me.item_type != me.tree_type) { if(me.tree_type=='Supplier') { var items = frappe.report_dump.data["Supplier"]; @@ -177,20 +177,20 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ me.parent_map[d.name] = d[me.tree_grid.parent_field]; } me.reset_item_values(d); - }); - + }); + this.set_indent(); - + } else { // otherwise, only reset values $.each(this.data, function(i, d) { me.reset_item_values(d); }); } - + this.prepare_balances(); if(me.tree_grid.show) { - this.set_totals(false); + this.set_totals(false); this.update_groups(); } else { this.set_totals(true); @@ -201,14 +201,14 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ var from_date = dateutil.str_to_obj(this.from_date); var to_date = dateutil.str_to_obj(this.to_date); var is_val = this.value_or_qty == 'Value'; - + $.each(this.tl[this.based_on], function(i, tl) { - if (me.is_default('company') ? true : tl.company === me.company) { + if (me.is_default('company') ? true : tl.company === me.company) { var posting_date = dateutil.str_to_obj(tl.posting_date); if (posting_date >= from_date && posting_date <= to_date) { - var item = me.item_by_name[tl[me.tree_grid.item_key]] || + var item = me.item_by_name[tl[me.tree_grid.item_key]] || me.item_by_name['Not Set']; - item[me.column_map[tl.posting_date].field] += (is_val ? tl.amount : tl.qty); + item[me.column_map[tl.posting_date].field] += (is_val ? tl.base_amount : tl.qty); } } }); @@ -220,10 +220,10 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ var parent = me.parent_map[item.name]; while(parent) { parent_group = me.item_by_name[parent]; - + $.each(me.columns, function(c, col) { if (col.formatter == me.currency_formatter) { - parent_group[col.field] = + parent_group[col.field] = flt(parent_group[col.field]) + flt(item[col.field]); } @@ -235,10 +235,10 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ set_totals: function(sort) { var me = this; var checked = false; - $.each(this.data, function(i, d) { + $.each(this.data, function(i, d) { d.total = 0.0; $.each(me.columns, function(i, col) { - if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total") + if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total") d.total += d[col.field]; if(d.checked) checked = true; }) @@ -251,7 +251,7 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ } }, get_plot_points: function(item, col, idx) { - return [[dateutil.str_to_obj(col.id).getTime(), item[col.field]], + return [[dateutil.str_to_obj(col.id).getTime(), item[col.field]], [dateutil.user_to_obj(col.name).getTime(), item[col.field]]]; } -}); \ No newline at end of file +}); diff --git a/erpnext/config/selling.py b/erpnext/config/selling.py index 4d3e059188..bb70ac9607 100644 --- a/erpnext/config/selling.py +++ b/erpnext/config/selling.py @@ -156,6 +156,11 @@ def get_data(): "name": "Industry Type", "description": _("Track Leads by Industry Type.") }, + { + "type": "doctype", + "name": "SMS Settings", + "description": _("Setup SMS gateway settings") + }, ] }, { diff --git a/erpnext/config/setup.py b/erpnext/config/setup.py index e538de5ab3..66b44e28c5 100644 --- a/erpnext/config/setup.py +++ b/erpnext/config/setup.py @@ -83,6 +83,11 @@ def get_data(): "name": "Jobs Email Settings", "description": _("Setup incoming server for jobs email id. (e.g. jobs@example.com)") }, + { + "type": "doctype", + "name": "SMS Settings", + "description": _("Setup SMS gateway settings") + }, ] }, { diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 9033065bd9..4567dd7005 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -97,11 +97,17 @@ class AccountsController(TransactionBase): args = item.as_dict() args.update(parent_dict) ret = get_item_details(args) + for fieldname, value in ret.items(): if item.meta.get_field(fieldname) and \ item.get(fieldname) is None and value is not None: item.set(fieldname, value) + if ret.get("pricing_rule"): + for field in ["base_price_list_rate", "price_list_rate", + "discount_percentage", "base_rate", "rate"]: + item.set(field, ret.get(field)) + def set_taxes(self, tax_parentfield, tax_master_field): if not self.meta.get_field(tax_parentfield): return @@ -409,7 +415,7 @@ class AccountsController(TransactionBase): if total_billed_amt - max_allowed_amt > 0.01: reduce_by = total_billed_amt - max_allowed_amt - frappe.throw(_("Cannot overbill for Item {0} in row {0} more than {1}. To allow overbilling, please set in 'Setup' > 'Global Defaults'").format(item.item_code, item.row, max_allowed_amt)) + frappe.throw(_("Cannot overbill for Item {0} in row {0} more than {1}. To allow overbilling, please set in Stock Settings").format(item.item_code, item.idx, max_allowed_amt)) def get_company_default(self, fieldname): from erpnext.accounts.utils import get_company_default diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 5cc7f6448c..a30cde72a5 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -234,3 +234,15 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters): 'posting_date': filters['posting_date'], 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype),'start': start, 'page_len': page_len}) + +def get_account_list(doctype, txt, searchfield, start, page_len, filters): + if isinstance(filters, dict): + if not filters.get("group_or_ledger"): + filters["group_or_ledger"] = "Ledger" + elif isinstance(filters, list): + if "group_or_ledger" not in [d[0] for d in filters]: + filters.append(["Account", "group_or_ledger", "=", "Ledger"]) + + return frappe.widgets.reportview.execute("Account", filters = filters, + fields = ["name", "parent_account"], + limit_start=start, limit_page_length=page_len, as_list=True) diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 0e4ac31e60..9322ca6aa6 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -156,8 +156,8 @@ class StatusUpdater(Document): item['max_allowed'] = flt(item[args['target_ref_field']] * (100+tolerance)/100) item['reduce_by'] = item[args['target_field']] - item['max_allowed'] - msgprint(_("Allowance for over-delivery / over-billing crossed for Item {0}").format(item["item_code"])) - throw(_("{0} must be less than or equal to {1}").format(_(item["target_ref_field"]), item[args["max_allowed"]])) + msgprint(_("Allowance for over-delivery / over-billing crossed for Item {0}.").format(item["item_code"])) + throw(_("{0} must be less than or equal to {1}").format(item["target_ref_field"].title(), item["max_allowed"])) def update_qty(self, change_modified=True): """ diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index ac023f360d..1cee6b9103 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -4,11 +4,11 @@ // On REFRESH cur_frm.cscript.refresh = function(doc,dt,dn){ cur_frm.toggle_enable("item", doc.__islocal); - + if (!doc.__islocal && doc.docstatus<2) { cur_frm.add_custom_button(__("Update Cost"), cur_frm.cscript.update_cost); } - + cur_frm.cscript.with_operations(doc); set_operation_no(doc); } @@ -41,14 +41,14 @@ var set_operation_no = function(doc) { var op = op_table[i].operation_no; if (op && !inList(operations, op)) operations.push(op); } - - frappe.meta.get_docfield("BOM Item", "operation_no", + + frappe.meta.get_docfield("BOM Item", "operation_no", cur_frm.docname).options = operations.join("\n"); - + $.each(doc.bom_materials || [], function(i, v) { if(!inList(operations, cstr(v.operation_no))) v.operation_no = null; }); - + refresh_field("bom_materials"); } @@ -97,7 +97,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) { doc: cur_frm.doc, method: "get_bom_material_detail", args: { - 'item_code': d.item_code, + 'item_code': d.item_code, 'bom_no': d.bom_no != null ? d.bom_no: '', 'qty': d.qty }, @@ -131,7 +131,7 @@ cur_frm.cscript.rate = function(doc, cdt, cdn) { } } -var calculate_op_cost = function(doc) { +var calculate_op_cost = function(doc) { var op = doc.bom_operations || []; total_op_cost = 0; for(var i=0;i 0""", args['item_code'], as_dict=1): + total_qty += flt(d.actual_qty) + total_value += flt(d.stock_value) + + return total_value / total_qty if total_qty else 0.0 def manage_default_bom(self): """ Uncheck others if current one is selected as default, diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.json b/erpnext/manufacturing/doctype/bom_item/bom_item.json index fbf478c756..0231a703f1 100644 --- a/erpnext/manufacturing/doctype/bom_item/bom_item.json +++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json @@ -1,5 +1,5 @@ { - "creation": "2013-02-22 01:27:49.000000", + "creation": "2013-02-22 01:27:49", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -79,7 +79,8 @@ "fieldtype": "Float", "in_list_view": 1, "label": "Rate", - "permlevel": 0 + "permlevel": 0, + "reqd": 1 }, { "fieldname": "col_break2", @@ -133,9 +134,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-03 12:47:39.000000", + "modified": "2014-05-29 15:56:31.859868", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/public/js/transaction.js b/erpnext/public/js/transaction.js index e12a30e14e..6d30ef0999 100644 --- a/erpnext/public/js/transaction.js +++ b/erpnext/public/js/transaction.js @@ -194,6 +194,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ } this.frm.script_manager.trigger("currency"); + this.apply_pricing_rule() } }, @@ -225,7 +226,9 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ this.frm.doc.plc_conversion_rate !== this.frm.doc.conversion_rate) { this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate); } - if(flt(this.frm.doc.conversion_rate)>0.0) this.calculate_taxes_and_totals(); + if(flt(this.frm.doc.conversion_rate)>0.0) { + this.apply_pricing_rule(); + } }, get_price_list_currency: function(buying_or_selling) { @@ -278,12 +281,12 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ } if(this.frm.doc.price_list_currency === this.frm.doc.currency) { this.frm.set_value("conversion_rate", this.frm.doc.plc_conversion_rate); - this.calculate_taxes_and_totals(); + this.apply_pricing_rule(); } }, qty: function(doc, cdt, cdn) { - this.calculate_taxes_and_totals(); + this.apply_pricing_rule(frappe.get_doc(cdt, cdn)); }, // tax rate @@ -326,6 +329,53 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ this.calculate_taxes_and_totals(); }, + apply_pricing_rule: function(item) { + var me = this; + + var _apply_pricing_rule = function(item) { + return me.frm.call({ + method: "erpnext.stock.get_item_details.apply_pricing_rule", + child: item, + args: { + args: { + item_code: item.item_code, + item_group: item.item_group, + brand: item.brand, + qty: item.qty, + customer: me.frm.doc.customer, + customer_group: me.frm.doc.customer_group, + territory: me.frm.doc.territory, + supplier: me.frm.doc.supplier, + supplier_type: me.frm.doc.supplier_type, + currency: me.frm.doc.currency, + conversion_rate: me.frm.doc.conversion_rate, + price_list: me.frm.doc.selling_price_list || + me.frm.doc.buying_price_list, + plc_conversion_rate: me.frm.doc.plc_conversion_rate, + company: me.frm.doc.company, + transaction_date: me.frm.doc.transaction_date || me.frm.doc.posting_date, + campaign: me.frm.doc.campaign, + sales_partner: me.frm.doc.sales_partner + } + }, + callback: function(r) { + if(!r.exc) { + me.frm.script_manager.trigger("price_list_rate", item.doctype, item.name); + } + } + }); + } + + + if(item) { + _apply_pricing_rule(item); + } else { + $.each(this.get_item_doclist(), function(n, item) { + _apply_pricing_rule(item); + }); + } + }, + included_in_print_rate: function(doc, cdt, cdn) { var tax = frappe.get_doc(cdt, cdn); try { diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 31abbb304f..40db97feb8 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -2,7 +2,7 @@ // License: GNU General Public License v3. See license.txt frappe.provide("erpnext.utils"); -erpnext.utils.get_party_details = function(frm, method, args) { +erpnext.utils.get_party_details = function(frm, method, args, callback) { if(!method) { method = "erpnext.accounts.party.get_party_details"; } @@ -33,6 +33,7 @@ erpnext.utils.get_party_details = function(frm, method, args) { frm.updating_party_details = true; frm.set_value(r.message); frm.updating_party_details = false; + if(callback) callback(); } } }); diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json index 4e19ee7970..a1807dd9ad 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.json +++ b/erpnext/selling/doctype/quotation_item/quotation_item.json @@ -1,6 +1,6 @@ { "autoname": "QUOD/.#####", - "creation": "2013-03-07 11:42:57.000000", + "creation": "2013-03-07 11:42:57", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -231,17 +231,9 @@ "width": "100px" }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -353,9 +345,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:20:34.000000", + "modified": "2014-05-28 12:41:40.811916", "modified_by": "Administrator", "module": "Selling", "name": "Quotation Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 9d0ae0e031..13ee085eef 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -1,6 +1,6 @@ { "autoname": "SOD/.#####", - "creation": "2013-03-07 11:42:58.000000", + "creation": "2013-03-07 11:42:58", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -217,17 +217,9 @@ "width": "100px" }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -439,9 +431,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:20:05.000000", + "modified": "2014-05-27 14:41:14.996650", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/selling/page/sales_analytics/sales_analytics.js b/erpnext/selling/page/sales_analytics/sales_analytics.js index 25c8f80497..2117370285 100644 --- a/erpnext/selling/page/sales_analytics/sales_analytics.js +++ b/erpnext/selling/page/sales_analytics/sales_analytics.js @@ -1,17 +1,17 @@ // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -frappe.pages['sales-analytics'].onload = function(wrapper) { +frappe.pages['sales-analytics'].onload = function(wrapper) { frappe.ui.make_app_page({ parent: wrapper, title: __('Sales Analytics'), single_column: true }); new erpnext.SalesAnalytics(wrapper); - + wrapper.appframe.add_module_icon("Selling") - + } erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ @@ -21,55 +21,55 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ page: wrapper, parent: $(wrapper).find('.layout-main'), appframe: wrapper.appframe, - doctypes: ["Item", "Item Group", "Customer", "Customer Group", "Company", "Territory", - "Fiscal Year", "Sales Invoice", "Sales Invoice Item", - "Sales Order", "Sales Order Item[Sales Analytics]", + doctypes: ["Item", "Item Group", "Customer", "Customer Group", "Company", "Territory", + "Fiscal Year", "Sales Invoice", "Sales Invoice Item", + "Sales Order", "Sales Order Item[Sales Analytics]", "Delivery Note", "Delivery Note Item[Sales Analytics]"], tree_grid: { show: true } }); - + this.tree_grids = { "Customer Group": { label: __("Customer Group / Customer"), - show: true, + show: true, item_key: "customer", - parent_field: "parent_customer_group", + parent_field: "parent_customer_group", formatter: function(item) { return item.name; } }, "Customer": { label: __("Customer"), - show: false, + show: false, item_key: "customer", formatter: function(item) { return item.name; } - }, + }, "Item Group": { label: __("Item"), - show: true, - parent_field: "parent_item_group", + show: true, + parent_field: "parent_item_group", item_key: "item_code", formatter: function(item) { return item.name; } - }, + }, "Item": { label: __("Item"), - show: false, + show: false, item_key: "item_code", formatter: function(item) { return item.name; } - }, + }, "Territory": { label: __("Territory / Customer"), - show: true, + show: true, item_key: "customer", - parent_field: "parent_territory", + parent_field: "parent_territory", formatter: function(item) { return item.name; } - } + } } }, setup_columns: function() { @@ -84,24 +84,24 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ formatter: this.currency_formatter} ]; - this.make_date_range_columns(); + this.make_date_range_columns(); this.columns = std_columns.concat(this.columns); }, filters: [ - {fieldtype:"Select", fieldname: "tree_type", label: __("Tree Type"), options:["Customer Group", "Customer", + {fieldtype:"Select", fieldname: "tree_type", label: __("Tree Type"), options:["Customer Group", "Customer", "Item Group", "Item", "Territory"], filter: function(val, item, opts, me) { return me.apply_zero_filter(val, item, opts, me); }}, - {fieldtype:"Select", fieldname: "based_on", label: __("Based On"), options:["Sales Invoice", + {fieldtype:"Select", fieldname: "based_on", label: __("Based On"), options:["Sales Invoice", "Sales Order", "Delivery Note"]}, {fieldtype:"Select", fieldname: "value_or_qty", label: __("Value or Qty"), options:["Value", "Quantity"]}, - {fieldtype:"Select", fieldname: "company", label: __("Company"), link:"Company", + {fieldtype:"Select", fieldname: "company", label: __("Company"), link:"Company", default_value: "Select Company..."}, {fieldtype:"Date", fieldname: "from_date", label: __("From Date")}, {fieldtype:"Label", fieldname: "to", label: __("To")}, {fieldtype:"Date", fieldname: "to_date", label: __("To Date")}, - {fieldtype:"Select", fieldname: "range", label: __("Range"), + {fieldtype:"Select", fieldname: "range", label: __("Range"), options:["Daily", "Weekly", "Monthly", "Quarterly", "Yearly"]}, {fieldtype:"Button", fieldname: "refresh", label: __("Refresh"), icon:"icon-refresh"}, {fieldtype:"Button", fieldname: "reset_filters", label: __("Reset Filters"), icon:"icon-filter"} @@ -109,10 +109,10 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ setup_filters: function() { var me = this; this._super(); - + this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on", "company"]); - this.show_zero_check() + this.show_zero_check() this.setup_plot_check(); }, init_filter_values: function() { @@ -125,14 +125,14 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ // add 'Not Set' Customer & Item // (Customer / Item are not mandatory!!) frappe.report_dump.data["Customer"].push({ - name: "Not Set", + name: "Not Set", parent_customer_group: "All Customer Groups", parent_territory: "All Territories", id: "Not Set", }); frappe.report_dump.data["Item"].push({ - name: "Not Set", + name: "Not Set", parent_item_group: "All Item Groups", id: "Not Set", }); @@ -141,7 +141,7 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ if (!this.tl || !this.tl[this.based_on]) { this.make_transaction_list(this.based_on, this.based_on + " Item"); } - + if(!this.data || me.item_type != me.tree_type) { if(me.tree_type=='Customer') { var items = frappe.report_dump.data["Customer"]; @@ -159,7 +159,7 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ me.parent_map = {}; me.item_by_name = {}; me.data = []; - + $.each(items, function(i, v) { var d = copy_dict(v); @@ -169,20 +169,20 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ me.parent_map[d.name] = d[me.tree_grid.parent_field]; } me.reset_item_values(d); - }); - + }); + this.set_indent(); - + } else { // otherwise, only reset values $.each(this.data, function(i, d) { me.reset_item_values(d); }); } - + this.prepare_balances(); if(me.tree_grid.show) { - this.set_totals(false); + this.set_totals(false); this.update_groups(); } else { this.set_totals(true); @@ -194,14 +194,14 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ var from_date = dateutil.str_to_obj(this.from_date); var to_date = dateutil.str_to_obj(this.to_date); var is_val = this.value_or_qty == 'Value'; - + $.each(this.tl[this.based_on], function(i, tl) { - if (me.is_default('company') ? true : tl.company === me.company) { + if (me.is_default('company') ? true : tl.company === me.company) { var posting_date = dateutil.str_to_obj(tl.posting_date); if (posting_date >= from_date && posting_date <= to_date) { - var item = me.item_by_name[tl[me.tree_grid.item_key]] || + var item = me.item_by_name[tl[me.tree_grid.item_key]] || me.item_by_name['Not Set']; - item[me.column_map[tl.posting_date].field] += (is_val ? tl.amount : tl.qty); + item[me.column_map[tl.posting_date].field] += (is_val ? tl.base_amount : tl.qty); } } }); @@ -213,10 +213,10 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ var parent = me.parent_map[item.name]; while(parent) { parent_group = me.item_by_name[parent]; - + $.each(me.columns, function(c, col) { if (col.formatter == me.currency_formatter) { - parent_group[col.field] = + parent_group[col.field] = flt(parent_group[col.field]) + flt(item[col.field]); } @@ -228,10 +228,10 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ set_totals: function(sort) { var me = this; var checked = false; - $.each(this.data, function(i, d) { + $.each(this.data, function(i, d) { d.total = 0.0; $.each(me.columns, function(i, col) { - if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total") + if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total") d.total += d[col.field]; if(d.checked) checked = true; }) @@ -244,7 +244,7 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ } }, get_plot_points: function(item, col, idx) { - return [[dateutil.str_to_obj(col.id).getTime(), item[col.field]], + return [[dateutil.str_to_obj(col.id).getTime(), item[col.field]], [dateutil.user_to_obj(col.name).getTime(), item[col.field]]]; } }); diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index 1e9643aeb8..b4841006e2 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -104,7 +104,8 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ }, customer: function() { - erpnext.utils.get_party_details(this.frm); + var me = this; + erpnext.utils.get_party_details(this.frm, null, null, function(){me.apply_pricing_rule()}); }, customer_address: function() { @@ -119,6 +120,14 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ erpnext.utils.get_contact_details(this.frm); }, + sales_partner: function() { + this.apply_pricing_rule(); + }, + + campaign: function() { + this.apply_pricing_rule(); + }, + barcode: function(doc, cdt, cdn) { this.item_code(doc, cdt, cdn); }, diff --git a/erpnext/startup/report_data_map.py b/erpnext/startup/report_data_map.py index e614c71ae0..ce71310ad9 100644 --- a/erpnext/startup/report_data_map.py +++ b/erpnext/startup/report_data_map.py @@ -18,14 +18,14 @@ data_map = { # Accounts "Account": { - "columns": ["name", "parent_account", "lft", "rgt", "report_type", + "columns": ["name", "parent_account", "lft", "rgt", "report_type", "company", "group_or_ledger"], "conditions": ["docstatus < 2"], "order_by": "lft", "links": { "company": ["Company", "name"], } - + }, "Cost Center": { "columns": ["name", "lft", "rgt"], @@ -33,7 +33,7 @@ data_map = { "order_by": "lft" }, "GL Entry": { - "columns": ["name", "account", "posting_date", "cost_center", "debit", "credit", + "columns": ["name", "account", "posting_date", "cost_center", "debit", "credit", "is_opening", "company", "voucher_type", "voucher_no", "remarks"], "order_by": "posting_date, account", "links": { @@ -45,8 +45,8 @@ data_map = { # Stock "Item": { - "columns": ["name", "if(item_name=name, '', item_name) as item_name", "description", - "item_group as parent_item_group", "stock_uom", "brand", "valuation_method", + "columns": ["name", "if(item_name=name, '', item_name) as item_name", "description", + "item_group as parent_item_group", "stock_uom", "brand", "valuation_method", "re_order_level", "re_order_qty"], # "conditions": ["docstatus < 2"], "order_by": "name", @@ -76,7 +76,7 @@ data_map = { "order_by": "name" }, "Stock Ledger Entry": { - "columns": ["name", "posting_date", "posting_time", "item_code", "warehouse", + "columns": ["name", "posting_date", "posting_time", "item_code", "warehouse", "actual_qty as qty", "voucher_type", "voucher_no", "project", "ifnull(incoming_rate,0) as incoming_rate", "stock_uom", "serial_no"], "order_by": "posting_date, posting_time, name", @@ -98,8 +98,8 @@ data_map = { "order_by": "posting_date, posting_time, name", }, "Production Order": { - "columns": ["name", "production_item as item_code", - "(ifnull(qty, 0) - ifnull(produced_qty, 0)) as qty", + "columns": ["name", "production_item as item_code", + "(ifnull(qty, 0) - ifnull(produced_qty, 0)) as qty", "fg_warehouse as warehouse"], "conditions": ["docstatus=1", "status != 'Stopped'", "ifnull(fg_warehouse, '')!=''", "ifnull(qty, 0) > ifnull(produced_qty, 0)"], @@ -109,7 +109,7 @@ data_map = { }, }, "Material Request Item": { - "columns": ["item.name as name", "item_code", "warehouse", + "columns": ["item.name as name", "item_code", "warehouse", "(ifnull(qty, 0) - ifnull(ordered_qty, 0)) as qty"], "from": "`tabMaterial Request Item` item, `tabMaterial Request` main", "conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'", @@ -120,21 +120,21 @@ data_map = { }, }, "Purchase Order Item": { - "columns": ["item.name as name", "item_code", "warehouse", + "columns": ["item.name as name", "item_code", "warehouse", "(ifnull(qty, 0) - ifnull(received_qty, 0)) as qty"], "from": "`tabPurchase Order Item` item, `tabPurchase Order` main", - "conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'", + "conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'", "ifnull(warehouse, '')!=''", "ifnull(qty, 0) > ifnull(received_qty, 0)"], "links": { "item_code": ["Item", "name"], "warehouse": ["Warehouse", "name"] }, }, - + "Sales Order Item": { "columns": ["item.name as name", "item_code", "(ifnull(qty, 0) - ifnull(delivered_qty, 0)) as qty", "warehouse"], "from": "`tabSales Order Item` item, `tabSales Order` main", - "conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'", + "conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'", "ifnull(warehouse, '')!=''", "ifnull(qty, 0) > ifnull(delivered_qty, 0)"], "links": { "item_code": ["Item", "name"], @@ -144,7 +144,7 @@ data_map = { # Sales "Customer": { - "columns": ["name", "if(customer_name=name, '', customer_name) as customer_name", + "columns": ["name", "if(customer_name=name, '', customer_name) as customer_name", "customer_group as parent_customer_group", "territory as parent_territory"], "conditions": ["docstatus < 2"], "order_by": "name", @@ -218,7 +218,7 @@ data_map = { } }, "Supplier": { - "columns": ["name", "if(supplier_name=name, '', supplier_name) as supplier_name", + "columns": ["name", "if(supplier_name=name, '', supplier_name) as supplier_name", "supplier_type as parent_supplier_type"], "conditions": ["docstatus < 2"], "order_by": "name", @@ -291,5 +291,5 @@ data_map = { "conditions": ["docstatus < 2"], "order_by": "creation" } - + } diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index e093def886..13307ef64a 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -1,6 +1,6 @@ { "autoname": "DND/.#######", - "creation": "2013-04-22 13:15:44.000000", + "creation": "2013-04-22 13:15:44", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -225,17 +225,9 @@ "width": "100px" }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -437,9 +429,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:20:58.000000", + "modified": "2014-05-28 12:42:05.788579", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index 0e12cd2963..92c16f8b90 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -439,16 +439,6 @@ "permlevel": 0, "read_only": 1 }, - { - "depends_on": "eval:doc.is_purchase_item==\"Yes\"", - "fieldname": "standard_rate", - "fieldtype": "Float", - "label": "Standard Rate", - "oldfieldname": "standard_rate", - "oldfieldtype": "Currency", - "permlevel": 0, - "read_only": 0 - }, { "depends_on": "eval:doc.is_purchase_item==\"Yes\"", "fieldname": "column_break2", @@ -835,7 +825,7 @@ "icon": "icon-tag", "idx": 1, "max_attachments": 1, - "modified": "2014-05-21 15:37:30.124881", + "modified": "2014-05-29 16:05:53.126214", "modified_by": "Administrator", "module": "Stock", "name": "Item", diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 104f905383..6d6db94f30 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -137,7 +137,6 @@ class Item(WebsiteGenerator): bom = frappe.db.sql("""select name from `tabBOM` where item = %s and is_active = 1""", (self.name,)) if bom and bom[0][0]: - print self.name frappe.throw(_("""Allow Bill of Materials should be 'Yes'. Because one or many active BOMs present for this item""")) def fill_customer_code(self): diff --git a/erpnext/stock/doctype/packing_slip/packing_slip.py b/erpnext/stock/doctype/packing_slip/packing_slip.py index e3d01999f1..63657b75ab 100644 --- a/erpnext/stock/doctype/packing_slip/packing_slip.py +++ b/erpnext/stock/doctype/packing_slip/packing_slip.py @@ -141,7 +141,7 @@ class PackingSlip(Document): note """ recommended_case_no = frappe.db.sql("""SELECT MAX(to_case_no) FROM `tabPacking Slip` - WHERE delivery_note = %(delivery_note)s AND docstatus=1""", self.as_dict()) + WHERE delivery_note = %s AND docstatus=1""", self.delivery_note) return cint(recommended_case_no[0][0]) + 1 diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index 0c8100ce7d..548a7dacf1 100755 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -1,6 +1,6 @@ { "autoname": "GRND/.#######", - "creation": "2013-05-24 19:29:10.000000", + "creation": "2013-05-24 19:29:10", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -256,17 +256,9 @@ "width": "100px" }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -553,9 +545,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:27:09.000000", + "modified": "2014-05-28 12:43:16.669040", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 900474be3b..cbe8c29749 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -41,6 +41,7 @@ class StockEntry(StockController): self.validate_return_reference_doc() self.validate_with_material_request() self.validate_fiscal_year() + self.validate_valuation_rate() self.set_total_amount() def on_submit(self): @@ -170,11 +171,26 @@ class StockEntry(StockController): frappe.throw(_("Stock Entries already created for Production Order ") + self.production_order + ":" + ", ".join(other_ste), DuplicateEntryForProductionOrderError) + def validate_valuation_rate(self): + if self.purpose == "Manufacture/Repack": + valuation_at_source, valuation_at_target = 0, 0 + for d in self.get("mtn_details"): + if d.s_warehouse and not d.t_warehouse: + valuation_at_source += flt(d.amount) + if d.t_warehouse and not d.s_warehouse: + valuation_at_target += flt(d.amount) + + if valuation_at_target < valuation_at_source: + frappe.throw(_("Total valuation for manufactured or repacked item(s) can not be less than total valuation of raw materials")) + def set_total_amount(self): self.total_amount = sum([flt(item.amount) for item in self.get("mtn_details")]) def get_stock_and_rate(self): """get stock and incoming rate on posting date""" + + raw_material_cost = 0.0 + for d in self.get('mtn_details'): args = frappe._dict({ "item_code": d.item_code, @@ -182,17 +198,28 @@ class StockEntry(StockController): "posting_date": self.posting_date, "posting_time": self.posting_time, "qty": d.s_warehouse and -1*d.transfer_qty or d.transfer_qty, - "serial_no": d.serial_no, - "bom_no": d.bom_no, + "serial_no": d.serial_no }) # get actual stock at source warehouse d.actual_qty = get_previous_sle(args).get("qty_after_transaction") or 0 # get incoming rate - if not flt(d.incoming_rate): - d.incoming_rate = self.get_incoming_rate(args) + if not d.bom_no: + if not flt(d.incoming_rate): + d.incoming_rate = self.get_incoming_rate(args) - d.amount = flt(d.transfer_qty) * flt(d.incoming_rate) + d.amount = flt(d.transfer_qty) * flt(d.incoming_rate) + raw_material_cost += flt(d.amount) + + # set incoming rate for fg item + if self.production_order and self.purpose == "Manufacture/Repack": + for d in self.get("mtn_details"): + if d.bom_no: + if not flt(d.incoming_rate): + bom = frappe.db.get_value("BOM", d.bom_no, ["operating_cost", "quantity"], as_dict=1) + operation_cost_per_unit = flt(bom.operating_cost) / flt(bom.quantity) + d.incoming_rate = operation_cost_per_unit + (raw_material_cost / flt(d.transfer_qty)) + d.amount = flt(d.transfer_qty) * flt(d.incoming_rate) def get_incoming_rate(self, args): incoming_rate = 0 @@ -365,17 +392,18 @@ class StockEntry(StockController): ret.update(stock_and_rate) return ret - def get_uom_details(self, arg = ''): - arg, ret = eval(arg), {} - uom = frappe.db.sql("""select conversion_factor from `tabUOM Conversion Detail` - where parent = %s and uom = %s""", (arg['item_code'], arg['uom']), as_dict = 1) - if not uom or not flt(uom[0].conversion_factor): - frappe.msgprint(_("UOM coversion factor required for UOM {0} in Item {1}").format(arg["uom"], arg["item_code"])) + def get_uom_details(self, args): + conversion_factor = frappe.db.get_value("UOM Conversion Detail", {"parent": args.get("item_code"), + "uom": args.get("uom")}, "conversion_factor") + + if not conversion_factor: + frappe.msgprint(_("UOM coversion factor required for UOM: {0} in Item: {1}") + .format(args.get("uom"), args.get("item_code"))) ret = {'uom' : ''} else: ret = { - 'conversion_factor' : flt(uom[0]['conversion_factor']), - 'transfer_qty' : flt(arg['qty']) * flt(uom[0]['conversion_factor']), + 'conversion_factor' : flt(conversion_factor), + 'transfer_qty' : flt(args.get("qty")) * flt(conversion_factor) } return ret diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 35030a6a78..78cf194cc2 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -11,8 +11,11 @@ from erpnext.stock.stock_ledger import update_entries_after from erpnext.controllers.stock_controller import StockController class StockReconciliation(StockController): - def validate(self): + def __init__(self, arg1, arg2=None): + super(StockReconciliation, self).__init__(arg1, arg2) self.head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"] + + def validate(self): self.entries = [] self.validate_data() @@ -300,4 +303,5 @@ class StockReconciliation(StockController): @frappe.whitelist() def upload(): from frappe.utils.datautils import read_csv_content_from_uploaded_file - return read_csv_content_from_uploaded_file() + csv_content = read_csv_content_from_uploaded_file() + return filter(lambda x: x and any(x), csv_content) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index f9c7526a96..4a295d8242 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -68,7 +68,12 @@ def get_item_details(args): if args.transaction_type == "selling" and cint(args.is_pos): out.update(get_pos_settings_item_details(args.company, args)) - apply_pricing_rule(out, args) + # update args with out, if key or value not exists + for key, value in out.iteritems(): + if args.get(key) is None: + args[key] = value + + out.update(apply_pricing_rule(args)) if args.get("doctype") in ("Sales Invoice", "Delivery Note"): if item_doc.has_serial_no == "Yes" and not args.serial_no: @@ -243,36 +248,51 @@ def get_pos_settings(company): return pos_settings and pos_settings[0] or None -def apply_pricing_rule(out, args): - args_dict = frappe._dict().update(args) - args_dict.update(out) - all_pricing_rules = get_pricing_rules(args_dict) +@frappe.whitelist() +def apply_pricing_rule(args): + if isinstance(args, basestring): + args = json.loads(args) - rule_for_price = False - for rule_for in ["price", "discount_percentage"]: - pricing_rules = filter(lambda x: x[rule_for] > 0.0, all_pricing_rules) - if rule_for_price: - pricing_rules = filter(lambda x: not x["for_price_list"], pricing_rules) + args = frappe._dict(args) + out = frappe._dict() - pricing_rule = filter_pricing_rules(args_dict, pricing_rules) + if not args.get("item_group") or not args.get("brand"): + args.item_group, args.brand = frappe.db.get_value("Item", + args.item_code, ["item_group", "brand"]) - if pricing_rule: - if rule_for == "discount_percentage": - out["discount_percentage"] = pricing_rule["discount_percentage"] - out["pricing_rule_for_discount"] = pricing_rule["name"] - else: - out["base_price_list_rate"] = pricing_rule["price"] - out["price_list_rate"] = pricing_rule["price"] * \ - flt(args_dict.plc_conversion_rate) / flt(args_dict.conversion_rate) - out["pricing_rule_for_price"] = pricing_rule["name"] - rule_for_price = True + if args.get("customer") and (not args.get("customer_group") or not args.get("territory")): + args.customer_group, args.territory = frappe.db.get_value("Customer", + args.customer, ["customer_group", "territory"]) -def get_pricing_rules(args_dict): + if args.get("supplier") and not args.get("supplier_type"): + args.supplier_type = frappe.db.get_value("Supplier", args.supplier, "supplier_type") + + pricing_rules = get_pricing_rules(args) + + pricing_rule = filter_pricing_rules(args, pricing_rules) + + if pricing_rule: + out.pricing_rule = pricing_rule.name + if pricing_rule.price_or_discount == "Price": + out.base_price_list_rate = pricing_rule.price + out.price_list_rate = pricing_rule.price*flt(args.plc_conversion_rate)/flt(args.conversion_rate) + out.base_rate = out.base_price_list_rate + out.rate = out.price_list_rate + out.discount_percentage = 0.0 + else: + out.discount_percentage = pricing_rule.discount_percentage + else: + out.pricing_rule = None + + return out + + +def get_pricing_rules(args): def _get_tree_conditions(doctype, allow_blank=True): field = frappe.scrub(doctype) condition = "" - if args_dict.get(field): - lft, rgt = frappe.db.get_value(doctype, args_dict[field], ["lft", "rgt"]) + if args.get(field): + lft, rgt = frappe.db.get_value(doctype, args[field], ["lft", "rgt"]) parent_groups = frappe.db.sql_list("""select name from `tab%s` where lft<=%s and rgt>=%s""" % (doctype, '%s', '%s'), (lft, rgt)) @@ -284,8 +304,8 @@ def get_pricing_rules(args_dict): conditions = "" - for field in ["customer", "supplier", "supplier_type", "campaign", "sales_partner"]: - if args_dict.get(field): + for field in ["company", "customer", "supplier", "supplier_type", "campaign", "sales_partner"]: + if args.get(field): conditions += " and ifnull("+field+", '') in (%("+field+")s, '')" else: conditions += " and ifnull("+field+", '') = ''" @@ -297,8 +317,7 @@ def get_pricing_rules(args_dict): conditions += " and ifnull(for_price_list, '') in (%(price_list)s, '')" - - if args_dict.get("transaction_date"): + if args.get("transaction_date"): conditions += """ and %(transaction_date)s between ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')""" @@ -307,13 +326,13 @@ def get_pricing_rules(args_dict): and docstatus < 2 and ifnull(disable, 0) = 0 {conditions} order by priority desc, name desc""".format( item_group_condition=_get_tree_conditions("Item Group", False), conditions=conditions), - args_dict, as_dict=1) + args, as_dict=1) -def filter_pricing_rules(args_dict, pricing_rules): +def filter_pricing_rules(args, pricing_rules): # filter for qty - if pricing_rules and args_dict.get("qty"): - pricing_rules = filter(lambda x: (args_dict.qty>=flt(x.min_qty) - and (args_dict.qty<=x.max_qty if x.max_qty else True)), pricing_rules) + if pricing_rules and args.get("qty"): + pricing_rules = filter(lambda x: (args.qty>=flt(x.min_qty) + and (args.qty<=x.max_qty if x.max_qty else True)), pricing_rules) # find pricing rule with highest priority if pricing_rules: @@ -323,16 +342,22 @@ def filter_pricing_rules(args_dict, pricing_rules): # apply internal priority all_fields = ["item_code", "item_group", "brand", "customer", "customer_group", "territory", - "supplier", "supplier_type", "campaign", "for_price_list", "sales_partner"] + "supplier", "supplier_type", "campaign", "sales_partner"] if len(pricing_rules) > 1: for field_set in [["item_code", "item_group", "brand"], ["customer", "customer_group", "territory"], ["supplier", "supplier_type"]]: remaining_fields = list(set(all_fields) - set(field_set)) if if_all_rules_same(pricing_rules, remaining_fields): - pricing_rules = apply_internal_priority(pricing_rules, field_set, args_dict) + pricing_rules = apply_internal_priority(pricing_rules, field_set, args) break + if len(pricing_rules) > 1: + price_or_discount = list(set([d.price_or_discount for d in pricing_rules])) + if len(price_or_discount) == 1 and price_or_discount[0] == "Discount Percentage": + pricing_rules = filter(lambda x: x.for_price_list==args.price_list, pricing_rules) \ + or pricing_rules + if len(pricing_rules) > 1: frappe.throw(_("Multiple Price Rule exists with same criteria, please resolve \ conflict by assigning priority. Price Rules: {0}") @@ -350,11 +375,11 @@ def if_all_rules_same(pricing_rules, fields): return all_rules_same -def apply_internal_priority(pricing_rules, field_set, args_dict): +def apply_internal_priority(pricing_rules, field_set, args): filtered_rules = [] for field in field_set: - if args_dict.get(field): - filtered_rules = filter(lambda x: x[field]==args_dict[field], pricing_rules) + if args.get(field): + filtered_rules = filter(lambda x: x[field]==args[field], pricing_rules) if filtered_rules: break return filtered_rules or pricing_rules diff --git a/erpnext/stock/page/stock_balance/stock_balance.js b/erpnext/stock/page/stock_balance/stock_balance.js index dbd8830774..18f79169a9 100644 --- a/erpnext/stock/page/stock_balance/stock_balance.js +++ b/erpnext/stock/page/stock_balance/stock_balance.js @@ -3,18 +3,18 @@ frappe.require("assets/erpnext/js/stock_analytics.js"); -frappe.pages['stock-balance'].onload = function(wrapper) { +frappe.pages['stock-balance'].onload = function(wrapper) { frappe.ui.make_app_page({ parent: wrapper, title: __('Stock Balance'), single_column: true }); - + new erpnext.StockBalance(wrapper); - + wrapper.appframe.add_module_icon("Stock") - + } erpnext.StockBalance = erpnext.StockAnalytics.extend({ @@ -30,40 +30,42 @@ erpnext.StockBalance = erpnext.StockAnalytics.extend({ {id: "name", name: __("Item"), field: "name", width: 300, formatter: this.tree_formatter}, {id: "item_name", name: __("Item Name"), field: "item_name", width: 100}, - {id: "description", name: __("Description"), field: "description", width: 200, + {id: "description", name: __("Description"), field: "description", width: 200, formatter: this.text_formatter}, {id: "brand", name: __("Brand"), field: "brand", width: 100}, {id: "stock_uom", name: __("UOM"), field: "stock_uom", width: 100}, - {id: "opening_qty", name: __("Opening Qty"), field: "opening_qty", width: 100, + {id: "opening_qty", name: __("Opening Qty"), field: "opening_qty", width: 100, formatter: this.currency_formatter}, - {id: "inflow_qty", name: __("In Qty"), field: "inflow_qty", width: 100, + {id: "inflow_qty", name: __("In Qty"), field: "inflow_qty", width: 100, formatter: this.currency_formatter}, - {id: "outflow_qty", name: __("Out Qty"), field: "outflow_qty", width: 100, + {id: "outflow_qty", name: __("Out Qty"), field: "outflow_qty", width: 100, formatter: this.currency_formatter}, - {id: "closing_qty", name: __("Closing Qty"), field: "closing_qty", width: 100, + {id: "closing_qty", name: __("Closing Qty"), field: "closing_qty", width: 100, formatter: this.currency_formatter}, - - {id: "opening_value", name: __("Opening Value"), field: "opening_value", width: 100, + + {id: "opening_value", name: __("Opening Value"), field: "opening_value", width: 100, formatter: this.currency_formatter}, - {id: "inflow_value", name: __("In Value"), field: "inflow_value", width: 100, + {id: "inflow_value", name: __("In Value"), field: "inflow_value", width: 100, formatter: this.currency_formatter}, - {id: "outflow_value", name: __("Out Value"), field: "outflow_value", width: 100, + {id: "outflow_value", name: __("Out Value"), field: "outflow_value", width: 100, formatter: this.currency_formatter}, - {id: "closing_value", name: __("Closing Value"), field: "closing_value", width: 100, + {id: "closing_value", name: __("Closing Value"), field: "closing_value", width: 100, + formatter: this.currency_formatter}, + {id: "valuation_rate", name: __("Valuation Rate"), field: "valuation_rate", width: 100, formatter: this.currency_formatter}, ]; }, - + filters: [ - {fieldtype:"Select", label: __("Brand"), link:"Brand", + {fieldtype:"Select", label: __("Brand"), link:"Brand", default_value: "Select Brand...", filter: function(val, item, opts) { return val == opts.default_value || item.brand == val || item._show; }, link_formatter: {filter_input: "brand"}}, - {fieldtype:"Select", label: __("Warehouse"), link:"Warehouse", + {fieldtype:"Select", label: __("Warehouse"), link:"Warehouse", default_value: "Select Warehouse...", filter: function(val, item, opts, me) { return me.apply_zero_filter(val, item, opts, me); }}, - {fieldtype:"Select", label: __("Project"), link:"Project", + {fieldtype:"Select", label: __("Project"), link:"Project", default_value: "Select Project...", filter: function(val, item, opts, me) { return me.apply_zero_filter(val, item, opts, me); }, link_formatter: {filter_input: "project"}}, @@ -73,16 +75,16 @@ erpnext.StockBalance = erpnext.StockAnalytics.extend({ {fieldtype:"Button", label: __("Refresh"), icon:"icon-refresh icon-white"}, {fieldtype:"Button", label: __("Reset Filters"), icon: "icon-filter"} ], - + setup_plot_check: function() { return; }, - + prepare_data: function() { this.stock_entry_map = this.make_name_map(frappe.report_dump.data["Stock Entry"], "name"); this._super(); }, - + prepare_balances: function() { var me = this; var from_date = dateutil.str_to_obj(this.from_date); @@ -95,26 +97,26 @@ erpnext.StockBalance = erpnext.StockAnalytics.extend({ for(var i=0, j=data.length; i 0) + item.valuation_rate = flt(item.closing_value) / flt(item.closing_qty); + else item.valuation_rate = 0.0 }); }, - + update_groups: function() { var me = this; @@ -155,24 +162,22 @@ erpnext.StockBalance = erpnext.StockAnalytics.extend({ while(parent) { parent_group = me.item_by_name[parent]; $.each(me.columns, function(c, col) { - if (col.formatter == me.currency_formatter) { - parent_group[col.field] = - flt(parent_group[col.field]) - + flt(item[col.field]); + if (col.formatter == me.currency_formatter && col.field != "valuation_rate") { + parent_group[col.field] = flt(parent_group[col.field]) + flt(item[col.field]); } }); - + // show parent if filtered by brand if(item.brand == me.brand) parent_group._show = true; - + parent = me.parent_map[parent]; } } }); }, - + get_plot_data: function() { return; } -}); \ No newline at end of file +}); diff --git a/erpnext/stock/page/stock_ledger/stock_ledger.js b/erpnext/stock/page/stock_ledger/stock_ledger.js index 02af7149f7..b4086dc66e 100644 --- a/erpnext/stock/page/stock_ledger/stock_ledger.js +++ b/erpnext/stock/page/stock_ledger/stock_ledger.js @@ -1,13 +1,13 @@ // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -frappe.pages['stock-ledger'].onload = function(wrapper) { +frappe.pages['stock-ledger'].onload = function(wrapper) { frappe.ui.make_app_page({ parent: wrapper, title: __('Stock Ledger'), single_column: true }); - + new erpnext.StockLedger(wrapper); wrapper.appframe.add_module_icon("Stock") } @@ -30,7 +30,7 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ this.columns = [ {id: "posting_datetime", name: __("Posting Date"), field: "posting_datetime", width: 120, formatter: this.date_formatter}, - {id: "item_code", name: __("Item Code"), field: "item_code", width: 160, + {id: "item_code", name: __("Item Code"), field: "item_code", width: 160, link_formatter: { filter_input: "item_code", open_btn: true, @@ -57,10 +57,10 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ doctype: "dataContext.voucher_type" }}, ]; - + }, filters: [ - {fieldtype:"Select", label: __("Warehouse"), link:"Warehouse", + {fieldtype:"Select", label: __("Warehouse"), link:"Warehouse", default_value: "Select Warehouse...", filter: function(val, item, opts) { return item.warehouse == val || val == opts.default_value; }}, @@ -68,7 +68,7 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ filter: function(val, item, opts) { return item.item_code == val || !val; }}, - {fieldtype:"Select", label: "Brand", link:"Brand", + {fieldtype:"Select", label: "Brand", link:"Brand", default_value: "Select Brand...", filter: function(val, item, opts) { return val == opts.default_value || item.brand == val || item._show; }, link_formatter: {filter_input: "brand"}}, @@ -87,17 +87,17 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ {fieldtype:"Button", label: __("Refresh"), icon:"icon-refresh icon-white"}, {fieldtype:"Button", label: __("Reset Filters"), icon: "icon-filter"} ], - + setup_filters: function() { var me = this; this._super(); - + this.wrapper.bind("apply_filters_from_route", function() { me.toggle_enable_brand(); }); this.filter_inputs.item_code.change(function() { me.toggle_enable_brand(); }); - + this.trigger_refresh_on_change(["item_code", "warehouse", "brand"]); }, - + toggle_enable_brand: function() { if(!this.filter_inputs.item_code.val()) { this.filter_inputs.brand.prop("disabled", false); @@ -107,7 +107,7 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ .prop("disabled", true); } }, - + init_filter_values: function() { this._super(); this.filter_inputs.warehouse.get(0).selectedIndex = 0; @@ -131,19 +131,19 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ item_code: "Total Out", qty: 0.0, balance: 0.0, balance_value: 0.0, id:"_total_out", _show: true, _style: "font-weight: bold" } - + // clear balance $.each(frappe.report_dump.data["Item"], function(i, item) { - item.balance = item.balance_value = 0.0; + item.balance = item.balance_value = 0.0; }); - + // initialize warehouse-item map this.item_warehouse = {}; this.serialized_buying_rates = this.get_serialized_buying_rates(); var from_datetime = dateutil.str_to_obj(me.from_date + " 00:00:00"); var to_datetime = dateutil.str_to_obj(me.to_date + " 23:59:59"); - - // + + // for(var i=0, j=data.length; i\n\n\n\n\n\n\n\n\n\n", - "idx": 1, - "modified": "2014-05-13 16:07:19.133031", - "modified_by": "Administrator", - "module": "Stock", - "name": "Delivery Note Packing List Wise", - "owner": "Administrator", - "standard": "Yes" -} \ No newline at end of file diff --git a/erpnext/stock/report/item_prices/item_prices.py b/erpnext/stock/report/item_prices/item_prices.py index 0d5539ecec..d2da54f8fa 100644 --- a/erpnext/stock/report/item_prices/item_prices.py +++ b/erpnext/stock/report/item_prices/item_prices.py @@ -7,7 +7,7 @@ from frappe.utils import flt def execute(filters=None): if not filters: filters = {} - + columns = get_columns(filters) item_map = get_item_details() pl = get_price_list() @@ -19,34 +19,33 @@ def execute(filters=None): precision = get_currency_precision() or 2 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(last_purchase_rate.get(item, 0), precision), - flt(val_rate_map.get(item, 0), precision), - pl.get(item, {}).get("Selling"), - pl.get(item, {}).get("Buying"), - flt(bom_rate.get(item, 0), precision), - flt(item_map[item]["standard_rate"], precision) + data.append([item, item_map[item]["item_name"], + item_map[item]["description"], item_map[item]["stock_uom"], + flt(last_purchase_rate.get(item, 0), precision), + flt(val_rate_map.get(item, 0), precision), + pl.get(item, {}).get("Selling"), + pl.get(item, {}).get("Buying"), + flt(bom_rate.get(item, 0), precision) ]) - + 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"] + + 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"] return columns def get_item_details(): """returns all items details""" - + item_map = {} - + for i in frappe.db.sql("select name, item_name, description, \ - stock_uom, standard_rate from tabItem \ + stock_uom from tabItem \ order by item_code", as_dict=1): item_map.setdefault(i.name, i) @@ -57,42 +56,42 @@ def get_price_list(): rate = {} - price_list = frappe.db.sql("""select ip.item_code, ip.buying, ip.selling, - concat(ip.price_list, " - ", ip.currency, " ", ip.price_list_rate) as price - from `tabItem Price` ip, `tabPrice List` pl + price_list = frappe.db.sql("""select ip.item_code, ip.buying, ip.selling, + concat(ip.price_list, " - ", ip.currency, " ", ip.price_list_rate) as price + from `tabItem Price` ip, `tabPrice List` pl where ip.price_list=pl.name and pl.enabled=1""", as_dict=1) for j in price_list: if j.price: rate.setdefault(j.item_code, {}).setdefault("Buying" if j.buying else "Selling", []).append(j.price) item_rate_map = {} - + for item in rate: for buying_or_selling in rate[item]: - item_rate_map.setdefault(item, {}).setdefault(buying_or_selling, + item_rate_map.setdefault(item, {}).setdefault(buying_or_selling, ", ".join(rate[item].get(buying_or_selling, []))) - + return item_rate_map def get_last_purchase_rate(): item_last_purchase_rate_map = {} - query = """select * from (select + query = """select * from (select result.item_code, result.base_rate from ( - (select + (select po_item.item_code, po_item.item_name, po.transaction_date as posting_date, - po_item.base_price_list_rate, - po_item.discount_percentage, + po_item.base_price_list_rate, + po_item.discount_percentage, po_item.base_rate from `tabPurchase Order` po, `tabPurchase Order Item` po_item where po.name = po_item.parent and po.docstatus = 1) union - (select + (select pr_item.item_code, pr_item.item_name, pr.posting_date, @@ -114,8 +113,8 @@ def get_item_bom_rate(): """Get BOM rate of an item from BOM""" item_bom_map = {} - - for b in frappe.db.sql("""select item, (total_cost/quantity) as bom_rate + + for b in frappe.db.sql("""select item, (total_cost/quantity) as bom_rate from `tabBOM` where is_active=1 and is_default=1""", as_dict=1): item_bom_map.setdefault(b.item, flt(b.bom_rate)) @@ -125,8 +124,8 @@ def get_valuation_rate(): """Get an average valuation rate of an item from all warehouses""" item_val_rate_map = {} - - for d in frappe.db.sql("""select item_code, + + for d in frappe.db.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): item_val_rate_map.setdefault(d.item_code, d.val_rate) diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index 5068326af0..73a2c2a278 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -17,23 +17,25 @@ def execute(filters=None): % ("/".join(["#Form", sle.voucher_type, sle.voucher_no]),) data.append([sle.date, sle.item_code, item_detail.item_name, item_detail.item_group, - item_detail.brand, item_detail.description, sle.warehouse, item_detail.stock_uom, - sle.actual_qty, sle.qty_after_transaction, sle.valuation_rate, sle.stock_value, - sle.voucher_type, sle.voucher_no, voucher_link_icon, sle.batch_no, sle.serial_no, sle.company]) + item_detail.brand, item_detail.description, sle.warehouse, + item_detail.stock_uom, sle.actual_qty, sle.qty_after_transaction, + (sle.incoming_rate if sle.actual_qty > 0 else 0.0), + sle.valuation_rate, sle.stock_value, sle.voucher_type, sle.voucher_no, + voucher_link_icon, sle.batch_no, sle.serial_no, sle.company]) return columns, data def get_columns(): - return ["Date:Datetime:95", "Item:Link/Item:130", "Item Name::100", - "Item Group:Link/Item Group:100", "Brand:Link/Brand:100", - "Description::200", "Warehouse:Link/Warehouse:100", - "Stock UOM:Link/UOM:100", "Qty:Float:50", "Balance Qty:Float:100", "Valuation Rate:Currency:110", - "Balance Value:Currency:110", "Voucher Type::110", "Voucher #::100", "Link::30", - "Batch:Link/Batch:100", "Serial #:Link/Serial No:100", "Company:Link/Company:100"] + return ["Date:Datetime:95", "Item:Link/Item:130", "Item Name::100", "Item Group:Link/Item Group:100", + "Brand:Link/Brand:100", "Description::200", "Warehouse:Link/Warehouse:100", + "Stock UOM:Link/UOM:100", "Qty:Float:50", "Balance Qty:Float:100", + "Incoming Rate:Currency:110", "Valuation Rate:Currency:110", "Balance Value:Currency:110", + "Voucher Type::110", "Voucher #::100", "Link::30", "Batch:Link/Batch:100", + "Serial #:Link/Serial No:100", "Company:Link/Company:100"] def get_stock_ledger_entries(filters): return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date, - item_code, warehouse, actual_qty, qty_after_transaction, valuation_rate, + item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate, stock_value, voucher_type, voucher_no, batch_no, serial_no, company from `tabStock Ledger Entry` where company = %(company)s and diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index 8fe5284c47..b5c98bf2e1 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -68,10 +68,6 @@ def get_incoming_rate(args): in_rate = 0 if args.get("serial_no"): in_rate = get_avg_purchase_rate(args.get("serial_no")) - elif args.get("bom_no"): - result = frappe.db.sql("""select ifnull(total_cost, 0) / ifnull(quantity, 1) - from `tabBOM` where name = %s and docstatus=1 and is_active=1""", args.get("bom_no")) - in_rate = result and flt(result[0][0]) or 0 else: valuation_method = get_valuation_method(args.get("item_code")) previous_sle = get_previous_sle(args) diff --git a/erpnext/utilities/__init__.py b/erpnext/utilities/__init__.py index e96ae83c8a..bfb3fe4bdf 100644 --- a/erpnext/utilities/__init__.py +++ b/erpnext/utilities/__init__.py @@ -22,12 +22,3 @@ from frappe.utils import cint, comma_or def validate_status(status, options): if status not in options: frappe.throw(_("Status must be one of {0}").format(comma_or(options))) - -def build_filter_conditions(filters): - conditions, filter_values = [], [] - for key in filters: - conditions.append('`' + key + '` = %s') - filter_values.append(filters[key]) - - conditions = conditions and " and " + " and ".join(conditions) or "" - return conditions, filter_values