blob: c6a634ba806f6ccd88316e16c2e4f80ab38776b7 [file] [log] [blame]
Anand Doshi885e0742015-03-03 14:55:30 +05301# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
Nabin Hait3237c752015-02-17 11:11:11 +05302# License: GNU General Public License v3. See license.txt
3
Chillar Anand915b3432021-09-02 16:44:59 +05304
Nabin Hait3237c752015-02-17 11:11:11 +05305import json
Chillar Anand915b3432021-09-02 16:44:59 +05306
7import frappe
Nabin Hait3769d872015-12-18 13:12:02 +05308from frappe import _, scrub
Nabin Haitb962fc12017-07-17 18:02:31 +05309from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
Chillar Anand915b3432021-09-02 16:44:59 +053010
11import erpnext
Deepesh Gargbfc17e42020-12-25 18:34:39 +053012from erpnext.accounts.doctype.journal_entry.journal_entry import get_exchange_rate
Chillar Anand915b3432021-09-02 16:44:59 +053013from erpnext.accounts.doctype.pricing_rule.utils import get_applied_pricing_rules
14from erpnext.controllers.accounts_controller import (
15 validate_conversion_rate,
16 validate_inclusive_tax,
17 validate_taxes_and_charges,
18)
19from erpnext.stock.get_item_details import _get_item_tax_template
20
Nabin Hait3237c752015-02-17 11:11:11 +053021
Nabin Haitfe81da22015-02-18 12:23:18 +053022class calculate_taxes_and_totals(object):
Nabin Hait3237c752015-02-17 11:11:11 +053023 def __init__(self, doc):
24 self.doc = doc
Deepesh Garg6a5ef262021-02-19 14:30:23 +053025 frappe.flags.round_off_applicable_accounts = []
26 get_round_off_applicable_accounts(self.doc.company, frappe.flags.round_off_applicable_accounts)
Nabin Haitfe81da22015-02-18 12:23:18 +053027 self.calculate()
28
Nabin Hait3237c752015-02-17 11:11:11 +053029 def calculate(self):
Nabin Haitb315acb2019-07-12 14:27:19 +053030 if not len(self.doc.get("items")):
31 return
32
Nabin Hait3237c752015-02-17 11:11:11 +053033 self.discount_amount_applied = False
34 self._calculate()
35
36 if self.doc.meta.get_field("discount_amount"):
Nabin Hait3769d872015-12-18 13:12:02 +053037 self.set_discount_amount()
Nabin Hait3237c752015-02-17 11:11:11 +053038 self.apply_discount_amount()
39
Deepesh Garg3b159662022-08-21 17:51:05 +053040 # Update grand total as per cash and non trade discount
41 if self.doc.apply_discount_on == "Grand Total" and self.doc.get("is_cash_or_non_trade_discount"):
42 self.doc.grand_total -= self.doc.discount_amount
43 self.doc.base_grand_total -= self.doc.base_discount_amount
Deepesh Garg318da162022-08-29 14:18:39 +053044 self.set_rounded_total()
Deepesh Garg3b159662022-08-21 17:51:05 +053045
Deepesh Gargd596e0e2022-03-10 20:56:36 +053046 self.calculate_shipping_charges()
47
Nabin Haitbd00e812015-02-17 12:50:51 +053048 if self.doc.doctype in ["Sales Invoice", "Purchase Invoice"]:
Nabin Hait3237c752015-02-17 11:11:11 +053049 self.calculate_total_advance()
Vishal Dhayaguded42242d2017-11-29 16:09:59 +053050
Nabin Hait852cb642017-07-05 12:58:19 +053051 if self.doc.meta.get_field("other_charges_calculation"):
52 self.set_item_wise_tax_breakup()
Nabin Hait3237c752015-02-17 11:11:11 +053053
54 def _calculate(self):
Faris Ansarieae2dda2018-05-02 12:19:30 +053055 self.validate_conversion_rate()
Nabin Haite7679702015-02-20 14:40:35 +053056 self.calculate_item_values()
Deepesh Gargef0d26c2020-01-06 15:34:15 +053057 self.validate_item_tax_template()
Nabin Haite7679702015-02-20 14:40:35 +053058 self.initialize_taxes()
59 self.determine_exclusive_rate()
60 self.calculate_net_total()
niralisataparae758a752022-10-03 16:39:35 +053061 self.calculate_tax_withholding_net_total()
Nabin Haite7679702015-02-20 14:40:35 +053062 self.calculate_taxes()
Nabin Haita1bf43b2015-03-17 10:50:47 +053063 self.manipulate_grand_total_for_inclusive_tax()
Nabin Haite7679702015-02-20 14:40:35 +053064 self.calculate_totals()
65 self._cleanup()
rohitwaghchaurea8fb2db2018-05-26 09:23:02 +053066 self.calculate_total_net_weight()
Nabin Haite7679702015-02-20 14:40:35 +053067
niralisataparae758a752022-10-03 16:39:35 +053068 def calculate_tax_withholding_net_total(self):
69 if hasattr(self.doc, "tax_withholding_net_total"):
niralisataparae758a752022-10-03 16:39:35 +053070 sum_net_amount = 0
niralisatapara2ca0cf62022-11-02 12:19:51 +053071 sum_base_net_amount = 0
niralisataparae758a752022-10-03 16:39:35 +053072 for item in self.doc.get("items"):
73 if hasattr(item, "apply_tds") and item.apply_tds:
74 sum_net_amount += item.net_amount
niralisatapara2ca0cf62022-11-02 12:19:51 +053075 sum_base_net_amount += item.base_net_amount
76
niralisataparae758a752022-10-03 16:39:35 +053077 self.doc.tax_withholding_net_total = sum_net_amount
niralisatapara2ca0cf62022-11-02 12:19:51 +053078 self.doc.base_tax_withholding_net_total = sum_base_net_amount
niralisataparae758a752022-10-03 16:39:35 +053079
Deepesh Gargef0d26c2020-01-06 15:34:15 +053080 def validate_item_tax_template(self):
Ankush Menat494bd9e2022-03-28 18:52:46 +053081 for item in self.doc.get("items"):
82 if item.item_code and item.get("item_tax_template"):
Deepesh Gargef0d26c2020-01-06 15:34:15 +053083 item_doc = frappe.get_cached_doc("Item", item.item_code)
84 args = {
Ankush Menat494bd9e2022-03-28 18:52:46 +053085 "net_rate": item.net_rate or item.rate,
86 "tax_category": self.doc.get("tax_category"),
87 "posting_date": self.doc.get("posting_date"),
88 "bill_date": self.doc.get("bill_date"),
89 "transaction_date": self.doc.get("transaction_date"),
90 "company": self.doc.get("company"),
Deepesh Gargef0d26c2020-01-06 15:34:15 +053091 }
92
93 item_group = item_doc.item_group
94 item_group_taxes = []
95
96 while item_group:
Ankush Menat494bd9e2022-03-28 18:52:46 +053097 item_group_doc = frappe.get_cached_doc("Item Group", item_group)
Deepesh Gargef0d26c2020-01-06 15:34:15 +053098 item_group_taxes += item_group_doc.taxes or []
99 item_group = item_group_doc.parent_item_group
100
101 item_taxes = item_doc.taxes or []
102
103 if not item_group_taxes and (not item_taxes):
104 # No validation if no taxes in item or item group
105 continue
106
107 taxes = _get_item_tax_template(args, item_taxes + item_group_taxes, for_validate=True)
108
Deepesh Garg18be7672021-06-06 13:25:34 +0530109 if taxes:
110 if item.item_tax_template not in taxes:
111 item.item_tax_template = taxes[0]
Ankush Menat494bd9e2022-03-28 18:52:46 +0530112 frappe.msgprint(
113 _("Row {0}: Item Tax template updated as per validity and rate applied").format(
114 item.idx, frappe.bold(item.item_code)
115 )
116 )
Deepesh Gargef0d26c2020-01-06 15:34:15 +0530117
Nabin Haite7679702015-02-20 14:40:35 +0530118 def validate_conversion_rate(self):
Nabin Hait3237c752015-02-17 11:11:11 +0530119 # validate conversion rate
Rushabh Mehtacc8b2b22017-03-31 12:44:29 +0530120 company_currency = erpnext.get_company_currency(self.doc.company)
Nabin Hait3237c752015-02-17 11:11:11 +0530121 if not self.doc.currency or self.doc.currency == company_currency:
122 self.doc.currency = company_currency
123 self.doc.conversion_rate = 1.0
124 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530125 validate_conversion_rate(
126 self.doc.currency,
127 self.doc.conversion_rate,
128 self.doc.meta.get_label("conversion_rate"),
129 self.doc.company,
130 )
Nabin Hait3237c752015-02-17 11:11:11 +0530131
132 self.doc.conversion_rate = flt(self.doc.conversion_rate)
133
Nabin Hait3237c752015-02-17 11:11:11 +0530134 def calculate_item_values(self):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530135 if self.doc.get("is_consolidated"):
Saqib Ansari0452d7d2022-02-08 11:26:23 +0530136 return
137
Nabin Hait3237c752015-02-17 11:11:11 +0530138 if not self.discount_amount_applied:
139 for item in self.doc.get("items"):
140 self.doc.round_floats_in(item)
141
142 if item.discount_percentage == 100:
143 item.rate = 0.0
Nabin Hait593242f2019-04-05 19:35:02 +0530144 elif item.price_list_rate:
Deepesh Garga83a0a02022-03-25 12:28:55 +0530145 if not item.rate or (item.pricing_rules and item.discount_percentage > 0):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530146 item.rate = flt(
147 item.price_list_rate * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate")
148 )
Deepesh Gargd95f8932022-03-01 23:09:59 +0530149
Deepesh Garga83a0a02022-03-25 12:28:55 +0530150 item.discount_amount = item.price_list_rate * (item.discount_percentage / 100.0)
Deepesh Gargd95f8932022-03-01 23:09:59 +0530151
Deepesh Garg97e102c2022-03-25 12:39:59 +0530152 elif item.discount_amount and item.pricing_rules:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530153 item.rate = item.price_list_rate - item.discount_amount
Nabin Hait3237c752015-02-17 11:11:11 +0530154
Ankush Menat494bd9e2022-03-28 18:52:46 +0530155 if item.doctype in [
156 "Quotation Item",
157 "Sales Order Item",
158 "Delivery Note Item",
159 "Sales Invoice Item",
160 "POS Invoice Item",
161 "Purchase Invoice Item",
162 "Purchase Order Item",
163 "Purchase Receipt Item",
164 ]:
Shreya Shahbe690ef2017-11-14 17:22:41 +0530165 item.rate_with_margin, item.base_rate_with_margin = self.calculate_margin(item)
Nabin Hait64bfdd92019-04-23 13:37:19 +0530166 if flt(item.rate_with_margin) > 0:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530167 item.rate = flt(
168 item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate")
169 )
Nabin Hait10c61372021-04-13 15:46:01 +0530170
Walstan Baptista37b826b2021-04-03 19:48:46 +0530171 if item.discount_amount and not item.discount_percentage:
Nabin Hait10c61372021-04-13 15:46:01 +0530172 item.rate = item.rate_with_margin - item.discount_amount
Walstan Baptista37b826b2021-04-03 19:48:46 +0530173 else:
174 item.discount_amount = item.rate_with_margin - item.rate
Nabin Hait10c61372021-04-13 15:46:01 +0530175
Nabin Hait64bfdd92019-04-23 13:37:19 +0530176 elif flt(item.price_list_rate) > 0:
177 item.discount_amount = item.price_list_rate - item.rate
Rohit Waghchaure8bfe3302019-03-18 14:34:19 +0530178 elif flt(item.price_list_rate) > 0 and not item.discount_amount:
179 item.discount_amount = item.price_list_rate - item.rate
mbauskara52472c2016-03-05 15:10:25 +0530180
Nabin Haite7679702015-02-20 14:40:35 +0530181 item.net_rate = item.rate
Deepesh Gargb65c7612019-07-31 15:58:01 +0530182
deepeshgarg0078bf19ce2019-08-03 13:40:37 +0530183 if not item.qty and self.doc.get("is_return"):
Deepesh Gargb65c7612019-07-31 15:58:01 +0530184 item.amount = flt(-1 * item.rate, item.precision("amount"))
Saqib Ansari04ea42c2021-12-22 13:23:42 +0530185 elif not item.qty and self.doc.get("is_debit_note"):
186 item.amount = flt(item.rate, item.precision("amount"))
Deepesh Gargb65c7612019-07-31 15:58:01 +0530187 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530188 item.amount = flt(item.rate * item.qty, item.precision("amount"))
Deepesh Gargb65c7612019-07-31 15:58:01 +0530189
Nabin Haite7679702015-02-20 14:40:35 +0530190 item.net_amount = item.amount
Nabin Hait3237c752015-02-17 11:11:11 +0530191
Ankush Menat494bd9e2022-03-28 18:52:46 +0530192 self._set_in_company_currency(
193 item, ["price_list_rate", "rate", "net_rate", "amount", "net_amount"]
194 )
Nabin Hait3237c752015-02-17 11:11:11 +0530195
Nabin Haite7679702015-02-20 14:40:35 +0530196 item.item_tax_amount = 0.0
197
198 def _set_in_company_currency(self, doc, fields):
Nabin Hait3237c752015-02-17 11:11:11 +0530199 """set values in base currency"""
Nabin Haite7679702015-02-20 14:40:35 +0530200 for f in fields:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530201 val = flt(
202 flt(doc.get(f), doc.precision(f)) * self.doc.conversion_rate, doc.precision("base_" + f)
203 )
Nabin Haite7679702015-02-20 14:40:35 +0530204 doc.set("base_" + f, val)
Nabin Hait3237c752015-02-17 11:11:11 +0530205
206 def initialize_taxes(self):
207 for tax in self.doc.get("taxes"):
Nabin Hait86cd4cc2015-02-28 19:11:51 +0530208 if not self.discount_amount_applied:
209 validate_taxes_and_charges(tax)
210 validate_inclusive_tax(tax, self.doc)
Nabin Hait613d0812015-02-23 11:58:15 +0530211
Ankush Menat494bd9e2022-03-28 18:52:46 +0530212 if not (self.doc.get("is_consolidated") or tax.get("dont_recompute_tax")):
Deepesh Garg5f3d7f52021-04-12 10:56:47 +0530213 tax.item_wise_tax_detail = {}
214
Ankush Menat494bd9e2022-03-28 18:52:46 +0530215 tax_fields = [
216 "total",
217 "tax_amount_after_discount_amount",
218 "tax_amount_for_current_item",
219 "grand_total_for_current_item",
220 "tax_fraction_for_current_item",
221 "grand_total_fraction_for_current_item",
222 ]
Nabin Hait3237c752015-02-17 11:11:11 +0530223
Ankush Menat494bd9e2022-03-28 18:52:46 +0530224 if tax.charge_type != "Actual" and not (
225 self.discount_amount_applied and self.doc.apply_discount_on == "Grand Total"
226 ):
227 tax_fields.append("tax_amount")
Nabin Hait3237c752015-02-17 11:11:11 +0530228
229 for fieldname in tax_fields:
230 tax.set(fieldname, 0.0)
231
Nabin Hait3237c752015-02-17 11:11:11 +0530232 self.doc.round_floats_in(tax)
233
Nabin Hait3237c752015-02-17 11:11:11 +0530234 def determine_exclusive_rate(self):
Ankush Menat8fe5feb2021-11-04 19:48:32 +0530235 if not any(cint(tax.included_in_print_rate) for tax in self.doc.get("taxes")):
Nabin Hait37b047d2015-02-23 16:01:33 +0530236 return
Nabin Hait3237c752015-02-17 11:11:11 +0530237
238 for item in self.doc.get("items"):
239 item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
240 cumulated_tax_fraction = 0
Nabin Hait19ea7212020-08-11 20:34:57 +0530241 total_inclusive_tax_amount_per_qty = 0
Nabin Hait3237c752015-02-17 11:11:11 +0530242 for i, tax in enumerate(self.doc.get("taxes")):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530243 (
244 tax.tax_fraction_for_current_item,
245 inclusive_tax_amount_per_qty,
246 ) = self.get_current_tax_fraction(tax, item_tax_map)
Nabin Hait3237c752015-02-17 11:11:11 +0530247
Ankush Menat494bd9e2022-03-28 18:52:46 +0530248 if i == 0:
Nabin Hait3237c752015-02-17 11:11:11 +0530249 tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item
250 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530251 tax.grand_total_fraction_for_current_item = (
252 self.doc.get("taxes")[i - 1].grand_total_fraction_for_current_item
Nabin Hait3237c752015-02-17 11:11:11 +0530253 + tax.tax_fraction_for_current_item
Ankush Menat494bd9e2022-03-28 18:52:46 +0530254 )
Nabin Hait3237c752015-02-17 11:11:11 +0530255
256 cumulated_tax_fraction += tax.tax_fraction_for_current_item
Nabin Haite2ee4552020-08-12 20:58:03 +0530257 total_inclusive_tax_amount_per_qty += inclusive_tax_amount_per_qty * flt(item.qty)
Nabin Hait3237c752015-02-17 11:11:11 +0530258
Ankush Menat494bd9e2022-03-28 18:52:46 +0530259 if (
260 not self.discount_amount_applied
261 and item.qty
262 and (cumulated_tax_fraction or total_inclusive_tax_amount_per_qty)
263 ):
Nabin Hait19ea7212020-08-11 20:34:57 +0530264 amount = flt(item.amount) - total_inclusive_tax_amount_per_qty
265
266 item.net_amount = flt(amount / (1 + cumulated_tax_fraction))
Nabin Haite7679702015-02-20 14:40:35 +0530267 item.net_rate = flt(item.net_amount / item.qty, item.precision("net_rate"))
Ankush Menat494bd9e2022-03-28 18:52:46 +0530268 item.discount_percentage = flt(item.discount_percentage, item.precision("discount_percentage"))
Nabin Hait3237c752015-02-17 11:11:11 +0530269
Nabin Haite7679702015-02-20 14:40:35 +0530270 self._set_in_company_currency(item, ["net_rate", "net_amount"])
271
Nabin Hait3237c752015-02-17 11:11:11 +0530272 def _load_item_tax_rate(self, item_tax_rate):
273 return json.loads(item_tax_rate) if item_tax_rate else {}
274
275 def get_current_tax_fraction(self, tax, item_tax_map):
276 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530277 Get tax fraction for calculating tax exclusive amount
278 from tax inclusive amount
Nabin Hait3237c752015-02-17 11:11:11 +0530279 """
280 current_tax_fraction = 0
Nabin Hait19ea7212020-08-11 20:34:57 +0530281 inclusive_tax_amount_per_qty = 0
Nabin Hait3237c752015-02-17 11:11:11 +0530282
283 if cint(tax.included_in_print_rate):
284 tax_rate = self._get_tax_rate(tax, item_tax_map)
285
286 if tax.charge_type == "On Net Total":
287 current_tax_fraction = tax_rate / 100.0
288
289 elif tax.charge_type == "On Previous Row Amount":
Ankush Menat494bd9e2022-03-28 18:52:46 +0530290 current_tax_fraction = (tax_rate / 100.0) * self.doc.get("taxes")[
291 cint(tax.row_id) - 1
292 ].tax_fraction_for_current_item
Nabin Hait3237c752015-02-17 11:11:11 +0530293
294 elif tax.charge_type == "On Previous Row Total":
Ankush Menat494bd9e2022-03-28 18:52:46 +0530295 current_tax_fraction = (tax_rate / 100.0) * self.doc.get("taxes")[
296 cint(tax.row_id) - 1
297 ].grand_total_fraction_for_current_item
marination733fd5f2020-08-26 18:23:12 +0530298
Nabin Hait19ea7212020-08-11 20:34:57 +0530299 elif tax.charge_type == "On Item Quantity":
300 inclusive_tax_amount_per_qty = flt(tax_rate)
Nabin Hait3237c752015-02-17 11:11:11 +0530301
Nabin Hait19ea7212020-08-11 20:34:57 +0530302 if getattr(tax, "add_deduct_tax", None) and tax.add_deduct_tax == "Deduct":
303 current_tax_fraction *= -1.0
304 inclusive_tax_amount_per_qty *= -1.0
305
306 return current_tax_fraction, inclusive_tax_amount_per_qty
Nabin Hait3237c752015-02-17 11:11:11 +0530307
308 def _get_tax_rate(self, tax, item_tax_map):
Achilles Rasquinha87dab142018-03-08 14:21:48 +0530309 if tax.account_head in item_tax_map:
Nabin Hait3237c752015-02-17 11:11:11 +0530310 return flt(item_tax_map.get(tax.account_head), self.doc.precision("rate", tax))
311 else:
312 return tax.rate
313
314 def calculate_net_total(self):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530315 self.doc.total_qty = (
316 self.doc.total
317 ) = self.doc.base_total = self.doc.net_total = self.doc.base_net_total = 0.0
rohitwaghchaure3a595d02018-06-25 10:10:29 +0530318
Nabin Hait3237c752015-02-17 11:11:11 +0530319 for item in self.doc.get("items"):
Nabin Haitf0bc9b62015-02-23 01:40:01 +0530320 self.doc.total += item.amount
Shreya Shahe3290382018-05-28 11:49:08 +0530321 self.doc.total_qty += item.qty
Nabin Haitf0bc9b62015-02-23 01:40:01 +0530322 self.doc.base_total += item.base_amount
Nabin Haite7679702015-02-20 14:40:35 +0530323 self.doc.net_total += item.net_amount
324 self.doc.base_net_total += item.base_net_amount
Nabin Hait3237c752015-02-17 11:11:11 +0530325
Nabin Haitf0bc9b62015-02-23 01:40:01 +0530326 self.doc.round_floats_in(self.doc, ["total", "base_total", "net_total", "base_net_total"])
Nabin Hait3237c752015-02-17 11:11:11 +0530327
Subin Toma8e2c022021-11-16 19:06:49 +0530328 def calculate_shipping_charges(self):
Deepesh Garg714fc082022-04-04 20:05:10 +0530329
330 # Do not apply shipping rule for POS
Deepesh Garg631545a2022-04-06 09:27:40 +0530331 if self.doc.get("is_pos"):
Deepesh Garg714fc082022-04-04 20:05:10 +0530332 return
333
Subin Tomaf1fce02021-11-10 16:49:12 +0530334 if hasattr(self.doc, "shipping_rule") and self.doc.shipping_rule:
Subin Tom18ae03d2021-11-10 15:57:41 +0530335 shipping_rule = frappe.get_doc("Shipping Rule", self.doc.shipping_rule)
336 shipping_rule.apply(self.doc)
337
Deepesh Gargd596e0e2022-03-10 20:56:36 +0530338 self._calculate()
339
Nabin Hait3237c752015-02-17 11:11:11 +0530340 def calculate_taxes(self):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530341 rounding_adjustment_computed = self.doc.get("is_consolidated") and self.doc.get(
342 "rounding_adjustment"
343 )
Saqib Ansari17445c72022-03-07 18:01:07 +0530344 if not rounding_adjustment_computed:
Subin Tom75a76e62021-10-29 16:45:04 +0530345 self.doc.rounding_adjustment = 0
346
Nabin Hait3237c752015-02-17 11:11:11 +0530347 # maintain actual tax rate based on idx
Ankush Menat494bd9e2022-03-28 18:52:46 +0530348 actual_tax_dict = dict(
349 [
350 [tax.idx, flt(tax.tax_amount, tax.precision("tax_amount"))]
351 for tax in self.doc.get("taxes")
352 if tax.charge_type == "Actual"
353 ]
354 )
Nabin Hait3237c752015-02-17 11:11:11 +0530355
356 for n, item in enumerate(self.doc.get("items")):
357 item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
Nabin Hait3237c752015-02-17 11:11:11 +0530358 for i, tax in enumerate(self.doc.get("taxes")):
359 # tax_amount represents the amount of tax for the current step
360 current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map)
361
362 # Adjust divisional loss to the last item
363 if tax.charge_type == "Actual":
364 actual_tax_dict[tax.idx] -= current_tax_amount
365 if n == len(self.doc.get("items")) - 1:
366 current_tax_amount += actual_tax_dict[tax.idx]
367
Nabin Hait2b019ed2015-02-22 23:03:07 +0530368 # accumulate tax amount into tax.tax_amount
Ankush Menat494bd9e2022-03-28 18:52:46 +0530369 if tax.charge_type != "Actual" and not (
370 self.discount_amount_applied and self.doc.apply_discount_on == "Grand Total"
371 ):
372 tax.tax_amount += current_tax_amount
Nabin Hait2b019ed2015-02-22 23:03:07 +0530373
Nabin Hait3237c752015-02-17 11:11:11 +0530374 # store tax_amount for current item as it will be used for
375 # charge type = 'On Previous Row Amount'
376 tax.tax_amount_for_current_item = current_tax_amount
377
Nabin Hait2b019ed2015-02-22 23:03:07 +0530378 # set tax after discount
Nabin Hait3237c752015-02-17 11:11:11 +0530379 tax.tax_amount_after_discount_amount += current_tax_amount
380
Nabin Haitcd951342017-07-31 18:07:45 +0530381 current_tax_amount = self.get_tax_amount_if_for_valuation_or_deduction(current_tax_amount, tax)
Nabin Hait3237c752015-02-17 11:11:11 +0530382
Nabin Hait3237c752015-02-17 11:11:11 +0530383 # note: grand_total_for_current_item contains the contribution of
384 # item's amount, previously applied tax and the current tax on that item
Ankush Menat494bd9e2022-03-28 18:52:46 +0530385 if i == 0:
Nabin Haitcd951342017-07-31 18:07:45 +0530386 tax.grand_total_for_current_item = flt(item.net_amount + current_tax_amount)
Nabin Hait3237c752015-02-17 11:11:11 +0530387 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530388 tax.grand_total_for_current_item = flt(
389 self.doc.get("taxes")[i - 1].grand_total_for_current_item + current_tax_amount
390 )
Nabin Hait3237c752015-02-17 11:11:11 +0530391
392 # set precision in the last item iteration
393 if n == len(self.doc.get("items")) - 1:
394 self.round_off_totals(tax)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530395 self._set_in_company_currency(tax, ["tax_amount", "tax_amount_after_discount_amount"])
Deepesh Gargb6705882021-04-14 11:20:27 +0530396
397 self.round_off_base_values(tax)
Nabin Haitcd951342017-07-31 18:07:45 +0530398 self.set_cumulative_total(i, tax)
399
Deepesh Gargb6705882021-04-14 11:20:27 +0530400 self._set_in_company_currency(tax, ["total"])
Anand Doshiec5ec602015-03-05 19:31:23 +0530401
Nabin Hait3237c752015-02-17 11:11:11 +0530402 # adjust Discount Amount loss in last tax iteration
Ankush Menat494bd9e2022-03-28 18:52:46 +0530403 if (
404 i == (len(self.doc.get("taxes")) - 1)
405 and self.discount_amount_applied
406 and self.doc.discount_amount
407 and self.doc.apply_discount_on == "Grand Total"
408 and not rounding_adjustment_computed
409 ):
410 self.doc.rounding_adjustment = flt(
411 self.doc.grand_total - flt(self.doc.discount_amount) - tax.total,
412 self.doc.precision("rounding_adjustment"),
413 )
Anand Doshiec5ec602015-03-05 19:31:23 +0530414
Nabin Haitcd951342017-07-31 18:07:45 +0530415 def get_tax_amount_if_for_valuation_or_deduction(self, tax_amount, tax):
416 # if just for valuation, do not add the tax amount in total
417 # if tax/charges is for deduction, multiply by -1
418 if getattr(tax, "category", None):
419 tax_amount = 0.0 if (tax.category == "Valuation") else tax_amount
Ankush Menat494bd9e2022-03-28 18:52:46 +0530420 if self.doc.doctype in [
421 "Purchase Order",
422 "Purchase Invoice",
423 "Purchase Receipt",
424 "Supplier Quotation",
425 ]:
Rushabh Mehta30dc9a12017-11-17 14:31:09 +0530426 tax_amount *= -1.0 if (tax.add_deduct_tax == "Deduct") else 1.0
Nabin Haitcd951342017-07-31 18:07:45 +0530427 return tax_amount
Anand Doshiec5ec602015-03-05 19:31:23 +0530428
Nabin Haitcd951342017-07-31 18:07:45 +0530429 def set_cumulative_total(self, row_idx, tax):
430 tax_amount = tax.tax_amount_after_discount_amount
431 tax_amount = self.get_tax_amount_if_for_valuation_or_deduction(tax_amount, tax)
432
433 if row_idx == 0:
434 tax.total = flt(self.doc.net_total + tax_amount, tax.precision("total"))
435 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530436 tax.total = flt(self.doc.get("taxes")[row_idx - 1].total + tax_amount, tax.precision("total"))
Nabin Hait3237c752015-02-17 11:11:11 +0530437
438 def get_current_tax_amount(self, item, tax, item_tax_map):
439 tax_rate = self._get_tax_rate(tax, item_tax_map)
440 current_tax_amount = 0.0
441
442 if tax.charge_type == "Actual":
443 # distribute the tax amount proportionally to each item row
Nabin Haite7679702015-02-20 14:40:35 +0530444 actual = flt(tax.tax_amount, tax.precision("tax_amount"))
Ankush Menat494bd9e2022-03-28 18:52:46 +0530445 current_tax_amount = (
446 item.net_amount * actual / self.doc.net_total if self.doc.net_total else 0.0
447 )
Nabin Haite7679702015-02-20 14:40:35 +0530448
Nabin Hait3237c752015-02-17 11:11:11 +0530449 elif tax.charge_type == "On Net Total":
Nabin Haite7679702015-02-20 14:40:35 +0530450 current_tax_amount = (tax_rate / 100.0) * item.net_amount
Nabin Hait3237c752015-02-17 11:11:11 +0530451 elif tax.charge_type == "On Previous Row Amount":
Ankush Menat494bd9e2022-03-28 18:52:46 +0530452 current_tax_amount = (tax_rate / 100.0) * self.doc.get("taxes")[
453 cint(tax.row_id) - 1
454 ].tax_amount_for_current_item
Nabin Hait3237c752015-02-17 11:11:11 +0530455 elif tax.charge_type == "On Previous Row Total":
Ankush Menat494bd9e2022-03-28 18:52:46 +0530456 current_tax_amount = (tax_rate / 100.0) * self.doc.get("taxes")[
457 cint(tax.row_id) - 1
458 ].grand_total_for_current_item
Himanshu Mishra35b26272018-11-13 11:13:04 +0530459 elif tax.charge_type == "On Item Quantity":
Nabin Hait19ea7212020-08-11 20:34:57 +0530460 current_tax_amount = tax_rate * item.qty
Nabin Hait3237c752015-02-17 11:11:11 +0530461
Ankush Menatdfdd1c62021-07-23 15:50:37 +0530462 if not (self.doc.get("is_consolidated") or tax.get("dont_recompute_tax")):
Deepesh Garg5f3d7f52021-04-12 10:56:47 +0530463 self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount)
Nabin Hait3237c752015-02-17 11:11:11 +0530464
465 return current_tax_amount
466
Nabin Haite7679702015-02-20 14:40:35 +0530467 def set_item_wise_tax(self, item, tax, tax_rate, current_tax_amount):
468 # store tax breakup for each item
469 key = item.item_code or item.item_name
Ankush Menat494bd9e2022-03-28 18:52:46 +0530470 item_wise_tax_amount = current_tax_amount * self.doc.conversion_rate
Nabin Haite7679702015-02-20 14:40:35 +0530471 if tax.item_wise_tax_detail.get(key):
472 item_wise_tax_amount += tax.item_wise_tax_detail[key][1]
473
Ankush Menat494bd9e2022-03-28 18:52:46 +0530474 tax.item_wise_tax_detail[key] = [tax_rate, flt(item_wise_tax_amount)]
Nabin Haite7679702015-02-20 14:40:35 +0530475
Nabin Hait3237c752015-02-17 11:11:11 +0530476 def round_off_totals(self, tax):
Deepesh Gargb6705882021-04-14 11:20:27 +0530477 if tax.account_head in frappe.flags.round_off_applicable_accounts:
478 tax.tax_amount = round(tax.tax_amount, 0)
479 tax.tax_amount_after_discount_amount = round(tax.tax_amount_after_discount_amount, 0)
480
Nabin Haite7679702015-02-20 14:40:35 +0530481 tax.tax_amount = flt(tax.tax_amount, tax.precision("tax_amount"))
Ankush Menat494bd9e2022-03-28 18:52:46 +0530482 tax.tax_amount_after_discount_amount = flt(
483 tax.tax_amount_after_discount_amount, tax.precision("tax_amount")
484 )
Nabin Haitce245122015-02-22 20:14:49 +0530485
Deepesh Gargb6705882021-04-14 11:20:27 +0530486 def round_off_base_values(self, tax):
487 # Round off to nearest integer based on regional settings
488 if tax.account_head in frappe.flags.round_off_applicable_accounts:
489 tax.base_tax_amount = round(tax.base_tax_amount, 0)
490 tax.base_tax_amount_after_discount_amount = round(tax.base_tax_amount_after_discount_amount, 0)
491
Nabin Haita1bf43b2015-03-17 10:50:47 +0530492 def manipulate_grand_total_for_inclusive_tax(self):
493 # if fully inclusive taxes and diff
Ankush Menat98917802021-06-11 18:40:22 +0530494 if self.doc.get("taxes") and any(cint(t.included_in_print_rate) for t in self.doc.get("taxes")):
Nabin Haita1bf43b2015-03-17 10:50:47 +0530495 last_tax = self.doc.get("taxes")[-1]
Ankush Menat494bd9e2022-03-28 18:52:46 +0530496 non_inclusive_tax_amount = sum(
497 flt(d.tax_amount_after_discount_amount)
498 for d in self.doc.get("taxes")
499 if not d.included_in_print_rate
500 )
Nabin Haitf32fc232019-12-25 13:59:24 +0530501
Ankush Menat494bd9e2022-03-28 18:52:46 +0530502 diff = (
503 self.doc.total + non_inclusive_tax_amount - flt(last_tax.total, last_tax.precision("total"))
504 )
Nabin Haitf32fc232019-12-25 13:59:24 +0530505
506 # If discount amount applied, deduct the discount amount
507 # because self.doc.total is always without discount, but last_tax.total is after discount
508 if self.discount_amount_applied and self.doc.discount_amount:
509 diff -= flt(self.doc.discount_amount)
510
511 diff = flt(diff, self.doc.precision("rounding_adjustment"))
512
Ankush Menat494bd9e2022-03-28 18:52:46 +0530513 if diff and abs(diff) <= (5.0 / 10 ** last_tax.precision("tax_amount")):
Nabin Haitf32fc232019-12-25 13:59:24 +0530514 self.doc.rounding_adjustment = diff
Nabin Hait3237c752015-02-17 11:11:11 +0530515
516 def calculate_totals(self):
Subin Tom75a76e62021-10-29 16:45:04 +0530517 if self.doc.get("taxes"):
518 self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment)
519 else:
520 self.doc.grand_total = flt(self.doc.net_total)
Nabin Hait3237c752015-02-17 11:11:11 +0530521
Subin Tom75a76e62021-10-29 16:45:04 +0530522 if self.doc.get("taxes"):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530523 self.doc.total_taxes_and_charges = flt(
524 self.doc.grand_total - self.doc.net_total - flt(self.doc.rounding_adjustment),
525 self.doc.precision("total_taxes_and_charges"),
526 )
Subin Tom75a76e62021-10-29 16:45:04 +0530527 else:
528 self.doc.total_taxes_and_charges = 0.0
Anand Doshiec5ec602015-03-05 19:31:23 +0530529
Nabin Hait2e4de832017-09-19 14:53:16 +0530530 self._set_in_company_currency(self.doc, ["total_taxes_and_charges", "rounding_adjustment"])
Anand Doshiec5ec602015-03-05 19:31:23 +0530531
Ankush Menat494bd9e2022-03-28 18:52:46 +0530532 if self.doc.doctype in [
533 "Quotation",
534 "Sales Order",
535 "Delivery Note",
536 "Sales Invoice",
537 "POS Invoice",
538 ]:
539 self.doc.base_grand_total = (
540 flt(self.doc.grand_total * self.doc.conversion_rate, self.doc.precision("base_grand_total"))
541 if self.doc.total_taxes_and_charges
542 else self.doc.base_net_total
543 )
Nabin Hait3237c752015-02-17 11:11:11 +0530544 else:
Anand Doshiec5ec602015-03-05 19:31:23 +0530545 self.doc.taxes_and_charges_added = self.doc.taxes_and_charges_deducted = 0.0
Nabin Hait3237c752015-02-17 11:11:11 +0530546 for tax in self.doc.get("taxes"):
547 if tax.category in ["Valuation and Total", "Total"]:
548 if tax.add_deduct_tax == "Add":
Nabin Haitdb53a782015-07-31 16:53:13 +0530549 self.doc.taxes_and_charges_added += flt(tax.tax_amount_after_discount_amount)
Nabin Hait3237c752015-02-17 11:11:11 +0530550 else:
Nabin Haitdb53a782015-07-31 16:53:13 +0530551 self.doc.taxes_and_charges_deducted += flt(tax.tax_amount_after_discount_amount)
Nabin Hait3237c752015-02-17 11:11:11 +0530552
Nabin Haite7679702015-02-20 14:40:35 +0530553 self.doc.round_floats_in(self.doc, ["taxes_and_charges_added", "taxes_and_charges_deducted"])
Nabin Hait3237c752015-02-17 11:11:11 +0530554
Ankush Menat494bd9e2022-03-28 18:52:46 +0530555 self.doc.base_grand_total = (
556 flt(self.doc.grand_total * self.doc.conversion_rate)
557 if (self.doc.taxes_and_charges_added or self.doc.taxes_and_charges_deducted)
Nabin Haite7679702015-02-20 14:40:35 +0530558 else self.doc.base_net_total
Ankush Menat494bd9e2022-03-28 18:52:46 +0530559 )
Nabin Hait3237c752015-02-17 11:11:11 +0530560
Ankush Menat494bd9e2022-03-28 18:52:46 +0530561 self._set_in_company_currency(
562 self.doc, ["taxes_and_charges_added", "taxes_and_charges_deducted"]
563 )
Nabin Hait3237c752015-02-17 11:11:11 +0530564
Nabin Haite7679702015-02-20 14:40:35 +0530565 self.doc.round_floats_in(self.doc, ["grand_total", "base_grand_total"])
Nabin Hait3237c752015-02-17 11:11:11 +0530566
Nabin Hait2e4de832017-09-19 14:53:16 +0530567 self.set_rounded_total()
568
rohitwaghchaurea8fb2db2018-05-26 09:23:02 +0530569 def calculate_total_net_weight(self):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530570 if self.doc.meta.get_field("total_net_weight"):
rohitwaghchaurea8fb2db2018-05-26 09:23:02 +0530571 self.doc.total_net_weight = 0.0
572 for d in self.doc.items:
573 if d.total_weight:
574 self.doc.total_net_weight += d.total_weight
575
Nabin Hait2e4de832017-09-19 14:53:16 +0530576 def set_rounded_total(self):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530577 if self.doc.get("is_consolidated") and self.doc.get("rounding_adjustment"):
Saqib Ansari17445c72022-03-07 18:01:07 +0530578 return
Nabin Hait877e1bb2017-11-17 12:27:43 +0530579
Saqib Ansari17445c72022-03-07 18:01:07 +0530580 if self.doc.meta.get_field("rounded_total"):
581 if self.doc.is_rounded_total_disabled():
582 self.doc.rounded_total = self.doc.base_rounded_total = 0
583 return
Nabin Hait2e4de832017-09-19 14:53:16 +0530584
Ankush Menat494bd9e2022-03-28 18:52:46 +0530585 self.doc.rounded_total = round_based_on_smallest_currency_fraction(
586 self.doc.grand_total, self.doc.currency, self.doc.precision("rounded_total")
587 )
Nabin Hait877e1bb2017-11-17 12:27:43 +0530588
Ankush Menat494bd9e2022-03-28 18:52:46 +0530589 # if print_in_rate is set, we would have already calculated rounding adjustment
590 self.doc.rounding_adjustment += flt(
591 self.doc.rounded_total - self.doc.grand_total, self.doc.precision("rounding_adjustment")
592 )
Saqib Ansari17445c72022-03-07 18:01:07 +0530593
594 self._set_in_company_currency(self.doc, ["rounding_adjustment", "rounded_total"])
Nabin Hait877e1bb2017-11-17 12:27:43 +0530595
Nabin Hait3237c752015-02-17 11:11:11 +0530596 def _cleanup(self):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530597 if not self.doc.get("is_consolidated"):
Deepesh Garg5f3d7f52021-04-12 10:56:47 +0530598 for tax in self.doc.get("taxes"):
Ankush Menatdfdd1c62021-07-23 15:50:37 +0530599 if not tax.get("dont_recompute_tax"):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530600 tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail, separators=(",", ":"))
Anand Doshi15f7b1e2016-04-04 15:03:28 +0530601
Nabin Hait3769d872015-12-18 13:12:02 +0530602 def set_discount_amount(self):
Nabin Haite0405102016-10-13 12:14:32 +0530603 if self.doc.additional_discount_percentage:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530604 self.doc.discount_amount = flt(
605 flt(self.doc.get(scrub(self.doc.apply_discount_on)))
606 * self.doc.additional_discount_percentage
607 / 100,
608 self.doc.precision("discount_amount"),
609 )
Nabin Hait3237c752015-02-17 11:11:11 +0530610
611 def apply_discount_amount(self):
612 if self.doc.discount_amount:
Nabin Hait37b047d2015-02-23 16:01:33 +0530613 if not self.doc.apply_discount_on:
614 frappe.throw(_("Please select Apply Discount On"))
615
Deepesh Garg3b159662022-08-21 17:51:05 +0530616 self.doc.base_discount_amount = flt(
617 self.doc.discount_amount * self.doc.conversion_rate, self.doc.precision("base_discount_amount")
618 )
619
Deepesh Garge54ec4b2022-07-03 11:02:21 +0530620 if self.doc.apply_discount_on == "Grand Total" and self.doc.get(
621 "is_cash_or_non_trade_discount"
622 ):
Deepesh Garg169ff5a2022-06-19 21:18:12 +0530623 self.discount_amount_applied = True
624 return
625
Nabin Haite7679702015-02-20 14:40:35 +0530626 total_for_discount_amount = self.get_total_for_discount_amount()
Nabin Hait25bd84d2015-03-04 15:06:56 +0530627 taxes = self.doc.get("taxes")
628 net_total = 0
Nabin Hait3237c752015-02-17 11:11:11 +0530629
Nabin Haite7679702015-02-20 14:40:35 +0530630 if total_for_discount_amount:
Nabin Hait3237c752015-02-17 11:11:11 +0530631 # calculate item amount after Discount Amount
Nabin Hait25bd84d2015-03-04 15:06:56 +0530632 for i, item in enumerate(self.doc.get("items")):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530633 distributed_amount = (
634 flt(self.doc.discount_amount) * item.net_amount / total_for_discount_amount
635 )
Anand Doshiec5ec602015-03-05 19:31:23 +0530636
Nabin Haite7679702015-02-20 14:40:35 +0530637 item.net_amount = flt(item.net_amount - distributed_amount, item.precision("net_amount"))
Nabin Hait25bd84d2015-03-04 15:06:56 +0530638 net_total += item.net_amount
Anand Doshiec5ec602015-03-05 19:31:23 +0530639
Nabin Hait25bd84d2015-03-04 15:06:56 +0530640 # discount amount rounding loss adjustment if no taxes
Ankush Menat494bd9e2022-03-28 18:52:46 +0530641 if (
642 self.doc.apply_discount_on == "Net Total"
643 or not taxes
644 or total_for_discount_amount == self.doc.net_total
645 ) and i == len(self.doc.get("items")) - 1:
646 discount_amount_loss = flt(
647 self.doc.net_total - net_total - self.doc.discount_amount, self.doc.precision("net_total")
648 )
Rushabh Mehtac6bd7ad2016-12-21 17:30:29 +0530649
Ankush Menat494bd9e2022-03-28 18:52:46 +0530650 item.net_amount = flt(item.net_amount + discount_amount_loss, item.precision("net_amount"))
Anand Doshiec5ec602015-03-05 19:31:23 +0530651
Nabin Hait51e980d2015-10-10 18:10:05 +0530652 item.net_rate = flt(item.net_amount / item.qty, item.precision("net_rate")) if item.qty else 0
Anand Doshiec5ec602015-03-05 19:31:23 +0530653
Nabin Haite7679702015-02-20 14:40:35 +0530654 self._set_in_company_currency(item, ["net_rate", "net_amount"])
Nabin Hait3237c752015-02-17 11:11:11 +0530655
656 self.discount_amount_applied = True
657 self._calculate()
658 else:
659 self.doc.base_discount_amount = 0
660
Nabin Haite7679702015-02-20 14:40:35 +0530661 def get_total_for_discount_amount(self):
Nabin Haitde9c8a92015-02-23 01:06:00 +0530662 if self.doc.apply_discount_on == "Net Total":
663 return self.doc.net_total
Nabin Haite7679702015-02-20 14:40:35 +0530664 else:
665 actual_taxes_dict = {}
Nabin Hait3237c752015-02-17 11:11:11 +0530666
Nabin Haite7679702015-02-20 14:40:35 +0530667 for tax in self.doc.get("taxes"):
Nabin Hait19ea7212020-08-11 20:34:57 +0530668 if tax.charge_type in ["Actual", "On Item Quantity"]:
Nabin Haitaf9bdfe2017-12-12 18:50:05 +0530669 tax_amount = self.get_tax_amount_if_for_valuation_or_deduction(tax.tax_amount, tax)
670 actual_taxes_dict.setdefault(tax.idx, tax_amount)
Nabin Haite7679702015-02-20 14:40:35 +0530671 elif tax.row_id in actual_taxes_dict:
672 actual_tax_amount = flt(actual_taxes_dict.get(tax.row_id, 0)) * flt(tax.rate) / 100
673 actual_taxes_dict.setdefault(tax.idx, actual_tax_amount)
Nabin Hait3237c752015-02-17 11:11:11 +0530674
Ankush Menat494bd9e2022-03-28 18:52:46 +0530675 return flt(
676 self.doc.grand_total - sum(actual_taxes_dict.values()), self.doc.precision("grand_total")
677 )
Nabin Hait3237c752015-02-17 11:11:11 +0530678
Nabin Hait7b19b9e2015-02-24 09:42:24 +0530679 def calculate_total_advance(self):
680 if self.doc.docstatus < 2:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530681 total_allocated_amount = sum(
682 flt(adv.allocated_amount, adv.precision("allocated_amount"))
683 for adv in self.doc.get("advances")
684 )
Nabin Hait3237c752015-02-17 11:11:11 +0530685
Nabin Haite7679702015-02-20 14:40:35 +0530686 self.doc.total_advance = flt(total_allocated_amount, self.doc.precision("total_advance"))
Anand Doshi15f7b1e2016-04-04 15:03:28 +0530687
Faris Ansari6041f5c2018-02-08 13:33:52 +0530688 grand_total = self.doc.rounded_total or self.doc.grand_total
689
Nabin Hait289ffb72016-02-08 11:06:55 +0530690 if self.doc.party_account_currency == self.doc.currency:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530691 invoice_total = flt(
692 grand_total - flt(self.doc.write_off_amount), self.doc.precision("grand_total")
693 )
Nabin Hait8d8cba72017-04-03 17:26:22 +0530694 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530695 base_write_off_amount = flt(
696 flt(self.doc.write_off_amount) * self.doc.conversion_rate,
697 self.doc.precision("base_write_off_amount"),
698 )
699 invoice_total = (
700 flt(grand_total * self.doc.conversion_rate, self.doc.precision("grand_total"))
701 - base_write_off_amount
702 )
Vishal Dhayaguded42242d2017-11-29 16:09:59 +0530703
Nabin Haitadc09232016-02-09 10:31:11 +0530704 if invoice_total > 0 and self.doc.total_advance > invoice_total:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530705 frappe.throw(
706 _("Advance amount cannot be greater than {0} {1}").format(
707 self.doc.party_account_currency, invoice_total
708 )
709 )
Nabin Hait3237c752015-02-17 11:11:11 +0530710
Rushabh Mehta8bb6e532015-02-18 20:22:59 +0530711 if self.doc.docstatus == 0:
Ankush Menat3821a972022-03-28 20:14:19 +0530712 if self.doc.get("write_off_outstanding_amount_automatically"):
Deepesh Garg19b1b1f2022-03-25 18:02:14 +0530713 self.doc.write_off_amount = 0
714
Nabin Hait3237c752015-02-17 11:11:11 +0530715 self.calculate_outstanding_amount()
Deepesh Gargf57f4af2022-03-24 12:31:37 +0530716 self.calculate_write_off_amount()
Nabin Hait3237c752015-02-17 11:11:11 +0530717
Deepesh Gargf17ea2c2020-12-11 21:30:39 +0530718 def is_internal_invoice(self):
719 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530720 Checks if its an internal transfer invoice
721 and decides if to calculate any out standing amount or not
Deepesh Gargf17ea2c2020-12-11 21:30:39 +0530722 """
723
Ankush Menat494bd9e2022-03-28 18:52:46 +0530724 if self.doc.doctype in ("Sales Invoice", "Purchase Invoice") and self.doc.is_internal_transfer():
Deepesh Gargf17ea2c2020-12-11 21:30:39 +0530725 return True
726
727 return False
728
Nabin Hait3237c752015-02-17 11:11:11 +0530729 def calculate_outstanding_amount(self):
730 # NOTE:
731 # write_off_amount is only for POS Invoice
732 # total_advance is only for non POS Invoice
Rohit Waghchaureefb5bf22016-08-25 02:09:53 +0530733 if self.doc.doctype == "Sales Invoice":
734 self.calculate_paid_amount()
735
Ankush Menat494bd9e2022-03-28 18:52:46 +0530736 if (
737 self.doc.is_return
738 and self.doc.return_against
739 and not self.doc.get("is_pos")
740 or self.is_internal_invoice()
741 ):
742 return
Anand Doshi15f7b1e2016-04-04 15:03:28 +0530743
Nabin Hait4ffd7f32015-08-27 12:28:36 +0530744 self.doc.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount"])
Ankush Menat494bd9e2022-03-28 18:52:46 +0530745 self._set_in_company_currency(self.doc, ["write_off_amount"])
Anand Doshi15f7b1e2016-04-04 15:03:28 +0530746
Nabin Hait877e1bb2017-11-17 12:27:43 +0530747 if self.doc.doctype in ["Sales Invoice", "Purchase Invoice"]:
748 grand_total = self.doc.rounded_total or self.doc.grand_total
Deepesh Garg9d3a5c32022-01-06 18:58:49 +0530749 base_grand_total = self.doc.base_rounded_total or self.doc.base_grand_total
750
Nabin Hait877e1bb2017-11-17 12:27:43 +0530751 if self.doc.party_account_currency == self.doc.currency:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530752 total_amount_to_pay = flt(
753 grand_total - self.doc.total_advance - flt(self.doc.write_off_amount),
754 self.doc.precision("grand_total"),
755 )
Nabin Hait877e1bb2017-11-17 12:27:43 +0530756 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530757 total_amount_to_pay = flt(
758 flt(base_grand_total, self.doc.precision("base_grand_total"))
759 - self.doc.total_advance
760 - flt(self.doc.base_write_off_amount),
761 self.doc.precision("base_grand_total"),
762 )
Anand Doshi15f7b1e2016-04-04 15:03:28 +0530763
Nabin Hait4ffd7f32015-08-27 12:28:36 +0530764 self.doc.round_floats_in(self.doc, ["paid_amount"])
Nabin Hait877e1bb2017-11-17 12:27:43 +0530765 change_amount = 0
766
Ankush Menat494bd9e2022-03-28 18:52:46 +0530767 if self.doc.doctype == "Sales Invoice" and not self.doc.get("is_return"):
Nabin Hait877e1bb2017-11-17 12:27:43 +0530768 self.calculate_change_amount()
Ankush Menat494bd9e2022-03-28 18:52:46 +0530769 change_amount = (
770 self.doc.change_amount
771 if self.doc.party_account_currency == self.doc.currency
772 else self.doc.base_change_amount
773 )
Nabin Hait877e1bb2017-11-17 12:27:43 +0530774
Ankush Menat494bd9e2022-03-28 18:52:46 +0530775 paid_amount = (
776 self.doc.paid_amount
777 if self.doc.party_account_currency == self.doc.currency
778 else self.doc.base_paid_amount
779 )
Rohit Waghchaure6087fe12016-04-09 14:31:09 +0530780
Ankush Menat494bd9e2022-03-28 18:52:46 +0530781 self.doc.outstanding_amount = flt(
782 total_amount_to_pay - flt(paid_amount) + flt(change_amount),
783 self.doc.precision("outstanding_amount"),
784 )
Rushabh Mehtac6bd7ad2016-12-21 17:30:29 +0530785
Saqib Ansarie8a7a542022-03-12 19:20:48 +0530786 if (
Ankush Menat494bd9e2022-03-28 18:52:46 +0530787 self.doc.doctype == "Sales Invoice"
788 and self.doc.get("is_pos")
Saqib Ansari33762db2022-08-10 14:17:28 +0530789 and self.doc.get("pos_profile")
790 and self.doc.get("is_consolidated")
791 ):
792 write_off_limit = flt(
793 frappe.db.get_value("POS Profile", self.doc.pos_profile, "write_off_limit")
794 )
795 if write_off_limit and abs(self.doc.outstanding_amount) <= write_off_limit:
796 self.doc.write_off_outstanding_amount_automatically = 1
797
798 if (
799 self.doc.doctype == "Sales Invoice"
800 and self.doc.get("is_pos")
Ankush Menat494bd9e2022-03-28 18:52:46 +0530801 and self.doc.get("is_return")
802 and not self.doc.get("is_consolidated")
Saqib Ansarie8a7a542022-03-12 19:20:48 +0530803 ):
Subin Tom7d627df2021-08-23 11:05:07 +0530804 self.set_total_amount_to_default_mop(total_amount_to_pay)
805 self.calculate_paid_amount()
Deepesh Garg0ebace52020-02-25 13:21:16 +0530806
Rohit Waghchaure6087fe12016-04-09 14:31:09 +0530807 def calculate_paid_amount(self):
Manas Solankida486ee2018-07-06 12:36:57 +0530808
Rohit Waghchaure6087fe12016-04-09 14:31:09 +0530809 paid_amount = base_paid_amount = 0.0
Rohit Waghchauref58cad62017-01-17 12:11:57 +0530810
811 if self.doc.is_pos:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530812 for payment in self.doc.get("payments"):
Ayush Shuklae9cf1ab2017-05-25 14:14:55 +0530813 payment.amount = flt(payment.amount)
814 payment.base_amount = payment.amount * flt(self.doc.conversion_rate)
Rohit Waghchauref58cad62017-01-17 12:11:57 +0530815 paid_amount += payment.amount
816 base_paid_amount += payment.base_amount
rohitwaghchaure73456ac2017-05-16 11:29:57 +0530817 elif not self.doc.is_return:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530818 self.doc.set("payments", [])
Rohit Waghchaure6087fe12016-04-09 14:31:09 +0530819
Manas Solankida486ee2018-07-06 12:36:57 +0530820 if self.doc.redeem_loyalty_points and self.doc.loyalty_amount:
821 base_paid_amount += self.doc.loyalty_amount
Ankush Menat494bd9e2022-03-28 18:52:46 +0530822 paid_amount += self.doc.loyalty_amount / flt(self.doc.conversion_rate)
Manas Solankida486ee2018-07-06 12:36:57 +0530823
Rohit Waghchaure6087fe12016-04-09 14:31:09 +0530824 self.doc.paid_amount = flt(paid_amount, self.doc.precision("paid_amount"))
825 self.doc.base_paid_amount = flt(base_paid_amount, self.doc.precision("base_paid_amount"))
826
Nabin Hait3bb1a422016-08-02 16:41:10 +0530827 def calculate_change_amount(self):
828 self.doc.change_amount = 0.0
Rohit Waghchaure609e2b42016-08-31 02:04:37 +0530829 self.doc.base_change_amount = 0.0
Saqib Ansaric2b83a02022-02-08 17:07:51 +0530830 grand_total = self.doc.rounded_total or self.doc.grand_total
831 base_grand_total = self.doc.base_rounded_total or self.doc.base_grand_total
Nabin Hait877e1bb2017-11-17 12:27:43 +0530832
Ankush Menat494bd9e2022-03-28 18:52:46 +0530833 if (
834 self.doc.doctype == "Sales Invoice"
835 and self.doc.paid_amount > grand_total
836 and not self.doc.is_return
837 and any(d.type == "Cash" for d in self.doc.payments)
838 ):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530839 self.doc.change_amount = flt(
Ankush Menat3821a972022-03-28 20:14:19 +0530840 self.doc.paid_amount - grand_total, self.doc.precision("change_amount")
Ankush Menat494bd9e2022-03-28 18:52:46 +0530841 )
Nabin Haitac3b2aa2017-05-30 15:35:01 +0530842
Ankush Menat494bd9e2022-03-28 18:52:46 +0530843 self.doc.base_change_amount = flt(
Ankush Menat3821a972022-03-28 20:14:19 +0530844 self.doc.base_paid_amount - base_grand_total, self.doc.precision("base_change_amount")
Ankush Menat494bd9e2022-03-28 18:52:46 +0530845 )
mbauskar36b51892016-01-18 16:31:10 +0530846
Rohit Waghchaure7127a8f2016-08-04 14:56:15 +0530847 def calculate_write_off_amount(self):
Ankush Menat3821a972022-03-28 20:14:19 +0530848 if self.doc.get("write_off_outstanding_amount_automatically"):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530849 self.doc.write_off_amount = flt(
Ankush Menat3821a972022-03-28 20:14:19 +0530850 self.doc.outstanding_amount, self.doc.precision("write_off_amount")
Ankush Menat494bd9e2022-03-28 18:52:46 +0530851 )
852 self.doc.base_write_off_amount = flt(
853 self.doc.write_off_amount * self.doc.conversion_rate,
854 self.doc.precision("base_write_off_amount"),
855 )
Rohit Waghchaure7127a8f2016-08-04 14:56:15 +0530856
Deepesh Gargf57f4af2022-03-24 12:31:37 +0530857 self.calculate_outstanding_amount()
858
mbauskar36b51892016-01-18 16:31:10 +0530859 def calculate_margin(self, item):
Makarand Bauskar0e4c5c92017-05-11 11:40:02 +0530860 rate_with_margin = 0.0
Shreya Shahbe690ef2017-11-14 17:22:41 +0530861 base_rate_with_margin = 0.0
mbauskar36b51892016-01-18 16:31:10 +0530862 if item.price_list_rate:
Rohit Waghchaure8bfe3302019-03-18 14:34:19 +0530863 if item.pricing_rules and not self.doc.ignore_pricing_rule:
Rohit Waghchaurea248dfb2020-07-16 17:27:26 +0530864 has_margin = False
marination733fd5f2020-08-26 18:23:12 +0530865 for d in get_applied_pricing_rules(item.pricing_rules):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530866 pricing_rule = frappe.get_cached_doc("Pricing Rule", d)
Shreya Shahf718b0c2018-02-20 11:26:46 +0530867
Ankush Menat494bd9e2022-03-28 18:52:46 +0530868 if pricing_rule.margin_rate_or_amount and (
869 (
870 pricing_rule.currency == self.doc.currency
871 and pricing_rule.margin_type in ["Amount", "Percentage"]
872 )
873 or pricing_rule.margin_type == "Percentage"
874 ):
Rohit Waghchaure8bfe3302019-03-18 14:34:19 +0530875 item.margin_type = pricing_rule.margin_type
876 item.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
Rohit Waghchaurea248dfb2020-07-16 17:27:26 +0530877 has_margin = True
878
879 if not has_margin:
880 item.margin_type = None
881 item.margin_rate_or_amount = 0.0
mbauskar36b51892016-01-18 16:31:10 +0530882
Rohit Waghchaure01faa9c2021-06-21 00:59:02 +0530883 if not item.pricing_rules and flt(item.rate) > flt(item.price_list_rate):
884 item.margin_type = "Amount"
Ankush Menat494bd9e2022-03-28 18:52:46 +0530885 item.margin_rate_or_amount = flt(
886 item.rate - item.price_list_rate, item.precision("margin_rate_or_amount")
887 )
Rohit Waghchaure01faa9c2021-06-21 00:59:02 +0530888 item.rate_with_margin = item.rate
889
890 elif item.margin_type and item.margin_rate_or_amount:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530891 margin_value = (
892 item.margin_rate_or_amount
893 if item.margin_type == "Amount"
894 else flt(item.price_list_rate) * flt(item.margin_rate_or_amount) / 100
895 )
Makarand Bauskar0e4c5c92017-05-11 11:40:02 +0530896 rate_with_margin = flt(item.price_list_rate) + flt(margin_value)
Shreya Shahbe690ef2017-11-14 17:22:41 +0530897 base_rate_with_margin = flt(rate_with_margin) * flt(self.doc.conversion_rate)
mbauskar36b51892016-01-18 16:31:10 +0530898
Shreya Shahbe690ef2017-11-14 17:22:41 +0530899 return rate_with_margin, base_rate_with_margin
Nabin Hait852cb642017-07-05 12:58:19 +0530900
901 def set_item_wise_tax_breakup(self):
Nabin Hait9c421612017-07-20 13:32:01 +0530902 self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
Vishal Dhayaguded42242d2017-11-29 16:09:59 +0530903
Subin Tom7d627df2021-08-23 11:05:07 +0530904 def set_total_amount_to_default_mop(self, total_amount_to_pay):
Deepesh Garg06e8e282022-10-31 19:58:46 +0530905 total_paid_amount = 0
906 for payment in self.doc.get("payments"):
907 total_paid_amount += (
908 payment.amount if self.doc.party_account_currency == self.doc.currency else payment.base_amount
Ankush Menat494bd9e2022-03-28 18:52:46 +0530909 )
910
Deepesh Garg06e8e282022-10-31 19:58:46 +0530911 pending_amount = total_amount_to_pay - total_paid_amount
912
913 if pending_amount > 0:
914 default_mode_of_payment = frappe.db.get_value(
915 "POS Payment Method",
916 {"parent": self.doc.pos_profile, "default": 1},
917 ["mode_of_payment"],
918 as_dict=1,
919 )
920
921 if default_mode_of_payment:
922 self.doc.payments = []
923 self.doc.append(
924 "payments",
925 {
926 "mode_of_payment": default_mode_of_payment.mode_of_payment,
927 "amount": pending_amount,
928 "default": 1,
929 },
930 )
931
Deepesh Garg0ebace52020-02-25 13:21:16 +0530932
Nabin Hait9c421612017-07-20 13:32:01 +0530933def get_itemised_tax_breakup_html(doc):
934 if not doc.taxes:
935 return
936 frappe.flags.company = doc.company
Vishal Dhayaguded42242d2017-11-29 16:09:59 +0530937
Nabin Hait9c421612017-07-20 13:32:01 +0530938 # get headers
Nabin Haitcaab5822017-08-24 16:22:28 +0530939 tax_accounts = []
940 for tax in doc.taxes:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530941 if getattr(tax, "category", None) and tax.category == "Valuation":
Nabin Haitcaab5822017-08-24 16:22:28 +0530942 continue
rohitwaghchaure4e17fae2017-12-12 14:40:52 +0530943 if tax.description not in tax_accounts:
Nabin Haitcaab5822017-08-24 16:22:28 +0530944 tax_accounts.append(tax.description)
945
Nabin Hait9c421612017-07-20 13:32:01 +0530946 headers = get_itemised_tax_breakup_header(doc.doctype + " Item", tax_accounts)
Vishal Dhayaguded42242d2017-11-29 16:09:59 +0530947
Nabin Hait9c421612017-07-20 13:32:01 +0530948 # get tax breakup data
949 itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(doc)
Nabin Haitcaab5822017-08-24 16:22:28 +0530950
951 get_rounded_tax_amount(itemised_tax, doc.precision("tax_amount", "taxes"))
952
rohitwaghchaured4526682017-12-28 14:20:13 +0530953 update_itemised_tax_data(doc)
Nabin Hait9c421612017-07-20 13:32:01 +0530954 frappe.flags.company = None
Vishal Dhayaguded42242d2017-11-29 16:09:59 +0530955
Nabin Hait9c421612017-07-20 13:32:01 +0530956 return frappe.render_template(
Ankush Menat494bd9e2022-03-28 18:52:46 +0530957 "templates/includes/itemised_tax_breakup.html",
958 dict(
Nabin Hait9c421612017-07-20 13:32:01 +0530959 headers=headers,
960 itemised_tax=itemised_tax,
961 itemised_taxable_amount=itemised_taxable_amount,
962 tax_accounts=tax_accounts,
Ankush Menat494bd9e2022-03-28 18:52:46 +0530963 doc=doc,
964 ),
Nabin Hait9c421612017-07-20 13:32:01 +0530965 )
Nabin Hait852cb642017-07-05 12:58:19 +0530966
Ankush Menat494bd9e2022-03-28 18:52:46 +0530967
Deepesh Garg6a5ef262021-02-19 14:30:23 +0530968@frappe.whitelist()
969def get_round_off_applicable_accounts(company, account_list):
970 account_list = get_regional_round_off_accounts(company, account_list)
971
972 return account_list
973
Ankush Menat494bd9e2022-03-28 18:52:46 +0530974
Deepesh Garg6a5ef262021-02-19 14:30:23 +0530975@erpnext.allow_regional
976def get_regional_round_off_accounts(company, account_list):
977 pass
rohitwaghchaured4526682017-12-28 14:20:13 +0530978
Ankush Menat494bd9e2022-03-28 18:52:46 +0530979
rohitwaghchaured4526682017-12-28 14:20:13 +0530980@erpnext.allow_regional
981def update_itemised_tax_data(doc):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530982 # Don't delete this method, used for localization
rohitwaghchaured4526682017-12-28 14:20:13 +0530983 pass
984
Ankush Menat494bd9e2022-03-28 18:52:46 +0530985
Nabin Haitb962fc12017-07-17 18:02:31 +0530986@erpnext.allow_regional
987def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
988 return [_("Item"), _("Taxable Amount")] + tax_accounts
989
Ankush Menat494bd9e2022-03-28 18:52:46 +0530990
Nabin Haitb962fc12017-07-17 18:02:31 +0530991@erpnext.allow_regional
992def get_itemised_tax_breakup_data(doc):
993 itemised_tax = get_itemised_tax(doc.taxes)
994
995 itemised_taxable_amount = get_itemised_taxable_amount(doc.items)
996
997 return itemised_tax, itemised_taxable_amount
998
Ankush Menat494bd9e2022-03-28 18:52:46 +0530999
Nabin Hait34c551d2019-07-03 10:34:31 +05301000def get_itemised_tax(taxes, with_tax_account=False):
Nabin Haitb962fc12017-07-17 18:02:31 +05301001 itemised_tax = {}
1002 for tax in taxes:
Ankush Menat494bd9e2022-03-28 18:52:46 +05301003 if getattr(tax, "category", None) and tax.category == "Valuation":
Nabin Haitcaab5822017-08-24 16:22:28 +05301004 continue
1005
Nabin Haitb962fc12017-07-17 18:02:31 +05301006 item_tax_map = json.loads(tax.item_wise_tax_detail) if tax.item_wise_tax_detail else {}
Nabin Hait2e4de832017-09-19 14:53:16 +05301007 if item_tax_map:
1008 for item_code, tax_data in item_tax_map.items():
1009 itemised_tax.setdefault(item_code, frappe._dict())
Vishal Dhayaguded42242d2017-11-29 16:09:59 +05301010
Prateeksha Singhea7533f2018-06-11 13:31:33 +05301011 tax_rate = 0.0
1012 tax_amount = 0.0
1013
Nabin Hait2e4de832017-09-19 14:53:16 +05301014 if isinstance(tax_data, list):
Prateeksha Singhea7533f2018-06-11 13:31:33 +05301015 tax_rate = flt(tax_data[0])
1016 tax_amount = flt(tax_data[1])
Nabin Hait2e4de832017-09-19 14:53:16 +05301017 else:
Prateeksha Singhea7533f2018-06-11 13:31:33 +05301018 tax_rate = flt(tax_data)
1019
Ankush Menat494bd9e2022-03-28 18:52:46 +05301020 itemised_tax[item_code][tax.description] = frappe._dict(
1021 dict(tax_rate=tax_rate, tax_amount=tax_amount)
1022 )
Rohit Waghchaure296fbfe2017-07-10 13:03:29 +05301023
Nabin Hait34c551d2019-07-03 10:34:31 +05301024 if with_tax_account:
1025 itemised_tax[item_code][tax.description].tax_account = tax.account_head
1026
Nabin Haitb962fc12017-07-17 18:02:31 +05301027 return itemised_tax
1028
Ankush Menat494bd9e2022-03-28 18:52:46 +05301029
Nabin Haitb962fc12017-07-17 18:02:31 +05301030def get_itemised_taxable_amount(items):
1031 itemised_taxable_amount = frappe._dict()
1032 for item in items:
Rohit Waghchaure296fbfe2017-07-10 13:03:29 +05301033 item_code = item.item_code or item.item_name
Nabin Haitb962fc12017-07-17 18:02:31 +05301034 itemised_taxable_amount.setdefault(item_code, 0)
1035 itemised_taxable_amount[item_code] += item.net_amount
1036
Nabin Haitcaab5822017-08-24 16:22:28 +05301037 return itemised_taxable_amount
1038
Ankush Menat494bd9e2022-03-28 18:52:46 +05301039
Nabin Haitcaab5822017-08-24 16:22:28 +05301040def get_rounded_tax_amount(itemised_tax, precision):
1041 # Rounding based on tax_amount precision
1042 for taxes in itemised_tax.values():
1043 for tax_account in taxes:
Himanshu Mishra35b26272018-11-13 11:13:04 +05301044 taxes[tax_account]["tax_amount"] = flt(taxes[tax_account]["tax_amount"], precision)
Deepesh Gargbfc17e42020-12-25 18:34:39 +05301045
Ankush Menat494bd9e2022-03-28 18:52:46 +05301046
Deepesh Gargbfc17e42020-12-25 18:34:39 +05301047class init_landed_taxes_and_totals(object):
1048 def __init__(self, doc):
1049 self.doc = doc
Ankush Menat494bd9e2022-03-28 18:52:46 +05301050 self.tax_field = "taxes" if self.doc.doctype == "Landed Cost Voucher" else "additional_costs"
Deepesh Gargbfc17e42020-12-25 18:34:39 +05301051 self.set_account_currency()
1052 self.set_exchange_rate()
1053 self.set_amounts_in_company_currency()
1054
1055 def set_account_currency(self):
1056 company_currency = erpnext.get_company_currency(self.doc.company)
1057 for d in self.doc.get(self.tax_field):
1058 if not d.account_currency:
Daizy Modi4efc9472022-11-07 09:21:03 +05301059 account_currency = frappe.get_cached_value("Account", d.expense_account, "account_currency")
Deepesh Gargbfc17e42020-12-25 18:34:39 +05301060 d.account_currency = account_currency or company_currency
1061
1062 def set_exchange_rate(self):
1063 company_currency = erpnext.get_company_currency(self.doc.company)
1064 for d in self.doc.get(self.tax_field):
1065 if d.account_currency == company_currency:
1066 d.exchange_rate = 1
Deepesh Garg22f5ff82021-03-17 10:56:52 +05301067 elif not d.exchange_rate:
Ankush Menat494bd9e2022-03-28 18:52:46 +05301068 d.exchange_rate = get_exchange_rate(
1069 self.doc.posting_date,
1070 account=d.expense_account,
1071 account_currency=d.account_currency,
1072 company=self.doc.company,
1073 )
Deepesh Gargbfc17e42020-12-25 18:34:39 +05301074
1075 if not d.exchange_rate:
1076 frappe.throw(_("Row {0}: Exchange Rate is mandatory").format(d.idx))
1077
1078 def set_amounts_in_company_currency(self):
1079 for d in self.doc.get(self.tax_field):
1080 d.amount = flt(d.amount, d.precision("amount"))
niralisatapara12456f92022-11-03 10:46:30 +05301081 d.base_amount = flt(d.amount * flt(d.exchange_rate), d.precision("base_amount"))