blob: 01c8c61702426a025c3051ec751cd6ecf839a64a [file] [log] [blame]
Nabin Haitec52db82013-01-22 11:53:14 +05301# ERPNext - web based ERP (http://erpnext.com)
2# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17from __future__ import unicode_literals
18import webnotes
Anand Doshif3096132013-05-21 19:35:06 +053019from webnotes.utils import cint, flt, comma_or
Nabin Haitec52db82013-01-22 11:53:14 +053020from setup.utils import get_company_currency
Nabin Hait0fc24542013-03-25 11:06:00 +053021from webnotes import msgprint, _
Anand Doshi21f4ea32013-05-10 18:08:32 +053022import json
Nabin Haitec52db82013-01-22 11:53:14 +053023
Nabin Haitc3afb252013-03-19 12:01:24 +053024from controllers.stock_controller import StockController
Nabin Haitbf495c92013-01-30 12:49:08 +053025
Nabin Haitc3afb252013-03-19 12:01:24 +053026class SellingController(StockController):
Anand Doshif3096132013-05-21 19:35:06 +053027 def onload_post_render(self):
28 self.set_price_list_currency()
29
30 # contact, address, item details and pos details (if applicable)
31 self.set_missing_values()
32
33 if self.meta.get_field("other_charges"):
34 self.set_taxes()
35
Nabin Haitec52db82013-01-22 11:53:14 +053036 def validate(self):
Saurabh6f753182013-03-20 12:55:28 +053037 super(SellingController, self).validate()
Anand Doshif3096132013-05-21 19:35:06 +053038 # self.calculate_taxes_and_totals()
Nabin Haitec52db82013-01-22 11:53:14 +053039 self.set_total_in_words()
Anand Doshif3096132013-05-21 19:35:06 +053040 self.set_missing_values(for_validate=True)
41
42 def set_price_list_currency(self):
43 if self.doc.price_list_name and not self.doc.price_list_currency:
44 # TODO - change this, since price list now has only one currency allowed
45 from setup.utils import get_price_list_currency
46 self.doc.fields.update(get_price_list_currency(
47 {"price_list_name": self.doc.price_list_name, "use_for": "selling"}))
48
49 def set_missing_values(self, for_validate=False):
50 # set contact and address details for customer, if they are not mentioned
51 if self.doc.customer and not (self.doc.contact_person and self.doc.customer_address):
52 for fieldname, val in self.get_default_address_and_contact("customer").items():
53 if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname):
54 self.doc.fields[fieldname] = val
55
56 # set missing item values
57 from selling.utils import get_item_details
58 for item in self.doclist.get({"parentfield": "entries"}):
59 if item.fields.get("item_code"):
Anand Doshi65d87552013-05-21 19:53:33 +053060 args = item.fields.copy().update(self.doc.fields)
61 ret = get_item_details(args)
Anand Doshif3096132013-05-21 19:35:06 +053062 for fieldname, value in ret.items():
63 if self.meta.get_field(fieldname, parentfield="entries") and \
64 not item.fields.get(fieldname):
65 item.fields[fieldname] = value
66
67 def set_taxes(self):
68 if not self.doclist.get({"parentfield": "other_charges"}):
69 if not self.doc.charge:
70 # get the default tax master
71 self.doc.charge = webnotes.conn.get_value("Sales Taxes and Charges Master",
72 {"is_default": 1})
73
74 if self.doc.charge:
75 from webnotes.model import default_fields
76 tax_master = webnotes.bean("Sales Taxes and Charges Master", self.doc.charge)
77 for i, tax in enumerate(tax_master.doclist.get({"parentfield": "other_charges"})):
78 for fieldname in default_fields:
79 tax.fields[fieldname] = None
80
81 tax.fields.update({
82 "doctype": "Sales Taxes and Charges",
83 "parentfield": "other_charges",
84 "idx": i+1
85 })
86
87 self.doclist.append(tax)
88
89 def get_other_charges(self):
90 self.doclist = self.doc.clear_table(self.doclist, "other_charges")
91 self.set_taxes()
92
93 def set_customer_defaults(self):
94 self.get_default_customer_address()
Nabin Haitec52db82013-01-22 11:53:14 +053095
96 def set_total_in_words(self):
97 from webnotes.utils import money_in_words
98 company_currency = get_company_currency(self.doc.company)
Nabin Hait6f1a5ec2013-02-20 16:25:05 +053099
100 disable_rounded_total = cint(webnotes.conn.get_value("Global Defaults", None,
101 "disable_rounded_total"))
102
Nabin Haitec52db82013-01-22 11:53:14 +0530103 if self.meta.get_field("in_words"):
Nabin Hait6f1a5ec2013-02-20 16:25:05 +0530104 self.doc.in_words = money_in_words(disable_rounded_total and
105 self.doc.grand_total or self.doc.rounded_total, company_currency)
Nabin Haitec52db82013-01-22 11:53:14 +0530106 if self.meta.get_field("in_words_export"):
Nabin Hait6f1a5ec2013-02-20 16:25:05 +0530107 self.doc.in_words_export = money_in_words(disable_rounded_total and
Nabin Hait8c7234f2013-03-11 16:32:33 +0530108 self.doc.grand_total_export or self.doc.rounded_total_export, self.doc.currency)
Nabin Haita0e7c152013-03-21 18:37:06 +0530109
Nabin Hait787c02e2013-03-29 16:42:33 +0530110 def set_buying_amount(self, stock_ledger_entries = None):
Anand Doshi8c5844e2013-03-21 20:24:10 +0530111 from stock.utils import get_buying_amount
Nabin Hait787c02e2013-03-29 16:42:33 +0530112 if not stock_ledger_entries:
113 stock_ledger_entries = self.get_stock_ledger_entries()
Anand Doshi8c5844e2013-03-21 20:24:10 +0530114
115 item_sales_bom = {}
116 for d in self.doclist.get({"parentfield": "packing_details"}):
117 new_d = webnotes._dict(d.fields.copy())
118 new_d.total_qty = -1 * d.qty
119 item_sales_bom.setdefault(d.parent_item, []).append(new_d)
Nabin Haita0e7c152013-03-21 18:37:06 +0530120
121 if stock_ledger_entries:
122 for item in self.doclist.get({"parentfield": self.fname}):
123 if item.item_code in self.stock_items or \
124 (item_sales_bom and item_sales_bom.get(item.item_code)):
125 buying_amount = get_buying_amount(item.item_code, item.warehouse, -1*item.qty,
126 self.doc.doctype, self.doc.name, item.name, stock_ledger_entries,
127 item_sales_bom)
Nabin Haitf2d4df92013-05-07 13:12:02 +0530128
129 item.buying_amount = buying_amount >= 0.01 and buying_amount or 0
Nabin Hait0fc24542013-03-25 11:06:00 +0530130 webnotes.conn.set_value(item.doctype, item.name, "buying_amount",
131 item.buying_amount)
132
133 def check_expense_account(self, item):
134 if item.buying_amount and not item.expense_account:
135 msgprint(_("""Expense account is mandatory for item: """) + item.item_code,
Nabin Hait787c02e2013-03-29 16:42:33 +0530136 raise_exception=1)
137
138 if item.buying_amount and not item.cost_center:
139 msgprint(_("""Cost Center is mandatory for item: """) + item.item_code,
Anand Doshi21f4ea32013-05-10 18:08:32 +0530140 raise_exception=1)
141
142 def calculate_taxes_and_totals(self):
143 self.doc.conversion_rate = flt(self.doc.conversion_rate)
144 self.item_doclist = self.doclist.get({"parentfield": self.fname})
145 self.tax_doclist = self.doclist.get({"parentfield": "other_charges"})
146
147 self.calculate_item_values()
148 self.initialize_taxes()
Anand Doshif3096132013-05-21 19:35:06 +0530149 self.determine_exclusive_rate()
Anand Doshi21f4ea32013-05-10 18:08:32 +0530150 self.calculate_net_total()
151 self.calculate_taxes()
152 self.calculate_totals()
Anand Doshif3096132013-05-21 19:35:06 +0530153 self.calculate_commission()
154 self.calculate_contribution()
Anand Doshi21f4ea32013-05-10 18:08:32 +0530155 # self.calculate_outstanding_amount()
Anand Doshi21f4ea32013-05-10 18:08:32 +0530156 self._cleanup()
157
Anand Doshif3096132013-05-21 19:35:06 +0530158 # TODO
159 # print format: show net_total_export instead of net_total
160
161 def determine_exclusive_rate(self):
Anand Doshi21f4ea32013-05-10 18:08:32 +0530162 if not any((cint(tax.included_in_print_rate) for tax in self.tax_doclist)):
163 # no inclusive tax
164 return
165
166 for item in self.item_doclist:
167 item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
168 cumulated_tax_fraction = 0
169 for i, tax in enumerate(self.tax_doclist):
Anand Doshif3096132013-05-21 19:35:06 +0530170 tax.tax_fraction_for_current_item = self.get_current_tax_fraction(tax, item_tax_map)
171
Anand Doshi21f4ea32013-05-10 18:08:32 +0530172 if i==0:
Anand Doshif3096132013-05-21 19:35:06 +0530173 tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item
Anand Doshi21f4ea32013-05-10 18:08:32 +0530174 else:
175 tax.grand_total_fraction_for_current_item = \
176 self.tax_doclist[i-1].grand_total_fraction_for_current_item \
177 + tax.tax_fraction_for_current_item
178
179 cumulated_tax_fraction += tax.tax_fraction_for_current_item
180
181 if cumulated_tax_fraction:
182 item.basic_rate = flt((item.export_rate * self.doc.conversion_rate) /
Anand Doshi39384d32013-05-11 19:39:53 +0530183 (1 + cumulated_tax_fraction), self.precision("basic_rate", item))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530184
Anand Doshi39384d32013-05-11 19:39:53 +0530185 item.amount = flt(item.basic_rate * item.qty, self.precision("amount", item))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530186
Anand Doshif3096132013-05-21 19:35:06 +0530187 if item.adj_rate == 100:
188 item.base_ref_rate = item.basic_rate
189 item.basic_rate = 0.0
190 else:
191 item.base_ref_rate = flt(item.basic_rate / (1 - (item.adj_rate / 100.0)),
192 self.precision("base_ref_rate", item))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530193
194 def get_current_tax_fraction(self, tax, item_tax_map):
195 """
196 Get tax fraction for calculating tax exclusive amount
197 from tax inclusive amount
198 """
199 current_tax_fraction = 0
200
201 if cint(tax.included_in_print_rate):
202 tax_rate = self._get_tax_rate(tax, item_tax_map)
203
204 if tax.charge_type == "On Net Total":
205 current_tax_fraction = tax_rate / 100.0
206
207 elif tax.charge_type == "On Previous Row Amount":
208 current_tax_fraction = (tax_rate / 100.0) * \
209 self.tax_doclist[cint(tax.row_id) - 1].tax_fraction_for_current_item
210
211 elif tax.charge_type == "On Previous Row Total":
212 current_tax_fraction = (tax_rate / 100.0) * \
213 self.tax_doclist[cint(tax.row_id) - 1].grand_total_fraction_for_current_item
214
215 return current_tax_fraction
216
217 def calculate_item_values(self):
218 def _set_base(item, print_field, base_field):
219 """set values in base currency"""
220 item.fields[base_field] = flt((flt(item.fields[print_field],
Anand Doshi39384d32013-05-11 19:39:53 +0530221 self.precision(print_field, item)) * self.doc.conversion_rate),
222 self.precision(base_field, item))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530223
224 for item in self.item_doclist:
Anand Doshi39384d32013-05-11 19:39:53 +0530225 self.round_floats_in(item)
Anand Doshi21f4ea32013-05-10 18:08:32 +0530226
227 if item.adj_rate == 100:
228 item.ref_rate = item.ref_rate or item.export_rate
229 item.export_rate = 0
230 else:
231 if item.ref_rate:
232 item.export_rate = flt(item.ref_rate * (1.0 - (item.adj_rate / 100.0)),
Anand Doshi39384d32013-05-11 19:39:53 +0530233 self.precision("export_rate", item))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530234 else:
235 # assume that print rate and discount are specified
236 item.ref_rate = flt(item.export_rate / (1.0 - (item.adj_rate / 100.0)),
Anand Doshi39384d32013-05-11 19:39:53 +0530237 self.precision("ref_rate", item))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530238
239 item.export_amount = flt(item.export_rate * item.qty,
Anand Doshi39384d32013-05-11 19:39:53 +0530240 self.precision("export_amount", item))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530241
242 _set_base(item, "ref_rate", "base_ref_rate")
243 _set_base(item, "export_rate", "basic_rate")
244 _set_base(item, "export_amount", "amount")
245
246 def initialize_taxes(self):
247 for tax in self.tax_doclist:
248 tax.tax_amount = tax.total = 0.0
Anand Doshif3096132013-05-21 19:35:06 +0530249 tax.item_wise_tax_detail = {}
250
Anand Doshi21f4ea32013-05-10 18:08:32 +0530251 # temporary fields
252 tax.tax_amount_for_current_item = tax.grand_total_for_current_item = 0.0
Anand Doshif3096132013-05-21 19:35:06 +0530253
Anand Doshi21f4ea32013-05-10 18:08:32 +0530254 self.validate_on_previous_row(tax)
255 self.validate_inclusive_tax(tax)
Anand Doshi39384d32013-05-11 19:39:53 +0530256 self.round_floats_in(tax)
Anand Doshi21f4ea32013-05-10 18:08:32 +0530257
258 def calculate_net_total(self):
Anand Doshif3096132013-05-21 19:35:06 +0530259 self.doc.net_total = self.doc.net_total_export = 0.0
Anand Doshi21f4ea32013-05-10 18:08:32 +0530260
261 for item in self.item_doclist:
262 self.doc.net_total += item.amount
263 self.doc.net_total_export += item.export_amount
Anand Doshif3096132013-05-21 19:35:06 +0530264
265 self.round_floats_in(self.doc, ["net_total", "net_total_export"])
Anand Doshi21f4ea32013-05-10 18:08:32 +0530266
267 def calculate_taxes(self):
268 for item in self.item_doclist:
269 item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
270
271 for i, tax in enumerate(self.tax_doclist):
272 # tax_amount represents the amount of tax for the current step
273 current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map)
274
275 # case when net total is 0 but there is an actual type charge
276 # in this case add the actual amount to tax.tax_amount
277 # and tax.grand_total_for_current_item for the first such iteration
Anand Doshif3096132013-05-21 19:35:06 +0530278 if tax.charge_type=="Actual" and \
279 not (current_tax_amount or self.doc.net_total or tax.tax_amount):
Anand Doshi39384d32013-05-11 19:39:53 +0530280 zero_net_total_adjustment = flt(tax.rate, self.precision("tax_amount", tax))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530281 current_tax_amount += zero_net_total_adjustment
282
283 # store tax_amount for current item as it will be used for
284 # charge type = 'On Previous Row Amount'
285 tax.tax_amount_for_current_item = current_tax_amount
286
287 # accumulate tax amount into tax.tax_amount
Anand Doshif3096132013-05-21 19:35:06 +0530288 tax.tax_amount += current_tax_amount
Anand Doshi21f4ea32013-05-10 18:08:32 +0530289
290 # Calculate tax.total viz. grand total till that step
291 # note: grand_total_for_current_item contains the contribution of
292 # item's amount, previously applied tax and the current tax on that item
293 if i==0:
294 tax.grand_total_for_current_item = flt(item.amount +
Anand Doshi39384d32013-05-11 19:39:53 +0530295 current_tax_amount, self.precision("total", tax))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530296
297 else:
298 tax.grand_total_for_current_item = \
299 flt(self.tax_doclist[i-1].grand_total_for_current_item +
Anand Doshi39384d32013-05-11 19:39:53 +0530300 current_tax_amount, self.precision("total", tax))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530301
302 # in tax.total, accumulate grand total of each item
303 tax.total += tax.grand_total_for_current_item
304
Anand Doshif3096132013-05-21 19:35:06 +0530305 # store tax breakup for each item
Anand Doshi21f4ea32013-05-10 18:08:32 +0530306 tax.item_wise_tax_detail[item.item_code] = current_tax_amount
307
308 def calculate_totals(self):
309 self.doc.grand_total = flt(self.tax_doclist and \
Anand Doshi5af812a2013-05-10 19:23:02 +0530310 self.tax_doclist[-1].total or self.doc.net_total, self.precision("grand_total"))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530311 self.doc.grand_total_export = flt(self.doc.grand_total / self.doc.conversion_rate,
Anand Doshi5af812a2013-05-10 19:23:02 +0530312 self.precision("grand_total_export"))
Anand Doshif3096132013-05-21 19:35:06 +0530313
314 self.doc.other_charges_total = flt(self.doc.grand_total - self.doc.net_total,
315 self.precision("other_charges_total"))
316 self.doc.other_charges_total_export = flt(self.doc.grand_total_export - self.doc.net_total_export,
317 self.precision("other_charges_total_export"))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530318
319 self.doc.rounded_total = round(self.doc.grand_total)
320 self.doc.rounded_total_export = round(self.doc.grand_total_export)
321
Anand Doshif3096132013-05-21 19:35:06 +0530322 def calculate_commission(self):
Anand Doshi65d87552013-05-21 19:53:33 +0530323 self.round_floats_in(self.doc, ["net_total", "commission_rate"])
324 if self.doc.commission_rate > 100.0:
Anand Doshif3096132013-05-21 19:35:06 +0530325 msgprint(_(self.meta.get_label("commission_rate")) + " " +
326 _("cannot be greater than 100"), raise_exception=True)
327
328 self.doc.total_commission = flt(self.doc.net_total * self.doc.commission_rate / 100.0,
329 self.precision("total_commission"))
330
331 def calculate_contribution(self):
332 total = 0.0
333 sales_team = self.doclist.get({"parentfield": "sales_team"})
334 for sales_person in sales_team:
335 self.round_floats_in(sales_person)
336
337 sales_person.allocated_amount = flt(
338 self.doc.net_total * sales_person.allocated_percentage / 100.0,
339 self.precision("allocated_amount", sales_person))
340
341 total += sales_person.allocated_percentage
342
343 if sales_team and total != 100.0:
344 msgprint(_("Total") + " " +
345 _(self.meta.get_label("allocated_percentage", parentfield="sales_team")) +
346 " " + _("should be 100%"), raise_exception=True)
347
Anand Doshi21f4ea32013-05-10 18:08:32 +0530348 def get_current_tax_amount(self, item, tax, item_tax_map):
349 tax_rate = self._get_tax_rate(tax, item_tax_map)
Anand Doshif3096132013-05-21 19:35:06 +0530350 current_tax_amount = 0.0
Anand Doshi21f4ea32013-05-10 18:08:32 +0530351
352 if tax.charge_type == "Actual":
353 # distribute the tax amount proportionally to each item row
Anand Doshi39384d32013-05-11 19:39:53 +0530354 actual = flt(tax.rate, self.precision("tax_amount", tax))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530355 current_tax_amount = (self.doc.net_total
356 and ((item.amount / self.doc.net_total) * actual)
357 or 0)
358 elif tax.charge_type == "On Net Total":
359 current_tax_amount = (tax_rate / 100.0) * item.amount
360 elif tax.charge_type == "On Previous Row Amount":
361 current_tax_amount = (tax_rate / 100.0) * \
362 self.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item
363 elif tax.charge_type == "On Previous Row Total":
364 current_tax_amount = (tax_rate / 100.0) * \
365 self.tax_doclist[cint(tax.row_id) - 1].grand_total_for_current_item
366
Anand Doshi39384d32013-05-11 19:39:53 +0530367 return flt(current_tax_amount, self.precision("tax_amount", tax))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530368
369 def validate_on_previous_row(self, tax):
370 """
371 validate if a valid row id is mentioned in case of
372 On Previous Row Amount and On Previous Row Total
373 """
374 if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"] and \
375 (not tax.row_id or cint(tax.row_id) >= tax.idx):
376 msgprint((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \
377 _("Please specify a valid") + " %(row_id_label)s") % {
378 "idx": tax.idx,
Anand Doshif3096132013-05-21 19:35:06 +0530379 "taxes_doctype": tax.doctype,
Anand Doshi21f4ea32013-05-10 18:08:32 +0530380 "row_id_label": self.meta.get_label("row_id",
381 parentfield="other_charges")
382 }, raise_exception=True)
383
384 def validate_inclusive_tax(self, tax):
Anand Doshif3096132013-05-21 19:35:06 +0530385 def _on_previous_row_error(row_range):
386 msgprint((_("Row") + " # %(idx)s [%(doctype)s]: " +
387 _("to be included in Item's rate, it is required that: ") +
388 " [" + _("Row") + " # %(row_range)s] " + _("also be included in Item's rate")) % {
Anand Doshi21f4ea32013-05-10 18:08:32 +0530389 "idx": tax.idx,
Anand Doshif3096132013-05-21 19:35:06 +0530390 "doctype": tax.doctype,
Anand Doshi21f4ea32013-05-10 18:08:32 +0530391 "inclusive_label": self.meta.get_label("included_in_print_rate",
392 parentfield="other_charges"),
393 "charge_type_label": self.meta.get_label("charge_type",
394 parentfield="other_charges"),
395 "charge_type": tax.charge_type,
396 "row_range": row_range
397 }, raise_exception=True)
398
399 if cint(tax.included_in_print_rate):
400 if tax.charge_type == "Actual":
Anand Doshif3096132013-05-21 19:35:06 +0530401 # inclusive tax cannot be of type Actual
Anand Doshi21f4ea32013-05-10 18:08:32 +0530402 msgprint((_("Row")
Anand Doshif3096132013-05-21 19:35:06 +0530403 + " # %(idx)s [%(doctype)s]: %(charge_type_label)s = \"%(charge_type)s\" "
Anand Doshi21f4ea32013-05-10 18:08:32 +0530404 + "cannot be included in Item's rate") % {
405 "idx": tax.idx,
Anand Doshif3096132013-05-21 19:35:06 +0530406 "doctype": tax.doctype,
Anand Doshi21f4ea32013-05-10 18:08:32 +0530407 "charge_type_label": self.meta.get_label("charge_type",
408 parentfield="other_charges"),
409 "charge_type": tax.charge_type,
410 }, raise_exception=True)
411 elif tax.charge_type == "On Previous Row Amount" and \
412 not cint(self.tax_doclist[tax.row_id - 1].included_in_print_rate):
413 # referred row should also be inclusive
Anand Doshif3096132013-05-21 19:35:06 +0530414 _on_previous_row_error(tax.row_id)
Anand Doshi21f4ea32013-05-10 18:08:32 +0530415 elif tax.charge_type == "On Previous Row Total" and \
Anand Doshif3096132013-05-21 19:35:06 +0530416 not all([cint(t.included_in_print_rate) for t in self.tax_doclist[:tax.row_id - 1]]):
417 # all rows about the reffered tax should be inclusive
418 _on_previous_row_error("1 - %d" % (tax.row_id,))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530419
420 def _load_item_tax_rate(self, item_tax_rate):
Anand Doshif3096132013-05-21 19:35:06 +0530421 return json.loads(item_tax_rate) if item_tax_rate else {}
Anand Doshi21f4ea32013-05-10 18:08:32 +0530422
423 def _get_tax_rate(self, tax, item_tax_map):
424 if item_tax_map.has_key(tax.account_head):
Anand Doshi39384d32013-05-11 19:39:53 +0530425 return flt(item_tax_map.get(tax.account_head), self.precision("rate", tax))
Anand Doshi21f4ea32013-05-10 18:08:32 +0530426 else:
427 return tax.rate
428
429 def _cleanup(self):
430 for tax in self.tax_doclist:
Anand Doshif3096132013-05-21 19:35:06 +0530431 for fieldname in ("grand_total_for_current_item",
432 "tax_amount_for_current_item",
433 "tax_fraction_for_current_item",
Anand Doshi21f4ea32013-05-10 18:08:32 +0530434 "grand_total_fraction_for_current_item"):
435 if fieldname in tax.fields:
436 del tax.fields[fieldname]
437
438 tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail)
Anand Doshi1dde46a2013-05-15 21:15:57 +0530439
440 def validate_order_type(self):
441 valid_types = ["Sales", "Maintenance"]
442 if self.doc.order_type not in valid_types:
443 msgprint(_(self.meta.get_label("order_type")) + " " +
444 _("must be one of") + ": " + comma_or(valid_types),
445 raise_exception=True)