Commonified taxes and totals calculation in server side

This commit is contained in:
Nabin Hait
2015-02-17 11:11:11 +05:30
parent 188f69a713
commit 3237c75d98
4 changed files with 408 additions and 433 deletions

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint, flt, rounded, cstr, comma_or
from frappe.utils import cint, flt, cstr, comma_or
from erpnext.setup.utils import get_company_currency
from frappe import _, throw
from erpnext.stock.get_item_details import get_available_qty
@@ -121,157 +121,6 @@ class SellingController(StockController):
self.in_words = money_in_words(disable_rounded_total and
self.grand_total or self.rounded_total, self.currency)
def calculate_taxes_and_totals(self):
super(SellingController, self).calculate_taxes_and_totals()
self.calculate_total_advance("Sales Invoice", "advances")
self.calculate_commission()
self.calculate_contribution()
def determine_exclusive_rate(self):
if not any((cint(tax.included_in_print_rate) for tax in self.get("taxes"))):
# no inclusive tax
return
for item in self.get("items"):
item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
cumulated_tax_fraction = 0
for i, tax in enumerate(self.get("taxes")):
tax.tax_fraction_for_current_item = self.get_current_tax_fraction(tax, item_tax_map)
if i==0:
tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item
else:
tax.grand_total_fraction_for_current_item = \
self.get("taxes")[i-1].grand_total_fraction_for_current_item \
+ tax.tax_fraction_for_current_item
cumulated_tax_fraction += tax.tax_fraction_for_current_item
if cumulated_tax_fraction and not self.discount_amount_applied and item.qty:
item.base_amount = flt((item.amount * self.conversion_rate) /
(1 + cumulated_tax_fraction), self.precision("base_amount", item))
item.base_rate = flt(item.base_amount / item.qty, self.precision("base_rate", item))
item.discount_percentage = flt(item.discount_percentage, self.precision("discount_percentage", item))
if item.discount_percentage == 100:
item.base_price_list_rate = item.base_rate
item.base_rate = 0.0
else:
item.base_price_list_rate = flt(item.base_rate / (1 - (item.discount_percentage / 100.0)),
self.precision("base_price_list_rate", item))
def get_current_tax_fraction(self, tax, item_tax_map):
"""
Get tax fraction for calculating tax exclusive amount
from tax inclusive amount
"""
current_tax_fraction = 0
if cint(tax.included_in_print_rate):
tax_rate = self._get_tax_rate(tax, item_tax_map)
if tax.charge_type == "On Net Total":
current_tax_fraction = tax_rate / 100.0
elif tax.charge_type == "On Previous Row Amount":
current_tax_fraction = (tax_rate / 100.0) * \
self.get("taxes")[cint(tax.row_id) - 1].tax_fraction_for_current_item
elif tax.charge_type == "On Previous Row Total":
current_tax_fraction = (tax_rate / 100.0) * \
self.get("taxes")[cint(tax.row_id) - 1].grand_total_fraction_for_current_item
return current_tax_fraction
def calculate_item_values(self):
if not self.discount_amount_applied:
for item in self.get("items"):
self.round_floats_in(item)
if item.discount_percentage == 100:
item.rate = 0
elif not item.rate:
item.rate = flt(item.price_list_rate * (1.0 - (item.discount_percentage / 100.0)),
self.precision("rate", item))
item.amount = flt(item.rate * item.qty,
self.precision("amount", item))
self._set_in_company_currency(item, "price_list_rate", "base_price_list_rate")
self._set_in_company_currency(item, "rate", "base_rate")
self._set_in_company_currency(item, "amount", "base_amount")
def calculate_net_total(self):
self.base_net_total = self.net_total = 0.0
for item in self.get("items"):
self.base_net_total += item.base_amount
self.net_total += item.amount
self.round_floats_in(self, ["base_net_total", "net_total"])
def calculate_totals(self):
self.base_grand_total = flt(self.get("taxes")[-1].total if self.get("taxes") else self.base_net_total)
self.base_total_taxes_and_charges = flt(self.base_grand_total - self.base_net_total, self.precision("base_total_taxes_and_charges"))
self.grand_total = flt(self.base_grand_total / self.conversion_rate) \
if (self.base_total_taxes_and_charges or self.discount_amount) else self.net_total
self.total_taxes_and_charges = flt(self.grand_total - self.net_total +
flt(self.discount_amount), self.precision("total_taxes_and_charges"))
self.base_grand_total = flt(self.base_grand_total, self.precision("base_grand_total"))
self.grand_total = flt(self.grand_total, self.precision("grand_total"))
self.base_rounded_total = rounded(self.base_grand_total)
self.rounded_total = rounded(self.grand_total)
def apply_discount_amount(self):
if self.discount_amount:
self.base_discount_amount = flt(self.discount_amount * self.conversion_rate, self.precision("base_discount_amount"))
grand_total_for_discount_amount = self.get_grand_total_for_discount_amount()
if grand_total_for_discount_amount:
# calculate item amount after Discount Amount
for item in self.get("items"):
distributed_amount = flt(self.base_discount_amount) * item.base_amount / grand_total_for_discount_amount
item.base_amount = flt(item.base_amount - distributed_amount, self.precision("base_amount", item))
self.discount_amount_applied = True
self._calculate_taxes_and_totals()
else:
self.base_discount_amount = 0
def get_grand_total_for_discount_amount(self):
actual_taxes_dict = {}
for tax in self.get("taxes"):
if tax.charge_type == "Actual":
actual_taxes_dict.setdefault(tax.idx, tax.tax_amount)
elif tax.row_id in actual_taxes_dict:
actual_tax_amount = flt(actual_taxes_dict.get(tax.row_id, 0)) * \
flt(tax.rate) / 100
actual_taxes_dict.setdefault(tax.idx, actual_tax_amount)
grand_total_for_discount_amount = flt(self.base_grand_total - sum(actual_taxes_dict.values()),
self.precision("base_grand_total"))
return grand_total_for_discount_amount
def calculate_outstanding_amount(self):
# NOTE:
# write_off_amount is only for POS Invoice
# total_advance is only for non POS Invoice
if self.doctype == "Sales Invoice" and self.docstatus == 0:
self.round_floats_in(self, ["base_grand_total", "total_advance", "write_off_amount",
"paid_amount"])
total_amount_to_pay = self.base_grand_total - self.write_off_amount
self.outstanding_amount = flt(total_amount_to_pay - self.total_advance \
- self.paid_amount, self.precision("outstanding_amount"))
def calculate_commission(self):
if self.meta.get_field("commission_rate"):
self.round_floats_in(self, ["base_net_total", "commission_rate"])