diff --git a/erpnext/accounts/Print Format/POS Invoice/POS Invoice.txt b/erpnext/accounts/Print Format/POS Invoice/POS Invoice.txt index aab8e18491..7f1bba4c96 100644 --- a/erpnext/accounts/Print Format/POS Invoice/POS Invoice.txt +++ b/erpnext/accounts/Print Format/POS Invoice/POS Invoice.txt @@ -2,14 +2,14 @@ { "creation": "2011-12-21 11:08:55", "docstatus": 0, - "modified": "2013-09-13 17:17:47", + "modified": "2014-01-08 19:32:16", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Sales Invoice", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n \n \n \n \n \n \n \n
RECEIPT NO: DATE:
M/s
\n\n
\n\n\n", + "html": "\n\t\n\n\t\t\n\t\t\n\n\t\t\n\t\t\n\t\n\n\t\n\t\t\n\t\t
\n\t\t
\n\t\t
\n\t\t
\n\t\t
\n\t\n", "module": "Accounts", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py index a6e993863d..2475fdaf66 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import webnotes from webnotes import _ +from webnotes.utils import cint class DocType: def __init__(self, d, dl): @@ -14,7 +15,12 @@ class DocType: def on_update(self): webnotes.conn.set_default("auto_accounting_for_stock", self.doc.auto_accounting_for_stock) - if self.doc.auto_accounting_for_stock: + if cint(self.doc.auto_accounting_for_stock): + # set default perpetual account in company + for company in webnotes.conn.sql("select name from tabCompany"): + webnotes.bean("Company", company[0]).save() + + # Create account head for warehouses warehouse_list = webnotes.conn.sql("select name, company from tabWarehouse", as_dict=1) warehouse_with_no_company = [d.name for d in warehouse_list if not d.company] if warehouse_with_no_company: diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py index ff44d555ff..20cd8993bf 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -146,11 +146,12 @@ def update_outstanding_amt(account, against_voucher_type, against_voucher, on_ca webnotes.conn.sql("update `tab%s` set outstanding_amount=%s where name='%s'" % (against_voucher_type, bal, against_voucher)) -def validate_frozen_account(account, adv_adj): +def validate_frozen_account(account, adv_adj=None): frozen_account = webnotes.conn.get_value("Account", account, "freeze_account") if frozen_account == 'Yes' and not adv_adj: frozen_accounts_modifier = webnotes.conn.get_value( 'Accounts Settings', None, 'frozen_accounts_modifier') + if not frozen_accounts_modifier: webnotes.throw(account + _(" is a frozen account. Either make the account active or assign role in Accounts Settings who can create / modify entries against this account")) elif frozen_accounts_modifier not in webnotes.user.get_roles(): diff --git a/erpnext/accounts/doctype/journal_voucher/journal_voucher.js b/erpnext/accounts/doctype/journal_voucher/journal_voucher.js index 1eb8b1d730..342fa23afa 100644 --- a/erpnext/accounts/doctype/journal_voucher/journal_voucher.js +++ b/erpnext/accounts/doctype/journal_voucher/journal_voucher.js @@ -120,7 +120,8 @@ cur_frm.cscript.refresh = function(doc) { "voucher_no": doc.name, "from_date": doc.posting_date, "to_date": doc.posting_date, - "company": doc.company + "company": doc.company, + group_by_voucher: 0 }; wn.set_route("query-report", "General Ledger"); }, "icon-table"); diff --git a/erpnext/accounts/doctype/payment_to_invoice_matching_tool/payment_to_invoice_matching_tool.py b/erpnext/accounts/doctype/payment_to_invoice_matching_tool/payment_to_invoice_matching_tool.py index 0c6cdb6a78..2904c7d695 100644 --- a/erpnext/accounts/doctype/payment_to_invoice_matching_tool/payment_to_invoice_matching_tool.py +++ b/erpnext/accounts/doctype/payment_to_invoice_matching_tool/payment_to_invoice_matching_tool.py @@ -140,13 +140,13 @@ def gl_entry_details(doctype, txt, searchfield, start, page_len, filters): and ifnull(gle.%(account_type)s, 0) > 0 and (select ifnull(abs(sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))), 0) from `tabGL Entry` - where against_voucher_type = '%(dt)s' + where account = '%(acc)s' + and against_voucher_type = '%(dt)s' and against_voucher = gle.voucher_no and voucher_no != gle.voucher_no) - != abs(ifnull(gle.debit, 0) - ifnull(gle.credit, 0) - ) - and if(gle.voucher_type='Sales Invoice', (select is_pos from `tabSales Invoice` - where name=gle.voucher_no), 0)=0 + != abs(ifnull(gle.debit, 0) - ifnull(gle.credit, 0)) + and if(gle.voucher_type='Sales Invoice', ifnull((select is_pos from `tabSales Invoice` + where name=gle.voucher_no), 0), 0)=0 %(mcond)s ORDER BY gle.posting_date desc, gle.voucher_no desc limit %(start)s, %(page_len)s""" % { diff --git a/erpnext/accounts/doctype/pos_setting/pos_setting.js b/erpnext/accounts/doctype/pos_setting/pos_setting.js index a1ebb59602..5c291b403a 100755 --- a/erpnext/accounts/doctype/pos_setting/pos_setting.js +++ b/erpnext/accounts/doctype/pos_setting/pos_setting.js @@ -7,7 +7,7 @@ cur_frm.cscript.onload = function(doc,cdt,cdn){ }); cur_frm.set_query("selling_price_list", function() { - return { filters: { buying_or_selling: "Selling" } }; + return { filters: { selling: 1 } }; }); } diff --git a/erpnext/accounts/doctype/pos_setting/pos_setting.txt b/erpnext/accounts/doctype/pos_setting/pos_setting.txt index 22edcddea3..1c9e0bf844 100755 --- a/erpnext/accounts/doctype/pos_setting/pos_setting.txt +++ b/erpnext/accounts/doctype/pos_setting/pos_setting.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 12:15:51", "docstatus": 0, - "modified": "2013-12-20 19:24:16", + "modified": "2014-01-15 16:23:58", "modified_by": "Administrator", "owner": "Administrator" }, @@ -156,7 +156,7 @@ "reqd": 1 }, { - "depends_on": "eval:sys_defaults.auto_accounting_for_stock", + "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "doctype": "DocField", "fieldname": "expense_account", "fieldtype": "Link", diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index aa3b45f899..dda621950c 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -35,7 +35,8 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({ "voucher_no": doc.name, "from_date": doc.posting_date, "to_date": doc.posting_date, - "company": doc.company + "company": doc.company, + group_by_voucher: 0 }; wn.set_route("query-report", "General Ledger"); }, "icon-table"); diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index f6b6ef4035..db42a12753 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -302,6 +302,7 @@ class DocType(BuyingController): self.make_gl_entries() self.update_against_document_in_jv() self.update_prevdoc_status() + self.update_billing_status_for_zero_amount_refdoc("Purchase Order") def make_gl_entries(self): auto_accounting_for_stock = \ @@ -350,7 +351,6 @@ class DocType(BuyingController): # item gl entries stock_item_and_auto_accounting_for_stock = False stock_items = self.get_stock_items() - # rounding_diff = 0.0 for item in self.doclist.get({"parentfield": "entries"}): if auto_accounting_for_stock and item.item_code in stock_items: if flt(item.valuation_rate): @@ -359,12 +359,8 @@ class DocType(BuyingController): # expense will be booked in sales invoice stock_item_and_auto_accounting_for_stock = True - valuation_amt = item.amount + item.item_tax_amount + item.rm_supp_cost - - # rounding_diff += (flt(item.amount, self.precision("amount", item)) + - # flt(item.item_tax_amount, self.precision("item_tax_amount", item)) + - # flt(item.rm_supp_cost, self.precision("rm_supp_cost", item)) - - # valuation_amt) + valuation_amt = flt(item.amount + item.item_tax_amount + item.rm_supp_cost, + self.precision("amount", item)) gl_entries.append( self.get_gl_dict({ @@ -392,12 +388,6 @@ class DocType(BuyingController): # this will balance out valuation amount included in cost of goods sold expenses_included_in_valuation = \ self.get_company_default("expenses_included_in_valuation") - - # if rounding_diff: - # import operator - # cost_center_with_max_value = max(valuation_tax.iteritems(), - # key=operator.itemgetter(1))[0] - # valuation_tax[cost_center_with_max_value] -= flt(rounding_diff) for cost_center, amount in valuation_tax.items(): gl_entries.append( @@ -432,7 +422,7 @@ class DocType(BuyingController): remove_against_link_from_jv(self.doc.doctype, self.doc.name, "against_voucher") self.update_prevdoc_status() - + self.update_billing_status_for_zero_amount_refdoc("Purchase Order") self.make_cancel_gl_entries() def on_update(self): diff --git a/erpnext/accounts/doctype/sales_invoice/pos.js b/erpnext/accounts/doctype/sales_invoice/pos.js index c432765981..ce5350908d 100644 --- a/erpnext/accounts/doctype/sales_invoice/pos.js +++ b/erpnext/accounts/doctype/sales_invoice/pos.js @@ -19,8 +19,10 @@ erpnext.POS = Class.extend({ \ \ \ - \ - \ + \ + \ + \ + \ \ \ \ @@ -60,10 +62,16 @@ erpnext.POS = Class.extend({ \ \

\ - \ - \ +
\ +
\ + \ +
\ +
\ + \ +
\ +
\

\ \
\ @@ -82,7 +90,7 @@ erpnext.POS = Class.extend({ me.refresh(); }); - this.call_function("delete-items", function() {me.remove_selected_item();}); + this.call_function("remove-items", function() {me.remove_selected_items();}); this.call_function("make-payment", function() {me.make_payment();}); }, check_transaction_type: function() { @@ -333,7 +341,7 @@ erpnext.POS = Class.extend({ } this.disable_text_box_and_button(); - this.make_payment_button(); + this.hide_payment_button(); // If quotation to is not Customer then remove party if (this.frm.doctype == "Quotation") { @@ -351,8 +359,18 @@ erpnext.POS = Class.extend({ $(repl('
\ \ - \ + \ + \ \ ', { @@ -364,27 +382,32 @@ erpnext.POS = Class.extend({ } )).appendTo($items); }); + + this.wrapper.find(".increase-qty, .decrease-qty").on("click", function() { + var item_code = $(this).closest("tr").attr("id"); + me.selected_item_qty_operation(item_code, $(this).attr("class")); + }); }, show_taxes: function() { var me = this; var taxes = wn.model.get_children(this.sales_or_purchase + " Taxes and Charges", this.frm.doc.name, this.frm.cscript.other_fname, this.frm.doctype); $(this.wrapper).find(".tax-table") - .toggle((taxes && taxes.length && - flt(me.frm.doc.other_charges_total_export || - me.frm.doc.other_charges_added_import) != 0.0) ? true : false) + .toggle((taxes && taxes.length) ? true : false) .find("tbody").empty(); $.each(taxes, function(i, d) { - $(repl('\ - \ - \ - ', { - description: d.description, - rate: ((d.charge_type == "Actual") ? '' : ("(" + d.rate + "%)")), - tax_amount: format_currency(flt(d.tax_amount)/flt(me.frm.doc.conversion_rate), - me.frm.doc.currency) - })).appendTo(".tax-table tbody"); + if (d.tax_amount) { + $(repl('\ + \ + \ + ', { + description: d.description, + rate: ((d.charge_type == "Actual") ? '' : ("(" + d.rate + "%)")), + tax_amount: format_currency(flt(d.tax_amount)/flt(me.frm.doc.conversion_rate), + me.frm.doc.currency) + })).appendTo(".tax-table tbody"); + } }); }, set_totals: function() { @@ -427,7 +450,7 @@ erpnext.POS = Class.extend({ $(this.wrapper).find('input, button').each(function () { $(this).prop('disabled', true); }); - $(this.wrapper).find(".delete-items").hide(); + $(this.wrapper).find(".remove-items").hide(); $(this.wrapper).find(".make-payment").hide(); } else { @@ -437,14 +460,14 @@ erpnext.POS = Class.extend({ $(this.wrapper).find(".make-payment").show(); } }, - make_payment_button: function() { + hide_payment_button: function() { var me = this; // Show Make Payment button only in Sales Invoice if (this.frm.doctype != "Sales Invoice") $(this.wrapper).find(".make-payment").hide(); }, refresh_delete_btn: function() { - $(this.wrapper).find(".delete-items").toggle($(".item-cart .warning").length ? true : false); + $(this.wrapper).find(".remove-items").toggle($(".item-cart .warning").length ? true : false); }, add_item_thru_barcode: function() { var me = this; @@ -466,7 +489,7 @@ erpnext.POS = Class.extend({ } }); }, - remove_selected_item: function() { + remove_selected_items: function() { var me = this; var selected_items = []; var no_of_items = $(this.wrapper).find("#cart tbody tr").length; @@ -487,6 +510,7 @@ erpnext.POS = Class.extend({ } } }); + this.refresh_grid(); }, refresh_grid: function() { @@ -494,6 +518,22 @@ erpnext.POS = Class.extend({ this.frm.script_manager.trigger("calculate_taxes_and_totals"); this.refresh(); }, + selected_item_qty_operation: function(item_code, operation) { + var me = this; + var child = wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, + this.frm.cscript.fname, this.frm.doctype); + + $.each(child, function(i, d) { + if (d.item_code == item_code) { + if (operation == "increase-qty") + d.qty += 1; + else if (operation == "decrease-qty") + d.qty != 1 ? d.qty -= 1 : d.qty = 1; + + me.refresh(); + } + }); + }, make_payment: function() { var me = this; var no_of_items = $(this.wrapper).find("#cart tbody tr").length; diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 9c6a9b223d..8e6ecc410f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -54,7 +54,8 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte "voucher_no": doc.name, "from_date": doc.posting_date, "to_date": doc.posting_date, - "company": doc.company + "company": doc.company, + group_by_voucher: 0 }; wn.set_route("query-report", "General Ledger"); }, "icon-table"); diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index f77abfe72a..decfb425bd 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -88,6 +88,7 @@ class DocType(SellingController): self.update_status_updater_args() self.update_prevdoc_status() + self.update_billing_status_for_zero_amount_refdoc("Sales Order") # this sequence because outstanding may get -ve self.make_gl_entries() @@ -114,6 +115,7 @@ class DocType(SellingController): self.update_status_updater_args() self.update_prevdoc_status() + self.update_billing_status_for_zero_amount_refdoc("Sales Order") self.make_cancel_gl_entries() diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt b/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt index 7de68a06ed..1a5bdf1efc 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:05", "docstatus": 0, - "modified": "2013-12-20 19:24:29", + "modified": "2014-01-16 15:36:16", "modified_by": "Administrator", "owner": "Administrator" }, @@ -1094,7 +1094,7 @@ "fieldtype": "Select", "label": "Recurring Type", "no_copy": 1, - "options": "Monthly\nQuarterly\nHalf-yearly\nYearly", + "options": "\nMonthly\nQuarterly\nHalf-yearly\nYearly", "print_hide": 1, "read_only": 0 }, diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index c68b97a3b2..34ff97ff1c 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -565,16 +565,17 @@ class TestSalesInvoice(unittest.TestCase): where against_invoice=%s""", si.doc.name)) def test_recurring_invoice(self): - from webnotes.utils import now_datetime, get_first_day, get_last_day, add_to_date - today = now_datetime().date() - + from webnotes.utils import get_first_day, get_last_day, add_to_date, nowdate, getdate + from accounts.utils import get_fiscal_year + today = nowdate() base_si = webnotes.bean(copy=test_records[0]) base_si.doc.fields.update({ "convert_into_recurring_invoice": 1, "recurring_type": "Monthly", "notification_email_address": "test@example.com, test1@example.com, test2@example.com", - "repeat_on_day_of_month": today.day, + "repeat_on_day_of_month": getdate(today).day, "posting_date": today, + "fiscal_year": get_fiscal_year(today)[0], "invoice_period_from_date": get_first_day(today), "invoice_period_to_date": get_last_day(today) }) diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.py b/erpnext/accounts/report/accounts_payable/accounts_payable.py index adb126b0dd..07cca7385e 100644 --- a/erpnext/accounts/report/accounts_payable/accounts_payable.py +++ b/erpnext/accounts/report/accounts_payable/accounts_payable.py @@ -9,18 +9,20 @@ from erpnext.accounts.report.accounts_receivable.accounts_receivable import get_ def execute(filters=None): if not filters: filters = {} - columns = get_columns() + supplier_naming_by = webnotes.conn.get_value("Buying Settings", None, "supp_master_name") + columns = get_columns(supplier_naming_by) entries = get_gl_entries(filters) - account_supplier = dict(webnotes.conn.sql("""select account.name, supplier.supplier_name - from `tabAccount` account, `tabSupplier` supplier - where account.master_type="Supplier" and supplier.name=account.master_name""")) - + account_map = dict(((r.name, r) for r in webnotes.conn.sql("""select acc.name, + supp.supplier_name, supp.name as supplier + from `tabAccount` acc, `tabSupplier` supp + where acc.master_type="Supplier" and supp.name=acc.master_name""", as_dict=1))) + entries_after_report_date = [[gle.voucher_type, gle.voucher_no] for gle in get_gl_entries(filters, before_report_date=False)] - + account_supplier_type_map = get_account_supplier_type_map() voucher_detail_map = get_voucher_details() - + # Age of the invoice on this date age_on = getdate(filters.get("report_date")) > getdate(nowdate()) \ and nowdate() or filters.get("report_date") @@ -37,9 +39,7 @@ def execute(filters=None): if abs(flt(outstanding_amount)) > 0.01: paid_amount = invoiced_amount - outstanding_amount - row = [gle.posting_date, gle.account, account_supplier.get(gle.account, ""), - gle.voucher_type, gle.voucher_no, gle.remarks, - account_supplier_type_map.get(gle.account), + row = [gle.posting_date, gle.account, gle.voucher_type, gle.voucher_no, voucher_details.get("due_date", ""), voucher_details.get("bill_no", ""), voucher_details.get("bill_date", ""), invoiced_amount, paid_amount, outstanding_amount] @@ -50,21 +50,38 @@ def execute(filters=None): else: ageing_based_on_date = gle.posting_date - row += get_ageing_data(age_on, ageing_based_on_date, outstanding_amount) + row += get_ageing_data(age_on, ageing_based_on_date, outstanding_amount) + \ + [account_map.get(gle.account).get("supplier") or ""] + + if supplier_naming_by == "Naming Series": + row += [account_map.get(gle.account).get("supplier_name") or ""] + + row += [account_supplier_type_map.get(gle.account), gle.remarks] data.append(row) - + + for i in range(0, len(data)): + data[i].insert(4, """""" \ + % ("/".join(["#Form", data[i][2], data[i][3]]),)) + return columns, data -def get_columns(): - return [ - "Posting Date:Date:80", "Account:Link/Account:150", "Supplier::150", "Voucher Type::110", - "Voucher No::120", "Remarks::150", "Supplier Type:Link/Supplier Type:120", - "Due Date:Date:80", "Bill No::80", "Bill Date:Date:80", +def get_columns(supplier_naming_by): + columns = [ + "Posting Date:Date:80", "Account:Link/Account:150", "Voucher Type::110", + "Voucher No::120", "::30", "Due Date:Date:80", "Bill No::80", "Bill Date:Date:80", "Invoiced Amount:Currency:100", "Paid Amount:Currency:100", "Outstanding Amount:Currency:100", "Age:Int:50", "0-30:Currency:100", - "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100" + "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100", + "Supplier:Link/Supplier:150" ] - + + if supplier_naming_by == "Naming Series": + columns += ["Supplier Name::110"] + + columns += ["Supplier Type:Link/Supplier Type:120", "Remarks::150"] + + return columns + def get_gl_entries(filters, before_report_date=True): conditions, supplier_accounts = get_conditions(filters, before_report_date) gl_entries = [] @@ -101,10 +118,10 @@ def get_conditions(filters, before_report_date=True): def get_account_supplier_type_map(): account_supplier_type_map = {} - for each in webnotes.conn.sql("""select t2.name, t1.supplier_type from `tabSupplier` t1, - `tabAccount` t2 where t1.name = t2.master_name group by t2.name"""): + for each in webnotes.conn.sql("""select acc.name, supp.supplier_type from `tabSupplier` supp, + `tabAccount` acc where supp.name = acc.master_name group by acc.name"""): account_supplier_type_map[each[0]] = each[1] - + return account_supplier_type_map def get_voucher_details(): diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 945bae434a..de96abb7d7 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -15,26 +15,34 @@ class AccountsReceivableReport(object): else self.filters.report_date def run(self): - return self.get_columns(), self.get_data() + customer_naming_by = webnotes.conn.get_value("Selling Settings", None, "cust_master_name") + return self.get_columns(customer_naming_by), self.get_data(customer_naming_by) - def get_columns(self): - return [ + def get_columns(self, customer_naming_by): + columns = [ "Posting Date:Date:80", "Account:Link/Account:150", "Voucher Type::110", "Voucher No::120", "::30", "Due Date:Date:80", "Invoiced Amount:Currency:100", "Payment Received:Currency:100", "Outstanding Amount:Currency:100", "Age:Int:50", "0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100", - "Customer:Link/Customer:200", "Territory:Link/Territory:80", "Remarks::200" + "Customer:Link/Customer:200" ] - - def get_data(self): + + if customer_naming_by == "Naming Series": + columns += ["Customer Name::110"] + + columns += ["Territory:Link/Territory:80", "Remarks::200"] + + return columns + + def get_data(self, customer_naming_by): data = [] future_vouchers = self.get_entries_after(self.filters.report_date) for gle in self.get_entries_till(self.filters.report_date): if self.is_receivable(gle, future_vouchers): outstanding_amount = self.get_outstanding_amount(gle, self.filters.report_date) - if abs(outstanding_amount) > 0.01: + if abs(outstanding_amount) > 0.0: due_date = self.get_due_date(gle) invoiced_amount = gle.debit if (gle.debit > 0) else 0 payment_received = invoiced_amount - outstanding_amount @@ -42,18 +50,23 @@ class AccountsReceivableReport(object): gle.voucher_type, gle.voucher_no, due_date, invoiced_amount, payment_received, outstanding_amount] - entry_date = due_date if self.filters.ageing_based_on=="Due Date" \ + entry_date = due_date if self.filters.ageing_based_on == "Due Date" \ else gle.posting_date - row += get_ageing_data(self.age_as_on, entry_date, outstanding_amount) - row += [self.get_customer(gle.account), self.get_territory(gle.account), gle.remarks] + row += get_ageing_data(self.age_as_on, entry_date, outstanding_amount) + \ + [self.get_customer(gle.account)] + + if customer_naming_by == "Naming Series": + row += [self.get_customer_name(gle.account)] + + row += [self.get_territory(gle.account), gle.remarks] data.append(row) - for i in range(0,len(data)): + for i in range(0, len(data)): data[i].insert(4, """""" \ % ("/".join(["#Form", data[i][2], data[i][3]]),)) return data - + def get_entries_after(self, report_date): # returns a distinct list return list(set([(e.voucher_type, e.voucher_no) for e in self.get_gl_entries() @@ -65,30 +78,41 @@ class AccountsReceivableReport(object): if getdate(e.posting_date) <= report_date) def is_receivable(self, gle, future_vouchers): - return ((not gle.against_voucher) or (gle.against_voucher==gle.voucher_no) or - ((gle.against_voucher_type, gle.against_voucher) in future_vouchers)) + return ( + # advance + (not gle.against_voucher) or + + # sales invoice + (gle.against_voucher==gle.voucher_no and gle.debit > 0) or + + # entries adjusted with future vouchers + ((gle.against_voucher_type, gle.against_voucher) in future_vouchers) + ) def get_outstanding_amount(self, gle, report_date): payment_received = 0.0 for e in self.get_gl_entries_for(gle.account, gle.voucher_type, gle.voucher_no): if getdate(e.posting_date) <= report_date and e.name!=gle.name: payment_received += (flt(e.credit) - flt(e.debit)) - + return flt(gle.debit) - flt(gle.credit) - payment_received def get_customer(self, account): + return self.get_account_map().get(account).get("customer") or "" + + def get_customer_name(self, account): return self.get_account_map().get(account).get("customer_name") or "" - + def get_territory(self, account): return self.get_account_map().get(account).get("territory") or "" def get_account_map(self): if not hasattr(self, "account_map"): self.account_map = dict(((r.name, r) for r in webnotes.conn.sql("""select - account.name, customer.name as customer_name, customer.territory - from `tabAccount` account, `tabCustomer` customer - where account.master_type="Customer" - and customer.name=account.master_name""", as_dict=True))) + acc.name, cust.name as customer, cust.customer_name, cust.territory + from `tabAccount` acc, `tabCustomer` cust + where acc.master_type="Customer" + and cust.name=acc.master_name""", as_dict=True))) return self.account_map @@ -147,7 +171,7 @@ class AccountsReceivableReport(object): def execute(filters=None): return AccountsReceivableReport(filters).run() - + def get_ageing_data(age_as_on, entry_date, outstanding_amount): # [0-30, 30-60, 60-90, 90-above] outstanding_range = [0.0, 0.0, 0.0, 0.0] 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 b93f182f31..7f32e261c7 100644 --- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js +++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js @@ -8,6 +8,7 @@ wn.query_reports["Bank Reconciliation Statement"] = { "label": wn._("Bank Account"), "fieldtype": "Link", "options": "Account", + "reqd": 1, "get_query": function() { return { "query": "accounts.utils.get_account_list", @@ -22,7 +23,8 @@ wn.query_reports["Bank Reconciliation Statement"] = { "fieldname":"report_date", "label": wn._("Date"), "fieldtype": "Date", - "default": get_today() + "default": get_today(), + "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 f2a1edda52..646906f907 100644 --- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py +++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py @@ -3,13 +3,14 @@ from __future__ import unicode_literals import webnotes -from webnotes import _, msgprint from webnotes.utils import flt def execute(filters=None): if not filters: filters = {} - - columns = get_columns() + + debit_or_credit = webnotes.conn.get_value("Account", filters["account"], "debit_or_credit") + + columns = get_columns() data = get_entries(filters) from erpnext.accounts.utils import get_balance_on @@ -20,47 +21,39 @@ def execute(filters=None): total_debit += flt(d[4]) total_credit += flt(d[5]) - if webnotes.conn.get_value("Account", filters["account"], "debit_or_credit") == 'Debit': + if debit_or_credit == 'Debit': bank_bal = flt(balance_as_per_company) - flt(total_debit) + flt(total_credit) else: bank_bal = flt(balance_as_per_company) + flt(total_debit) - flt(total_credit) data += [ - ["", "", "", "Balance as per company books", balance_as_per_company, ""], + get_balance_row("Balance as per company books", balance_as_per_company, debit_or_credit), ["", "", "", "Amounts not reflected in bank", total_debit, total_credit], - ["", "", "", "Balance as per bank", bank_bal, ""] + get_balance_row("Balance as per bank", bank_bal, debit_or_credit) ] - - return columns, data + 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", "Debit:Currency:120", "Credit:Currency:120" ] - -def get_conditions(filters): - conditions = "" - if not filters.get("account"): - msgprint(_("Please select Bank Account"), raise_exception=1) - else: - conditions += " and jvd.account = %(account)s" - - if not filters.get("report_date"): - msgprint(_("Please select Date on which you want to run the report"), raise_exception=1) - else: - conditions += """ and jv.posting_date <= %(report_date)s - and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s""" - - return conditions def get_entries(filters): - conditions = get_conditions(filters) - entries = webnotes.conn.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 ifnull(jv.cheque_no, '')!= '' %s - order by jv.name DESC""" % conditions, filters, as_list=1) + entries = webnotes.conn.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 ifnull(jv.cheque_no, '')!= '' + 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 \ No newline at end of file + return entries + +def get_balance_row(label, amount, debit_or_credit): + if debit_or_credit == "Debit": + return ["", "", "", label, amount, 0] + else: + return ["", "", "", label, 0, amount] diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index acfe6a0d86..a22a114a7e 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -72,6 +72,11 @@ def get_conditions(filters): if filters.get("voucher_no"): conditions.append("voucher_no=%(voucher_no)s") + + + from webnotes.widgets.reportview import build_match_conditions + match_conditions = build_match_conditions("GL Entry") + if match_conditions: conditions.append(match_conditions) return "and {}".format(" and ".join(conditions)) if conditions else "" @@ -136,7 +141,7 @@ def get_accountwise_gle(filters, gl_entries, gle_map): or cstr(gle.is_advance) == "Yes"): gle_map[gle.account].opening += amount opening += amount - elif gle.posting_date < filters.to_date: + elif gle.posting_date <= filters.to_date: gle_map[gle.account].entries.append(gle) gle_map[gle.account].total_debit += flt(gle.debit) gle_map[gle.account].total_credit += flt(gle.credit) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 7d81308a80..7d8a358aa1 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -12,7 +12,8 @@ def execute(filters=None): item_list = get_items(filters) aii_account_map = get_aii_accounts() - item_tax, tax_accounts = get_tax_accounts(item_list, columns) + if item_list: + item_tax, tax_accounts = get_tax_accounts(item_list, columns) data = [] for d in item_list: diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index dc5ecda3da..9f1fd87f70 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -11,7 +11,8 @@ def execute(filters=None): last_col = len(columns) item_list = get_items(filters) - item_tax, tax_accounts = get_tax_accounts(item_list, columns) + if item_list: + item_tax, tax_accounts = get_tax_accounts(item_list, columns) data = [] for d in item_list: @@ -39,7 +40,6 @@ def get_columns(): "Qty:Float:120", "Rate:Currency:120", "Amount:Currency:120" ] - def get_conditions(filters): conditions = "" diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 6d74abd591..5d9c09bcce 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import nowdate, nowtime, cstr, flt, now, getdate, add_months +from webnotes.utils import nowdate, cstr, flt, now, getdate, add_months from webnotes.model.doc import addchild from webnotes import msgprint, _ from webnotes.utils import formatdate @@ -31,6 +31,8 @@ def get_fiscal_years(date=None, fiscal_year=None, label="Date", verbose=1): if not fy: error_msg = """%s %s not in any Fiscal Year""" % (label, formatdate(date)) + error_msg = """{msg}: {date}""".format(msg=_("Fiscal Year does not exist for date"), + date=formatdate(date)) if verbose: webnotes.msgprint(error_msg) raise FiscalYearError, error_msg @@ -62,7 +64,6 @@ def get_balance_on(account=None, date=None): try: year_start_date = get_fiscal_year(date, verbose=0)[1] except FiscalYearError, e: - from webnotes.utils import getdate if getdate(date) > getdate(nowdate()): # if fiscal year not found and the date is greater than today # get fiscal year for today's date and its corresponding year start date @@ -220,17 +221,26 @@ def get_cost_center_list(doctype, txt, searchfield, start, page_len, filters): tuple(filter_values + ["%%%s%%" % txt, start, page_len])) def remove_against_link_from_jv(ref_type, ref_no, against_field): - webnotes.conn.sql("""update `tabJournal Voucher Detail` set `%s`=null, - modified=%s, modified_by=%s - where `%s`=%s and docstatus < 2""" % (against_field, "%s", "%s", against_field, "%s"), - (now(), webnotes.session.user, ref_no)) + linked_jv = webnotes.conn.sql_list("""select parent from `tabJournal Voucher Detail` + where `%s`=%s and docstatus < 2""" % (against_field, "%s"), (ref_no)) + + if linked_jv: + webnotes.conn.sql("""update `tabJournal Voucher Detail` set `%s`=null, + modified=%s, modified_by=%s + where `%s`=%s and docstatus < 2""" % (against_field, "%s", "%s", against_field, "%s"), + (now(), webnotes.session.user, ref_no)) - webnotes.conn.sql("""update `tabGL Entry` - set against_voucher_type=null, against_voucher=null, - modified=%s, modified_by=%s - where against_voucher_type=%s and against_voucher=%s - and voucher_no != ifnull(against_voucher, '')""", - (now(), webnotes.session.user, ref_type, ref_no)) + webnotes.conn.sql("""update `tabGL Entry` + set against_voucher_type=null, against_voucher=null, + modified=%s, modified_by=%s + where against_voucher_type=%s and against_voucher=%s + and voucher_no != ifnull(against_voucher, '')""", + (now(), webnotes.session.user, ref_type, ref_no)) + + webnotes.msgprint("{msg} {linked_jv}".format(msg = _("""Following linked Journal Vouchers \ + made against this transaction has been unlinked. You can link them again with other \ + transactions via Payment Reconciliation Tool."""), linked_jv="\n".join(linked_jv))) + @webnotes.whitelist() def get_company_default(company, fieldname): diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.js b/erpnext/buying/doctype/purchase_common/purchase_common.js index cc24925905..ea7a963e4b 100644 --- a/erpnext/buying/doctype/purchase_common/purchase_common.js +++ b/erpnext/buying/doctype/purchase_common/purchase_common.js @@ -22,7 +22,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ if(this.frm.fields_dict.buying_price_list) { this.frm.set_query("buying_price_list", function() { return{ - filters: { 'buying_or_selling': "Buying" } + filters: { 'buying': 1 } } }); } @@ -302,11 +302,11 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ calculate_totals: function() { var tax_count = this.frm.tax_doclist.length; - this.frm.doc.grand_total = flt( - tax_count ? this.frm.tax_doclist[tax_count - 1].total : this.frm.doc.net_total, + this.frm.doc.grand_total = flt(tax_count ? + this.frm.tax_doclist[tax_count - 1].total : this.frm.doc.net_total, precision("grand_total")); - this.frm.doc.grand_total_import = flt(this.frm.doc.grand_total / this.frm.doc.conversion_rate, - precision("grand_total_import")); + this.frm.doc.grand_total_import = flt(this.frm.doc.grand_total / + this.frm.doc.conversion_rate, precision("grand_total_import")); this.frm.doc.total_tax = flt(this.frm.doc.grand_total - this.frm.doc.net_total, precision("total_tax")); @@ -321,20 +321,26 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ } // other charges added/deducted + this.frm.doc.other_charges_added = 0.0 + this.frm.doc.other_charges_deducted = 0.0 if(tax_count) { this.frm.doc.other_charges_added = wn.utils.sum($.map(this.frm.tax_doclist, - function(tax) { return (tax.add_deduct_tax == "Add" && in_list(["Valuation and Total", "Total"], tax.category)) ? tax.tax_amount : 0.0; })); + function(tax) { return (tax.add_deduct_tax == "Add" + && in_list(["Valuation and Total", "Total"], tax.category)) ? + tax.tax_amount : 0.0; })); this.frm.doc.other_charges_deducted = wn.utils.sum($.map(this.frm.tax_doclist, - function(tax) { return (tax.add_deduct_tax == "Deduct" && in_list(["Valuation and Total", "Total"], tax.category)) ? tax.tax_amount : 0.0; })); + function(tax) { return (tax.add_deduct_tax == "Deduct" + && in_list(["Valuation and Total", "Total"], tax.category)) ? + tax.tax_amount : 0.0; })); - wn.model.round_floats_in(this.frm.doc, ["other_charges_added", "other_charges_deducted"]); - - this.frm.doc.other_charges_added_import = flt(this.frm.doc.other_charges_added / this.frm.doc.conversion_rate, - precision("other_charges_added_import")); - this.frm.doc.other_charges_deducted_import = flt(this.frm.doc.other_charges_deducted / this.frm.doc.conversion_rate, - precision("other_charges_deducted_import")); + wn.model.round_floats_in(this.frm.doc, + ["other_charges_added", "other_charges_deducted"]); } + this.frm.doc.other_charges_added_import = flt(this.frm.doc.other_charges_added / + this.frm.doc.conversion_rate, precision("other_charges_added_import")); + this.frm.doc.other_charges_deducted_import = flt(this.frm.doc.other_charges_deducted / + this.frm.doc.conversion_rate, precision("other_charges_deducted_import")); }, _cleanup: function() { diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 3659f6ddee..f2c33fc841 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -22,7 +22,7 @@ class TestPurchaseOrder(unittest.TestCase): pr = make_purchase_receipt(po.doc.name) pr[0]["supplier_warehouse"] = "_Test Warehouse 1 - _TC" - + pr[0]["posting_date"] = "2013-05-12" self.assertEquals(pr[0]["doctype"], "Purchase Receipt") self.assertEquals(len(pr), len(test_records[0])) @@ -52,7 +52,7 @@ class TestPurchaseOrder(unittest.TestCase): self.assertEquals(pr[0]["doctype"], "Purchase Receipt") self.assertEquals(len(pr), len(test_records[0])) - + pr[0]["posting_date"] = "2013-05-12" pr[0].naming_series = "_T-Purchase Receipt-" pr[1].qty = 4.0 pr_bean = webnotes.bean(pr) @@ -66,6 +66,7 @@ class TestPurchaseOrder(unittest.TestCase): pr1 = make_purchase_receipt(po.doc.name) pr1[0].naming_series = "_T-Purchase Receipt-" + pr1[0]["posting_date"] = "2013-05-12" pr1[1].qty = 8 pr1_bean = webnotes.bean(pr1) pr1_bean.insert() @@ -88,7 +89,7 @@ class TestPurchaseOrder(unittest.TestCase): self.assertEquals(pi[0]["doctype"], "Purchase Invoice") self.assertEquals(len(pi), len(test_records[0])) - + pi[0]["posting_date"] = "2013-05-12" pi[0].bill_no = "NA" webnotes.bean(pi).insert() diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js index e1780abee9..b3dec80cfa 100644 --- a/erpnext/buying/doctype/supplier/supplier.js +++ b/erpnext/buying/doctype/supplier/supplier.js @@ -95,6 +95,6 @@ cur_frm.cscript.make_contact = function() { cur_frm.fields_dict['default_price_list'].get_query = function(doc,cdt,cdn) { return{ - filters:{'buying_or_selling': "Buying"} + filters:{'buying': 1} } } \ No newline at end of file diff --git a/erpnext/buying/utils.py b/erpnext/buying/utils.py index 8a4ae3f304..d7e3d81776 100644 --- a/erpnext/buying/utils.py +++ b/erpnext/buying/utils.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import webnotes -from webnotes import msgprint, _ +from webnotes import msgprint, _, throw from webnotes.utils import getdate, flt, add_days, cstr import json @@ -90,7 +90,7 @@ def _get_price_list_rate(args, item_bean, meta): # try fetching from price list if args.buying_price_list and args.price_list_currency: price_list_rate = webnotes.conn.sql("""select ref_rate from `tabItem Price` - where price_list=%s and item_code=%s and buying_or_selling='Buying'""", + where price_list=%s and item_code=%s and buying=1""", (args.buying_price_list, args.item_code), as_dict=1) if price_list_rate: @@ -122,14 +122,12 @@ def _validate_item_details(args, item): # validate if purchase item or subcontracted item if item.is_purchase_item != "Yes": - msgprint(_("Item") + (" %s: " % item.name) + _("not a purchase item"), - raise_exception=True) + throw(_("Item") + (" %s: " % item.name) + _("not a purchase item")) if args.is_subcontracted == "Yes" and item.is_sub_contracted_item != "Yes": - msgprint(_("Item") + (" %s: " % item.name) + + throw(_("Item") + (" %s: " % item.name) + _("not a sub-contracted item.") + - _("Please select a sub-contracted item or do not sub-contract the transaction."), - raise_exception=True) + _("Please select a sub-contracted item or do not sub-contract the transaction.")) def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0): """returns last purchase details in stock uom""" diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index d48a7a6d17..4b7e79b75d 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import webnotes -from webnotes import _, msgprint +from webnotes import _, throw from webnotes.utils import flt, cint, today, cstr from webnotes.model.code import get_obj from erpnext.setup.utils import get_company_currency @@ -44,14 +44,13 @@ class AccountsController(TransactionBase): def validate_for_freezed_account(self): for fieldname in ["customer", "supplier"]: if self.meta.get_field(fieldname) and self.doc.fields.get(fieldname): - accounts = webnotes.conn.get_values("Account", {"master_type": fieldname.title(), - "master_name": self.doc.fields[fieldname], "company": self.doc.company}, - "freeze_account", as_dict=1) - + accounts = webnotes.conn.get_values("Account", + {"master_type": fieldname.title(), "master_name": self.doc.fields[fieldname], + "company": self.doc.company}, "name") if accounts: - if not filter(lambda x: cstr(x.freeze_account) in ["", "No"], accounts): - msgprint(_("Account for this ") + fieldname + _(" has been freezed. ") + - self.doc.doctype + _(" can not be made."), raise_exception=1) + from accounts.doctype.gl_entry.gl_entry import validate_frozen_account + for account in accounts: + validate_frozen_account(account[0]) def set_price_list_currency(self, buying_or_selling): if self.meta.get_field("currency"): @@ -179,17 +178,17 @@ class AccountsController(TransactionBase): """ if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"] and \ (not tax.row_id or cint(tax.row_id) >= tax.idx): - msgprint((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \ + throw((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \ _("Please specify a valid") + " %(row_id_label)s") % { "idx": tax.idx, "taxes_doctype": tax.doctype, "row_id_label": self.meta.get_label("row_id", parentfield=self.other_fname) - }, raise_exception=True) + }) def validate_inclusive_tax(self, tax): def _on_previous_row_error(row_range): - msgprint((_("Row") + " # %(idx)s [%(doctype)s]: " + + throw((_("Row") + " # %(idx)s [%(doctype)s]: " + _("to be included in Item's rate, it is required that: ") + " [" + _("Row") + " # %(row_range)s] " + _("also be included in Item's rate")) % { "idx": tax.idx, @@ -200,12 +199,12 @@ class AccountsController(TransactionBase): parentfield=self.other_fname), "charge_type": tax.charge_type, "row_range": row_range - }, raise_exception=True) + }) if cint(tax.included_in_print_rate): if tax.charge_type == "Actual": # inclusive tax cannot be of type Actual - msgprint((_("Row") + throw((_("Row") + " # %(idx)s [%(doctype)s]: %(charge_type_label)s = \"%(charge_type)s\" " + "cannot be included in Item's rate") % { "idx": tax.idx, @@ -213,7 +212,7 @@ class AccountsController(TransactionBase): "charge_type_label": self.meta.get_label("charge_type", parentfield=self.other_fname), "charge_type": tax.charge_type, - }, raise_exception=True) + }) elif tax.charge_type == "On Previous Row Amount" and \ not cint(self.tax_doclist[tax.row_id - 1].included_in_print_rate): # referred row should also be inclusive @@ -224,23 +223,22 @@ class AccountsController(TransactionBase): _on_previous_row_error("1 - %d" % (tax.row_id,)) def calculate_taxes(self): - for item in self.item_doclist: + # maintain actual tax rate based on idx + actual_tax_dict = dict([[tax.idx, tax.rate] for tax in self.tax_doclist + if tax.charge_type == "Actual"]) + + for n, item in enumerate(self.item_doclist): item_tax_map = self._load_item_tax_rate(item.item_tax_rate) for i, tax in enumerate(self.tax_doclist): # tax_amount represents the amount of tax for the current step current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map) - - if hasattr(self, "set_item_tax_amount"): - self.set_item_tax_amount(item, tax, current_tax_amount) - - # case when net total is 0 but there is an actual type charge - # in this case add the actual amount to tax.tax_amount - # and tax.grand_total_for_current_item for the first such iteration - if tax.charge_type=="Actual" and \ - not (current_tax_amount or self.doc.net_total or tax.tax_amount): - zero_net_total_adjustment = flt(tax.rate, self.precision("tax_amount", tax)) - current_tax_amount += zero_net_total_adjustment + + # Adjust divisional loss to the last item + if tax.charge_type == "Actual": + actual_tax_dict[tax.idx] -= current_tax_amount + if n == len(self.item_doclist) - 1: + current_tax_amount += actual_tax_dict[tax.idx] # store tax_amount for current item as it will be used for # charge type = 'On Previous Row Amount' @@ -252,7 +250,8 @@ class AccountsController(TransactionBase): if tax.category: # if just for valuation, do not add the tax amount in total # hence, setting it as 0 for further steps - current_tax_amount = 0.0 if (tax.category == "Valuation") else current_tax_amount + current_tax_amount = 0.0 if (tax.category == "Valuation") \ + else current_tax_amount current_tax_amount *= -1.0 if (tax.add_deduct_tax == "Deduct") else 1.0 @@ -271,6 +270,11 @@ class AccountsController(TransactionBase): # in tax.total, accumulate grand total of each item tax.total += tax.grand_total_for_current_item + # set precision in the last item iteration + if n == len(self.item_doclist) - 1: + tax.total = flt(tax.total, self.precision("total", tax)) + tax.tax_amount = flt(tax.tax_amount, self.precision("tax_amount", tax)) + def get_current_tax_amount(self, item, tax, item_tax_map): tax_rate = self._get_tax_rate(tax, item_tax_map) current_tax_amount = 0.0 @@ -384,24 +388,45 @@ class AccountsController(TransactionBase): }) def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield): + from controllers.status_updater import get_tolerance_for + item_tolerance = {} + global_tolerance = None + for item in self.doclist.get({"parentfield": "entries"}): if item.fields.get(item_ref_dn): - already_billed = webnotes.conn.sql("""select sum(%s) from `tab%s` - where %s=%s and docstatus=1""" % (based_on, self.tname, item_ref_dn, '%s'), - item.fields[item_ref_dn])[0][0] - - max_allowed_amt = flt(webnotes.conn.get_value(ref_dt + " Item", + ref_amt = flt(webnotes.conn.get_value(ref_dt + " Item", item.fields[item_ref_dn], based_on), self.precision(based_on, item)) + if not ref_amt: + webnotes.msgprint(_("As amount for item") + ": " + item.item_code + _(" in ") + + ref_dt + _(" is zero, system will not check for over-billed")) + else: + already_billed = webnotes.conn.sql("""select sum(%s) from `tab%s` + where %s=%s and docstatus=1 and parent != %s""" % + (based_on, self.tname, item_ref_dn, '%s', '%s'), + (item.fields[item_ref_dn], self.doc.name))[0][0] - total_billed_amt = flt(flt(already_billed) + flt(item.fields[based_on]), - self.precision(based_on, item)) + total_billed_amt = flt(flt(already_billed) + flt(item.fields[based_on]), + self.precision(based_on, item)) + + tolerance, item_tolerance, global_tolerance = get_tolerance_for(item.item_code, + item_tolerance, global_tolerance) - if max_allowed_amt and total_billed_amt - max_allowed_amt > 0.02: - webnotes.msgprint(_("Row ")+ cstr(item.idx) + ": " + cstr(item.item_code) + - _(" will be over-billed against mentioned ") + cstr(ref_dt) + - _(". Max allowed " + cstr(based_on) + ": " + cstr(max_allowed_amt)), - raise_exception=1) - + max_allowed_amt = flt(ref_amt * (100 + tolerance) / 100) + + if total_billed_amt - max_allowed_amt > 0.01: + reduce_by = total_billed_amt - max_allowed_amt + + webnotes.throw(_("Row #") + cstr(item.idx) + ": " + + _(" Max amount allowed for Item ") + cstr(item.item_code) + + _(" against ") + ref_dt + " " + + cstr(item.fields[ref_dt.lower().replace(" ", "_")]) + _(" is ") + + cstr(max_allowed_amt) + ". \n" + + _("""If you want to increase your overflow tolerance, please increase \ + tolerance % in Global Defaults or Item master. + Or, you must reduce the amount by """) + cstr(reduce_by) + "\n" + + _("""Also, please check if the order item has already been billed \ + in the Sales Order""")) + def get_company_default(self, fieldname): from erpnext.accounts.utils import get_company_default return get_company_default(self.doc.company, fieldname) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 40de926ea0..7ba29c20bd 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -122,8 +122,8 @@ class BuyingController(StockController): self.round_floats_in(self.doc, ["net_total", "net_total_import"]) def calculate_totals(self): - self.doc.grand_total = flt(self.tax_doclist and \ - self.tax_doclist[-1].total or self.doc.net_total, self.precision("grand_total")) + self.doc.grand_total = flt(self.tax_doclist[-1].total if self.tax_doclist + else self.doc.net_total, self.precision("grand_total")) self.doc.grand_total_import = flt(self.doc.grand_total / self.doc.conversion_rate, self.precision("grand_total_import")) @@ -135,6 +135,24 @@ class BuyingController(StockController): if self.meta.get_field("rounded_total_import"): self.doc.rounded_total_import = _round(self.doc.grand_total_import) + + if self.meta.get_field("other_charges_added"): + self.doc.other_charges_added = flt(sum([flt(d.tax_amount) for d in self.tax_doclist + if d.add_deduct_tax=="Add" and d.category in ["Valuation and Total", "Total"]]), + self.precision("other_charges_added")) + + if self.meta.get_field("other_charges_deducted"): + self.doc.other_charges_deducted = flt(sum([flt(d.tax_amount) for d in self.tax_doclist + if d.add_deduct_tax=="Deduct" and d.category in ["Valuation and Total", "Total"]]), + self.precision("other_charges_deducted")) + + if self.meta.get_field("other_charges_added_import"): + self.doc.other_charges_added_import = flt(self.doc.other_charges_added / + self.doc.conversion_rate, self.precision("other_charges_added_import")) + + if self.meta.get_field("other_charges_deducted_import"): + self.doc.other_charges_deducted_import = flt(self.doc.other_charges_deducted / + self.doc.conversion_rate, self.precision("other_charges_deducted_import")) def calculate_outstanding_amount(self): if self.doc.doctype == "Purchase Invoice" and self.doc.docstatus < 2: @@ -161,30 +179,49 @@ class BuyingController(StockController): if not self.meta.get_field("item_tax_amount", parentfield=self.fname): for item in self.item_doclist: del item.fields["item_tax_amount"] - - def set_item_tax_amount(self, item, tax, current_tax_amount): + + # update valuation rate + def update_valuation_rate(self, parentfield): """ item_tax_amount is the total tax amount applied on that item stored for valuation TODO: rename item_tax_amount to valuation_tax_amount """ - if tax.category in ["Valuation", "Valuation and Total"] and \ - self.meta.get_field("item_tax_amount", parentfield=self.fname): - item.item_tax_amount += flt(current_tax_amount, self.precision("item_tax_amount", item)) - - # update valuation rate - def update_valuation_rate(self, parentfield): - for item in self.doclist.get({"parentfield": parentfield}): - item.conversion_factor = item.conversion_factor or flt(webnotes.conn.get_value( - "UOM Conversion Detail", {"parent": item.item_code, "uom": item.uom}, - "conversion_factor")) or 1 + stock_items = self.get_stock_items() + + stock_items_qty, stock_items_amount = 0, 0 + last_stock_item_idx = 1 + for d in self.doclist.get({"parentfield": parentfield}): + if d.item_code and d.item_code in stock_items: + stock_items_qty += flt(d.qty) + stock_items_amount += flt(d.amount) + last_stock_item_idx = d.idx - if item.item_code and item.qty: + total_valuation_amount = sum([flt(d.tax_amount) for d in + self.doclist.get({"parentfield": "purchase_tax_details"}) + if d.category in ["Valuation", "Valuation and Total"]]) + + + valuation_amount_adjustment = total_valuation_amount + for i, item in enumerate(self.doclist.get({"parentfield": parentfield})): + if item.item_code and item.qty and item.item_code in stock_items: + item_proportion = flt(item.amount) / stock_items_amount if stock_items_amount \ + else flt(item.qty) / stock_items_qty + + if i == (last_stock_item_idx - 1): + item.item_tax_amount = flt(valuation_amount_adjustment, + self.precision("item_tax_amount", item)) + else: + item.item_tax_amount = flt(item_proportion * total_valuation_amount, + self.precision("item_tax_amount", item)) + valuation_amount_adjustment -= item.item_tax_amount + self.round_floats_in(item) - - # if no item code, which is sometimes the case in purchase invoice, - # then it is not possible to track valuation against it + + item.conversion_factor = item.conversion_factor or flt(webnotes.conn.get_value( + "UOM Conversion Detail", {"parent": item.item_code, "uom": item.uom}, + "conversion_factor")) or 1 qty_in_stock_uom = flt(item.qty * item.conversion_factor) item.valuation_rate = ((item.amount + item.item_tax_amount + item.rm_supp_cost) / qty_in_stock_uom) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index f950f28181..7447121ee6 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -191,7 +191,8 @@ class SellingController(StockController): self.doc.other_charges_total = flt(self.doc.grand_total - self.doc.net_total, self.precision("other_charges_total")) - self.doc.other_charges_total_export = flt(self.doc.grand_total_export - self.doc.net_total_export, + self.doc.other_charges_total_export = flt( + self.doc.grand_total_export - self.doc.net_total_export, self.precision("other_charges_total_export")) self.doc.rounded_total = _round(self.doc.grand_total) diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index b2745268f7..1743887bf7 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -151,7 +151,9 @@ class StatusUpdater(DocListController): """ # check if overflow is within tolerance - tolerance = self.get_tolerance_for(item['item_code']) + tolerance, self.tolerance, self.global_tolerance = get_tolerance_for(item['item_code'], + self.tolerance, self.global_tolerance) + overflow_percent = ((item[args['target_field']] - item[args['target_ref_field']]) / item[args['target_ref_field']]) * 100 @@ -170,23 +172,6 @@ class StatusUpdater(DocListController): Also, please check if the order item has already been billed in the Sales Order""" % item, raise_exception=1) - - def get_tolerance_for(self, item_code): - """ - Returns the tolerance for the item, if not set, returns global tolerance - """ - if self.tolerance.get(item_code): return self.tolerance[item_code] - - tolerance = flt(webnotes.conn.get_value('Item',item_code,'tolerance') or 0) - - if not tolerance: - if self.global_tolerance == None: - self.global_tolerance = flt(webnotes.conn.get_value('Global Defaults', None, - 'tolerance')) - tolerance = self.global_tolerance - - self.tolerance[item_code] = tolerance - return tolerance def update_qty(self, change_modified=True): @@ -245,4 +230,59 @@ class StatusUpdater(DocListController): set %(status_field)s = if(ifnull(%(target_parent_field)s,0)<0.001, 'Not %(keyword)s', if(%(target_parent_field)s>=99.99, 'Fully %(keyword)s', 'Partly %(keyword)s')) - where name='%(name)s'""" % args) \ No newline at end of file + where name='%(name)s'""" % args) + + + def update_billing_status_for_zero_amount_refdoc(self, ref_dt): + ref_fieldname = ref_dt.lower().replace(" ", "_") + zero_amount_refdoc = [] + all_zero_amount_refdoc = webnotes.conn.sql_list("""select name from `tab%s` + where docstatus=1 and net_total = 0""" % ref_dt) + + for item in self.doclist.get({"parentfield": "entries"}): + if item.fields.get(ref_fieldname) \ + and item.fields.get(ref_fieldname) in all_zero_amount_refdoc \ + and item.fields.get(ref_fieldname) not in zero_amount_refdoc: + zero_amount_refdoc.append(item.fields[ref_fieldname]) + + if zero_amount_refdoc: + self.update_biling_status(zero_amount_refdoc, ref_dt, ref_fieldname) + + def update_biling_status(self, zero_amount_refdoc, ref_dt, ref_fieldname): + for ref_dn in zero_amount_refdoc: + ref_doc_qty = flt(webnotes.conn.sql("""select sum(ifnull(qty, 0)) from `tab%s Item` + where parent=%s""" % (ref_dt, '%s'), (ref_dn))[0][0]) + + billed_qty = flt(webnotes.conn.sql("""select sum(ifnull(qty, 0)) + from `tab%s Item` where %s=%s and docstatus=1""" % + (self.doc.doctype, ref_fieldname, '%s'), (ref_dn))[0][0]) + + per_billed = ((ref_doc_qty if billed_qty > ref_doc_qty else billed_qty)\ + / ref_doc_qty)*100 + webnotes.conn.set_value(ref_dt, ref_dn, "per_billed", per_billed) + + from webnotes.model.meta import has_field + if has_field(ref_dt, "billing_status"): + if per_billed < 0.001: billing_status = "Not Billed" + elif per_billed >= 99.99: billing_status = "Fully Billed" + else: billing_status = "Partly Billed" + + webnotes.conn.set_value(ref_dt, ref_dn, "billing_status", billing_status) + +def get_tolerance_for(item_code, item_tolerance={}, global_tolerance=None): + """ + Returns the tolerance for the item, if not set, returns global tolerance + """ + if item_tolerance.get(item_code): + return item_tolerance[item_code], item_tolerance, global_tolerance + + tolerance = flt(webnotes.conn.get_value('Item',item_code,'tolerance') or 0) + + if not tolerance: + if global_tolerance == None: + global_tolerance = flt(webnotes.conn.get_value('Global Defaults', None, + 'tolerance')) + tolerance = global_tolerance + + item_tolerance[item_code] = tolerance + return tolerance, item_tolerance, global_tolerance \ No newline at end of file diff --git a/erpnext/hr/doctype/salary_manager/salary_manager.js b/erpnext/hr/doctype/salary_manager/salary_manager.js index 032c29e509..ec485ca671 100644 --- a/erpnext/hr/doctype/salary_manager/salary_manager.js +++ b/erpnext/hr/doctype/salary_manager/salary_manager.js @@ -43,7 +43,7 @@ cur_frm.cscript.make_jv = function(doc, dt, dn) { jv = locals['Journal Voucher'][jv]; jv.voucher_type = 'Bank Voucher'; jv.user_remark = wn._('Payment of salary for the month: ') + doc.month + - wn._('and fiscal year: ') + doc.fiscal_year; + wn._(' and fiscal year: ') + doc.fiscal_year; jv.fiscal_year = doc.fiscal_year; jv.company = doc.company; jv.posting_date = dateutil.obj_to_str(new Date()); diff --git a/erpnext/hr/report/monthly_salary_register/monthly_salary_register.js b/erpnext/hr/report/monthly_salary_register/monthly_salary_register.js index 5d3abccde9..32b4ef35fb 100644 --- a/erpnext/hr/report/monthly_salary_register/monthly_salary_register.js +++ b/erpnext/hr/report/monthly_salary_register/monthly_salary_register.js @@ -7,7 +7,7 @@ wn.query_reports["Monthly Salary Register"] = { "fieldname":"month", "label": wn._("Month"), "fieldtype": "Select", - "options": "Jan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug\nSep\nOct\nNov\nDec", + "options": "\nJan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug\nSep\nOct\nNov\nDec", "default": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][wn.datetime.str_to_obj(wn.datetime.get_today()).getMonth()], }, diff --git a/erpnext/hr/report/monthly_salary_register/monthly_salary_register.py b/erpnext/hr/report/monthly_salary_register/monthly_salary_register.py index 8bd8f36ac8..42c62e474b 100644 --- a/erpnext/hr/report/monthly_salary_register/monthly_salary_register.py +++ b/erpnext/hr/report/monthly_salary_register/monthly_salary_register.py @@ -50,17 +50,17 @@ def get_columns(salary_slips): where ifnull(d_modified_amount, 0) != 0 and parent in (%s)""" % (', '.join(['%s']*len(salary_slips))), tuple([d.name for d in salary_slips])) - columns = columns + [(e + ":Link/Earning Type:120") for e in earning_types] + \ + columns = columns + [(e + ":Currency:120") for e in earning_types] + \ ["Arrear Amount:Currency:120", "Leave Encashment Amount:Currency:150", - "Gross Pay:Currency:120"] + [(d + ":Link/Deduction Type:120") for d in ded_types] + \ + "Gross Pay:Currency:120"] + [(d + ":Currency:120") for d in ded_types] + \ ["Total Deduction:Currency:120", "Net Pay:Currency:120"] return columns, earning_types, ded_types def get_salary_slips(filters): conditions, filters = get_conditions(filters) - salary_slips = webnotes.conn.sql("""select * from `tabSalary Slip` where docstatus = 1 %s""" % - conditions, filters, as_dict=1) + salary_slips = webnotes.conn.sql("""select * from `tabSalary Slip` where docstatus = 1 %s + order by employee, month""" % conditions, filters, as_dict=1) if not salary_slips: msgprint(_("No salary slip found for month: ") + cstr(filters.get("month")) + @@ -102,6 +102,6 @@ def get_ss_ded_map(salary_slips): ss_ded_map = {} for d in ss_deductions: ss_ded_map.setdefault(d.parent, webnotes._dict()).setdefault(d.d_type, []) - ss_ded_map[d.parent][d.e_type] = flt(d.d_modified_amount) + ss_ded_map[d.parent][d.d_type] = flt(d.d_modified_amount) return ss_ded_map \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/production_order/test_production_order.py b/erpnext/manufacturing/doctype/production_order/test_production_order.py index 9b1300f039..e2ff92174e 100644 --- a/erpnext/manufacturing/doctype/production_order/test_production_order.py +++ b/erpnext/manufacturing/doctype/production_order/test_production_order.py @@ -35,6 +35,8 @@ class TestProductionOrder(unittest.TestCase): stock_entry = webnotes.bean(stock_entry) stock_entry.doc.fiscal_year = "_Test Fiscal Year 2013" stock_entry.doc.fg_completed_qty = 4 + stock_entry.doc.posting_date = "2013-05-12" + stock_entry.doc.fiscal_year = "_Test Fiscal Year 2013" stock_entry.run_method("get_items") stock_entry.submit() @@ -51,6 +53,7 @@ class TestProductionOrder(unittest.TestCase): stock_entry = make_stock_entry(pro_order, "Manufacture/Repack") stock_entry = webnotes.bean(stock_entry) + stock_entry.doc.posting_date = "2013-05-12" stock_entry.doc.fiscal_year = "_Test Fiscal Year 2013" stock_entry.doc.fg_completed_qty = 15 stock_entry.run_method("get_items") diff --git a/erpnext/setup/report/__init__.py b/erpnext/patches/1401/__init__.py similarity index 100% rename from erpnext/setup/report/__init__.py rename to erpnext/patches/1401/__init__.py diff --git a/erpnext/patches/1401/p01_make_buying_selling_as_check_box_in_price_list.py b/erpnext/patches/1401/p01_make_buying_selling_as_check_box_in_price_list.py new file mode 100644 index 0000000000..b764a7f935 --- /dev/null +++ b/erpnext/patches/1401/p01_make_buying_selling_as_check_box_in_price_list.py @@ -0,0 +1,29 @@ +# Copyright (c) 2014, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes + +def execute(): + webnotes.reload_doc("stock", "doctype", "price_list") + webnotes.reload_doc("stock", "doctype", "item_price") + + if "buying_or_selling" in webnotes.conn.get_table_columns("Price List"): + webnotes.conn.sql("""update `tabPrice List` set + selling = + case + when buying_or_selling='Selling' + then 1 + end, + buying = + case + when buying_or_selling='Buying' + then 1 + end + """) + webnotes.conn.sql("""update `tabItem Price` ip, `tabPrice List` pl + set ip.buying=pl.buying, ip.selling=pl.selling + where ip.price_list=pl.name""") + + webnotes.conn.sql("""update `tabItem Price` set selling=1 where ifnull(selling, 0)=0 and + ifnull(buying, 0)=0""") \ No newline at end of file diff --git a/erpnext/patches/1401/p01_move_related_property_setters_to_custom_field.py b/erpnext/patches/1401/p01_move_related_property_setters_to_custom_field.py new file mode 100644 index 0000000000..cf9221bcfd --- /dev/null +++ b/erpnext/patches/1401/p01_move_related_property_setters_to_custom_field.py @@ -0,0 +1,25 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +import webnotes + +def execute(): + webnotes.reload_doc("core", "doctype", "custom_field") + + cf_doclist = webnotes.get_doctype("Custom Field") + + delete_list = [] + for d in webnotes.conn.sql("""select cf.name as cf_name, ps.property, + ps.value, ps.name as ps_name + from `tabProperty Setter` ps, `tabCustom Field` cf + where ps.doctype_or_field = 'DocField' and ps.property != 'previous_field' + and ps.doc_type=cf.dt and ps.field_name=cf.fieldname""", as_dict=1): + if cf_doclist.get_field(d.property): + webnotes.conn.sql("""update `tabCustom Field` + set `%s`=%s where name=%s""" % (d.property, '%s', '%s'), (d.value, d.cf_name)) + + delete_list.append(d.ps_name) + + if delete_list: + webnotes.conn.sql("""delete from `tabProperty Setter` where name in (%s)""" % + ', '.join(['%s']*len(delete_list)), tuple(delete_list)) \ No newline at end of file diff --git a/erpnext/patches/1401/update_billing_status_for_zero_value_order.py b/erpnext/patches/1401/update_billing_status_for_zero_value_order.py new file mode 100644 index 0000000000..afeed55ed4 --- /dev/null +++ b/erpnext/patches/1401/update_billing_status_for_zero_value_order.py @@ -0,0 +1,29 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +import webnotes +from webnotes.utils import flt + +def execute(): + for order_type in ["Sales", "Purchase"]: + for d in webnotes.conn.sql("""select par.name, sum(ifnull(child.qty, 0)) as total_qty + from `tab%s Order` par, `tab%s Order Item` child + where par.name = child.parent and par.docstatus = 1 + and ifnull(par.net_total, 0) = 0 group by par.name""" % + (order_type, order_type), as_dict=1): + + billed_qty = flt(webnotes.conn.sql("""select sum(ifnull(qty, 0)) + from `tab%s Invoice Item` where %s=%s and docstatus=1""" % + (order_type, "sales_order" if order_type=="Sales" else "purchase_order", '%s'), + (d.name))[0][0]) + + per_billed = ((d.total_qty if billed_qty > d.total_qty else billed_qty)\ + / d.total_qty)*100 + webnotes.conn.set_value(order_type+ " Order", d.name, "per_billed", per_billed) + + if order_type == "Sales": + if per_billed < 0.001: billing_status = "Not Billed" + elif per_billed >= 99.99: billing_status = "Fully Billed" + else: billing_status = "Partly Billed" + + webnotes.conn.set_value("Sales Order", d.name, "billing_status", billing_status) \ No newline at end of file diff --git a/erpnext/patches/june_2013/p03_buying_selling_for_price_list.py b/erpnext/patches/june_2013/p03_buying_selling_for_price_list.py index 2f92fe6a9e..15da085e53 100644 --- a/erpnext/patches/june_2013/p03_buying_selling_for_price_list.py +++ b/erpnext/patches/june_2013/p03_buying_selling_for_price_list.py @@ -8,20 +8,7 @@ from webnotes.utils import cint def execute(): webnotes.reload_doc("stock", "doctype", "price_list") webnotes.reload_doc("stock", "doctype", "item_price") - - try: - for price_list in webnotes.conn.sql_list("""select name from `tabPrice List`"""): - buying, selling = False, False - for b, s in webnotes.conn.sql("""select distinct buying, selling - from `tabItem Price` where price_list_name=%s""", price_list): - buying = buying or cint(b) - selling = selling or cint(s) - - buying_or_selling = "Selling" if selling else "Buying" - webnotes.conn.set_value("Price List", price_list, "buying_or_selling", buying_or_selling) - except webnotes.SQLError, e: - if e.args[0] == 1054: - webnotes.conn.sql("""update `tabPrice List` set buying_or_selling='Selling' - where ifnull(buying_or_selling, '')='' """) - else: - raise \ No newline at end of file + + webnotes.conn.sql("""update `tabPrice List` pl, `tabItem Price` ip + set pl.selling=ip.selling, pl.buying=ip.buying + where pl.name=ip.price_list_name""") \ No newline at end of file diff --git a/erpnext/patches/october_2013/p02_update_price_list_and_item_details_in_item_price.py b/erpnext/patches/october_2013/p02_update_price_list_and_item_details_in_item_price.py index 3b4ca833f1..b92f7d052a 100644 --- a/erpnext/patches/october_2013/p02_update_price_list_and_item_details_in_item_price.py +++ b/erpnext/patches/october_2013/p02_update_price_list_and_item_details_in_item_price.py @@ -12,9 +12,7 @@ def execute(): where ip.item_code=i.name""") webnotes.conn.sql("""update `tabItem Price` ip, `tabPrice List` pl - set ip.price_list=pl.name, ip.currency=pl.currency, - ip.buying_or_selling=pl.buying_or_selling - where ip.parent=pl.name""") + set ip.price_list=pl.name, ip.currency=pl.currency where ip.parent=pl.name""") webnotes.conn.sql("""update `tabItem Price` set parent=null, parenttype=null, parentfield=null, idx=null""") \ No newline at end of file diff --git a/erpnext/patches/patch_list.py b/erpnext/patches/patch_list.py index e455913f59..7c4ac332b0 100644 --- a/erpnext/patches/patch_list.py +++ b/erpnext/patches/patch_list.py @@ -262,4 +262,7 @@ patch_list = [ "execute:webnotes.delete_doc('DocType', 'Warehouse Type')", "patches.1312.p01_delete_old_stock_reports", "patches.1312.p02_update_item_details_in_item_price", + "patches.1401.p01_move_related_property_setters_to_custom_field", + "patches.1401.p01_make_buying_selling_as_check_box_in_price_list", + "patches.1401.update_billing_status_for_zero_value_order", ] \ No newline at end of file diff --git a/erpnext/public/js/conf.js b/erpnext/public/js/conf.js index d902fe1fdc..73099d1f37 100644 --- a/erpnext/public/js/conf.js +++ b/erpnext/public/js/conf.js @@ -24,14 +24,16 @@ $(document).bind('toolbar_setup', function() { wn.provide('wn.ui.misc'); wn.ui.misc.about = function() { if(!wn.ui.misc.about_dialog) { - var d = new wn.ui.Dialog({title: wn._('About ERPNext')}) + var d = new wn.ui.Dialog({title: wn._('About')}) $(d.body).html(repl("
\ -

"+wn._("ERPNext is an open-source web based ERP made by Web Notes Technologies Pvt Ltd. to provide an integrated tool to manage most processes in a small organization. For more information about Web Notes, or to buy hosting servies, go to ")+ - "https://erpnext.com.

\ -

"+wn._("To report an issue, go to ")+"GitHub Issues

\ -
\ +

ERPNext

\ +

"+wn._("An open source ERP made for the web.

") + + "

"+wn._("To report an issue, go to ")+"GitHub Issues

\ +

http://erpnext.org.

\

License: GNU General Public License Version 3

\ +
\ +

© 2014 Web Notes Technologies Pvt. Ltd and contributers

\
", wn.app)); wn.ui.misc.about_dialog = d; diff --git a/erpnext/public/js/controllers/stock_controller.js b/erpnext/public/js/controllers/stock_controller.js index d2fb904419..6a4261c22a 100644 --- a/erpnext/public/js/controllers/stock_controller.js +++ b/erpnext/public/js/controllers/stock_controller.js @@ -28,7 +28,8 @@ erpnext.stock.StockController = wn.ui.form.Controller.extend({ voucher_no: me.frm.doc.name, from_date: me.frm.doc.posting_date, to_date: me.frm.doc.posting_date, - company: me.frm.doc.company + company: me.frm.doc.company, + group_by_voucher: false }; wn.set_route("query-report", "General Ledger"); }, "icon-table"); diff --git a/erpnext/public/js/toolbar.js b/erpnext/public/js/toolbar.js index e0affaf61d..1d6fa919b2 100644 --- a/erpnext/public/js/toolbar.js +++ b/erpnext/public/js/toolbar.js @@ -21,6 +21,6 @@ erpnext.toolbar.setup = function() { '+wn._('Live Chat')+''); } - $("#toolbar-tools").append('
  • \ + $("#toolbar-tools").append('
  • \ Latest Updates
  • '); -} \ No newline at end of file +} diff --git a/erpnext/public/js/transaction.js b/erpnext/public/js/transaction.js index 5b48820c9c..ad73d77616 100644 --- a/erpnext/public/js/transaction.js +++ b/erpnext/public/js/transaction.js @@ -330,8 +330,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ doctype: tax.doctype, row_id_label: wn.meta.get_label(tax.doctype, "row_id", tax.name) }); - msgprint(msg); - throw msg; + wn.throw(msg); } }, @@ -347,8 +346,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name), charge_type: tax.charge_type }); - msgprint(msg); - throw msg; + wn.throw(msg); }; var on_previous_row_error = function(row_range) { @@ -363,8 +361,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ row_range: row_range, }); - msgprint(msg); - throw msg; + wn.throw(msg); }; if(cint(tax.included_in_print_rate)) { @@ -543,6 +540,14 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ calculate_taxes: function() { var me = this; + var actual_tax_dict = {}; + + // maintain actual tax rate based on idx + $.each(this.frm.tax_doclist, function(i, tax) { + if (tax.charge_type == "Actual") { + actual_tax_dict[tax.idx] = flt(tax.rate); + } + }); $.each(this.frm.item_doclist, function(n, item) { var item_tax_map = me._load_item_tax_rate(item.item_tax_rate); @@ -552,15 +557,15 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ var current_tax_amount = me.get_current_tax_amount(item, tax, item_tax_map); me.set_item_tax_amount && me.set_item_tax_amount(item, tax, current_tax_amount); - - // case when net total is 0 but there is an actual type charge - // in this case add the actual amount to tax.tax_amount - // and tax.grand_total_for_current_item for the first such iteration - if(tax.charge_type == "Actual" && - !(current_tax_amount || me.frm.doc.net_total || tax.tax_amount)) { - var zero_net_total_adjustment = flt(tax.rate, precision("tax_amount", tax)); - current_tax_amount += zero_net_total_adjustment; + + // Adjust divisional loss to the last item + if (tax.charge_type == "Actual") { + actual_tax_dict[tax.idx] -= current_tax_amount; + if (n == me.frm.item_doclist.length - 1) { + current_tax_amount += actual_tax_dict[tax.idx] } + } + // store tax_amount for current item as it will be used for // charge type = 'On Previous Row Amount' @@ -592,6 +597,11 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ // in tax.total, accumulate grand total for each item tax.total += tax.grand_total_for_current_item; + + if (n == me.frm.item_doclist.length - 1) { + tax.total = flt(tax.total, precision("total", tax)); + tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax)); + } }); }); }, diff --git a/erpnext/selling/doctype/campaign/campaign.js b/erpnext/selling/doctype/campaign/campaign.js index 6271a163cb..33479579a5 100644 --- a/erpnext/selling/doctype/campaign/campaign.js +++ b/erpnext/selling/doctype/campaign/campaign.js @@ -1,13 +1,2 @@ // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - - - -//--------- ONLOAD ------------- -cur_frm.cscript.onload = function(doc, cdt, cdn) { - -} - -cur_frm.cscript.refresh = function(doc, cdt, cdn) { - -} \ No newline at end of file +// License: GNU General Public License v3. See license.txt \ No newline at end of file diff --git a/erpnext/selling/doctype/campaign/campaign.txt b/erpnext/selling/doctype/campaign/campaign.txt index 07cddd419f..eb7cb89822 100644 --- a/erpnext/selling/doctype/campaign/campaign.txt +++ b/erpnext/selling/doctype/campaign/campaign.txt @@ -2,12 +2,13 @@ { "creation": "2013-01-10 16:34:18", "docstatus": 0, - "modified": "2013-12-20 19:23:58", + "modified": "2014-01-16 12:52:19", "modified_by": "Administrator", "owner": "Administrator" }, { "allow_import": 1, + "allow_rename": 1, "autoname": "field:campaign_name", "description": "Keep Track of Sales Campaigns. Keep track of Leads, Quotations, Sales Order etc from Campaigns to gauge Return on Investment. ", "doctype": "DocType", diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js index e8130aec5e..9578558484 100644 --- a/erpnext/selling/doctype/customer/customer.js +++ b/erpnext/selling/doctype/customer/customer.js @@ -122,6 +122,6 @@ cur_frm.fields_dict.lead_name.get_query = function(doc,cdt,cdn) { cur_frm.fields_dict['default_price_list'].get_query = function(doc,cdt,cdn) { return{ - filters:{'buying_or_selling': "Selling"} + filters:{'selling': 1} } } diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index 00cbd6cd9e..650095c848 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -28,6 +28,7 @@ class TestQuotation(unittest.TestCase): sales_order[0]["delivery_date"] = "2014-01-01" sales_order[0]["naming_series"] = "_T-Quotation-" + sales_order[0]["transaction_date"] = "2013-05-12" webnotes.bean(sales_order).insert() diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 68e6775b49..4ee166c35a 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -56,6 +56,7 @@ class TestSalesOrder(unittest.TestCase): self.assertEquals(len([d for d in si if d["doctype"]=="Sales Invoice Item"]), 1) si = webnotes.bean(si) + si.doc.posting_date = "2013-10-10" si.insert() si.submit() diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index 1c8aed3553..d8afec5cd0 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -48,7 +48,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ if(this.frm.fields_dict.selling_price_list) { this.frm.set_query("selling_price_list", function() { - return { filters: { buying_or_selling: "Selling" } }; + return { filters: { selling: 1 } }; }); } diff --git a/erpnext/selling/utils.py b/erpnext/selling/utils.py index 7949e472dd..118318f5b4 100644 --- a/erpnext/selling/utils.py +++ b/erpnext/selling/utils.py @@ -3,8 +3,8 @@ from __future__ import unicode_literals import webnotes -from webnotes import msgprint, _ -from webnotes.utils import flt, cint, comma_and +from webnotes import _, throw +from webnotes.utils import flt, cint import json def get_customer_list(doctype, txt, searchfield, start, page_len, filters): @@ -100,7 +100,7 @@ def _get_item_code(barcode=None, serial_no=None): where name=%s""", serial_no) if not item_code: - msgprint(_("No Item found with ") + input_type + ": %s" % (barcode or serial_no), raise_exception=True) + throw(_("No Item found with ") + input_type + ": %s" % (barcode or serial_no)) return item_code[0] @@ -111,22 +111,26 @@ def _validate_item_details(args, item): # validate if sales item or service item if args.order_type == "Maintenance": if item.is_service_item != "Yes": - msgprint(_("Item") + (" %s: " % item.name) + + throw(_("Item") + (" %s: " % item.name) + _("not a service item.") + - _("Please select a service item or change the order type to Sales."), - raise_exception=True) + _("Please select a service item or change the order type to Sales.")) elif item.is_sales_item != "Yes": - msgprint(_("Item") + (" %s: " % item.name) + _("not a sales item"), - raise_exception=True) + throw(_("Item") + (" %s: " % item.name) + _("not a sales item")) def _get_basic_details(args, item_bean, warehouse_fieldname): item = item_bean.doc + from webnotes.defaults import get_user_default_as_list + user_default_warehouse_list = get_user_default_as_list('warehouse') + user_default_warehouse = user_default_warehouse_list[0] \ + if len(user_default_warehouse_list)==1 else "" + out = webnotes._dict({ "item_code": item.name, "description": item.description_html or item.description, - warehouse_fieldname: item.default_warehouse or args.get(warehouse_fieldname), + warehouse_fieldname: user_default_warehouse or item.default_warehouse \ + or args.get(warehouse_fieldname), "income_account": item.default_income_account or args.income_account \ or webnotes.conn.get_value("Company", args.company, "default_income_account"), "expense_account": item.purchase_account or args.expense_account \ @@ -147,7 +151,7 @@ def _get_basic_details(args, item_bean, warehouse_fieldname): def _get_price_list_rate(args, item_bean, meta): ref_rate = webnotes.conn.sql("""select ref_rate from `tabItem Price` - where price_list=%s and item_code=%s and buying_or_selling='Selling'""", + where price_list=%s and item_code=%s and selling=1""", (args.selling_price_list, args.item_code), as_dict=1) if not ref_rate: @@ -207,4 +211,4 @@ def apply_pos_settings(pos_settings, opts): if out.get("warehouse"): out["actual_qty"] = get_available_qty(opts.item_code, out.get("warehouse")).get("actual_qty") - return out \ No newline at end of file + return out diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 12281b4415..34e5ca4a59 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import webnotes from webnotes import _, msgprint -from webnotes.utils import cstr +from webnotes.utils import cstr, cint import webnotes.defaults @@ -237,21 +237,24 @@ class DocType: account.insert() def set_default_accounts(self): - accounts = { - "default_income_account": "Sales", - "default_expense_account": "Cost of Goods Sold", + def _set_default_accounts(accounts): + for a in accounts: + account_name = accounts[a] + " - " + self.doc.abbr + if not self.doc.fields.get(a) and webnotes.conn.exists("Account", account_name): + webnotes.conn.set(self.doc, a, account_name) + + _set_default_accounts({ "receivables_group": "Accounts Receivable", "payables_group": "Accounts Payable", - "default_cash_account": "Cash", - "stock_received_but_not_billed": "Stock Received But Not Billed", - "stock_adjustment_account": "Stock Adjustment", - "expenses_included_in_valuation": "Expenses Included In Valuation" - } + "default_cash_account": "Cash" + }) - for a in accounts: - account_name = accounts[a] + " - " + self.doc.abbr - if not self.doc.fields.get(a) and webnotes.conn.exists("Account", account_name): - webnotes.conn.set(self.doc, a, account_name) + if cint(webnotes.conn.get_value("Accounts Settings", None, "auto_accounting_for_stock")): + _set_default_accounts({ + "stock_received_but_not_billed": "Stock Received But Not Billed", + "stock_adjustment_account": "Stock Adjustment", + "expenses_included_in_valuation": "Expenses Included In Valuation" + }) def create_default_cost_center(self): cc_list = [ diff --git a/erpnext/setup/page/setup_wizard/setup_wizard.py b/erpnext/setup/page/setup_wizard/setup_wizard.py index 62989736c7..eec92aad68 100644 --- a/erpnext/setup/page/setup_wizard/setup_wizard.py +++ b/erpnext/setup/page/setup_wizard/setup_wizard.py @@ -98,7 +98,8 @@ def create_price_lists(args): { "doctype": "Price List", "price_list_name": "Standard " + pl_type, - "buying_or_selling": pl_type, + "buying": 1 if pl_type == "Buying" else 0, + "selling": 1 if pl_type == "Selling" else 0, "currency": args["currency"] }, { diff --git a/erpnext/startup/event_handlers.py b/erpnext/startup/event_handlers.py index f9723e13f2..cefd4dc98c 100644 --- a/erpnext/startup/event_handlers.py +++ b/erpnext/startup/event_handlers.py @@ -54,4 +54,4 @@ def check_if_expired(): webnotes.msgprint(msg) webnotes.response['message'] = 'Account Expired' - raise webnotes.AuthenticationError + raise webnotes.AuthenticationError \ No newline at end of file diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index 1ee5e049e4..5fca4f455e 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -29,10 +29,7 @@ cur_frm.cscript.make_dashboard = function() { cur_frm.cscript.edit_prices_button = function() { cur_frm.add_custom_button("Add / Edit Prices", function() { - wn.route_options = { - "item_code": cur_frm.doc.name - }; - wn.set_route("Report", "Item Price"); + wn.set_route("Report", "Item Price", {"item_code": cur_frm.doc.name}); }, "icon-money"); } diff --git a/erpnext/stock/doctype/item_price/item_price.js b/erpnext/stock/doctype/item_price/item_price.js index bece26c6b5..9f38fdb18e 100644 --- a/erpnext/stock/doctype/item_price/item_price.js +++ b/erpnext/stock/doctype/item_price/item_price.js @@ -2,11 +2,10 @@ // License: GNU General Public License v3. See license.txt $.extend(cur_frm.cscript, { - onload: function () { - // Fetch price list details - cur_frm.add_fetch("price_list", "buying_or_selling", "buying_or_selling"); + cur_frm.add_fetch("price_list", "buying", "buying"); + cur_frm.add_fetch("price_list", "selling", "selling"); cur_frm.add_fetch("price_list", "currency", "currency"); // Fetch item details diff --git a/erpnext/stock/doctype/item_price/item_price.py b/erpnext/stock/doctype/item_price/item_price.py index 072d70096e..e2c9f2fcb0 100644 --- a/erpnext/stock/doctype/item_price/item_price.py +++ b/erpnext/stock/doctype/item_price/item_price.py @@ -1,7 +1,5 @@ # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# MIT License. See license.txt - -# For license information, please see license.txt +# License: GNU General Public License v3. See license.txt from __future__ import unicode_literals import webnotes @@ -19,8 +17,8 @@ class DocType: self.update_item_details() def update_price_list_details(self): - self.doc.buying_or_selling, self.doc.currency = webnotes.conn.get_value("Price List", - self.doc.price_list, ["buying_or_selling", "currency"]) + self.doc.buying, self.doc.selling, self.doc.currency = webnotes.conn.get_value("Price List", + self.doc.price_list, ["buying", "selling", "currency"]) def update_item_details(self): self.doc.item_name, self.doc.item_description = webnotes.conn.get_value("Item", diff --git a/erpnext/stock/doctype/item_price/item_price.txt b/erpnext/stock/doctype/item_price/item_price.txt index c21f127b7a..281b7a6e37 100644 --- a/erpnext/stock/doctype/item_price/item_price.txt +++ b/erpnext/stock/doctype/item_price/item_price.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-02 16:29:48", "docstatus": 0, - "modified": "2013-12-20 19:24:10", + "modified": "2014-01-07 19:16:49", "modified_by": "Administrator", "owner": "Administrator" }, @@ -46,6 +46,13 @@ "doctype": "DocType", "name": "Item Price" }, + { + "doctype": "DocField", + "fieldname": "price_list_details", + "fieldtype": "Section Break", + "label": "Price List", + "options": "icon-tags" + }, { "doctype": "DocField", "fieldname": "price_list", @@ -55,6 +62,29 @@ "options": "Price List", "reqd": 1 }, + { + "doctype": "DocField", + "fieldname": "buying", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Buying", + "read_only": 1 + }, + { + "doctype": "DocField", + "fieldname": "selling", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Selling", + "read_only": 1 + }, + { + "doctype": "DocField", + "fieldname": "item_details", + "fieldtype": "Section Break", + "label": "Item", + "options": "icon-tag" + }, { "doctype": "DocField", "fieldname": "item_code", @@ -86,16 +116,6 @@ "fieldname": "col_br_1", "fieldtype": "Column Break" }, - { - "doctype": "DocField", - "fieldname": "buying_or_selling", - "fieldtype": "Select", - "in_filter": 1, - "in_list_view": 1, - "label": "Valid for Buying or Selling?", - "options": "Selling\nBuying", - "reqd": 0 - }, { "doctype": "DocField", "fieldname": "item_name", diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 5266f49257..499fbb0167 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -125,6 +125,7 @@ class TestMaterialRequest(unittest.TestCase): from erpnext.stock.doctype.material_request.material_request import make_purchase_order po_doclist = make_purchase_order(mr.doc.name) po_doclist[0].supplier = "_Test Supplier" + po_doclist[0].transaction_date = "2013-07-07" po_doclist[1].qty = 27.0 po_doclist[2].qty = 1.5 po_doclist[1].schedule_date = "2013-07-09" diff --git a/erpnext/stock/doctype/price_list/price_list.py b/erpnext/stock/doctype/price_list/price_list.py index 7644af5f23..bdcd1df1af 100644 --- a/erpnext/stock/doctype/price_list/price_list.py +++ b/erpnext/stock/doctype/price_list/price_list.py @@ -3,16 +3,15 @@ from __future__ import unicode_literals import webnotes -from webnotes import msgprint, _ -from webnotes.utils import comma_or, cint +from webnotes import msgprint, _, throw +from webnotes.utils import cint from webnotes.model.controller import DocListController import webnotes.defaults class DocType(DocListController): def validate(self): - if self.doc.buying_or_selling not in ["Buying", "Selling"]: - msgprint(_(self.meta.get_label("buying_or_selling")) + " " + _("must be one of") + " " + - comma_or(["Buying", "Selling"]), raise_exception=True) + if not cint(self.doc.buying) and not cint(self.doc.selling): + throw(_("Price List must be applicable for Buying or Selling")) if not self.doclist.get({"parentfield": "valid_for_territories"}): # if no territory, set default territory @@ -25,21 +24,21 @@ class DocType(DocListController): else: # at least one territory self.validate_table_has_rows("valid_for_territories") - + def on_update(self): self.set_default_if_missing() self.update_item_price() - + def set_default_if_missing(self): - if self.doc.buying_or_selling=="Selling": + if cint(self.doc.selling): if not webnotes.conn.get_value("Selling Settings", None, "selling_price_list"): webnotes.set_value("Selling Settings", "Selling Settings", "selling_price_list", self.doc.name) - elif self.doc.buying_or_selling=="Buying": + elif cint(self.doc.buying): if not webnotes.conn.get_value("Buying Settings", None, "buying_price_list"): webnotes.set_value("Buying Settings", "Buying Settings", "buying_price_list", self.doc.name) def update_item_price(self): webnotes.conn.sql("""update `tabItem Price` set currency=%s, - buying_or_selling=%s, modified=NOW() where price_list=%s""", - (self.doc.currency, self.doc.buying_or_selling, self.doc.name)) \ No newline at end of file + buying=%s, selling=%s, modified=NOW() where price_list=%s""", + (self.doc.currency, cint(self.doc.buying), cint(self.doc.selling), self.doc.name)) diff --git a/erpnext/stock/doctype/price_list/price_list.txt b/erpnext/stock/doctype/price_list/price_list.txt index dabc7e0dc9..69d72d9337 100644 --- a/erpnext/stock/doctype/price_list/price_list.txt +++ b/erpnext/stock/doctype/price_list/price_list.txt @@ -2,7 +2,7 @@ { "creation": "2013-01-25 11:35:09", "docstatus": 0, - "modified": "2013-12-20 18:28:50", + "modified": "2014-01-06 18:28:23", "modified_by": "Administrator", "owner": "Administrator" }, @@ -60,14 +60,19 @@ "reqd": 1 }, { - "default": "Selling", "doctype": "DocField", - "fieldname": "buying_or_selling", - "fieldtype": "Select", + "fieldname": "buying", + "fieldtype": "Check", "in_list_view": 1, - "label": "Valid for Buying or Selling?", - "options": "Buying\nSelling", - "reqd": 1 + "label": "Buying" + }, + { + "doctype": "DocField", + "fieldname": "selling", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Selling", + "reqd": 0 }, { "doctype": "DocField", diff --git a/erpnext/stock/doctype/price_list/test_price_list.py b/erpnext/stock/doctype/price_list/test_price_list.py index 86dcd1a594..bdcacc3452 100644 --- a/erpnext/stock/doctype/price_list/test_price_list.py +++ b/erpnext/stock/doctype/price_list/test_price_list.py @@ -12,7 +12,7 @@ test_records = [ "doctype": "Price List", "price_list_name": "_Test Price List", "currency": "INR", - "buying_or_selling": "Selling" + "selling": 1 }, { "doctype": "Applicable Territory", @@ -25,7 +25,7 @@ test_records = [ "doctype": "Price List", "price_list_name": "_Test Price List 2", "currency": "INR", - "buying_or_selling": "Selling" + "selling": 1 }, { "doctype": "Applicable Territory", @@ -38,7 +38,7 @@ test_records = [ "doctype": "Price List", "price_list_name": "_Test Price List India", "currency": "INR", - "buying_or_selling": "Selling" + "selling": 1 }, { "doctype": "Applicable Territory", @@ -51,7 +51,7 @@ test_records = [ "doctype": "Price List", "price_list_name": "_Test Price List Rest of the World", "currency": "USD", - "buying_or_selling": "Selling" + "selling": 1 }, { "doctype": "Applicable Territory", diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt index 4f5004021c..9bc66a42da 100755 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:10", "docstatus": 0, - "modified": "2013-12-20 19:23:36", + "modified": "2014-01-15 16:00:44", "modified_by": "Administrator", "owner": "Administrator" }, @@ -334,6 +334,16 @@ "report_hide": 0, "reqd": 0 }, + { + "default": ":Company", + "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", + "doctype": "DocField", + "fieldname": "cost_center", + "fieldtype": "Link", + "label": "Cost Center", + "options": "Cost Center", + "print_hide": 1 + }, { "doctype": "DocField", "fieldname": "project_name", diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.txt b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.txt index 88c08a77b0..25835e0bf3 100644 --- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.txt +++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-29 18:22:12", "docstatus": 0, - "modified": "2013-12-20 19:21:48", + "modified": "2014-01-15 16:08:45", "modified_by": "Administrator", "owner": "Administrator" }, @@ -165,7 +165,7 @@ "read_only": 1 }, { - "depends_on": "eval:sys_defaults.auto_accounting_for_stock", + "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "doctype": "DocField", "fieldname": "expense_account", "fieldtype": "Link", @@ -175,7 +175,7 @@ }, { "default": ":Company", - "depends_on": "eval:sys_defaults.auto_accounting_for_stock", + "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "doctype": "DocField", "fieldname": "cost_center", "fieldtype": "Link", diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt index f95a1dddba..0a639d5e74 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt @@ -2,7 +2,11 @@ { "creation": "2013-03-28 10:35:31", "docstatus": 0, +<<<<<<< HEAD:erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt "modified": "2013-12-20 16:06:50", +======= + "modified": "2014-01-15 15:45:07", +>>>>>>> dbb495548352d46b30bf84fb4b29ef4a247cb21c:stock/doctype/stock_reconciliation/stock_reconciliation.txt "modified_by": "Administrator", "owner": "Administrator" }, @@ -101,7 +105,7 @@ "reqd": 1 }, { - "depends_on": "eval:sys_defaults.auto_accounting_for_stock", + "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "doctype": "DocField", "fieldname": "expense_account", "fieldtype": "Link", @@ -109,6 +113,7 @@ "options": "Account" }, { + "depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)", "doctype": "DocField", "fieldname": "cost_center", "fieldtype": "Link", diff --git a/erpnext/stock/report/item_prices/item_prices.py b/erpnext/stock/report/item_prices/item_prices.py index da8b5007d5..5eee7df42d 100644 --- a/erpnext/stock/report/item_prices/item_prices.py +++ b/erpnext/stock/report/item_prices/item_prices.py @@ -15,7 +15,7 @@ def execute(filters=None): bom_rate = get_item_bom_rate() val_rate_map = get_valuation_rate() - precision = get_currency_precision or 2 + precision = get_currency_precision() or 2 data = [] for item in sorted(item_map): @@ -65,13 +65,13 @@ def get_price_list(): rate = {} - price_list = webnotes.conn.sql("""select item_code, buying_or_selling, + price_list = webnotes.conn.sql("""select item_code, buying, selling, concat(price_list, " - ", currency, " ", ref_rate) as price from `tabItem Price`""", as_dict=1) for j in price_list: if j.price: - rate.setdefault(j.item_code, {}).setdefault(j.buying_or_selling, []).append(j.price) + rate.setdefault(j.item_code, {}).setdefault("Buying" if j.buying else "Selling", []).append(j.price) item_rate_map = {} for item in rate: diff --git a/erpnext/setup/report/item_wise_price_list_rate/__init__.py b/erpnext/stock/report/item_wise_price_list_rate/__init__.py similarity index 100% rename from erpnext/setup/report/item_wise_price_list_rate/__init__.py rename to erpnext/stock/report/item_wise_price_list_rate/__init__.py diff --git a/erpnext/setup/report/item_wise_price_list_rate/item_wise_price_list_rate.txt b/erpnext/stock/report/item_wise_price_list_rate/item_wise_price_list_rate.txt similarity index 74% rename from erpnext/setup/report/item_wise_price_list_rate/item_wise_price_list_rate.txt rename to erpnext/stock/report/item_wise_price_list_rate/item_wise_price_list_rate.txt index 888203d2b7..f4d1d67ca4 100644 --- a/erpnext/setup/report/item_wise_price_list_rate/item_wise_price_list_rate.txt +++ b/erpnext/stock/report/item_wise_price_list_rate/item_wise_price_list_rate.txt @@ -2,14 +2,14 @@ { "creation": "2013-09-25 10:21:15", "docstatus": 0, - "modified": "2013-10-21 16:06:22", + "modified": "2014-01-07 18:35:22", "modified_by": "Administrator", "owner": "Administrator" }, { "doctype": "Report", "is_standard": "Yes", - "json": "{\"filters\":[[\"Item Price\",\"price_list\",\"like\",\"%\"],[\"Item Price\",\"item_code\",\"like\",\"%\"]],\"columns\":[[\"name\",\"Item Price\"],[\"price_list\",\"Item Price\"],[\"item_code\",\"Item Price\"],[\"item_name\",\"Item Price\"],[\"item_description\",\"Item Price\"],[\"ref_rate\",\"Item Price\"],[\"buying_or_selling\",\"Item Price\"],[\"currency\",\"Item Price\"]],\"sort_by\":\"Item Price.modified\",\"sort_order\":\"desc\",\"sort_by_next\":\"\",\"sort_order_next\":\"desc\"}", + "json": "{\"filters\":[[\"Item Price\",\"price_list\",\"like\",\"%\"],[\"Item Price\",\"item_code\",\"like\",\"%\"]],\"columns\":[[\"name\",\"Item Price\"],[\"price_list\",\"Item Price\"],[\"item_code\",\"Item Price\"],[\"item_name\",\"Item Price\"],[\"item_description\",\"Item Price\"],[\"ref_rate\",\"Item Price\"],[\"buying\",\"Item Price\"],[\"selling\",\"Item Price\"],[\"currency\",\"Item Price\"]],\"sort_by\":\"Item Price.modified\",\"sort_order\":\"desc\",\"sort_by_next\":\"\",\"sort_order_next\":\"desc\"}", "name": "__common__", "ref_doctype": "Price List", "report_name": "Item-wise Price List Rate", diff --git a/erpnext/support/doctype/customer_issue/customer_issue.txt b/erpnext/support/doctype/customer_issue/customer_issue.txt index ae16c2ccf7..cc17fec7c9 100644 --- a/erpnext/support/doctype/customer_issue/customer_issue.txt +++ b/erpnext/support/doctype/customer_issue/customer_issue.txt @@ -2,11 +2,12 @@ { "creation": "2013-01-10 16:34:30", "docstatus": 0, - "modified": "2013-12-20 19:24:02", + "modified": "2014-01-14 15:56:22", "modified_by": "Administrator", "owner": "harshada@webnotestech.com" }, { + "allow_import": 1, "autoname": "naming_series:", "doctype": "DocType", "icon": "icon-bug", diff --git a/erpnext/support/doctype/support_ticket/get_support_mails.py b/erpnext/support/doctype/support_ticket/get_support_mails.py index b50e46ea08..49bd155c38 100644 --- a/erpnext/support/doctype/support_ticket/get_support_mails.py +++ b/erpnext/support/doctype/support_ticket/get_support_mails.py @@ -52,11 +52,6 @@ Original Query: subject = '['+cstr(d.name)+'] ' + cstr(d.subject), \ msg = cstr(response)) - def auto_close_tickets(self): - webnotes.conn.sql("""update `tabSupport Ticket` set status = 'Closed' - where status = 'Replied' - and date_sub(curdate(),interval 15 Day) > modified""") - def get_support_mails(): if cint(webnotes.conn.get_value('Email Settings', None, 'sync_support_mails')): SupportMailbox() diff --git a/erpnext/support/doctype/support_ticket/support_ticket.py b/erpnext/support/doctype/support_ticket/support_ticket.py index 0b95292c6a..1b14ccc328 100644 --- a/erpnext/support/doctype/support_ticket/support_ticket.py +++ b/erpnext/support/doctype/support_ticket/support_ticket.py @@ -66,4 +66,9 @@ class DocType(TransactionBase): def set_status(name, status): st = webnotes.bean("Support Ticket", name) st.doc.status = status - st.save() \ No newline at end of file + st.save() + +def auto_close_tickets(): + webnotes.conn.sql("""update `tabSupport Ticket` set status = 'Closed' + where status = 'Replied' + and date_sub(curdate(),interval 15 Day) > modified""") diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py index eed463961c..2c6357acff 100644 --- a/erpnext/utilities/transaction_base.py +++ b/erpnext/utilities/transaction_base.py @@ -78,10 +78,12 @@ class TransactionBase(StatusUpdater): 3. Clears existing Sales Team and fetches the one mentioned in Customer """ customer_defaults = self.get_customer_defaults() - - customer_defaults["selling_price_list"] = customer_defaults.get("price_list") or \ - webnotes.conn.get_value("Customer Group", self.doc.customer_group, "default_price_list") or \ - self.doc.selling_price_list + + customer_defaults["selling_price_list"] = \ + self.get_user_default_price_list("selling_price_list") or \ + customer_defaults.get("price_list") or \ + webnotes.conn.get_value("Customer Group", self.doc.customer_group, + "default_price_list") or self.doc.selling_price_list for fieldname, val in customer_defaults.items(): if self.meta.get_field(fieldname): @@ -90,6 +92,12 @@ class TransactionBase(StatusUpdater): if self.meta.get_field("sales_team") and self.doc.customer: self.set_sales_team_for_customer() + def get_user_default_price_list(self, price_list): + from webnotes.defaults import get_defaults_for + user_default_price_list = get_defaults_for(webnotes.session.user).get(price_list) + return cstr(user_default_price_list) \ + if not isinstance(user_default_price_list, list) else "" + def set_sales_team_for_customer(self): from webnotes.model import default_fields @@ -120,8 +128,9 @@ class TransactionBase(StatusUpdater): out["supplier_name"] = supplier.supplier_name if supplier.default_currency: out["currency"] = supplier.default_currency - if supplier.default_price_list: - out["buying_price_list"] = supplier.default_price_list + + out["buying_price_list"] = self.get_user_default_price_list("buying_price_list") or \ + supplier.default_price_list or self.doc.buying_price_list return out diff --git a/install_erpnext.py b/install_erpnext.py index c95a03d3e5..8e1448362b 100644 --- a/install_erpnext.py +++ b/install_erpnext.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import os, sys import argparse +import subprocess is_redhat = is_debian = None root_password = None @@ -19,7 +20,7 @@ requirements = [ "jinja2", "markdown2", "markupsafe", - "mysql-python", + "mysql-python", "pygeoip", "python-dateutil", "python-memcached", @@ -80,7 +81,7 @@ def validate_install(): return is_redhat, is_debian def install_using_yum(): - packages = "python python-setuptools gcc python-devel MySQL-python git memcached ntp vim-enhanced screen" + packages = "gcc MySQL-python git memcached ntp vim-enhanced screen" print "-"*80 print "Installing Packages: (This may take some time)" @@ -88,7 +89,10 @@ def install_using_yum(): print "-"*80 exec_in_shell("yum install -y %s" % packages) - if not exec_in_shell("which mysql"): + + try: + exec_in_shell("which mysql") + except subprocess.CalledProcessError: packages = "mysql mysql-server mysql-devel" print "Installing Packages:", packages exec_in_shell("yum install -y %s" % packages) @@ -101,26 +105,19 @@ def install_using_yum(): exec_in_shell('mysqladmin -u root password "%s"' % (root_password,)) print "Root password set as", root_password - # install htop - if not exec_in_shell("which htop"): - try: - exec_in_shell("cd /tmp && rpm -i --force http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm && yum install -y htop") - except: - pass - update_config_for_redhat() def update_config_for_redhat(): import re # set to autostart on startup - for service in ("mysqld", "memcached", "ntpd"): + for service in ("mysqld", "memcached"): exec_in_shell("chkconfig --level 2345 %s on" % service) exec_in_shell("service %s restart" % service) def install_using_apt(): exec_in_shell("apt-get update") - packages = "python python-setuptools python-dev build-essential python-pip python-mysqldb git memcached ntp vim screen htop" + packages = "python python-setuptools python-dev build-essential python-mysqldb git memcached ntp vim screen htop" print "-"*80 print "Installing Packages: (This may take some time)" print packages @@ -132,7 +129,9 @@ def install_using_apt(): exec_in_shell("echo mysql-server mysql-server/root_password password %s | sudo debconf-set-selections" % root_password) exec_in_shell("echo mysql-server mysql-server/root_password_again password %s | sudo debconf-set-selections" % root_password) - if not exec_in_shell("which mysql"): + try: + exec_in_shell("which mysql") + except subprocess.CalledProcessError: packages = "mysql-server libmysqlclient-dev" print "Installing Packages:", packages exec_in_shell("apt-get install -y %s" % packages) @@ -140,7 +139,7 @@ def install_using_apt(): update_config_for_debian() def update_config_for_debian(): - for service in ("mysql", "ntpd"): + for service in ("mysql",): exec_in_shell("service %s restart" % service) def install_python_modules(): @@ -148,13 +147,14 @@ def install_python_modules(): print "Installing Python Modules: (This may take some time)" print "-"*80 - if not exec_in_shell("which pip"): - exec_in_shell("easy_install pip") + try: + exec_in_shell("which pip2.7") + except subprocess.CalledProcessError: + exec_in_shell("easy_install-2.7 pip") - exec_in_shell("pip install --upgrade pip") - exec_in_shell("pip install --upgrade setuptools") - exec_in_shell("pip install --upgrade virtualenv") - exec_in_shell("pip install {}".format(' '.join(requirements))) + exec_in_shell("pip2.7 install --upgrade setuptools --no-use-wheel") + exec_in_shell("pip2.7 install --upgrade setuptools") + exec_in_shell("pip2.7 install {}".format(' '.join(requirements))) def install_erpnext(install_path): print @@ -200,7 +200,7 @@ def setup_folders(install_path): app = os.path.join(install_path, "app") if not os.path.exists(app): print "Cloning erpnext" - exec_in_shell("cd %s && git clone https://github.com/webnotes/erpnext.git app" % install_path) + exec_in_shell("cd %s && git clone --branch master https://github.com/webnotes/erpnext.git app" % install_path) exec_in_shell("cd app && git config core.filemode false") if not os.path.exists(app): raise Exception, "Couldn't clone erpnext repository" @@ -208,7 +208,7 @@ def setup_folders(install_path): lib = os.path.join(install_path, "lib") if not os.path.exists(lib): print "Cloning wnframework" - exec_in_shell("cd %s && git clone https://github.com/webnotes/wnframework.git lib" % install_path) + exec_in_shell("cd %s && git clone --branch master https://github.com/webnotes/wnframework.git lib" % install_path) exec_in_shell("cd lib && git config core.filemode false") if not os.path.exists(lib): raise Exception, "Couldn't clone wnframework repository" @@ -243,28 +243,8 @@ def post_install(install_path): def exec_in_shell(cmd): # using Popen instead of os.system - as recommended by python docs - from subprocess import Popen - import tempfile - - with tempfile.TemporaryFile() as stdout: - with tempfile.TemporaryFile() as stderr: - p = Popen(cmd, shell=True, stdout=stdout, stderr=stderr) - p.wait() - - stdout.seek(0) - out = stdout.read() - if out: out = out.decode('utf-8') - - stderr.seek(0) - err = stderr.read() - if err: err = err.decode('utf-8') - - if err and any((kw in err.lower() for kw in ["traceback", "error", "exception"])): - print out - raise Exception, err - else: - print "." - + import subprocess + out = subprocess.check_output(cmd, shell=True) return out def parse_args():
    ItemQtyItemQtyRate
    %(item_code)s%(item_name)s\ +
    \ + \ +
    \ +
    \ +
    \ + \ +
    \ +
    %(amount)s
    %(rate)s
    %(description)s %(rate)s%(tax_amount)s
    %(description)s %(rate)s%(tax_amount)s