diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 16c346baa8..48296e7e33 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from erpnext.hooks import regional_overrides -__version__ = '8.9.1' +__version__ = '8.9.2' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 92a805f37d..12e46c42d3 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -569,7 +569,7 @@ frappe.ui.form.on('Payment Entry', { }) var allocated_negative_outstanding = 0; - if((frm.doc.payment_type=="Receive" && frm.doc.party_type=="Customer") || + if ((frm.doc.payment_type=="Receive" && frm.doc.party_type=="Customer") || (frm.doc.payment_type=="Pay" && frm.doc.party_type=="Supplier") || (frm.doc.payment_type=="Pay" && frm.doc.party_type=="Employee")) { if(total_positive_outstanding_including_order > paid_amount) { @@ -579,7 +579,7 @@ frappe.ui.form.on('Payment Entry', { } var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding; - } else { + } else if (in_list(["Customer", "Supplier"], frm.doc.party_type)) { if(paid_amount > total_negative_outstanding) { if(total_negative_outstanding == 0) { frappe.msgprint(__("Cannot {0} {1} {2} without any negative outstanding invoice", diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 3171ff01bf..fa458df472 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -2,7 +2,7 @@ # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals -import frappe +import frappe, erpnext from frappe import _ from frappe.utils import flt from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import get_tax_accounts @@ -14,10 +14,12 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum if not filters: filters = {} columns = get_columns(additional_table_columns) + company_currency = erpnext.get_company_currency(filters.company) + item_list = get_items(filters, additional_query_columns) aii_account_map = get_aii_accounts() if item_list: - itemised_tax, tax_columns = get_tax_accounts(item_list, columns, + itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency, doctype="Purchase Invoice", tax_doctype="Purchase Taxes and Charges") columns.append({ @@ -26,7 +28,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum "fieldtype": "Data", "width": 80 }) - company_currency = frappe.db.get_value("Company", filters.company, "default_currency") + po_pr_map = get_purchase_receipts_against_purchase_order(item_list) data = [] diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 7009d5dc79..0fc58316ef 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -2,9 +2,10 @@ # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals -import frappe +import frappe, erpnext from frappe import _ from frappe.utils import flt +from frappe.model.meta import get_field_precision from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments def execute(filters=None): @@ -14,16 +15,17 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum if not filters: filters = {} columns = get_columns(additional_table_columns) + company_currency = erpnext.get_company_currency(filters.company) + item_list = get_items(filters, additional_query_columns) if item_list: - itemised_tax, tax_columns = get_tax_accounts(item_list, columns) + itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency) columns.append({ "fieldname": "currency", "label": _("Currency"), "fieldtype": "Data", "width": 80 }) - company_currency = frappe.db.get_value("Company", filters.get("company"), "default_currency") mode_of_payments = get_mode_of_payments(set([d.parent for d in item_list])) so_dn_map = get_delivery_notes_against_sales_order(item_list) @@ -140,16 +142,25 @@ def get_delivery_notes_against_sales_order(item_list): return so_dn_map -def get_tax_accounts(item_list, columns, doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"): +def get_tax_accounts(item_list, columns, company_currency, + doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"): import json item_row_map = {} tax_columns = [] invoice_item_row = {} itemised_tax = {} + + tax_amount_precision = get_field_precision(frappe.get_meta(tax_doctype).get_field("tax_amount"), + currency=company_currency) or 2 + for d in item_list: invoice_item_row.setdefault(d.parent, []).append(d) item_row_map.setdefault(d.parent, {}).setdefault(d.item_code, []).append(d) + conditions = "" + if doctype == "Purchase Invoice": + conditions = " and category in ('Total', 'Valuation and Total')" + tax_details = frappe.db.sql(""" select parent, description, item_wise_tax_detail, @@ -159,8 +170,9 @@ def get_tax_accounts(item_list, columns, doctype="Sales Invoice", tax_doctype="S parenttype = %s and docstatus = 1 and (description is not null and description != '') and parent in (%s) + %s order by description - """ % (tax_doctype, '%s', ', '.join(['%s']*len(invoice_item_row))), + """ % (tax_doctype, '%s', ', '.join(['%s']*len(invoice_item_row)), conditions), tuple([doctype] + invoice_item_row.keys())) for parent, description, item_wise_tax_detail, charge_type, tax_amount in tax_details: @@ -192,7 +204,7 @@ def get_tax_accounts(item_list, columns, doctype="Sales Invoice", tax_doctype="S if item_tax_amount: itemised_tax.setdefault(d.name, {})[description] = frappe._dict({ "tax_rate": tax_rate, - "tax_amount": item_tax_amount + "tax_amount": flt(item_tax_amount, tax_amount_precision) }) except ValueError: @@ -201,7 +213,8 @@ def get_tax_accounts(item_list, columns, doctype="Sales Invoice", tax_doctype="S for d in invoice_item_row.get(parent, []): itemised_tax.setdefault(d.name, {})[description] = frappe._dict({ "tax_rate": "NA", - "tax_amount": flt((tax_amount * d.base_net_amount) / d.base_net_total) + "tax_amount": flt((tax_amount * d.base_net_amount) / d.base_net_total, + tax_amount_precision) }) tax_columns.sort() diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 6d69a48ab8..11c0790976 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -232,7 +232,7 @@ def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, select `tabDelivery Note`.name, `tabDelivery Note`.customer, `tabDelivery Note`.posting_date from `tabDelivery Note` where `tabDelivery Note`.`%(key)s` like %(txt)s and - `tabDelivery Note`.docstatus = 1 and `tabDelivery Note`.is_return = 0 + `tabDelivery Note`.docstatus = 1 and `tabDelivery Note`.is_return = 0 and status not in ("Stopped", "Closed") %(fcond)s and (`tabDelivery Note`.per_billed < 100 or `tabDelivery Note`.grand_total = 0) %(mcond)s order by `tabDelivery Note`.`%(key)s` asc @@ -367,31 +367,30 @@ def warehouse_query(doctype, txt, searchfield, start, page_len, filters): sub_query = """ select round(`tabBin`.actual_qty, 2) from `tabBin` where `tabBin`.warehouse = `tabWarehouse`.name {bin_conditions} """.format( - bin_conditions=get_filters_cond(doctype, filter_dict.get("Bin"), + bin_conditions=get_filters_cond(doctype, filter_dict.get("Bin"), bin_conditions, ignore_permissions=True)) - response = frappe.db.sql("""select `tabWarehouse`.name, + query = """select `tabWarehouse`.name, CONCAT_WS(" : ", "Actual Qty", ifnull( ({sub_query}), 0) ) as actual_qty from `tabWarehouse` where - `tabWarehouse`.`{key}` like %(txt)s + `tabWarehouse`.`{key}` like '{txt}' {fcond} {mcond} order by `tabWarehouse`.name desc limit - %(start)s, %(page_len)s + {start}, {page_len} """.format( sub_query=sub_query, key=frappe.db.escape(searchfield), fcond=get_filters_cond(doctype, filter_dict.get("Warehouse"), conditions), - mcond=get_match_cond(doctype) - ), - { - "txt": "%%%s%%" % frappe.db.escape(txt), - "start": start, - "page_len": page_len - }) - return response + mcond=get_match_cond(doctype), + start=start, + page_len=page_len, + txt=frappe.db.escape('%{0}%'.format(txt)) + ) + + return frappe.db.sql(query) def get_doctype_wise_filters(filters): diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 97bd771fa2..c627664ea5 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -270,7 +270,7 @@ class calculate_taxes_and_totals(object): if tax.item_wise_tax_detail.get(key): item_wise_tax_amount += tax.item_wise_tax_detail[key][1] - tax.item_wise_tax_detail[key] = [tax_rate,flt(item_wise_tax_amount, tax.precision("base_tax_amount"))] + tax.item_wise_tax_detail[key] = [tax_rate,flt(item_wise_tax_amount)] def round_off_totals(self, tax): tax.tax_amount = flt(tax.tax_amount, tax.precision("tax_amount")) @@ -521,12 +521,20 @@ def get_itemised_tax_breakup_html(doc): frappe.flags.company = doc.company # get headers - tax_accounts = list(set([d.description for d in doc.taxes])) + tax_accounts = [] + for tax in doc.taxes: + if getattr(tax, "category", None) and tax.category=="Valuation": + continue + if tax.description not in tax_accounts: + tax_accounts.append(tax.description) + headers = get_itemised_tax_breakup_header(doc.doctype + " Item", tax_accounts) # get tax breakup data itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(doc) - + + get_rounded_tax_amount(itemised_tax, doc.precision("tax_amount", "taxes")) + frappe.flags.company = None return frappe.render_template( @@ -554,6 +562,9 @@ def get_itemised_tax_breakup_data(doc): def get_itemised_tax(taxes): itemised_tax = {} for tax in taxes: + if getattr(tax, "category", None) and tax.category=="Valuation": + continue + tax_amount_precision = tax.precision("tax_amount") tax_rate_precision = tax.precision("rate") @@ -562,16 +573,16 @@ def get_itemised_tax(taxes): for item_code, tax_data in item_tax_map.items(): itemised_tax.setdefault(item_code, frappe._dict()) - if isinstance(tax_data, list) and tax_data[0]: + if isinstance(tax_data, list): precision = tax_amount_precision if tax.charge_type == "Actual" else tax_rate_precision itemised_tax[item_code][tax.description] = frappe._dict(dict( - tax_rate=flt(tax_data[0], precision), - tax_amount=flt(tax_data[1], tax_amount_precision) + tax_rate=flt(tax_data[0]), + tax_amount=flt(tax_data[1]) )) else: itemised_tax[item_code][tax.description] = frappe._dict(dict( - tax_rate=flt(tax_data, tax_rate_precision), + tax_rate=flt(tax_data), tax_amount=0.0 )) @@ -584,4 +595,10 @@ def get_itemised_taxable_amount(items): itemised_taxable_amount.setdefault(item_code, 0) itemised_taxable_amount[item_code] += item.net_amount - return itemised_taxable_amount \ No newline at end of file + return itemised_taxable_amount + +def get_rounded_tax_amount(itemised_tax, precision): + # Rounding based on tax_amount precision + for taxes in itemised_tax.values(): + for tax_account in taxes: + taxes[tax_account]["tax_amount"] = flt(taxes[tax_account]["tax_amount"], precision) \ No newline at end of file diff --git a/erpnext/patches.txt b/erpnext/patches.txt index d781ec788f..35530fd9cf 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -432,4 +432,5 @@ erpnext.patches.v8_5.update_customer_group_in_POS_profile erpnext.patches.v8_6.update_timesheet_company_from_PO erpnext.patches.v8_6.set_write_permission_for_quotation_for_sales_manager erpnext.patches.v8_5.remove_project_type_property_setter -erpnext.patches.v8_7.add_more_gst_fields \ No newline at end of file +erpnext.patches.v8_7.add_more_gst_fields +erpnext.patches.v8_7.fix_purchase_receipt_status \ No newline at end of file diff --git a/erpnext/patches/v8_7/fix_purchase_receipt_status.py b/erpnext/patches/v8_7/fix_purchase_receipt_status.py new file mode 100644 index 0000000000..f7037dd7df --- /dev/null +++ b/erpnext/patches/v8_7/fix_purchase_receipt_status.py @@ -0,0 +1,12 @@ +import frappe + +def execute(): + # there is no more status called "Submitted", there was an old issue that used + # to set it as Submitted, fixed in this commit + frappe.db.sql(""" + update + `tabPurchase Receipt` + set + status = 'To Bill' + where + status = 'Submitted'""") \ No newline at end of file diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 0444369ff3..d12c288a28 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -115,9 +115,6 @@ class PurchaseReceipt(BuyingController): frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, self.company, self.base_grand_total) - # Set status as Submitted - frappe.db.set(self, 'status', 'Submitted') - self.update_prevdoc_status() if self.per_billed < 100: self.update_billing_status() @@ -152,8 +149,6 @@ class PurchaseReceipt(BuyingController): if submitted: frappe.throw(_("Purchase Invoice {0} is already submitted").format(submitted[0][0])) - frappe.db.set(self,'status','Cancelled') - self.update_prevdoc_status() self.update_billing_status() diff --git a/erpnext/templates/includes/itemised_tax_breakup.html b/erpnext/templates/includes/itemised_tax_breakup.html index 2ffc8b4b83..75212d5a1a 100644 --- a/erpnext/templates/includes/itemised_tax_breakup.html +++ b/erpnext/templates/includes/itemised_tax_breakup.html @@ -22,7 +22,9 @@ {% set tax_details = taxes.get(tax_account) %} {% if tax_details %} - ({{ tax_details.tax_rate }}) + {% if tax_details.tax_rate or not tax_details.tax_amount %} + ({{ tax_details.tax_rate }}) + {% endif %} {{ frappe.utils.fmt_money(tax_details.tax_amount, None, company_currency) }} {% else %}