diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py index 7814b0883d..917276293d 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) diff --git a/erpnext/accounts/doctype/cost_center/cost_center.js b/erpnext/accounts/doctype/cost_center/cost_center.js index 8f3ae194da..3df4da52ef 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) { diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index 287da08ef5..1ef7b5403c 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: 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 33af3135dd..8a313688b9 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", 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 13424dbcb5..0861b20f14 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 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 0000000000..e69de29bb2 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 0000000000..a123631663 --- /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 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"]); + }); + } 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 0000000000..91e4e197d3 --- /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 0000000000..e33bd61411 --- /dev/null +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py @@ -0,0 +1,321 @@ +# 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 _ +from frappe.utils import getdate, nowdate +from six import iteritems, itervalues + +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]) + + 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 + + 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" + discount_allowed_or_received = "Discount Allowed" if self.filters.party_type == "Customer" else "Discount Received" + + columns += [ + { + "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": _(discount_allowed_or_received), + "fieldname": "discount_amount", + "fieldtype": "Currency", + "options": "currency", + "width": 120 + }, + { + "label": _("Write Off Amount"), + "fieldname": "write_off_amount", + "fieldtype": "Currency", + "options": "currency", + "width": 120 + }, + { + "label": _("Other Adjustments"), + "fieldname": "adjustment_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 + } + ] + + return columns + + def get_data(self): + if not self.filters.get("company"): + self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company') + + 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" + + self.get_gl_entries() + self.get_return_invoices() + 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": gle.party_name, + "opening_balance": 0, + "invoiced_amount": 0, + "paid_amount": 0, + "return_amount": 0, + "closing_balance": 0, + "currency": company_currency + })) + + 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 + + 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 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) + 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() + 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 + 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 + 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 = [""] + + 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("""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)) + + 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_adjustment_amounts(self): + conditions = self.prepare_conditions() + 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" + + 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.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 + 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} + ) + """.format(conditions=conditions, income_or_expense=income_or_expense), self.filters, as_dict=True) + + self.party_adjustment_details = {} + adjustment_voucher_entries = {} + for gle in gl_entries: + adjustment_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), []) + adjustment_voucher_entries[(gle.voucher_type, gle.voucher_no)].append(gle) + + for voucher_gl_entries in itervalues(adjustment_voucher_entries): + parties = {} + accounts = {} + has_irrelevant_entry = False + + for gle in voucher_gl_entries: + 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, "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 accounts: + if len(parties) == 1: + 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 = { + "party_type": "Customer", + "naming_by": ["Selling Settings", "cust_master_name"], + } + return PartyLedgerSummaryReport(filters).run(args) 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 0000000000..e69de29bb2 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 0000000000..6fd16f2090 --- /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 0000000000..eb3b4123e2 --- /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 0000000000..d2c23ee4e7 --- /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 diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py index 9d8e1bf3c3..42d0df0a06 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", diff --git a/erpnext/regional/report/eway_bill/eway_bill.py b/erpnext/regional/report/eway_bill/eway_bill.py index 1b5de274c5..5b9896be2a 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: diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index 16676ac78a..70e047a4e8 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 01f8956a82..77c371e0cd 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", diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py index 0216c3ba69..01e0b7d441 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 diff --git a/erpnext/stock/dashboard/item_dashboard.py b/erpnext/stock/dashboard/item_dashboard.py index f95daafd38..d817e5ff2d 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 on 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_production', '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') diff --git a/erpnext/templates/includes/cart/cart_items.html b/erpnext/templates/includes/cart/cart_items.html index b2e68585a7..65b81d9320 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 74c9da0012..64fd32a992 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 %}