From 41236ed0e5a73ed3c767cd9812ddaf7cc6b51e90 Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Wed, 12 Dec 2018 05:12:20 +0500 Subject: [PATCH 01/38] feat: Customer Ledger Summary report --- .../customer_ledger_summary/__init__.py | 0 .../customer_ledger_summary.js | 97 +++++++ .../customer_ledger_summary.json | 26 ++ .../customer_ledger_summary.py | 264 ++++++++++++++++++ 4 files changed, 387 insertions(+) create mode 100644 erpnext/accounts/report/customer_ledger_summary/__init__.py create mode 100644 erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.js create mode 100644 erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.json create mode 100644 erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py diff --git a/erpnext/accounts/report/customer_ledger_summary/__init__.py b/erpnext/accounts/report/customer_ledger_summary/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.js b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.js new file mode 100644 index 00000000000..105977b6e4d --- /dev/null +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.js @@ -0,0 +1,97 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Customer Ledger Summary"] = { + "filters": [ + { + "fieldname":"company", + "label": __("Company"), + "fieldtype": "Link", + "options": "Company", + "default": frappe.defaults.get_user_default("Company") + }, + { + "fieldname":"from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1), + "reqd": 1, + "width": "60px" + }, + { + "fieldname":"to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.get_today(), + "reqd": 1, + "width": "60px" + }, + { + "fieldname":"finance_book", + "label": __("Finance Book"), + "fieldtype": "Link", + "options": "Finance Book" + }, + { + "fieldname":"party", + "label": __("Customer"), + "fieldtype": "Link", + "options": "Customer", + on_change: () => { + var customer = frappe.query_report.get_filter_value('customer'); + if (customer) { + frappe.db.get_value('Customer', customer, ["tax_id", "customer_name", "credit_limit", "payment_terms"], function(value) { + frappe.query_report.set_filter_value('tax_id', value["tax_id"]); + frappe.query_report.set_filter_value('customer_name', value["customer_name"]); + }); + } else { + frappe.query_report.set_filter_value('tax_id', ""); + frappe.query_report.set_filter_value('customer_name', ""); + } + } + }, + { + "fieldname":"customer_group", + "label": __("Customer Group"), + "fieldtype": "Link", + "options": "Customer Group" + }, + { + "fieldname":"payment_terms_template", + "label": __("Payment Terms Template"), + "fieldtype": "Link", + "options": "Payment Terms Template" + }, + { + "fieldname":"territory", + "label": __("Territory"), + "fieldtype": "Link", + "options": "Territory" + }, + { + "fieldname":"sales_partner", + "label": __("Sales Partner"), + "fieldtype": "Link", + "options": "Sales Partner" + }, + { + "fieldname":"sales_person", + "label": __("Sales Person"), + "fieldtype": "Link", + "options": "Sales Person" + }, + { + "fieldname":"tax_id", + "label": __("Tax Id"), + "fieldtype": "Data", + "hidden": 1 + }, + { + "fieldname":"customer_name", + "label": __("Customer Name"), + "fieldtype": "Data", + "hidden": 1 + } + ] +}; diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.json b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.json new file mode 100644 index 00000000000..91e4e197d3a --- /dev/null +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.json @@ -0,0 +1,26 @@ +{ + "add_total_row": 1, + "creation": "2018-12-11 00:58:19.078506", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "idx": 0, + "is_standard": "Yes", + "modified": "2018-12-11 00:59:21.708343", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Customer Ledger Summary", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Sales Invoice", + "report_name": "Customer Ledger Summary", + "report_type": "Script Report", + "roles": [ + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + } + ] +} \ No newline at end of file diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py new file mode 100644 index 00000000000..0b590db49dc --- /dev/null +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py @@ -0,0 +1,264 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +import erpnext +from frappe import _, scrub +from frappe.utils import getdate, nowdate, flt, cint + +class PartyLedgerSummaryReport(object): + def __init__(self, filters=None): + self.filters = frappe._dict(filters or {}) + self.filters.from_date = getdate(self.filters.from_date or nowdate()) + self.filters.to_date = getdate(self.filters.to_date or nowdate()) + + def run(self, args): + if self.filters.from_date > self.filters.to_date: + frappe.throw(_("From Date must be before To Date")) + + self.filters.party_type = args.get("party_type") + self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1]) + + columns = self.get_columns() + data = self.get_data() + return columns, data + + def get_columns(self): + columns = [{ + "label": _(self.filters.party_type), + "fieldtype": "Link", + "fieldname": "party", + "options": self.filters.party_type, + "width": 200 + }] + + if self.party_naming_by == "Naming Series": + columns.append({ + "label": _(self.filters.party_type + "Name"), + "fieldtype": "Data", + "fieldname": "party_name", + "width": 110 + }) + + credit_or_debit_note = "Credit Note" if self.filters.party_type == "Customer" else "Debit Note" + columns += [ + { + "label": _("Opening Balance"), + "fieldname": "opening_balance", + "fieldtype": "Currency", + "width": 120 + }, + { + "label": _("Invoiced Amount"), + "fieldname": "invoiced_amount", + "fieldtype": "Currency", + "width": 120 + }, + { + "label": _("Paid Amount"), + "fieldname": "paid_amount", + "fieldtype": "Currency", + "width": 120 + }, + { + "label": _(credit_or_debit_note), + "fieldname": "return_amount", + "fieldtype": "Currency", + "width": 120 + }, + { + "label": _("Write Off Amount"), + "fieldname": "write_off_amount", + "fieldtype": "Currency", + "width": 120 + }, + { + "label": _("Closing Balance"), + "fieldname": "closing_balance", + "fieldtype": "Currency", + "width": 120 + } + ] + + return columns + + def get_data(self): + if not self.filters.get("company"): + self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company') + + credit_or_debit_note = "Credit Note" if self.filters.party_type == "Customer" else "Debit Note" + invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit" + reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit" + + self.get_gl_entries() + self.get_return_invoices() + self.get_party_write_off_amounts() + + self.party_data = frappe._dict({}) + for gle in self.gl_entries: + self.party_data.setdefault(gle.party, frappe._dict({ + "party": gle.party, + "party_name": "", # TODO add party_name + "opening_balance": 0, + "invoiced_amount": 0, + "paid_amount": -self.party_write_off_amounts.get(gle.party, 0), + "return_amount": 0, + "write_off_amount": self.party_write_off_amounts.get(gle.party, 0), + "closing_balance": 0 + })) + + amount = gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr) + self.party_data[gle.party].closing_balance += amount + + if gle.posting_date < self.filters.from_date: + self.party_data[gle.party].opening_balance += amount + else: + if amount > 0: + self.party_data[gle.party].invoiced_amount += amount + elif gle.voucher_no in self.return_invoices: + self.party_data[gle.party].return_amount -= amount + else: + self.party_data[gle.party].paid_amount -= amount + + return [d for d in self.party_data.values() if d.opening_balance or d.invoiced_amount or d.paid_amount + or d.return_amount or d.write_off_amount or d.closing_amount] + + def get_gl_entries(self): + conditions = self.prepare_conditions() + + self.gl_entries = frappe.db.sql(""" + select + posting_date, party, voucher_type, voucher_no, against_voucher_type, against_voucher, debit, credit + from + `tabGL Entry` + where + docstatus < 2 and party_type=%(party_type)s and ifnull(party, '') != '' and posting_date <= %(to_date)s + {0} + order by posting_date""".format(conditions), self.filters, as_dict=True) + + def prepare_conditions(self): + conditions = [""] + + if self.filters.company: + conditions.append("company=%(company)s") + + self.filters.company_finance_book = erpnext.get_default_finance_book(self.filters.company) + + if not self.filters.finance_book or (self.filters.finance_book == self.filters.company_finance_book): + conditions.append("ifnull(finance_book,'') in (%(company_finance_book)s, '')") + elif self.filters.finance_book: + conditions.append("ifnull(finance_book,'') = %(finance_book)s") + + if self.filters.get("party"): + conditions.append("party=%(party)s") + + if self.filters.party_type == "Customer": + if self.filters.get("customer_group"): + lft, rgt = frappe.db.get_value("Customer Group", + self.filters.get("customer_group"), ["lft", "rgt"]) + + conditions.append("""party in (select name from tabCustomer + where exists(select name from `tabCustomer Group` where lft >= {0} and rgt <= {1} + and name=tabCustomer.customer_group))""".format(lft, rgt)) + + if self.filters.get("territory"): + lft, rgt = frappe.db.get_value("Territory", + self.filters.get("territory"), ["lft", "rgt"]) + + conditions.append("""party in (select name from tabCustomer + where exists(select name from `tabTerritory` where lft >= {0} and rgt <= {1} + and name=tabCustomer.territory))""".format(lft, rgt)) + + if self.filters.get("payment_terms_template"): + conditions.append("party in (select name from tabCustomer where payment_terms=%(payment_terms_template)s)") + + if self.filters.get("sales_partner"): + conditions.append("party in (select name from tabCustomer where default_sales_partner=%(sales_partner)s)") + + if self.filters.get("sales_person"): + lft, rgt = frappe.db.get_value("Sales Person", + self.filters.get("sales_person"), ["lft", "rgt"]) + + conditions.append("""party in (select parent from `tabSales Team` + where parenttype = 'Customer' and exists(select name from `tabSales Person` + where lft >= {0} and rgt <= {1} and name=`tabSales Team`.sales_person))""".format(lft, rgt)) + + if self.filters.party_type == "Supplier": + if self.filters.get("supplier_group"): + conditions.append("""party in (select name from tabSupplier + where supplier_group=%(supplier_group)s)""") + + return " and ".join(conditions) + + def get_return_invoices(self): + doctype = "Sales Invoice" if self.filters.party_type == "Customer" else "Purchase Invoice" + self.return_invoices = [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1, + "posting_date": ["between", [self.filters.from_date, self.filters.to_date]]})] + + def get_party_write_off_amounts(self): + conditions = self.prepare_conditions() + income_or_expense = "Expense Account" if self.filters.party_type == "Customer" else "Income Account" + invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit" + reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit" + round_off_account = frappe.get_cached_value('Company', self.filters.company, "round_off_account") + + gl_entries = frappe.db.sql(""" + select + posting_date, account, party, voucher_type, voucher_no, debit, credit + from + `tabGL Entry` + where + docstatus < 2 + and (voucher_type, voucher_no) in ( + select voucher_type, voucher_no from `tabGL Entry` gle, `tabAccount` acc + where acc.name = gle.account and acc.account_type = '{income_or_expense}' + and gle.posting_date between %(from_date)s and %(to_date)s and gle.docstatus < 2 + ) and (voucher_type, voucher_no) in ( + select voucher_type, voucher_no from `tabGL Entry` gle + where gle.party_type=%(party_type)s and ifnull(party, '') != '' + and gle.posting_date between %(from_date)s and %(to_date)s and gle.docstatus < 2 {conditions} + ) + order by posting_date + """.format(conditions=conditions, income_or_expense=income_or_expense), self.filters, as_dict=True) + + self.party_write_off_amounts = {} + write_off_voucher_entries = {} + for gle in gl_entries: + write_off_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), []) + write_off_voucher_entries[(gle.voucher_type, gle.voucher_no)].append(gle) + + for voucher, voucher_gl_entries in write_off_voucher_entries.iteritems(): + parties = {} + write_offs = {} + has_irrelevant_entry = False + + for gle in voucher_gl_entries: + if gle.account == round_off_account: + continue + elif gle.party: + parties.setdefault(gle.party, 0) + parties[gle.party] += gle.get(reverse_dr_or_cr) - gle.get(invoice_dr_or_cr) + elif frappe.get_cached_value("Account", gle.account, "account_type") == income_or_expense: + write_offs.setdefault(gle.account, 0) + write_offs[gle.account] += gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr) + else: + has_irrelevant_entry = True + + if parties and write_offs: + if len(parties) == 1: + for account, amount in write_offs.iteritems(): + party = parties.keys()[0] + self.party_write_off_amounts.setdefault(party, 0) + self.party_write_off_amounts[party] += amount + elif len(write_offs) == 1 and not has_irrelevant_entry: + for party, amount in parties.iteritems(): + self.party_write_off_amounts.setdefault(party, 0) + self.party_write_off_amounts[party] += amount + +def execute(filters=None): + args = { + "party_type": "Customer", + "naming_by": ["Selling Settings", "cust_master_name"], + } + return PartyLedgerSummaryReport(filters).run(args) \ No newline at end of file From b07d108beeb361309df1cb11d3be831e5f24841c Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Wed, 12 Dec 2018 05:45:49 +0500 Subject: [PATCH 02/38] feat: Supplier Ledger Summary --- .../customer_ledger_summary.js | 6 +- .../customer_ledger_summary.py | 18 +++- .../supplier_ledger_summary/__init__.py | 0 .../supplier_ledger_summary.js | 97 +++++++++++++++++++ .../supplier_ledger_summary.json | 27 ++++++ .../supplier_ledger_summary.py | 13 +++ 6 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 erpnext/accounts/report/supplier_ledger_summary/__init__.py create mode 100644 erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js create mode 100644 erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.json create mode 100644 erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.py diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.js b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.js index 105977b6e4d..a1236316638 100644 --- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.js +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.js @@ -39,9 +39,9 @@ frappe.query_reports["Customer Ledger Summary"] = { "fieldtype": "Link", "options": "Customer", on_change: () => { - var customer = frappe.query_report.get_filter_value('customer'); - if (customer) { - frappe.db.get_value('Customer', customer, ["tax_id", "customer_name", "credit_limit", "payment_terms"], function(value) { + var party = frappe.query_report.get_filter_value('party'); + if (party) { + frappe.db.get_value('Customer', party, ["tax_id", "customer_name"], function(value) { frappe.query_report.set_filter_value('tax_id', value["tax_id"]); frappe.query_report.set_filter_value('customer_name', value["customer_name"]); }); diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py index 0b590db49dc..63a3498f004 100644 --- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py @@ -47,37 +47,50 @@ class PartyLedgerSummaryReport(object): "label": _("Opening Balance"), "fieldname": "opening_balance", "fieldtype": "Currency", + "options": "currency", "width": 120 }, { "label": _("Invoiced Amount"), "fieldname": "invoiced_amount", "fieldtype": "Currency", + "options": "currency", "width": 120 }, { "label": _("Paid Amount"), "fieldname": "paid_amount", "fieldtype": "Currency", + "options": "currency", "width": 120 }, { "label": _(credit_or_debit_note), "fieldname": "return_amount", "fieldtype": "Currency", + "options": "currency", "width": 120 }, { "label": _("Write Off Amount"), "fieldname": "write_off_amount", "fieldtype": "Currency", + "options": "currency", "width": 120 }, { "label": _("Closing Balance"), "fieldname": "closing_balance", "fieldtype": "Currency", + "options": "currency", "width": 120 + }, + { + "label": _("Currency"), + "fieldname": "currency", + "fieldtype": "Link", + "options": "Currency", + "width": 50 } ] @@ -87,7 +100,7 @@ class PartyLedgerSummaryReport(object): if not self.filters.get("company"): self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company') - credit_or_debit_note = "Credit Note" if self.filters.party_type == "Customer" else "Debit Note" + company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency") invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit" reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit" @@ -105,7 +118,8 @@ class PartyLedgerSummaryReport(object): "paid_amount": -self.party_write_off_amounts.get(gle.party, 0), "return_amount": 0, "write_off_amount": self.party_write_off_amounts.get(gle.party, 0), - "closing_balance": 0 + "closing_balance": 0, + "currency": company_currency })) amount = gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr) diff --git a/erpnext/accounts/report/supplier_ledger_summary/__init__.py b/erpnext/accounts/report/supplier_ledger_summary/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js new file mode 100644 index 00000000000..6fd16f20908 --- /dev/null +++ b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js @@ -0,0 +1,97 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Supplier Ledger Summary"] = { + "filters": [ + { + "fieldname":"company", + "label": __("Company"), + "fieldtype": "Link", + "options": "Company", + "default": frappe.defaults.get_user_default("Company") + }, + { + "fieldname":"from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1), + "reqd": 1, + "width": "60px" + }, + { + "fieldname":"to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.get_today(), + "reqd": 1, + "width": "60px" + }, + { + "fieldname":"finance_book", + "label": __("Finance Book"), + "fieldtype": "Link", + "options": "Finance Book" + }, + { + "fieldname":"party", + "label": __("Customer"), + "fieldtype": "Link", + "options": "Customer", + on_change: () => { + var party = frappe.query_report.get_filter_value('party'); + if (party) { + frappe.db.get_value('Supplier', party, ["tax_id", "supplier_name"], function(value) { + frappe.query_report.set_filter_value('tax_id', value["tax_id"]); + frappe.query_report.set_filter_value('supplier_name', value["supplier_name"]); + }); + } else { + frappe.query_report.set_filter_value('tax_id', ""); + frappe.query_report.set_filter_value('supplier_name', ""); + } + } + }, + { + "fieldname":"supplier_group", + "label": __("Supplier Group"), + "fieldtype": "Link", + "options": "Supplier Group" + }, + { + "fieldname":"payment_terms_template", + "label": __("Payment Terms Template"), + "fieldtype": "Link", + "options": "Payment Terms Template" + }, + { + "fieldname":"territory", + "label": __("Territory"), + "fieldtype": "Link", + "options": "Territory" + }, + { + "fieldname":"sales_partner", + "label": __("Sales Partner"), + "fieldtype": "Link", + "options": "Sales Partner" + }, + { + "fieldname":"sales_person", + "label": __("Sales Person"), + "fieldtype": "Link", + "options": "Sales Person" + }, + { + "fieldname":"tax_id", + "label": __("Tax Id"), + "fieldtype": "Data", + "hidden": 1 + }, + { + "fieldname":"supplier_name", + "label": __("Supplier Name"), + "fieldtype": "Data", + "hidden": 1 + } + ] +}; diff --git a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.json b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.json new file mode 100644 index 00000000000..eb3b4123e23 --- /dev/null +++ b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.json @@ -0,0 +1,27 @@ +{ + "add_total_row": 1, + "creation": "2018-12-12 05:10:02.987274", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "idx": 0, + "is_standard": "Yes", + "letter_head": "Capital Traders", + "modified": "2018-12-12 05:10:02.987274", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Supplier Ledger Summary", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Purchase Invoice", + "report_name": "Supplier Ledger Summary", + "report_type": "Script Report", + "roles": [ + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + } + ] +} \ No newline at end of file diff --git a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.py b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.py new file mode 100644 index 00000000000..d2c23ee4e78 --- /dev/null +++ b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from erpnext.accounts.report.customer_ledger_summary.customer_ledger_summary import PartyLedgerSummaryReport + +def execute(filters=None): + args = { + "party_type": "Supplier", + "naming_by": ["Buying Settings", "supp_master_name"], + } + return PartyLedgerSummaryReport(filters).run(args) \ No newline at end of file From b53231595d5649ed9fb3d45853ab46ae73240e52 Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Wed, 12 Dec 2018 15:46:50 +0500 Subject: [PATCH 03/38] Using same filter for Sales Person from Accounts Receivable Added Customer/Supplier Ledger Summary in Accounts Module page --- .../customer_ledger_summary.py | 11 +++-- erpnext/config/accounts.py | 48 ++++++++++++------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py index 63a3498f004..2b228fd6b6f 100644 --- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py @@ -194,9 +194,14 @@ class PartyLedgerSummaryReport(object): lft, rgt = frappe.db.get_value("Sales Person", self.filters.get("sales_person"), ["lft", "rgt"]) - conditions.append("""party in (select parent from `tabSales Team` - where parenttype = 'Customer' and exists(select name from `tabSales Person` - where lft >= {0} and rgt <= {1} and name=`tabSales Team`.sales_person))""".format(lft, rgt)) + conditions.append("""exists(select name from `tabSales Team` steam where + steam.sales_person in (select name from `tabSales Person` where lft >= {0} and rgt <= {1}) + and ((steam.parent = voucher_no and steam.parenttype = voucher_type) + or (steam.parent = against_voucher and steam.parenttype = against_voucher_type) + or (steam.parent = party and steam.parenttype = 'Customer')))""".format(lft, rgt)) + #conditions.append("""party in (select parent from `tabSales Team` + # where parenttype = 'Customer' and exists(select name from `tabSales Person` + # where lft >= {0} and rgt <= {1} and name=`tabSales Team`.sales_person))""".format(lft, rgt)) if self.filters.party_type == "Supplier": if self.filters.get("supplier_group"): diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py index 15996c3a44b..bfa71624008 100644 --- a/erpnext/config/accounts.py +++ b/erpnext/config/accounts.py @@ -351,6 +351,36 @@ def get_data(): "is_query_report": True, "doctype": "Sales Invoice" }, + { + "type": "report", + "name": "Item-wise Sales Register", + "is_query_report": True, + "doctype": "Sales Invoice" + }, + { + "type": "report", + "name": "Item-wise Purchase Register", + "is_query_report": True, + "doctype": "Purchase Invoice" + }, + { + "type": "report", + "name": "Profitability Analysis", + "doctype": "GL Entry", + "is_query_report": True, + }, + { + "type": "report", + "name": "Customer Ledger Summary", + "doctype": "Sales Invoice", + "is_query_report": True, + }, + { + "type": "report", + "name": "Supplier Ledger Summary", + "doctype": "Sales Invoice", + "is_query_report": True, + } ] }, { @@ -363,12 +393,6 @@ def get_data(): "doctype": "GL Entry", "is_query_report": True, }, - { - "type": "report", - "name": "Profitability Analysis", - "doctype": "GL Entry", - "is_query_report": True, - }, { "type": "report", "name": "Payment Period Based On Invoice Date", @@ -381,18 +405,6 @@ def get_data(): "is_query_report": True, "doctype": "Sales Invoice" }, - { - "type": "report", - "name": "Item-wise Sales Register", - "is_query_report": True, - "doctype": "Sales Invoice" - }, - { - "type": "report", - "name": "Item-wise Purchase Register", - "is_query_report": True, - "doctype": "Purchase Invoice" - }, { "type": "report", "name": "Accounts Receivable Summary", From 701c762a68d6d88f1a8553aa1f67b01cc5ba643a Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 9 Jan 2019 14:07:55 +0530 Subject: [PATCH 04/38] Show outward entries in negative for Bank Clearance Summary report --- .../report/bank_clearance_summary/bank_clearance_summary.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py index 13424dbcb56..0861b20f14a 100644 --- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py +++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py @@ -36,8 +36,8 @@ def get_conditions(filters): def get_entries(filters): conditions = get_conditions(filters) journal_entries = frappe.db.sql("""SELECT - "Journal Entry", jv.name, jv.posting_date, jv.cheque_no, jv.clearance_date, jvd.against_account, - if((jvd.debit - jvd.credit) < 0, (jvd.debit - jvd.credit) * -1, (jvd.debit - jvd.credit)) + "Journal Entry", jv.name, jv.posting_date, jv.cheque_no, + jv.clearance_date, jvd.against_account, jvd.debit - jvd.credit FROM `tabJournal Entry Account` jvd, `tabJournal Entry` jv WHERE @@ -46,7 +46,7 @@ def get_entries(filters): payment_entries = frappe.db.sql("""SELECT "Payment Entry", name, posting_date, reference_no, clearance_date, party, - if(paid_from=%(account)s, paid_amount, received_amount) + if(paid_from=%(account)s, paid_amount * -1, received_amount) FROM `tabPayment Entry` WHERE From df7215dcb210dc506d433a1a46dfa41101768c5c Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 15 Jan 2019 14:48:06 +0530 Subject: [PATCH 05/38] Added supplier name in the tds report --- .../tds_computation_summary.py | 32 +++++++++++++++---- .../tds_payable_monthly.py | 32 ++++++++++++++----- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py index d81a8f3c9f9..b19f6306b73 100644 --- a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py +++ b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py @@ -8,7 +8,9 @@ from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category def execute(filters=None): validate_filters(filters) - columns = get_columns() + filters.naming_series = frappe.db.get_single_value('Buying Settings', 'supp_master_name') + + columns = get_columns(filters) res = get_result(filters) return columns, res @@ -29,7 +31,8 @@ def get_result(filters): # if no supplier selected, fetch data for all tds applicable supplier # else fetch relevant data for selected supplier pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id" - fields = ["name", pan+" as pan", "tax_withholding_category", "supplier_type"] + fields = ["name", pan+" as pan", "tax_withholding_category", "supplier_type", "supplier_name"] + if filters.supplier: filters.supplier = frappe.db.get_list('Supplier', {"name": filters.supplier}, fields) @@ -49,8 +52,13 @@ def get_result(filters): filters.company, filters.from_date, filters.to_date) if total_invoiced_amount or tds_deducted: - out.append([supplier.pan, supplier.name, tds.name, supplier.supplier_type, - rate, total_invoiced_amount, tds_deducted]) + row = [supplier.pan, supplier.name] + + if filters.naming_series == 'Naming Series': + row.append(supplier.supplier_name) + + row.extend([tds.name, supplier.supplier_type, rate, total_invoiced_amount, tds_deducted]) + out.append(row) return out @@ -86,7 +94,7 @@ def get_invoice_and_tds_amount(supplier, account, company, from_date, to_date): return total_invoiced_amount, tds_deducted -def get_columns(): +def get_columns(filters): columns = [ { "label": _("PAN"), @@ -100,7 +108,17 @@ def get_columns(): "fieldname": "supplier", "fieldtype": "Link", "width": 180 - }, + }] + + if filters.naming_series == 'Naming Series': + columns.append({ + "label": _("Supplier Name"), + "fieldname": "supplier_name", + "fieldtype": "Data", + "width": 180 + }) + + columns.extend([ { "label": _("Section Code"), "options": "Tax Withholding Category", @@ -132,6 +150,6 @@ def get_columns(): "fieldtype": "Float", "width": 90 } - ] + ]) return columns diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py index 843b58f4486..e55c022452d 100644 --- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py +++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py @@ -11,7 +11,7 @@ def execute(filters=None): validate_filters(filters) set_filters(filters) - columns = get_columns() + columns = get_columns(filters) if not filters["invoices"]: return columns, [] @@ -43,6 +43,7 @@ def set_filters(filters): invoices.append(d) filters["invoices"] = invoices if invoices else filters["invoices"] + filters.naming_series = frappe.db.get_single_value('Buying Settings', 'supp_master_name') def get_result(filters): supplier_map, tds_docs = get_supplier_map(filters) @@ -71,9 +72,14 @@ def get_result(filters): if getdate(filters.from_date) <= gle_map[d][0].posting_date \ and getdate(filters.to_date) >= gle_map[d][0].posting_date: - out.append([supplier.pan, supplier.name, tds_doc.name, - supplier.supplier_type, rate, total_amount_credited, tds_deducted, - gle_map[d][0].posting_date, "Purchase Invoice", d]) + row = [supplier.pan, supplier.name] + + if filters.naming_series == 'Naming Series': + row.append(supplier.supplier_name) + + row.extend([tds_doc.name, supplier.supplier_type, rate, total_amount_credited, + tds_deducted, gle_map[d][0].posting_date, "Purchase Invoice", d]) + out.append(row) return out @@ -84,7 +90,7 @@ def get_supplier_map(filters): pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id" supplier_detail = frappe.db.get_all('Supplier', {"name": ["in", [d.supplier for d in filters["invoices"]]]}, - ["tax_withholding_category", "name", pan+" as pan", "supplier_type"]) + ["tax_withholding_category", "name", pan+" as pan", "supplier_type", "supplier_name"]) for d in filters["invoices"]: supplier_map[d.get("name")] = [k for k in supplier_detail @@ -113,7 +119,7 @@ def get_gle_map(filters): return gle_map -def get_columns(): +def get_columns(filters): pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id" columns = [ { @@ -128,7 +134,17 @@ def get_columns(): "fieldname": "supplier", "fieldtype": "Link", "width": 180 - }, + }] + + if filters.naming_series == 'Naming Series': + columns.append({ + "label": _("Supplier Name"), + "fieldname": "supplier_name", + "fieldtype": "Data", + "width": 180 + }) + + columns.extend([ { "label": _("Section Code"), "options": "Tax Withholding Category", @@ -178,7 +194,7 @@ def get_columns(): "options": "transaction_type", "width": 90 } - ] + ]) return columns From f86123ad5a5a0da9be7e74f7b6e1360f3f9733f9 Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Tue, 15 Jan 2019 15:18:43 +0500 Subject: [PATCH 06/38] feat(Party Ledger Summary): Include columns for discount and other adjustments --- .../customer_ledger_summary.py | 91 +++++++++++++------ erpnext/setup/doctype/company/company.js | 2 + erpnext/setup/doctype/company/company.json | 68 +++++++++++++- 3 files changed, 131 insertions(+), 30 deletions(-) diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py index 2b228fd6b6f..c8044c532aa 100644 --- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py @@ -6,6 +6,7 @@ import frappe import erpnext from frappe import _, scrub from frappe.utils import getdate, nowdate, flt, cint +from six import iteritems class PartyLedgerSummaryReport(object): def __init__(self, filters=None): @@ -20,6 +21,11 @@ class PartyLedgerSummaryReport(object): self.filters.party_type = args.get("party_type") self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1]) + discount_account_field = "discount_allowed_account" if self.filters.party_type == "Customer" \ + else "discount_received_account" + self.round_off_account, self.write_off_account, self.discount_account = frappe.get_cached_value('Company', + self.filters.company, ["round_off_account", "write_off_account", discount_account_field]) + columns = self.get_columns() data = self.get_data() return columns, data @@ -42,6 +48,8 @@ class PartyLedgerSummaryReport(object): }) credit_or_debit_note = "Credit Note" if self.filters.party_type == "Customer" else "Debit Note" + discount_allowed_or_received = "Discount Allowed" if self.filters.party_type == "Customer" else "Discount Received" + columns += [ { "label": _("Opening Balance"), @@ -71,6 +79,13 @@ class PartyLedgerSummaryReport(object): "options": "currency", "width": 120 }, + { + "label": _(discount_allowed_or_received), + "fieldname": "discount_amount", + "fieldtype": "Currency", + "options": "currency", + "width": 120 + }, { "label": _("Write Off Amount"), "fieldname": "write_off_amount", @@ -78,6 +93,13 @@ class PartyLedgerSummaryReport(object): "options": "currency", "width": 120 }, + { + "label": _("Other Adjustments"), + "fieldname": "adjustment_amount", + "fieldtype": "Currency", + "options": "currency", + "width": 120 + }, { "label": _("Closing Balance"), "fieldname": "closing_balance", @@ -106,18 +128,17 @@ class PartyLedgerSummaryReport(object): self.get_gl_entries() self.get_return_invoices() - self.get_party_write_off_amounts() + self.get_party_adjustment_amounts() self.party_data = frappe._dict({}) for gle in self.gl_entries: self.party_data.setdefault(gle.party, frappe._dict({ "party": gle.party, - "party_name": "", # TODO add party_name + "party_name": "", # TODO add party_name "opening_balance": 0, "invoiced_amount": 0, - "paid_amount": -self.party_write_off_amounts.get(gle.party, 0), + "paid_amount": 0, "return_amount": 0, - "write_off_amount": self.party_write_off_amounts.get(gle.party, 0), "closing_balance": 0, "currency": company_currency })) @@ -135,8 +156,18 @@ class PartyLedgerSummaryReport(object): else: self.party_data[gle.party].paid_amount -= amount - return [d for d in self.party_data.values() if d.opening_balance or d.invoiced_amount or d.paid_amount - or d.return_amount or d.write_off_amount or d.closing_amount] + out = [] + for party, row in iteritems(self.party_data): + if row.opening_balance or row.invoiced_amount or row.paid_amount or row.return_amount or row.closing_amount: + total_party_adjustment = sum([amount for account, amount in iteritems(self.party_adjustment_details.get(party, {}))]) + row.paid_amount -= total_party_adjustment + row.discount_amount = self.party_adjustment_details.get(party, {}).get(self.discount_account, 0) + row.write_off_amount = self.party_adjustment_details.get(party, {}).get(self.write_off_account, 0) + row.adjustment_amount = total_party_adjustment - row.discount_amount - row.write_off_amount + + out.append(row) + + return out def get_gl_entries(self): conditions = self.prepare_conditions() @@ -215,12 +246,11 @@ class PartyLedgerSummaryReport(object): self.return_invoices = [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1, "posting_date": ["between", [self.filters.from_date, self.filters.to_date]]})] - def get_party_write_off_amounts(self): + def get_party_adjustment_amounts(self): conditions = self.prepare_conditions() - income_or_expense = "Expense Account" if self.filters.party_type == "Customer" else "Income Account" + income_or_expense = "Expense" if self.filters.party_type == "Customer" else "Income" invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit" reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit" - round_off_account = frappe.get_cached_value('Company', self.filters.company, "round_off_account") gl_entries = frappe.db.sql(""" select @@ -231,7 +261,7 @@ class PartyLedgerSummaryReport(object): docstatus < 2 and (voucher_type, voucher_no) in ( select voucher_type, voucher_no from `tabGL Entry` gle, `tabAccount` acc - where acc.name = gle.account and acc.account_type = '{income_or_expense}' + where acc.name = gle.account and acc.root_type = '{income_or_expense}' and gle.posting_date between %(from_date)s and %(to_date)s and gle.docstatus < 2 ) and (voucher_type, voucher_no) in ( select voucher_type, voucher_no from `tabGL Entry` gle @@ -241,39 +271,42 @@ class PartyLedgerSummaryReport(object): order by posting_date """.format(conditions=conditions, income_or_expense=income_or_expense), self.filters, as_dict=True) - self.party_write_off_amounts = {} - write_off_voucher_entries = {} + self.party_adjustment_details = {} + adjustment_voucher_entries = {} for gle in gl_entries: - write_off_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), []) - write_off_voucher_entries[(gle.voucher_type, gle.voucher_no)].append(gle) + adjustment_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), []) + adjustment_voucher_entries[(gle.voucher_type, gle.voucher_no)].append(gle) - for voucher, voucher_gl_entries in write_off_voucher_entries.iteritems(): + for voucher, voucher_gl_entries in iteritems(adjustment_voucher_entries): parties = {} - write_offs = {} + accounts = {} has_irrelevant_entry = False for gle in voucher_gl_entries: - if gle.account == round_off_account: + if gle.account == self.round_off_account: continue elif gle.party: parties.setdefault(gle.party, 0) parties[gle.party] += gle.get(reverse_dr_or_cr) - gle.get(invoice_dr_or_cr) - elif frappe.get_cached_value("Account", gle.account, "account_type") == income_or_expense: - write_offs.setdefault(gle.account, 0) - write_offs[gle.account] += gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr) + elif frappe.get_cached_value("Account", gle.account, "root_type") == income_or_expense: + accounts.setdefault(gle.account, 0) + accounts[gle.account] += gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr) else: has_irrelevant_entry = True - if parties and write_offs: + if parties and accounts: if len(parties) == 1: - for account, amount in write_offs.iteritems(): - party = parties.keys()[0] - self.party_write_off_amounts.setdefault(party, 0) - self.party_write_off_amounts[party] += amount - elif len(write_offs) == 1 and not has_irrelevant_entry: - for party, amount in parties.iteritems(): - self.party_write_off_amounts.setdefault(party, 0) - self.party_write_off_amounts[party] += amount + party = parties.keys()[0] + for account, amount in iteritems(accounts): + self.party_adjustment_details.setdefault(party, {}) + self.party_adjustment_details[party].setdefault(account, 0) + self.party_adjustment_details[party][account] += amount + elif len(accounts) == 1 and not has_irrelevant_entry: + account = accounts.keys()[0] + for party, amount in iteritems(parties): + self.party_adjustment_details.setdefault(party, {}) + self.party_adjustment_details[party].setdefault(account, 0) + self.party_adjustment_details[party][account] += amount def execute(filters=None): args = { diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index 16676ac78af..70e047a4e80 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -206,6 +206,8 @@ erpnext.company.setup_queries = function(frm) { ["default_payroll_payable_account", {"root_type": "Liability"}], ["round_off_account", {"root_type": "Expense"}], ["write_off_account", {"root_type": "Expense"}], + ["discount_allowed_account", {"root_type": "Expense"}], + ["discount_received_account", {"root_type": "Income"}], ["exchange_gain_loss_account", {"root_type": "Expense"}], ["unrealized_exchange_gain_loss_account", {"root_type": "Expense"}], ["accumulated_depreciation_account", diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 01f8956a826..77c371e0cdd 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -1250,6 +1250,72 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "discount_allowed_account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Discount Allowed Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "discount_received_account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Discount Received Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2903,7 +2969,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-10-24 12:57:46.776452", + "modified": "2019-01-15 13:29:54.510379", "modified_by": "Administrator", "module": "Setup", "name": "Company", From bdee57ca8d30a8f078785da7ec15ac0c0982fb53 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 15 Jan 2019 15:52:52 +0530 Subject: [PATCH 07/38] Added finance book in trial balance and fixed cost center not working issue in trial balance --- .../report/trial_balance/trial_balance.js | 41 ++++++++++++------- .../report/trial_balance/trial_balance.py | 18 ++++++-- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/report/trial_balance/trial_balance.js b/erpnext/accounts/report/trial_balance/trial_balance.js index c09fa715753..194f1bd497c 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.js +++ b/erpnext/accounts/report/trial_balance/trial_balance.js @@ -12,21 +12,6 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() { "default": frappe.defaults.get_user_default("Company"), "reqd": 1 }, - { - "fieldname":"cost_center", - "label": __("Cost Center"), - "fieldtype": "Link", - "options": "Cost Center", - "get_query": function() { - var company = frappe.query_report.get_filter_value('company'); - return { - "doctype": "Cost Center", - "filters": { - "company": company, - } - } - } - }, { "fieldname": "fiscal_year", "label": __("Fiscal Year"), @@ -60,6 +45,27 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() { "fieldtype": "Date", "default": frappe.defaults.get_user_default("year_end_date"), }, + { + "fieldname":"cost_center", + "label": __("Cost Center"), + "fieldtype": "Link", + "options": "Cost Center", + "get_query": function() { + var company = frappe.query_report.get_filter_value('company'); + return { + "doctype": "Cost Center", + "filters": { + "company": company, + } + } + } + }, + { + "fieldname":"finance_book", + "label": __("Finance Book"), + "fieldtype": "Link", + "options": "Finance Book", + }, { "fieldname": "with_period_closing_entry", "label": __("Period Closing Entry"), @@ -75,6 +81,11 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() { "fieldname": "show_unclosed_fy_pl_balances", "label": __("Show unclosed fiscal year's P&L balances"), "fieldtype": "Check" + }, + { + "fieldname": "include_non_finance_book_entries", + "label": __("Include Non Finance Book Entries"), + "fieldtype": "Check" } ], "formatter": erpnext.financial_statements.formatter, diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py index 07dcd4e7a94..696e63bb2cf 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.py +++ b/erpnext/accounts/report/trial_balance/trial_balance.py @@ -67,11 +67,10 @@ def get_data(filters): gl_entries_by_account = {} + opening_balances = get_opening_balances(filters) set_gl_entries_by_account(filters.company, filters.from_date, filters.to_date, min_lft, max_rgt, filters, gl_entries_by_account, ignore_closing_entries=not flt(filters.with_period_closing_entry)) - opening_balances = get_opening_balances(filters) - total_row = calculate_values(accounts, gl_entries_by_account, opening_balances, filters, company_currency) accumulate_values_into_parents(accounts, accounts_by_name) @@ -98,6 +97,18 @@ def get_rootwise_opening_balances(filters, report_type): if not flt(filters.with_period_closing_entry): additional_conditions += " and ifnull(voucher_type, '')!='Period Closing Voucher'" + if filters.cost_center: + lft, rgt = frappe.db.get_value('Cost Center', filters.cost_center, ['lft', 'rgt']) + additional_conditions += """ and cost_center in (select name from `tabCost Center` + where lft >= %s and rgt <= %s)""" % (lft, rgt) + + if filters.finance_book: + fb_conditions = " and finance_book = %(finance_book)s" + if filters.include_non_finance_book_entries: + fb_conditions = " and (finance_book = %(finance_book)s or finance_book is null)" + + additional_conditions += fb_conditions + gle = frappe.db.sql(""" select account, sum(debit) as opening_debit, sum(credit) as opening_credit @@ -112,7 +123,8 @@ def get_rootwise_opening_balances(filters, report_type): "company": filters.company, "from_date": filters.from_date, "report_type": report_type, - "year_start_date": filters.year_start_date + "year_start_date": filters.year_start_date, + "finance_book": filters.finance_book }, as_dict=True) From b2d08a498b76cbe9c1f491ed42072453002af85d Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 15 Jan 2019 16:11:29 +0530 Subject: [PATCH 08/38] Added bank account field in the payment entry --- .../doctype/bank_account/bank_account.py | 7 + .../doctype/payment_entry/payment_entry.js | 24 ++++ .../doctype/payment_entry/payment_entry.json | 131 ++++++++++++++++-- 3 files changed, 147 insertions(+), 15 deletions(-) diff --git a/erpnext/accounts/doctype/bank_account/bank_account.py b/erpnext/accounts/doctype/bank_account/bank_account.py index 08f8248f3d7..7a3f22b10c7 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account.py +++ b/erpnext/accounts/doctype/bank_account/bank_account.py @@ -31,3 +31,10 @@ def make_bank_account(doctype, docname): doc.is_default = 1 return doc + + +@frappe.whitelist() +def get_bank_account(bank_account): + if bank_account: + return frappe.db.get_value('Bank Account', + bank_account, 'account') \ No newline at end of file diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index afb44e8f92f..3663ffe0536 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -30,6 +30,13 @@ frappe.ui.form.on('Payment Entry', { } } }); + frm.set_query("bank_account", function() { + return{ + "filters": { + "party": frm.doc.party, + } + } + }); frm.set_query("contact_person", function() { if (frm.doc.party) { return { @@ -833,6 +840,23 @@ frappe.ui.form.on('Payment Entry', { } }) } + }, + + bank_account: function(frm) { + const field = frm.doc.payment_type == "Pay" ? "paid_from":"paid_to"; + if (frm.doc.bank_account && in_list(['Pay', 'Receive'], frm.doc.payment_type)) { + frappe.call({ + method: "erpnext.accounts.doctype.bank_account.bank_account.get_bank_account", + args: { + bank_account: frm.doc.bank_account + }, + callback: function(r) { + if (r.message) { + frm.set_value(field, r.message); + } + } + }); + } } }); diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json index bc9062b96c9..9354c61addb 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.json +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, @@ -379,24 +380,24 @@ { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "party", - "fieldname": "contact_person", - "fieldtype": "Link", + "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.party_type", + "description": "", + "fieldname": "party_name", + "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, - "in_global_search": 0, + "in_global_search": 1, "in_list_view": 0, "in_standard_filter": 0, - "label": "Contact", + "label": "Party Name", "length": 0, "no_copy": 0, - "options": "Contact", "permlevel": 0, "precision": "", "print_hide": 0, @@ -444,24 +445,24 @@ { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, - "allow_on_submit": 1, + "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.party_type", - "description": "", - "fieldname": "party_name", - "fieldtype": "Data", + "depends_on": "party", + "fieldname": "bank_account", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, - "in_global_search": 1, + "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Party Name", + "label": "Bank Account", "length": 0, "no_copy": 0, + "options": "Bank Account", "permlevel": 0, "precision": "", "print_hide": 0, @@ -509,6 +510,40 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "party", + "fieldname": "contact_person", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Contact", + "length": 0, + "no_copy": 0, + "options": "Contact", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1867,6 +1902,72 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_from": "bank_account.bank", + "fieldname": "bank", + "fieldtype": "Read Only", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Bank", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_from": "bank_account.bank_account_no", + "fieldname": "bank_account_no", + "fieldtype": "Read Only", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Bank Account No", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2040,7 +2141,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-09-25 14:38:48.312629", + "modified": "2019-01-15 15:58:40.742601", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry", From 1a4c1e11cb770ba4369a68c527b0c189e6cd75c6 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 15 Jan 2019 17:01:34 +0530 Subject: [PATCH 09/38] Fix: total invoiced amount in Accounts Receivable Summary report showing blank --- .../accounts_receivable_summary/accounts_receivable_summary.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py index 190031abb8c..0a955a79120 100644 --- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py +++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py @@ -185,6 +185,9 @@ class AccountsReceivableSummary(ReceivablePayableReport): if party_naming_by == "Naming Series": cols += ["party_name"] + if args.get("party_type") == 'Customer': + cols += ["contact"] + cols += ["voucher_type", "voucher_no", "due_date"] if args.get("party_type") == "Supplier": From affeb3dfecfc6d3515f950f41a427e5abb189442 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 15 Jan 2019 17:38:31 +0530 Subject: [PATCH 10/38] Added on account amount field in Accounts Payable/Receivable Summary --- erpnext/accounts/party.py | 9 +++++++++ .../accounts_receivable_summary.py | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index a69a1722845..d25e6de5e61 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -562,3 +562,12 @@ def get_party_shipping_address(doctype, name): return out[0][0] else: return '' + +def get_partywise_advanced_payment_amount(party_type="Customer"): + data = frappe.db.sql(""" SELECT party, sum({0}) as amount + FROM `tabGL Entry` + WHERE party_type = %s and against_voucher is null GROUP BY party""" + .format("credit" if party_type == "Customer" else "debit") , party_type, debug=1) + + if data: + return frappe._dict(data) \ No newline at end of file diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py index 0a955a79120..a272bfeb47b 100644 --- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py +++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe from frappe import _, scrub from frappe.utils import flt +from erpnext.accounts.party import get_partywise_advanced_payment_amount from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport from six import iteritems @@ -24,6 +25,12 @@ class AccountsReceivableSummary(ReceivablePayableReport): credit_debit_label = "Credit Note Amt" if args.get('party_type') == 'Customer' else "Debit Note Amt" columns += [{ + "label": _("On Account Amount"), + "fieldname": "on_account_amt", + "fieldtype": "Currency", + "options": "currency", + "width": 100 + },{ "label": _("Total Invoiced Amt"), "fieldname": "total_invoiced_amt", "fieldtype": "Currency", @@ -129,12 +136,15 @@ class AccountsReceivableSummary(ReceivablePayableReport): partywise_total = self.get_partywise_total(party_naming_by, args) + partywise_advance_amount = get_partywise_advanced_payment_amount(args.get("party_type")) or {} for party, party_dict in iteritems(partywise_total): row = [party] if party_naming_by == "Naming Series": row += [self.get_party_name(args.get("party_type"), party)] + row += [partywise_advance_amount.get(party, 0)] + row += [ party_dict.invoiced_amt, party_dict.paid_amt, party_dict.credit_amt, party_dict.outstanding_amt, party_dict.range1, party_dict.range2, party_dict.range3, party_dict.range4, From f7258168095a90cd6d4f9e5d4b2374027c6a9685 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 15 Jan 2019 18:12:04 +0530 Subject: [PATCH 11/38] Enhance: Added field limit in the Payment Reconciliation to handle large entries --- .../doctype/bank_account/bank_account.py | 8 +- .../doctype/payment_entry/payment_entry.js | 2 +- .../payment_reconciliation.json | 186 +++++++++++++++++- .../payment_reconciliation.py | 9 +- erpnext/accounts/utils.py | 8 +- erpnext/controllers/accounts_controller.py | 13 +- 6 files changed, 200 insertions(+), 26 deletions(-) diff --git a/erpnext/accounts/doctype/bank_account/bank_account.py b/erpnext/accounts/doctype/bank_account/bank_account.py index 7a3f22b10c7..7a79de56b86 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account.py +++ b/erpnext/accounts/doctype/bank_account/bank_account.py @@ -32,9 +32,7 @@ def make_bank_account(doctype, docname): return doc - @frappe.whitelist() -def get_bank_account(bank_account): - if bank_account: - return frappe.db.get_value('Bank Account', - bank_account, 'account') \ No newline at end of file +def get_account_from_bank_acc(name): + return frappe.db.get_value('Bank Account', + name, 'account') \ No newline at end of file diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 3663ffe0536..58a380c968b 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -846,7 +846,7 @@ frappe.ui.form.on('Payment Entry', { const field = frm.doc.payment_type == "Pay" ? "paid_from":"paid_to"; if (frm.doc.bank_account && in_list(['Pay', 'Receive'], frm.doc.payment_type)) { frappe.call({ - method: "erpnext.accounts.doctype.bank_account.bank_account.get_bank_account", + method: "erpnext.accounts.doctype.bank_account.bank_account.get_account_from_bank_acc", args: { bank_account: frm.doc.bank_account }, diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json index b211b500a15..cfb24c3954c 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json @@ -1,23 +1,34 @@ { "allow_copy": 1, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, + "beta": 0, "creation": "2014-07-09 12:04:51.681583", "custom": 0, "docstatus": 0, "doctype": "DocType", "document_type": "", + "editable_grid": 0, + "engine": "InnoDB", "fields": [ { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "company", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Company", "length": 0, "no_copy": 0, @@ -26,22 +37,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "party_type", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Party Type", "length": 0, "no_copy": 0, @@ -50,23 +69,31 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "depends_on": "", "fieldname": "party", "fieldtype": "Dynamic Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Party", "length": 0, "no_copy": 0, @@ -75,22 +102,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "receivable_payable_account", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Receivable / Payable Account", "length": 0, "no_copy": 0, @@ -100,22 +135,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "bank_cash_account", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Bank / Cash Account", "length": 0, "no_copy": 0, @@ -124,22 +167,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "col_break1", "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "", "length": 0, "no_copy": 0, @@ -147,22 +198,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "from_date", "fieldtype": "Date", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "From Invoice Date", "length": 0, "no_copy": 0, @@ -170,22 +229,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 1, + "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "to_date", "fieldtype": "Date", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "To Invoice Date", "length": 0, "no_copy": 0, @@ -193,22 +260,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 1, + "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "minimum_amount", "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Minimum Invoice Amount", "length": 0, "no_copy": 0, @@ -216,22 +291,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "maximum_amount", "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Maximum Invoice Amount", "length": 0, "no_copy": 0, @@ -239,22 +322,63 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, + "description": "System will fetch all the entries if limit value is zero.", + "fieldname": "limit", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Limit", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, "fieldname": "get_unreconciled_entries", "fieldtype": "Button", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Get Unreconciled Entries", "length": 0, "no_copy": 0, @@ -262,22 +386,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "sec_break1", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Unreconciled Payment Details", "length": 0, "no_copy": 0, @@ -285,22 +417,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "payments", "fieldtype": "Table", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Payments", "length": 0, "no_copy": 0, @@ -309,22 +449,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "reconcile", "fieldtype": "Button", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Reconcile", "length": 0, "no_copy": 0, @@ -332,22 +480,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "sec_break2", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Invoice/Journal Entry Details", "length": 0, "no_copy": 0, @@ -355,22 +511,30 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "invoices", "fieldtype": "Table", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Invoices", "length": 0, "no_copy": 0, @@ -379,25 +543,28 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 1, - "icon": "fa fa-resize-horizontal", + "icon": "icon-resize-horizontal", "idx": 0, + "image_view": 0, "in_create": 0, - "is_submittable": 0, "issingle": 1, "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-01-04 02:26:58.807921", + "modified": "2019-01-15 17:42:21.135214", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Reconciliation", @@ -406,7 +573,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -426,7 +592,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -445,8 +610,13 @@ "write": 1 } ], + "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "show_name_in_global_search": 0, "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index 7cd951aba46..094ece95e81 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -25,7 +25,7 @@ class PaymentReconciliation(Document): def get_payment_entries(self): order_doctype = "Sales Order" if self.party_type=="Customer" else "Purchase Order" payment_entries = get_advance_payment_entries(self.party_type, self.party, - self.receivable_payable_account, order_doctype, against_all_orders=True) + self.receivable_payable_account, order_doctype, against_all_orders=True, limit=self.limit) return payment_entries @@ -36,6 +36,8 @@ class PaymentReconciliation(Document): bank_account_condition = "t2.against_account like %(bank_cash_account)s" \ if self.bank_cash_account else "1=1" + limit_cond = "limit %s" % (self.limit or 1000) + journal_entries = frappe.db.sql(""" select "Journal Entry" as reference_type, t1.name as reference_name, @@ -55,10 +57,11 @@ class PaymentReconciliation(Document): THEN 1=1 ELSE {bank_account_condition} END) - order by t1.posting_date + order by t1.posting_date {limit_cond} """.format(**{ "dr_or_cr": dr_or_cr, "bank_account_condition": bank_account_condition, + "limit_cond": limit_cond }), { "party_type": self.party_type, "party": self.party, @@ -80,7 +83,7 @@ class PaymentReconciliation(Document): condition = self.check_condition() non_reconciled_invoices = get_outstanding_invoices(self.party_type, self.party, - self.receivable_payable_account, condition=condition) + self.receivable_payable_account, condition=condition, limit=self.limit) self.add_invoice_entries(non_reconciled_invoices) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 6fbe97de3e1..e145a35b17f 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -615,7 +615,7 @@ def get_held_invoices(party_type, party): return held_invoices -def get_outstanding_invoices(party_type, party, account, condition=None): +def get_outstanding_invoices(party_type, party, account, condition=None, limit=1000): outstanding_invoices = [] precision = frappe.get_precision("Sales Invoice", "outstanding_amount") @@ -628,6 +628,7 @@ def get_outstanding_invoices(party_type, party, account, condition=None): invoice = 'Sales Invoice' if erpnext.get_party_account_type(party_type) == 'Receivable' else 'Purchase Invoice' held_invoices = get_held_invoices(party_type, party) + limit_cond = "limit %s" % (limit or 1000) invoice_list = frappe.db.sql(""" select @@ -655,11 +656,12 @@ def get_outstanding_invoices(party_type, party, account, condition=None): or (voucher_type not in ('Journal Entry', 'Payment Entry'))) group by voucher_type, voucher_no having (invoice_amount - payment_amount) > 0.005 - order by posting_date, name""".format( + order by posting_date, name {limit_cond}""".format( dr_or_cr=dr_or_cr, invoice = invoice, payment_dr_or_cr=payment_dr_or_cr, - condition=condition or "" + condition=condition or "", + limit_cond = limit_cond ), { "party_type": party_type, "party": party, diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index cd373b84d7e..c0643f2e6e5 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -953,11 +953,12 @@ def get_advance_journal_entries(party_type, party, party_account, amount_field, return list(journal_entries) -def get_advance_payment_entries(party_type, party, party_account, - order_doctype, order_list=None, include_unallocated=True, against_all_orders=False): +def get_advance_payment_entries(party_type, party, party_account, order_doctype, + order_list=None, include_unallocated=True, against_all_orders=False, limit=1000): party_account_field = "paid_from" if party_type == "Customer" else "paid_to" payment_type = "Receive" if party_type == "Customer" else "Pay" payment_entries_against_order, unallocated_payment_entries = [], [] + limit_cond = "limit %s" % (limit or 1000) if order_list or against_all_orders: if order_list: @@ -977,8 +978,8 @@ def get_advance_payment_entries(party_type, party, party_account, t1.name = t2.parent and t1.{0} = %s and t1.payment_type = %s and t1.party_type = %s and t1.party = %s and t1.docstatus = 1 and t2.reference_doctype = %s {1} - order by t1.posting_date - """.format(party_account_field, reference_condition), + order by t1.posting_date {2} + """.format(party_account_field, reference_condition, limit_cond), [party_account, payment_type, party_type, party, order_doctype] + order_list, as_dict=1) @@ -990,8 +991,8 @@ def get_advance_payment_entries(party_type, party, party_account, where {0} = %s and party_type = %s and party = %s and payment_type = %s and docstatus = 1 and unallocated_amount > 0 - order by posting_date - """.format(party_account_field), (party_account, party_type, party, payment_type), as_dict=1) + order by posting_date {1} + """.format(party_account_field, limit_cond), (party_account, party_type, party, payment_type), as_dict=1) return list(payment_entries_against_order) + list(unallocated_payment_entries) From fa7ee0b3b67a04de136ce2673185cddc4f217cd3 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 17 Jan 2019 15:30:44 +0530 Subject: [PATCH 12/38] Added dafult bank account in the customer/supplier --- .../doctype/bank_account/bank_account.py | 11 ++++-- .../doctype/payment_entry/payment_entry.js | 13 +++++-- .../doctype/payment_entry/payment_entry.py | 22 +++++++++++- erpnext/accounts/party.py | 2 +- .../accounts_receivable_summary.py | 4 +-- erpnext/buying/doctype/supplier/supplier.json | 35 ++++++++++++++++++- .../selling/doctype/customer/customer.json | 35 ++++++++++++++++++- 7 files changed, 110 insertions(+), 12 deletions(-) diff --git a/erpnext/accounts/doctype/bank_account/bank_account.py b/erpnext/accounts/doctype/bank_account/bank_account.py index 7a79de56b86..b13259b55d3 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account.py +++ b/erpnext/accounts/doctype/bank_account/bank_account.py @@ -33,6 +33,11 @@ def make_bank_account(doctype, docname): return doc @frappe.whitelist() -def get_account_from_bank_acc(name): - return frappe.db.get_value('Bank Account', - name, 'account') \ No newline at end of file +def get_party_bank_account(party_type, party): + return frappe.db.get_value(party_type, + party, 'default_bank_account') + +@frappe.whitelist() +def get_bank_account_details(bank_account): + return frappe.db.get_value("Bank Account", + bank_account, ['account', 'bank', 'bank_account_no'], as_dict=1) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 58a380c968b..15cc3fdbb9d 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -291,7 +291,12 @@ frappe.ui.form.on('Payment Entry', { () => frm.events.get_outstanding_documents(frm), () => frm.events.hide_unhide_fields(frm), () => frm.events.set_dynamic_labels(frm), - () => { frm.set_party_account_based_on_party = false; } + () => { + frm.set_party_account_based_on_party = false; + if (r.message.bank_account) { + frm.set_value("bank_account", r.message.bank_account); + } + } ]); } } @@ -846,13 +851,15 @@ frappe.ui.form.on('Payment Entry', { const field = frm.doc.payment_type == "Pay" ? "paid_from":"paid_to"; if (frm.doc.bank_account && in_list(['Pay', 'Receive'], frm.doc.payment_type)) { frappe.call({ - method: "erpnext.accounts.doctype.bank_account.bank_account.get_account_from_bank_acc", + method: "erpnext.accounts.doctype.bank_account.bank_account.get_bank_account_details", args: { bank_account: frm.doc.bank_account }, callback: function(r) { if (r.message) { - frm.set_value(field, r.message); + frm.set_value(field, r.message.account); + frm.set_value('bank', r.message.bank); + frm.set_value('bank_account_no', r.message.bank_account_no); } } }); diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index f213ffa6580..7f1f55005c0 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -12,6 +12,7 @@ from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_ban from erpnext.setup.utils import get_exchange_rate from erpnext.accounts.general_ledger import make_gl_entries from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount +from erpnext.accounts.doctype.bank_account.bank_account import get_party_bank_account, get_bank_account_details from erpnext.controllers.accounts_controller import AccountsController, get_supplier_block_status from six import string_types, iteritems @@ -88,6 +89,16 @@ class PaymentEntry(AccountsController): .format(d.idx, d.reference_doctype, d.reference_name)) reference_names.append((d.reference_doctype, d.reference_name)) + def set_bank_account_data(self): + if self.bank_account: + bank_data = get_bank_account_details(self.bank_account) + + field = "paid_from" if self.payment_type == "Pay" else "paid_to" + + self.bank = bank_data.bank + self.bank_account_no = bank_data.bank_account_no + self.set(field, bank_data.account) + def validate_allocated_amount(self): for d in self.get("references"): if (flt(d.allocated_amount))> 0: @@ -670,6 +681,7 @@ def get_negative_outstanding_invoices(party_type, party, party_account, party_ac @frappe.whitelist() def get_party_details(company, party_type, party, date, cost_center=None): + bank_account = '' if not frappe.db.exists(party_type, party): frappe.throw(_("Invalid {0}: {1}").format(party_type, party)) @@ -680,13 +692,16 @@ def get_party_details(company, party_type, party, date, cost_center=None): _party_name = "title" if party_type == "Student" else party_type.lower() + "_name" party_name = frappe.db.get_value(party_type, party, _party_name) party_balance = get_balance_on(party_type=party_type, party=party, cost_center=cost_center) + if party_type in ["Customer", "Supplier"]: + bank_account = get_party_bank_account(party_type, party) return { "party_account": party_account, "party_name": party_name, "party_account_currency": account_currency, "party_balance": party_balance, - "account_balance": account_balance + "account_balance": account_balance, + "bank_account": bank_account } @@ -890,6 +905,11 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount= pe.allocate_payment_amount = 1 pe.letter_head = doc.get("letter_head") + if pe.party_type in ["Customer", "Supplier"]: + bank_account = get_party_bank_account(pe.party_type, pe.party) + pe.set("bank_account", bank_account) + pe.set_bank_account_data() + # only Purchase Invoice can be blocked individually if doc.doctype == "Purchase Invoice" and doc.invoice_is_blocked(): frappe.msgprint(_('{0} is on hold till {1}'.format(doc.name, doc.release_date))) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index d25e6de5e61..eb1146ba1ac 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -567,7 +567,7 @@ def get_partywise_advanced_payment_amount(party_type="Customer"): data = frappe.db.sql(""" SELECT party, sum({0}) as amount FROM `tabGL Entry` WHERE party_type = %s and against_voucher is null GROUP BY party""" - .format("credit" if party_type == "Customer" else "debit") , party_type, debug=1) + .format(("credit - debit") if party_type == "Customer" else "debit") , party_type, debug=1) if data: return frappe._dict(data) \ No newline at end of file diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py index a272bfeb47b..73ca8b48ef5 100644 --- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py +++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py @@ -25,8 +25,8 @@ class AccountsReceivableSummary(ReceivablePayableReport): credit_debit_label = "Credit Note Amt" if args.get('party_type') == 'Customer' else "Debit Note Amt" columns += [{ - "label": _("On Account Amount"), - "fieldname": "on_account_amt", + "label": _("Advance Amount"), + "fieldname": "advance_amount", "fieldtype": "Currency", "options": "currency", "width": 100 diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json index 3b1f4e0dfcc..4586c647155 100644 --- a/erpnext/buying/doctype/supplier/supplier.json +++ b/erpnext/buying/doctype/supplier/supplier.json @@ -149,6 +149,39 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "default_bank_account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Bank Account", + "length": 0, + "no_copy": 0, + "options": "Bank Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1463,7 +1496,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2019-01-07 16:52:04.660271", + "modified": "2019-01-17 13:58:08.597792", "modified_by": "Administrator", "module": "Buying", "name": "Supplier", diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json index 608c0e950ed..a82042f4a16 100644 --- a/erpnext/selling/doctype/customer/customer.json +++ b/erpnext/selling/doctype/customer/customer.json @@ -217,6 +217,39 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "default_bank_account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Bank Account", + "length": 0, + "no_copy": 0, + "options": "Bank Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1873,7 +1906,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-10-01 10:07:34.510264", + "modified": "2019-01-17 13:10:24.360875", "modified_by": "Administrator", "module": "Selling", "name": "Customer", From 55566b7f8e838fbeb349d754e6235737581af032 Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Sat, 19 Jan 2019 15:12:08 +0500 Subject: [PATCH 13/38] fix(Party Ledger Summary): Codacy fix --- .../customer_ledger_summary.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py index c8044c532aa..47116cf3366 100644 --- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py @@ -4,9 +4,9 @@ from __future__ import unicode_literals import frappe import erpnext -from frappe import _, scrub -from frappe.utils import getdate, nowdate, flt, cint -from six import iteritems +from frappe import _ +from frappe.utils import getdate, nowdate +from six import iteritems, itervalues class PartyLedgerSummaryReport(object): def __init__(self, filters=None): @@ -159,7 +159,7 @@ class PartyLedgerSummaryReport(object): out = [] for party, row in iteritems(self.party_data): if row.opening_balance or row.invoiced_amount or row.paid_amount or row.return_amount or row.closing_amount: - total_party_adjustment = sum([amount for account, amount in iteritems(self.party_adjustment_details.get(party, {}))]) + total_party_adjustment = sum([amount for amount in itervalues(self.party_adjustment_details.get(party, {}))]) row.paid_amount -= total_party_adjustment row.discount_amount = self.party_adjustment_details.get(party, {}).get(self.discount_account, 0) row.write_off_amount = self.party_adjustment_details.get(party, {}).get(self.write_off_account, 0) @@ -230,9 +230,6 @@ class PartyLedgerSummaryReport(object): and ((steam.parent = voucher_no and steam.parenttype = voucher_type) or (steam.parent = against_voucher and steam.parenttype = against_voucher_type) or (steam.parent = party and steam.parenttype = 'Customer')))""".format(lft, rgt)) - #conditions.append("""party in (select parent from `tabSales Team` - # where parenttype = 'Customer' and exists(select name from `tabSales Person` - # where lft >= {0} and rgt <= {1} and name=`tabSales Team`.sales_person))""".format(lft, rgt)) if self.filters.party_type == "Supplier": if self.filters.get("supplier_group"): @@ -277,7 +274,7 @@ class PartyLedgerSummaryReport(object): adjustment_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), []) adjustment_voucher_entries[(gle.voucher_type, gle.voucher_no)].append(gle) - for voucher, voucher_gl_entries in iteritems(adjustment_voucher_entries): + for voucher_gl_entries in itervalues(adjustment_voucher_entries): parties = {} accounts = {} has_irrelevant_entry = False @@ -313,4 +310,4 @@ def execute(filters=None): "party_type": "Customer", "naming_by": ["Selling Settings", "cust_master_name"], } - return PartyLedgerSummaryReport(filters).run(args) \ No newline at end of file + return PartyLedgerSummaryReport(filters).run(args) From 31d58eac01d2ef5f96185be15295e0f08172ccb7 Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Sat, 19 Jan 2019 15:28:40 +0500 Subject: [PATCH 14/38] fix(Party Ledger Summary): Added Supplier/Customer Name column --- .../customer_ledger_summary.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py index 47116cf3366..e33bd61411e 100644 --- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py @@ -134,7 +134,7 @@ class PartyLedgerSummaryReport(object): for gle in self.gl_entries: self.party_data.setdefault(gle.party, frappe._dict({ "party": gle.party, - "party_name": "", # TODO add party_name + "party_name": gle.party_name, "opening_balance": 0, "invoiced_amount": 0, "paid_amount": 0, @@ -171,16 +171,25 @@ class PartyLedgerSummaryReport(object): def get_gl_entries(self): conditions = self.prepare_conditions() + join = join_field = "" + if self.filters.party_type == "Customer": + join_field = ", p.customer_name as party_name" + join = "left join `tabCustomer` p on gle.party = p.name" + elif self.filters.party_type == "Supplier": + join_field = ", p.supplier_name as party_name" + join = "left join `tabSupplier` p on gle.party = p.name" self.gl_entries = frappe.db.sql(""" select - posting_date, party, voucher_type, voucher_no, against_voucher_type, against_voucher, debit, credit - from - `tabGL Entry` + gle.posting_date, gle.party, gle.voucher_type, gle.voucher_no, gle.against_voucher_type, + gle.against_voucher, gle.debit, gle.credit {join_field} + from `tabGL Entry` gle + {join} where - docstatus < 2 and party_type=%(party_type)s and ifnull(party, '') != '' and posting_date <= %(to_date)s - {0} - order by posting_date""".format(conditions), self.filters, as_dict=True) + gle.docstatus < 2 and gle.party_type=%(party_type)s and ifnull(gle.party, '') != '' + and gle.posting_date <= %(to_date)s {conditions} + order by gle.posting_date + """.format(join=join, join_field=join_field, conditions=conditions), self.filters, as_dict=True) def prepare_conditions(self): conditions = [""] @@ -265,7 +274,6 @@ class PartyLedgerSummaryReport(object): where gle.party_type=%(party_type)s and ifnull(party, '') != '' and gle.posting_date between %(from_date)s and %(to_date)s and gle.docstatus < 2 {conditions} ) - order by posting_date """.format(conditions=conditions, income_or_expense=income_or_expense), self.filters, as_dict=True) self.party_adjustment_details = {} From ddd9136d10c006ad8b596128bbe5844864ecd613 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 17 Jan 2019 17:53:58 +0530 Subject: [PATCH 15/38] Renamed field and added finance book column in the trial balance simple report --- erpnext/accounts/doctype/payment_entry/payment_entry.js | 7 ------- erpnext/accounts/party.py | 2 +- erpnext/accounts/report/trial_balance/trial_balance.js | 4 ++-- erpnext/accounts/report/trial_balance/trial_balance.py | 7 ++++--- erpnext/accounts/report/trial_balance_simple/__init__.py | 0 .../report/trial_balance_simple/trial_balance_simple.json | 4 ++-- 6 files changed, 9 insertions(+), 15 deletions(-) create mode 100644 erpnext/accounts/report/trial_balance_simple/__init__.py diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 15cc3fdbb9d..30ae54b18b0 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -30,13 +30,6 @@ frappe.ui.form.on('Payment Entry', { } } }); - frm.set_query("bank_account", function() { - return{ - "filters": { - "party": frm.doc.party, - } - } - }); frm.set_query("contact_person", function() { if (frm.doc.party) { return { diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index eb1146ba1ac..acb5dd1c09b 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -567,7 +567,7 @@ def get_partywise_advanced_payment_amount(party_type="Customer"): data = frappe.db.sql(""" SELECT party, sum({0}) as amount FROM `tabGL Entry` WHERE party_type = %s and against_voucher is null GROUP BY party""" - .format(("credit - debit") if party_type == "Customer" else "debit") , party_type, debug=1) + .format(("credit - debit") if party_type == "Customer" else "debit") , party_type) if data: return frappe._dict(data) \ No newline at end of file diff --git a/erpnext/accounts/report/trial_balance/trial_balance.js b/erpnext/accounts/report/trial_balance/trial_balance.js index 194f1bd497c..cdc77456d0a 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.js +++ b/erpnext/accounts/report/trial_balance/trial_balance.js @@ -83,8 +83,8 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() { "fieldtype": "Check" }, { - "fieldname": "include_non_finance_book_entries", - "label": __("Include Non Finance Book Entries"), + "fieldname": "include_default_book_entries", + "label": __("Include Default Book Entries"), "fieldtype": "Check" } ], diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py index 696e63bb2cf..6b18c5d8731 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.py +++ b/erpnext/accounts/report/trial_balance/trial_balance.py @@ -104,8 +104,8 @@ def get_rootwise_opening_balances(filters, report_type): if filters.finance_book: fb_conditions = " and finance_book = %(finance_book)s" - if filters.include_non_finance_book_entries: - fb_conditions = " and (finance_book = %(finance_book)s or finance_book is null)" + if filters.include_default_book_entries: + fb_conditions = " and (finance_book in (%(finance_book)s, %(company_fb)s) or finance_book is null)" additional_conditions += fb_conditions @@ -124,7 +124,8 @@ def get_rootwise_opening_balances(filters, report_type): "from_date": filters.from_date, "report_type": report_type, "year_start_date": filters.year_start_date, - "finance_book": filters.finance_book + "finance_book": filters.finance_book, + "company_fb": frappe.db.get_value("Company", filters.company, 'default_finance_book') }, as_dict=True) diff --git a/erpnext/accounts/report/trial_balance_simple/__init__.py b/erpnext/accounts/report/trial_balance_simple/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/accounts/report/trial_balance_simple/trial_balance_simple.json b/erpnext/accounts/report/trial_balance_simple/trial_balance_simple.json index ea5a97b1067..fab3a76a0c4 100644 --- a/erpnext/accounts/report/trial_balance_simple/trial_balance_simple.json +++ b/erpnext/accounts/report/trial_balance_simple/trial_balance_simple.json @@ -6,13 +6,13 @@ "doctype": "Report", "idx": 0, "is_standard": "Yes", - "modified": "2018-11-22 17:40:11.317567", + "modified": "2019-01-17 17:20:42.374958", "modified_by": "Administrator", "module": "Accounts", "name": "Trial Balance (Simple)", "owner": "Administrator", "prepared_report": 0, - "query": "select fiscal_year as \"Fiscal Year:Data:80\",\n\tcompany as \"Company:Data:220\",\n\tposting_date as \"Posting Date:Date:100\",\n\taccount as \"Account:Data:380\",\n\tsum(debit) as \"Debit:Currency:140\",\n\tsum(credit) as \"Credit:Currency:140\"\nfrom `tabGL Entry`\ngroup by fiscal_year, company, posting_date, account\norder by fiscal_year, company, posting_date, account", + "query": "select fiscal_year as \"Fiscal Year:Data:80\",\n\tcompany as \"Company:Data:220\",\n\tposting_date as \"Posting Date:Date:100\",\n\taccount as \"Account:Data:380\",\n\tsum(debit) as \"Debit:Currency:140\",\n\tsum(credit) as \"Credit:Currency:140\",\n\tfinance_book as \"Finance Book:Link/Finance Book:140\"\nfrom `tabGL Entry`\ngroup by fiscal_year, company, posting_date, account\norder by fiscal_year, company, posting_date, account", "ref_doctype": "GL Entry", "report_name": "Trial Balance (Simple)", "report_type": "Query Report", From a5270e561fd28a176eb9941ae4b9ed6bf6b97e18 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 22 Jan 2019 15:43:04 +0530 Subject: [PATCH 16/38] fix: Unicode issue in purchase invoice --- erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index d28dc936bb0..f2d5006cd0a 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -1,7 +1,8 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt +# -*- coding: utf-8 -*- - +from __future__ import unicode_literals import frappe, erpnext from frappe.utils import cint, cstr, formatdate, flt, getdate, nowdate from frappe import _, throw From ecf64677991ace56b29bd1002b47b7476b704ce3 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 22 Jan 2019 17:41:56 +0530 Subject: [PATCH 17/38] fix(travis): Redis must be working for caching, so reverting (#16455) --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index e21d59511a9..9e63c0e6b04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,16 +30,16 @@ before_script: - cd ~/frappe-bench - bench get-app erpnext $TRAVIS_BUILD_DIR - bench use test_site + - bench reinstall --yes + - bench scheduler disable + - sed -i 's/9000/9001/g' sites/common_site_config.json + - bench start & + - sleep 10 jobs: include: - stage: test script: - - bench reinstall --yes - - bench scheduler disable - - sed -i 's/9000/9001/g' sites/common_site_config.json - - bench start & - - sleep 10 - set -e - bench run-tests env: Server Side Test From 2a9a867f053624fc35032dfd0d45196c155f4a59 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 22 Jan 2019 18:35:44 +0550 Subject: [PATCH 18/38] bumped to version 10.1.79 --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index db9ca3309e9..ff8ca747900 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe from erpnext.hooks import regional_overrides from frappe.utils import getdate -__version__ = '10.1.78' +__version__ = '10.1.79' def get_default_company(user=None): '''Get default company for user''' From 5555b2802f6d3e91f03cce562c9457604528c0d7 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 22 Jan 2019 18:37:09 +0550 Subject: [PATCH 19/38] bumped to version 11.0.3-beta.36 --- erpnext/hooks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index bbadd7f150f..cd352de3940 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -12,7 +12,7 @@ app_license = "GNU General Public License (v3)" source_link = "https://github.com/frappe/erpnext" develop_version = '12.x.x-develop' -staging_version = '11.0.3-beta.35' +staging_version = '11.0.3-beta.36' error_report_email = "support@erpnext.com" From da32916396721c3592044ef6ddef5c6316667a38 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 22 Jan 2019 19:06:06 +0530 Subject: [PATCH 20/38] fix: Enforce pricing rule based on rate on server side --- erpnext/controllers/accounts_controller.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index cd373b84d7e..f4cea4ad964 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -248,7 +248,6 @@ class AccountsController(TransactionBase): if self.get("is_subcontracted"): args["is_subcontracted"] = self.is_subcontracted ret = get_item_details(args) - for fieldname, value in ret.items(): if item.meta.get_field(fieldname) and value is not None: if (item.get(fieldname) is None or fieldname in force_item_fields): @@ -267,9 +266,10 @@ class AccountsController(TransactionBase): if ret.get("pricing_rule"): # if user changed the discount percentage then set user's discount percentage ? + item.set("pricing_rule", ret.get("pricing_rule")) item.set("discount_percentage", ret.get("discount_percentage")) - if ret.get("pricing_rule_for") == "Price": - item.set("pricing_list_rate", ret.get("pricing_list_rate")) + if ret.get("pricing_rule_for") == "Rate": + item.set("price_list_rate", ret.get("price_list_rate")) if item.price_list_rate: item.rate = flt(item.price_list_rate * From 237a871f17787b6a8842a3f3ac1e3efb3072d89a Mon Sep 17 00:00:00 2001 From: "FinByz Tech Pvt. Ltd" Date: Tue, 22 Jan 2019 20:49:06 +0530 Subject: [PATCH 21/38] fix: NoneType object has no attribute "gstin" (#16458) * fix: NoneType object has no attribute "gstin" * fix: handle NoneType values --- erpnext/regional/india/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py index fd0eb34abc9..d7a025805c2 100644 --- a/erpnext/regional/india/utils.py +++ b/erpnext/regional/india/utils.py @@ -5,7 +5,7 @@ from erpnext.regional.india import states, state_numbers from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount def validate_gstin_for_india(doc, method): - if not hasattr(doc, 'gstin'): + if not hasattr(doc, 'gstin') or not doc.gstin: return doc.gstin = doc.gstin.upper().strip() From 4b4265f8a7521a55d0c250c660412f3b8afe03b0 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Tue, 22 Jan 2019 20:54:21 +0530 Subject: [PATCH 22/38] fix(dead-code): Remove .py files (#16457) --- erpnext/crm/doctype/lead/.py | 9 --------- erpnext/manufacturing/doctype/work_order/.py | 8 -------- 2 files changed, 17 deletions(-) delete mode 100644 erpnext/crm/doctype/lead/.py delete mode 100644 erpnext/manufacturing/doctype/work_order/.py diff --git a/erpnext/crm/doctype/lead/.py b/erpnext/crm/doctype/lead/.py deleted file mode 100644 index 70a6b22a99f..00000000000 --- a/erpnext/crm/doctype/lead/.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.document import Document - -class Lead(Document): - pass diff --git a/erpnext/manufacturing/doctype/work_order/.py b/erpnext/manufacturing/doctype/work_order/.py deleted file mode 100644 index 4476b16dbc9..00000000000 --- a/erpnext/manufacturing/doctype/work_order/.py +++ /dev/null @@ -1,8 +0,0 @@ -import frappe - -def set_required_items(production_order): - pass - -def reserve_for_production(production_order): - '''Reserve pending raw materials for production''' - pass \ No newline at end of file From 55a08dee785da2ba6239d20e2a2d7a1f8634530e Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 23 Jan 2019 00:28:02 +0530 Subject: [PATCH 23/38] style: Remove unusued local variable --- erpnext/stock/stock_balance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py index 09d4e438406..045bee52d92 100644 --- a/erpnext/stock/stock_balance.py +++ b/erpnext/stock/stock_balance.py @@ -257,7 +257,7 @@ def repost_all_stock_vouchers(): doc.update_stock_ledger() doc.make_gl_entries(repost_future_gle=False) frappe.db.commit() - except Exception as e: + except Exception: print(frappe.get_traceback()) rejected.append([voucher_type, voucher_no]) frappe.db.rollback() From f79937d64b7ae9a61fd138440e1b33585118398f Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 23 Jan 2019 00:28:37 +0530 Subject: [PATCH 24/38] style: Remove unused imports --- erpnext/accounts/party.py | 2 +- erpnext/controllers/item_variant.py | 2 -- erpnext/controllers/selling_controller.py | 2 +- erpnext/controllers/stock_controller.py | 2 +- erpnext/hub_node/api.py | 4 ---- erpnext/shopping_cart/product_info.py | 2 +- erpnext/startup/__init__.py | 1 - erpnext/templates/utils.py | 5 ++--- erpnext/tests/test_woocommerce.py | 2 +- erpnext/www/payment_setup_certification.py | 1 - 10 files changed, 7 insertions(+), 16 deletions(-) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index a69a1722845..1d1eb21eaca 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -14,7 +14,7 @@ from frappe.contacts.doctype.address.address import (get_address_display, from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact from erpnext.exceptions import PartyFrozen, PartyDisabled, InvalidAccountCurrency from erpnext.accounts.utils import get_fiscal_year -from erpnext import get_default_currency, get_company_currency +from erpnext import get_company_currency from six import iteritems diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py index 24726ad03b1..646f23879a9 100644 --- a/erpnext/controllers/item_variant.py +++ b/erpnext/controllers/item_variant.py @@ -260,8 +260,6 @@ def generate_keyed_value_combinations(args): return results def copy_attributes_to_variant(item, variant): - from frappe.model import no_value_fields - # copy non no-copy fields exclude_fields = ["naming_series", "item_code", "item_name", "show_in_website", diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 684a2cdbcbe..a9883017cfa 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -8,7 +8,7 @@ from frappe import _, throw from erpnext.stock.get_item_details import get_bin_details from erpnext.stock.utils import get_incoming_rate from erpnext.stock.get_item_details import get_conversion_factor -from erpnext.stock.doctype.item.item import get_item_defaults, set_item_default +from erpnext.stock.doctype.item.item import set_item_default from frappe.contacts.doctype.address.address import get_address_display from erpnext.controllers.stock_controller import StockController diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 0b19b7aaf9a..0a3cd3499b1 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe, erpnext from frappe.utils import cint, flt, cstr -from frappe import msgprint, _ +from frappe import _ import frappe.defaults from erpnext.accounts.utils import get_fiscal_year from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map diff --git a/erpnext/hub_node/api.py b/erpnext/hub_node/api.py index c236822490d..0c94df31596 100644 --- a/erpnext/hub_node/api.py +++ b/erpnext/hub_node/api.py @@ -2,10 +2,6 @@ from __future__ import unicode_literals import frappe import json -import io -import base64 -import os -import requests from frappe import _ from frappe.frappeclient import FrappeClient diff --git a/erpnext/shopping_cart/product_info.py b/erpnext/shopping_cart/product_info.py index b5f129b4aa2..3af5afa0442 100644 --- a/erpnext/shopping_cart/product_info.py +++ b/erpnext/shopping_cart/product_info.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe from erpnext.shopping_cart.cart import _get_cart_quotation from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings \ - import is_cart_enabled, get_shopping_cart_settings, show_quantity_in_website + import get_shopping_cart_settings, show_quantity_in_website from erpnext.utilities.product import get_price, get_qty_in_stock @frappe.whitelist(allow_guest=True) diff --git a/erpnext/startup/__init__.py b/erpnext/startup/__init__.py index b65fc0f10e4..deef4ba4d68 100644 --- a/erpnext/startup/__init__.py +++ b/erpnext/startup/__init__.py @@ -19,7 +19,6 @@ # default settings that can be made for a user. from __future__ import unicode_literals -import frappe product_name = "ERPNext" user_defaults = { diff --git a/erpnext/templates/utils.py b/erpnext/templates/utils.py index eb84bcc8d85..03060201bbe 100644 --- a/erpnext/templates/utils.py +++ b/erpnext/templates/utils.py @@ -3,9 +3,8 @@ from __future__ import unicode_literals -import frappe, json -from frappe import _ -from frappe.utils import cint, formatdate +import frappe + @frappe.whitelist(allow_guest=True) def send_message(subject="Website Query", message="", sender="", status="Open"): diff --git a/erpnext/tests/test_woocommerce.py b/erpnext/tests/test_woocommerce.py index 0347e953f49..a48d48cde13 100644 --- a/erpnext/tests/test_woocommerce.py +++ b/erpnext/tests/test_woocommerce.py @@ -1,4 +1,4 @@ -import unittest, frappe, requests, os, time, erpnext +import unittest, frappe, requests, os, time from erpnext.erpnext_integrations.connectors.woocommerce_connection import order class TestWoocommerce(unittest.TestCase): diff --git a/erpnext/www/payment_setup_certification.py b/erpnext/www/payment_setup_certification.py index 185c2209422..c65cddb5cac 100644 --- a/erpnext/www/payment_setup_certification.py +++ b/erpnext/www/payment_setup_certification.py @@ -1,5 +1,4 @@ import frappe -import foundation no_cache = 1 From 819a16d0f56a011e216c869ebf9107f8cb0e7571 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 23 Jan 2019 07:57:08 +0530 Subject: [PATCH 25/38] fix(dead-code): Remove .py files (#16462) --- erpnext/crm/doctype/lead/.py | 9 --------- erpnext/manufacturing/doctype/production_order/.py | 8 -------- 2 files changed, 17 deletions(-) delete mode 100644 erpnext/crm/doctype/lead/.py delete mode 100644 erpnext/manufacturing/doctype/production_order/.py diff --git a/erpnext/crm/doctype/lead/.py b/erpnext/crm/doctype/lead/.py deleted file mode 100644 index 70a6b22a99f..00000000000 --- a/erpnext/crm/doctype/lead/.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals -import frappe -from frappe.model.document import Document - -class Lead(Document): - pass diff --git a/erpnext/manufacturing/doctype/production_order/.py b/erpnext/manufacturing/doctype/production_order/.py deleted file mode 100644 index 4476b16dbc9..00000000000 --- a/erpnext/manufacturing/doctype/production_order/.py +++ /dev/null @@ -1,8 +0,0 @@ -import frappe - -def set_required_items(production_order): - pass - -def reserve_for_production(production_order): - '''Reserve pending raw materials for production''' - pass \ No newline at end of file From 8c2a2c8f604c09114df41eaf739535e1628f08df Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 23 Jan 2019 10:33:47 +0530 Subject: [PATCH 26/38] fix(accounts): Validate gst accounts defined in GST Settings in eway bill report --- .../regional/report/eway_bill/eway_bill.py | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/erpnext/regional/report/eway_bill/eway_bill.py b/erpnext/regional/report/eway_bill/eway_bill.py index 1b5de274c58..5b9896be2a1 100644 --- a/erpnext/regional/report/eway_bill/eway_bill.py +++ b/erpnext/regional/report/eway_bill/eway_bill.py @@ -16,7 +16,7 @@ def execute(filters=None): return columns, data def get_data(filters): - + conditions = get_conditions(filters) data = frappe.db.sql(""" @@ -25,7 +25,7 @@ def get_data(filters): FROM `tabDelivery Note` AS dn join `tabDelivery Note Item` AS dni on (dni.parent = dn.name) WHERE - dn.docstatus < 2 + dn.docstatus < 2 %s """ % conditions, as_dict=1) unit = { @@ -40,14 +40,14 @@ def get_data(filters): 'Set': "SETS" } - # Regular expression set to remove all the special characters + # Regular expression set to remove all the special characters special_characters = "[$%^*()+\\[\]{};':\"\\|<>.?]" for row in data: set_defaults(row) set_taxes(row, filters) set_address_details(row, special_characters) - + # Eway Bill accepts date as dd/mm/yyyy and not dd-mm-yyyy row.posting_date = '/'.join(str(row.posting_date).replace("-", "/").split('/')[::-1]) row.lr_date = '/'.join(str(row.lr_date).replace("-", "/").split('/')[::-1]) @@ -66,7 +66,7 @@ def get_data(filters): return data def get_conditions(filters): - + conditions = "" conditions += filters.get('company') and " AND dn.company = '%s' " % filters.get('company') or "" @@ -92,7 +92,7 @@ def set_address_details(row, special_characters): row.update({'from_pin_code': pincode and pincode.replace(" ", "") or ''}) row.update({'from_state': state and state.upper() or ''}) row.update({'dispatch_state': row.from_state}) - + if row.get('shipping_address_name'): address_line1, address_line2, city, pincode, state = frappe.db.get_value("Address", row.get('shipping_address_name'), ['address_line1', 'address_line2', 'city', 'pincode', 'state']) @@ -104,20 +104,23 @@ def set_address_details(row, special_characters): row.update({'ship_to_state': row.to_state}) def set_taxes(row, filters): - taxes = frappe.get_list("Sales Taxes and Charges", + taxes = frappe.get_list("Sales Taxes and Charges", filters={ 'parent': row.dn_id - }, + }, fields=('item_wise_tax_detail', 'account_head')) account_list = ["cgst_account", "sgst_account", "igst_account", "cess_account"] taxes_list = frappe.get_list("GST Account", filters={ - "parent": "GST Settings", + "parent": "GST Settings", "company": filters.company }, fields=account_list) + if not taxes_list: + frappe.throw(_("Please set GST Accounts in GST Settings")) + item_tax_rate = {} for tax in taxes: From 49e09624d675c13538cc571169766569f5d95bd9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 23 Jan 2019 10:43:00 +0530 Subject: [PATCH 27/38] fix(projects): None type handling while updating tasks --- erpnext/projects/doctype/project/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index 9654ca345eb..dcf485a8030 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -162,7 +162,7 @@ class Project(Document): def is_row_updated(self, row, existing_task_data, fields): if self.get("__islocal") or not existing_task_data: return True - d = existing_task_data.get(row.task_id) + d = existing_task_data.get(row.task_id, {}) for field in fields: if row.get(field) != d.get(field): From 342854f6f2388599f0ccaf1b8ea4ba72bee08880 Mon Sep 17 00:00:00 2001 From: Frappe Bot Date: Wed, 23 Jan 2019 08:08:53 +0000 Subject: [PATCH 28/38] bumped to version 10.1.80 --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index ff8ca747900..847618232c7 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe from erpnext.hooks import regional_overrides from frappe.utils import getdate -__version__ = '10.1.79' +__version__ = '10.1.80' def get_default_company(user=None): '''Get default company for user''' From 2d5bf69dc445a26f59b9cd4516b5b31f3be2c17f Mon Sep 17 00:00:00 2001 From: Frappe Bot Date: Wed, 23 Jan 2019 08:12:19 +0000 Subject: [PATCH 29/38] bumped to version 11.0.3-beta.37 --- erpnext/hooks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index cd352de3940..3c3750a4fbb 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -12,7 +12,7 @@ app_license = "GNU General Public License (v3)" source_link = "https://github.com/frappe/erpnext" develop_version = '12.x.x-develop' -staging_version = '11.0.3-beta.36' +staging_version = '11.0.3-beta.37' error_report_email = "support@erpnext.com" From 853d3fd1ab6e03cc1fd50429ea2d4139d1d15c77 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 23 Jan 2019 16:34:22 +0530 Subject: [PATCH 30/38] fix: Don't use .format in jinja templates - Jinja doesn't allow unicode strings to be formatted in templates --- erpnext/templates/includes/cart/cart_items.html | 5 ++--- erpnext/templates/pages/order.html | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/erpnext/templates/includes/cart/cart_items.html b/erpnext/templates/includes/cart/cart_items.html index b2e68585a70..65b81d93209 100644 --- a/erpnext/templates/includes/cart/cart_items.html +++ b/erpnext/templates/includes/cart/cart_items.html @@ -21,12 +21,11 @@ + - +
{{ d.get_formatted("amount") }} -

{{ - _("Rate: {0}").format(d.get_formatted("rate")) }}

+

{{ _("Rate") }} {{ d.get_formatted("rate") }}

{% endfor %} \ No newline at end of file diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html index 74c9da0012c..64fd32a992a 100644 --- a/erpnext/templates/pages/order.html +++ b/erpnext/templates/pages/order.html @@ -73,14 +73,12 @@
{{ d.qty }} {% if d.delivered_qty is defined and d.delivered_qty != None %} -

{{ - _("Delivered: {0}").format(d.delivered_qty) }}

+

{{ _("Delivered") }} {{ d.delivered_qty }}

{% endif %}
{{ d.get_formatted("amount") }} -

{{ - _("@ {0}").format(d.get_formatted("rate")) }}

+

{{ _("Rate:") }} {{ d.get_formatted("rate") }}

{% endfor %} From 19ab86a3a7345eb986e2553c78f7bc92d3f1578f Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Wed, 23 Jan 2019 17:28:13 +0530 Subject: [PATCH 31/38] fix:(cost_center): fix for update cost center number --- erpnext/accounts/doctype/cost_center/cost_center.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/cost_center/cost_center.js b/erpnext/accounts/doctype/cost_center/cost_center.js index 8f3ae194da0..3df4da52efc 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center.js +++ b/erpnext/accounts/doctype/cost_center/cost_center.js @@ -46,7 +46,7 @@ frappe.ui.form.on('Cost Center', { doctype_name: frm.doc.doctype, name: frm.doc.name, field_name: d.fields[0].fieldname, - field_value: data.cost_center_number, + number_value: data.cost_center_number, company: frm.doc.company }, callback: function(r) { From c1658382280e2377bee7899bcb6a9f769756e84c Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 24 Jan 2019 15:45:46 +0530 Subject: [PATCH 32/38] Filter bin list based on warehouses that are accessible to the user --- erpnext/stock/dashboard/item_dashboard.py | 56 ++++++++++------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/erpnext/stock/dashboard/item_dashboard.py b/erpnext/stock/dashboard/item_dashboard.py index f95daafd384..8762920c6e1 100644 --- a/erpnext/stock/dashboard/item_dashboard.py +++ b/erpnext/stock/dashboard/item_dashboard.py @@ -1,43 +1,37 @@ from __future__ import unicode_literals import frappe +from frappe.model.db_query import DatabaseQuery @frappe.whitelist() def get_data(item_code=None, warehouse=None, item_group=None, start=0, sort_by='actual_qty', sort_order='desc'): '''Return data to render the item dashboard''' - conditions = [] - values = [] + filters = [] if item_code: - conditions.append('b.item_code=%s') - values.append(item_code) + filters.append(['item_code', '=', item_code]) if warehouse: - conditions.append('b.warehouse=%s') - values.append(warehouse) + filters.append(['warehouse', '=', warehouse]) if item_group: - conditions.append('i.item_group=%s') - values.append(item_group) + filters.append(['item_group', '=', item_group]) + try: + # check if user has any restrictions based on user permissions on warehouse + if DatabaseQuery('Warehouse', user=frappe.session.user).build_match_conditions(): + filters.append(['warehouse', 'in', [w.name for w in frappe.get_list('Warehouse')]]) + except frappe.PermissionError: + # user does not have access to warehouse + return [] - if conditions: - conditions = ' and ' + ' and '.join(conditions) - else: - conditions = '' - - return frappe.db.sql(''' - select - b.item_code, b.warehouse, b.projected_qty, b.reserved_qty, - b.reserved_qty_for_production, b.reserved_qty_for_sub_contract, b.actual_qty, b.valuation_rate, i.item_name - from - tabBin b, tabItem i - where - b.item_code = i.name - and - (b.projected_qty != 0 or b.reserved_qty != 0 or b.reserved_qty_for_production != 0 - or b.reserved_qty_for_sub_contract != 0 or b.actual_qty != 0) - {conditions} - order by - {sort_by} {sort_order} - limit - {start}, 21 - '''.format(conditions=conditions, sort_by=sort_by, sort_order=sort_order, - start=start), values, as_dict=True) + return frappe.db.get_all('Bin', fields=['item_code', 'warehouse', 'projected_qty', + 'reserved_qty', 'reserved_qty_for_sub_contract', 'actual_qty', 'valuation_rate'], + or_filters={ + 'projected_qty': ['!=', 0], + 'reserved_qty': ['!=', 0], + 'reserved_qty_for_production': ['!=', 0], + 'reserved_qty_for_sub_contract': ['!=', 0], + 'actual_qty': ['!=', 0], + }, + filters=filters, + order_by=sort_by + ' ' + sort_order, + limit_start=start, + limit_page_length='21') \ No newline at end of file From dd0496f7aae119de4bfa1586e0a3d08c7da5b71a Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 24 Jan 2019 16:18:43 +0530 Subject: [PATCH 33/38] Add missed out field field --- erpnext/stock/dashboard/item_dashboard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/dashboard/item_dashboard.py b/erpnext/stock/dashboard/item_dashboard.py index 8762920c6e1..6667317bf0a 100644 --- a/erpnext/stock/dashboard/item_dashboard.py +++ b/erpnext/stock/dashboard/item_dashboard.py @@ -23,7 +23,7 @@ def get_data(item_code=None, warehouse=None, item_group=None, return [] return frappe.db.get_all('Bin', fields=['item_code', 'warehouse', 'projected_qty', - 'reserved_qty', 'reserved_qty_for_sub_contract', 'actual_qty', 'valuation_rate'], + 'reserved_qty', 'reserved_qty_for_production', 'reserved_qty_for_sub_contract', 'actual_qty', 'valuation_rate'], or_filters={ 'projected_qty': ['!=', 0], 'reserved_qty': ['!=', 0], From 7a45887fa192be2d3293777be252e8b0ac139375 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 24 Jan 2019 16:26:48 +0530 Subject: [PATCH 34/38] fix typo --- erpnext/stock/dashboard/item_dashboard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/dashboard/item_dashboard.py b/erpnext/stock/dashboard/item_dashboard.py index 6667317bf0a..d817e5ff2d9 100644 --- a/erpnext/stock/dashboard/item_dashboard.py +++ b/erpnext/stock/dashboard/item_dashboard.py @@ -19,7 +19,7 @@ def get_data(item_code=None, warehouse=None, item_group=None, if DatabaseQuery('Warehouse', user=frappe.session.user).build_match_conditions(): filters.append(['warehouse', 'in', [w.name for w in frappe.get_list('Warehouse')]]) except frappe.PermissionError: - # user does not have access to warehouse + # user does not have access on warehouse return [] return frappe.db.get_all('Bin', fields=['item_code', 'warehouse', 'projected_qty', @@ -34,4 +34,4 @@ def get_data(item_code=None, warehouse=None, item_group=None, filters=filters, order_by=sort_by + ' ' + sort_order, limit_start=start, - limit_page_length='21') \ No newline at end of file + limit_page_length='21') From badf1c42e043cc7f2962bbad0a817123dd6900b1 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 24 Jan 2019 16:28:53 +0530 Subject: [PATCH 35/38] chore: Add error logging for failed get_exchange_rate call --- erpnext/setup/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py index 0216c3ba69a..01e0b7d441a 100644 --- a/erpnext/setup/utils.py +++ b/erpnext/setup/utils.py @@ -109,6 +109,7 @@ def get_exchange_rate(from_currency, to_currency, transaction_date=None, args=No cache.setex(key, value, 6 * 60 * 60) return flt(value) except: + frappe.log_error(title="Get Exchange Rate") frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually").format(from_currency, to_currency, transaction_date)) return 0.0 From d6f837c5e5249f120990ecfc65848822e8c8bc7c Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 24 Jan 2019 17:10:33 +0530 Subject: [PATCH 36/38] fix: Dont show 0 amount taxes and tax breakup --- .../print_format/gst_pos_invoice/gst_pos_invoice.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/print_format/gst_pos_invoice/gst_pos_invoice.json b/erpnext/accounts/print_format/gst_pos_invoice/gst_pos_invoice.json index 33af3135dd2..8a313688b98 100644 --- a/erpnext/accounts/print_format/gst_pos_invoice/gst_pos_invoice.json +++ b/erpnext/accounts/print_format/gst_pos_invoice/gst_pos_invoice.json @@ -7,10 +7,10 @@ "docstatus": 0, "doctype": "Print Format", "font": "Default", - "html": "\n\n

\n\t{{ doc.company }}
\n\t{% if doc.company_address_display %}\n\t\t{% set company_address = doc.company_address_display.replace(\"\\n\", \" \").replace(\"
\", \" \") %}\n\t\t{% if \"GSTIN\" not in company_address %}\n\t\t\t{{ company_address }}\n\t\t\t{{ _(\"GSTIN\") }}:{{ doc.company_gstin }}\n\t\t{% else %}\n\t\t\t{{ company_address.replace(\"GSTIN\", \"
GSTIN\") }}\n\t\t{% endif %}\n\t{% endif %}\n\t
\n\t{% if doc.docstatus == 0 %}\n\t\t{{ doc.status + \" \"+ (doc.select_print_heading or _(\"Invoice\")) }}
\n\t{% else %}\n\t\t{{ doc.select_print_heading or _(\"Invoice\") }}
\n\t{% endif %}\n

\n

\n\t{{ _(\"Receipt No\") }}: {{ doc.name }}
\n\t{{ _(\"Date\") }}: {{ doc.get_formatted(\"posting_date\") }}
\n\t{% if doc.grand_total > 50000 %}\n\t\t{% set customer_address = doc.address_display.replace(\"\\n\", \" \").replace(\"
\", \" \") %}\n\t\t{{ _(\"Customer\") }}:
\n\t\t{{ doc.customer_name }}
\n\t\t{{ customer_address }}\n\t{% endif %}\n

\n\n
\n\n\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\n\t\n\t\t{%- for item in doc.items -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t{%- endfor -%}\n\t\n
{{ _(\"Item\") }}{{ _(\"Qty\") }}{{ _(\"Amount\") }}
\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t
{{ item.item_name }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.gst_hsn_code -%}\n\t\t\t\t\t
{{ _(\"HSN/SAC\") }}: {{ item.gst_hsn_code }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.serial_no -%}\n\t\t\t\t\t
{{ _(\"Serial No\") }}: {{ item.serial_no }}\n\t\t\t\t{%- endif -%}\n\t\t\t
{{ item.qty }}
@ {{ item.rate }}
{{ item.get_formatted(\"amount\") }}
\n\n\t\n\t\t\n\t\t\t{% if doc.flags.show_inclusive_tax_in_print %}\n\t\t\t\t\n\t\t\t\t\n\t\t\t{% else %}\n\t\t\t\t\n\t\t\t\t\n\t\t\t{% endif %}\n\t\t\n\t\t{%- for row in doc.taxes -%}\n\t\t {%- if not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print -%}\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t {%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t{%- endif -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t{%- if doc.rounded_total -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t{%- endif -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t{%- if doc.change_amount -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t{%- endif -%}\n\t\n
\n\t\t\t\t\t{{ _(\"Total Excl. Tax\") }}\n\t\t\t\t\n\t\t\t\t\t{{ doc.get_formatted(\"net_total\", doc) }}\n\t\t\t\t\n\t\t\t\t\t{{ _(\"Total\") }}\n\t\t\t\t\n\t\t\t\t\t{{ doc.get_formatted(\"total\", doc) }}\n\t\t\t\t
\n\t\t\t\t\t{{ row.description }}\n\t\t\t\t\n\t\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t\t
\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t
\n\t\t\t\t{{ _(\"Grand Total\") }}\n\t\t\t\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t
\n\t\t\t\t{{ _(\"Rounded Total\") }}\n\t\t\t\n\t\t\t\t{{ doc.get_formatted(\"rounded_total\") }}\n\t\t\t
\n\t\t\t\t{{ _(\"Paid Amount\") }}\n\t\t\t\n\t\t\t\t{{ doc.get_formatted(\"paid_amount\") }}\n\t\t\t
\n\t\t\t\t{{ _(\"Change Amount\") }}\n\t\t\t\n\t\t\t\t{{ doc.get_formatted(\"change_amount\") }}\n\t\t\t
\n

Tax Breakup:

\n
\n\t{{ doc.other_charges_calculation }}\n
\n

{{ doc.terms or \"\" }}

\n

{{ _(\"Thank you, please visit again.\") }}

", + "html": "\n\n

\n\t{{ doc.company }}
\n\t{% if doc.company_address_display %}\n\t\t{% set company_address = doc.company_address_display.replace(\"\\n\", \" \").replace(\"
\", \" \") %}\n\t\t{% if \"GSTIN\" not in company_address %}\n\t\t\t{{ company_address }}\n\t\t\t{{ _(\"GSTIN\") }}:{{ doc.company_gstin }}\n\t\t{% else %}\n\t\t\t{{ company_address.replace(\"GSTIN\", \"
GSTIN\") }}\n\t\t{% endif %}\n\t{% endif %}\n\t
\n\t{% if doc.docstatus == 0 %}\n\t\t{{ doc.status + \" \"+ (doc.select_print_heading or _(\"Invoice\")) }}
\n\t{% else %}\n\t\t{{ doc.select_print_heading or _(\"Invoice\") }}
\n\t{% endif %}\n

\n

\n\t{{ _(\"Receipt No\") }}: {{ doc.name }}
\n\t{{ _(\"Date\") }}: {{ doc.get_formatted(\"posting_date\") }}
\n\t{% if doc.grand_total > 50000 %}\n\t\t{% set customer_address = doc.address_display.replace(\"\\n\", \" \").replace(\"
\", \" \") %}\n\t\t{{ _(\"Customer\") }}:
\n\t\t{{ doc.customer_name }}
\n\t\t{{ customer_address }}\n\t{% endif %}\n

\n\n
\n\n\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\n\t\n\t\t{%- for item in doc.items -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t{%- endfor -%}\n\t\n
{{ _(\"Item\") }}{{ _(\"Qty\") }}{{ _(\"Amount\") }}
\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t
{{ item.item_name }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.gst_hsn_code -%}\n\t\t\t\t\t
{{ _(\"HSN/SAC\") }}: {{ item.gst_hsn_code }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.serial_no -%}\n\t\t\t\t\t
{{ _(\"Serial No\") }}: {{ item.serial_no }}\n\t\t\t\t{%- endif -%}\n\t\t\t
{{ item.qty }}
@ {{ item.rate }}
{{ item.get_formatted(\"amount\") }}
\n\n\t\n\t\t\n\t\t\t{% if doc.flags.show_inclusive_tax_in_print %}\n\t\t\t\t\n\t\t\t\t\n\t\t\t{% else %}\n\t\t\t\t\n\t\t\t\t\n\t\t\t{% endif %}\n\t\t\n\t\t{%- for row in doc.taxes -%}\n\t\t {%- if (not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) and row.tax_amount != 0 -%}\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t {%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t{%- endif -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t{%- if doc.rounded_total -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t{%- endif -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t{%- if doc.change_amount -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t{%- endif -%}\n\t\n
\n\t\t\t\t\t{{ _(\"Total Excl. Tax\") }}\n\t\t\t\t\n\t\t\t\t\t{{ doc.get_formatted(\"net_total\", doc) }}\n\t\t\t\t\n\t\t\t\t\t{{ _(\"Total\") }}\n\t\t\t\t\n\t\t\t\t\t{{ doc.get_formatted(\"total\", doc) }}\n\t\t\t\t
\n\t\t\t\t\t{{ row.description }}\n\t\t\t\t\n\t\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t\t
\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t
\n\t\t\t\t{{ _(\"Grand Total\") }}\n\t\t\t\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t
\n\t\t\t\t{{ _(\"Rounded Total\") }}\n\t\t\t\n\t\t\t\t{{ doc.get_formatted(\"rounded_total\") }}\n\t\t\t
\n\t\t\t\t{{ _(\"Paid Amount\") }}\n\t\t\t\n\t\t\t\t{{ doc.get_formatted(\"paid_amount\") }}\n\t\t\t
\n\t\t\t\t{{ _(\"Change Amount\") }}\n\t\t\t\n\t\t\t\t{{ doc.get_formatted(\"change_amount\") }}\n\t\t\t
\n

{{ doc.terms or \"\" }}

\n

{{ _(\"Thank you, please visit again.\") }}

", "idx": 0, "line_breaks": 0, - "modified": "2018-03-20 14:24:08.167930", + "modified": "2019-01-24 17:09:27.190929", "modified_by": "Administrator", "module": "Accounts", "name": "GST POS Invoice", From 74df01d3d10bfeb89b6605602a11fd8826c47b71 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 24 Jan 2019 23:59:00 +0530 Subject: [PATCH 37/38] fix: ascii code while opening offline POS --- erpnext/accounts/doctype/sales_invoice/pos.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index 287da08ef5f..1ef7b5403c5 100755 --- a/erpnext/accounts/doctype/sales_invoice/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/pos.py @@ -333,10 +333,12 @@ def get_bin_data(pos_profile): itemwise_bin_data = {} cond = "1=1" if pos_profile.get('warehouse'): - cond = "warehouse = '{0}'".format(pos_profile.get('warehouse')) + cond = "warehouse = %(warehouse)s" bin_data = frappe.db.sql(""" select item_code, warehouse, actual_qty from `tabBin` - where actual_qty > 0 and {cond}""".format(cond=cond), as_dict=1) + where actual_qty > 0 and {cond}""".format(cond=cond), { + 'warehouse': frappe.db.escape(pos_profile.get('warehouse')) + }, as_dict=1) for bins in bin_data: if bins.item_code not in itemwise_bin_data: From e14cc8f2b67393c23f7c6e6f087670369bb0e446 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 25 Jan 2019 00:23:41 +0530 Subject: [PATCH 38/38] fix: bank reconcilliation showing multiple entries against one JV --- .../doctype/bank_reconciliation/bank_reconciliation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py index 7814b0883da..917276293d2 100644 --- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py +++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py @@ -26,7 +26,7 @@ class BankReconciliation(Document): select "Journal Entry" as payment_document, t1.name as payment_entry, t1.cheque_no as cheque_number, t1.cheque_date, - t2.debit_in_account_currency as debit, t2.credit_in_account_currency as credit, + sum(t2.debit_in_account_currency) as debit, sum(t2.credit_in_account_currency) as credit, t1.posting_date, t2.against_account, t1.clearance_date, t2.account_currency from `tabJournal Entry` t1, `tabJournal Entry Account` t2 @@ -34,6 +34,7 @@ class BankReconciliation(Document): t2.parent = t1.name and t2.account = %s and t1.docstatus=1 and t1.posting_date >= %s and t1.posting_date <= %s and ifnull(t1.is_opening, 'No') = 'No' {0} + group by t2.account, t1.name order by t1.posting_date ASC, t1.name DESC """.format(condition), (self.bank_account, self.from_date, self.to_date), as_dict=1)