diff --git a/posawesome/__init__.py b/posawesome/__init__.py index 245ac8d9..36bec1d3 100644 --- a/posawesome/__init__.py +++ b/posawesome/__init__.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals import frappe -__version__ = "6.1.1" +__version__ = "6.1.2" def console(*data): diff --git a/posawesome/hooks.py b/posawesome/hooks.py index dab4e16e..46a71f9d 100644 --- a/posawesome/hooks.py +++ b/posawesome/hooks.py @@ -143,6 +143,10 @@ # "Task": "posawesome.task.get_dashboard_data" # } +override_doctype_class = { + "Sales Invoice": "posawesome.posawesome.api.taxes.customSalesInvoice", +} + # exempt linked doctypes from being automatically cancelled # # auto_cancel_exempted_doctypes = ["Auto Repeat"] diff --git a/posawesome/posawesome/api/posapp.py b/posawesome/posawesome/api/posapp.py index d737a14c..23fbb0f1 100644 --- a/posawesome/posawesome/api/posapp.py +++ b/posawesome/posawesome/api/posapp.py @@ -30,7 +30,6 @@ get_applicable_delivery_charges as _get_applicable_delivery_charges, ) from frappe.utils.caching import redis_cache -from posawesome.posawesome.api.taxes import calculate_taxes @frappe.whitelist() @@ -493,7 +492,6 @@ def update_invoice(data): for tax in invoice_doc.taxes: tax.included_in_print_rate = 1 - calculate_taxes(invoice_doc) invoice_doc.save() return invoice_doc diff --git a/posawesome/posawesome/api/taxes.py b/posawesome/posawesome/api/taxes.py index 58af9b6b..59409c09 100644 --- a/posawesome/posawesome/api/taxes.py +++ b/posawesome/posawesome/api/taxes.py @@ -6,160 +6,19 @@ from __future__ import unicode_literals # import frappe -import json -from frappe import _ -from frappe.utils import flt, cint, nowdate +from frappe.utils import flt +from erpnext.controllers.taxes_and_totals import calculate_taxes_and_totals +from erpnext.accounts.doctype.sales_invoice.sales_invoice import SalesInvoice -def calculate_taxes(invoice_doc): - invoice_doc.transaction_date = nowdate() - rounding_adjustment_computed = invoice_doc.get( - "is_consolidated" - ) and invoice_doc.get("rounding_adjustment") - if not rounding_adjustment_computed: - invoice_doc.rounding_adjustment = 0 +class custom_calculate_taxes_and_totals(calculate_taxes_and_totals): + def _get_tax_rate(self, tax, item_tax_map): + if tax.account_head in item_tax_map: + return flt(item_tax_map.get(tax.account_head), self.doc.precision("rate", tax)) + else: + return 0 - # maintain actual tax rate based on idx - actual_tax_dict = dict( - [ - [tax.idx, flt(tax.tax_amount, tax.precision("tax_amount"))] - for tax in invoice_doc.get("taxes") - if tax.charge_type == "Actual" - ] - ) - for tax in invoice_doc.get("taxes"): - if not (invoice_doc.get("is_consolidated") or tax.get("dont_recompute_tax")): - tax.item_wise_tax_detail = {} - tax.tax_amount = 0.0 - tax.tax_amount_after_discount_amount = 0.0 - - discount_amount_applied = False - if invoice_doc.apply_discount_on == "Grand Total" and invoice_doc.get( - "is_cash_or_non_trade_discount" - ): - discount_amount_applied = True - - for n, item in enumerate(invoice_doc.items): - item.net_amount = item.amount - item_tax_map = _load_item_tax_rate(item.item_tax_rate) - - for i, tax in enumerate(invoice_doc.get("taxes")): - # tax_amount represents the amount of tax for the current step - current_tax_amount = get_current_tax_amount( - invoice_doc, item, tax, item_tax_map - ) - - # Adjust divisional loss to the last item - if tax.charge_type == "Actual": - actual_tax_dict[tax.idx] -= current_tax_amount - if n == len(invoice_doc.items) - 1: - current_tax_amount += actual_tax_dict[tax.idx] - - # accumulate tax amount into tax.tax_amount - if tax.charge_type != "Actual" and not ( - discount_amount_applied - and invoice_doc.apply_discount_on == "Grand Total" - ): - tax.tax_amount += current_tax_amount - - # store tax_amount for current item as it will be used for - # charge type = 'On Previous Row Amount' - tax.tax_amount_for_current_item = current_tax_amount - - # set tax after discount - tax.tax_amount_after_discount_amount += current_tax_amount - - current_tax_amount = get_tax_amount_if_for_valuation_or_deduction( - invoice_doc, current_tax_amount, tax - ) - - # note: grand_total_for_current_item contains the contribution of - # item's amount, previously applied tax and the current tax on that item - if i == 0: - tax.grand_total_for_current_item = flt( - item.net_amount + current_tax_amount - ) - else: - tax.grand_total_for_current_item = flt( - invoice_doc.get("taxes")[i - 1].grand_total_for_current_item - + current_tax_amount - ) - - for tax in invoice_doc.get("taxes"): - tax.dont_recompute_tax = 1 - tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail) - - -def _load_item_tax_rate(item_tax_rate): - return json.loads(item_tax_rate) if item_tax_rate else {} - - -def _get_tax_rate(invoice_doc, tax, item_tax_map): - if tax.account_head in item_tax_map: - return flt( - item_tax_map.get(tax.account_head), invoice_doc.precision("rate", tax) - ) - else: - return 0.0 - - -def set_item_wise_tax(invoice_doc, item, tax, tax_rate, current_tax_amount): - # store tax breakup for each item - key = item.item_code or item.item_name - item_wise_tax_amount = current_tax_amount * invoice_doc.conversion_rate - if ( - tax.item_wise_tax_detail.get(key) - and tax.item_wise_tax_detail.get(key)[0] == tax_rate - ): - item_wise_tax_amount += tax.item_wise_tax_detail[key][1] - - elif not tax.item_wise_tax_detail.get(key): - tax.item_wise_tax_detail[key] = [tax_rate, flt(item_wise_tax_amount)] - - -def get_current_tax_amount(invoice_doc, item, tax, item_tax_map): - tax_rate = _get_tax_rate(invoice_doc, tax, item_tax_map) - current_tax_amount = 0.0 - - if tax.charge_type == "Actual": - # distribute the tax amount proportionally to each item row - actual = flt(tax.tax_amount, tax.precision("tax_amount")) - current_tax_amount = ( - item.net_amount * actual / invoice_doc.doc.net_total - if invoice_doc.net_total - else 0.0 - ) - - elif tax.charge_type == "On Net Total": - current_tax_amount = (tax_rate / 100.0) * item.net_amount - elif tax.charge_type == "On Previous Row Amount": - current_tax_amount = (tax_rate / 100.0) * invoice_doc.get("taxes")[ - cint(tax.row_id) - 1 - ].tax_amount_for_current_item - elif tax.charge_type == "On Previous Row Total": - current_tax_amount = (tax_rate / 100.0) * invoice_doc.get("taxes")[ - cint(tax.row_id) - 1 - ].grand_total_for_current_item - elif tax.charge_type == "On Item Quantity": - current_tax_amount = tax_rate * item.qty - - if not (invoice_doc.get("is_consolidated") or tax.get("dont_recompute_tax")): - set_item_wise_tax(invoice_doc, item, tax, tax_rate, current_tax_amount) - - return current_tax_amount - - -def get_tax_amount_if_for_valuation_or_deduction(invoice_doc, tax_amount, tax): - # if just for valuation, do not add the tax amount in total - # if tax/charges is for deduction, multiply by -1 - if getattr(tax, "category", None): - tax_amount = 0.0 if (tax.category == "Valuation") else tax_amount - if invoice_doc.doctype in [ - "Purchase Order", - "Purchase Invoice", - "Purchase Receipt", - "Supplier Quotation", - ]: - tax_amount *= -1.0 if (tax.add_deduct_tax == "Deduct") else 1.0 - return tax_amount +class customSalesInvoice(SalesInvoice): + def calculate_taxes_and_totals(object): + return custom_calculate_taxes_and_totals(object)