blob: 1fc411fad42758511f1532b6ca817f4019f75b19 [file] [log] [blame]
Anand Doshi756dca72013-01-15 18:39:21 +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 Doshif8f0c0d2013-01-17 20:20:56 +053019from webnotes import _, msgprint
Anand Doshi8595fcf2013-02-08 19:28:14 +053020from webnotes.utils import flt, cint
21import json
Anand Doshi756dca72013-01-15 18:39:21 +053022
23from buying.utils import get_item_details
Anand Doshif8f0c0d2013-01-17 20:20:56 +053024from setup.utils import get_company_currency
Anand Doshi1dde46a2013-05-15 21:15:57 +053025from utilities.transaction_base import validate_conversion_rate
Anand Doshi756dca72013-01-15 18:39:21 +053026
Nabin Hait89a94d82013-03-19 12:01:46 +053027from controllers.stock_controller import StockController
Nabin Haitbf495c92013-01-30 12:49:08 +053028
Rushabh Mehtaecb36f22013-05-02 11:34:37 +053029class WrongWarehouseCompany(Exception): pass
30
Nabin Hait89a94d82013-03-19 12:01:46 +053031class BuyingController(StockController):
Saurabh6f753182013-03-20 12:55:28 +053032 def validate(self):
33 super(BuyingController, self).validate()
Nabin Hait205f7ce2013-04-26 13:35:06 +053034 self.validate_stock_or_nonstock_items()
Rushabh Mehtaecb36f22013-05-02 11:34:37 +053035 self.validate_warehouse_belongs_to_company()
Anand Doshi1dde46a2013-05-15 21:15:57 +053036
Anand Doshif8f0c0d2013-01-17 20:20:56 +053037 if self.meta.get_field("currency"):
38 self.company_currency = get_company_currency(self.doc.company)
Anand Doshi1dde46a2013-05-15 21:15:57 +053039 validate_conversion_rate(self.doc.currency, self.doc.conversion_rate,
40 self.meta.get_label("conversion_rate"), self.doc.company)
Anand Doshi8595fcf2013-02-08 19:28:14 +053041
42 # IMPORTANT: enable this only when client side code is similar to this one
Anand Doshi3576b182013-02-08 19:30:06 +053043 # self.calculate_taxes_and_totals()
Saurabh6f753182013-03-20 12:55:28 +053044
Nabin Haitd3b62502013-01-21 17:24:31 +053045 # set total in words
Nabin Hait5b4c2942013-01-22 11:12:02 +053046 self.set_total_in_words()
Rushabh Mehtaecb36f22013-05-02 11:34:37 +053047
48 def validate_warehouse_belongs_to_company(self):
Rushabh Mehtac7115982013-05-02 14:22:40 +053049 for warehouse, company in webnotes.conn.get_values("Warehouse",
50 self.doclist.get_distinct_values("warehouse"), "company").items():
51 if company and company != self.doc.company:
Anand Doshieb41ffd2013-05-02 18:10:19 +053052 webnotes.msgprint(_("Company mismatch for Warehouse") + (": %s" % (warehouse,)),
Rushabh Mehtaecb36f22013-05-02 11:34:37 +053053 raise_exception=WrongWarehouseCompany)
Rushabh Mehtac7115982013-05-02 14:22:40 +053054
Nabin Hait205f7ce2013-04-26 13:35:06 +053055 def validate_stock_or_nonstock_items(self):
56 items = [d.item_code for d in self.doclist.get({"parentfield": self.fname})]
Nabin Haitd58d1b52013-04-26 17:25:44 +053057 if self.stock_items:
Nabin Hait205f7ce2013-04-26 13:35:06 +053058 nonstock_items = list(set(items) - set(self.stock_items))
Nabin Haitd58d1b52013-04-26 17:25:44 +053059 if nonstock_items:
60 webnotes.msgprint(_("Stock and non-stock items can not be entered in the same ") +
61 self.doc.doctype + _(""". You should make separate documents for them.
62 Stock Items: """) + ", ".join(self.stock_items) + _("""
63 Non-stock Items: """) + ", ".join(nonstock_items), raise_exception=1)
Nabin Hait205f7ce2013-04-26 13:35:06 +053064
65 elif items and not self.stock_items:
66 tax_for_valuation = [d.account_head for d in
67 self.doclist.get({"parentfield": "purchase_tax_details"})
68 if d.category in ["Valuation", "Valuation and Total"]]
69 if tax_for_valuation:
70 webnotes.msgprint(_("""Tax Category can not be 'Valuation' or 'Valuation and Total'
71 as all items are non-stock items"""), raise_exception=1)
72
Anand Doshi756dca72013-01-15 18:39:21 +053073 def update_item_details(self):
74 for item in self.doclist.get({"parentfield": self.fname}):
75 ret = get_item_details({
76 "doctype": self.doc.doctype,
77 "docname": self.doc.name,
78 "item_code": item.item_code,
79 "warehouse": item.warehouse,
80 "supplier": self.doc.supplier,
81 "transaction_date": self.doc.posting_date,
Nabin Haitc10c90a2013-02-06 11:44:43 +053082 "conversion_rate": self.doc.conversion_rate,
83 "price_list_name": self.doc.price_list_name,
84 "price_list_currency": self.doc.price_list_currency,
85 "plc_conversion_rate": self.doc.plc_conversion_rate
Anand Doshi756dca72013-01-15 18:39:21 +053086 })
87 for r in ret:
88 if not item.fields.get(r):
89 item.fields[r] = ret[r]
Anand Doshif8f0c0d2013-01-17 20:20:56 +053090
Nabin Haitd3b62502013-01-21 17:24:31 +053091 def set_total_in_words(self):
Nabin Hait5b4c2942013-01-22 11:12:02 +053092 from webnotes.utils import money_in_words
Nabin Haitd3b62502013-01-21 17:24:31 +053093 company_currency = get_company_currency(self.doc.company)
Nabin Hait5b4c2942013-01-22 11:12:02 +053094 if self.meta.get_field("in_words"):
95 self.doc.in_words = money_in_words(self.doc.grand_total, company_currency)
96 if self.meta.get_field("in_words_import"):
97 self.doc.in_words_import = money_in_words(self.doc.grand_total_import,
Anand Doshi613cb6a2013-02-06 17:33:46 +053098 self.doc.currency)
99
100 def calculate_taxes_and_totals(self):
Anand Doshi62090462013-02-07 19:47:34 +0530101 self.doc.conversion_rate = flt(self.doc.conversion_rate)
Anand Doshi8595fcf2013-02-08 19:28:14 +0530102 self.item_doclist = self.doclist.get({"parentfield": self.fname})
103 self.tax_doclist = self.doclist.get({"parentfield": "purchase_tax_details"})
Anand Doshi62090462013-02-07 19:47:34 +0530104
Anand Doshi8595fcf2013-02-08 19:28:14 +0530105 self.calculate_item_values()
106 self.initialize_taxes()
107 self.calculate_net_total()
108 self.calculate_taxes()
109 self.calculate_totals()
110 self.calculate_outstanding_amount()
111
112 self._cleanup()
113
114 def calculate_item_values(self):
115 def _set_base(item, print_field, base_field):
116 """set values in base currency"""
117 item.fields[base_field] = flt((flt(item.fields[print_field],
Anand Doshi39384d32013-05-11 19:39:53 +0530118 self.precision(print_field, item)) * self.doc.conversion_rate),
119 self.precision(base_field, item))
Anand Doshib8b1e582013-05-06 12:52:46 +0530120
121 # hack! - cleaned up in _cleanup()
122 if self.doc.doctype != "Purchase Invoice":
Anand Doshi21f4ea32013-05-10 18:08:32 +0530123 df = self.meta.get_field("purchase_rate", parentfield=self.fname)
124 df.fieldname = "rate"
Anand Doshia1d4b782013-02-26 18:09:47 +0530125
Anand Doshib8b1e582013-05-06 12:52:46 +0530126 for item in self.item_doclist:
Anand Doshia1d4b782013-02-26 18:09:47 +0530127 # hack! - cleaned up in _cleanup()
128 if self.doc.doctype != "Purchase Invoice":
129 item.rate = item.purchase_rate
Anand Doshia1d4b782013-02-26 18:09:47 +0530130
Anand Doshi39384d32013-05-11 19:39:53 +0530131 self.round_floats_in(item)
Anand Doshi8595fcf2013-02-08 19:28:14 +0530132
Anand Doshib8b1e582013-05-06 12:52:46 +0530133 if item.discount_rate == 100:
134 item.import_ref_rate = item.import_ref_rate or item.import_rate
Anand Doshi8595fcf2013-02-08 19:28:14 +0530135 item.import_rate = 0
136 else:
137 if item.import_ref_rate:
Anand Doshib8b1e582013-05-06 12:52:46 +0530138 item.import_rate = flt(item.import_ref_rate * (1.0 - (item.discount_rate / 100.0)),
Anand Doshi39384d32013-05-11 19:39:53 +0530139 self.precision("import_rate", item))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530140 else:
Anand Doshib8b1e582013-05-06 12:52:46 +0530141 # assume that print rate and discount_rate are specified
142 item.import_ref_rate = flt(item.import_rate / (1.0 - (item.discount_rate / 100.0)),
Anand Doshi39384d32013-05-11 19:39:53 +0530143 self.precision("import_ref_rate", item))
Anand Doshia1d4b782013-02-26 18:09:47 +0530144
Anand Doshi8595fcf2013-02-08 19:28:14 +0530145 item.import_amount = flt(item.import_rate * item.qty,
Anand Doshi39384d32013-05-11 19:39:53 +0530146 self.precision("import_amount", item))
Anand Doshia1d4b782013-02-26 18:09:47 +0530147
Anand Doshi8595fcf2013-02-08 19:28:14 +0530148 _set_base(item, "import_ref_rate", "purchase_ref_rate")
149 _set_base(item, "import_rate", "rate")
150 _set_base(item, "import_amount", "amount")
Anand Doshi5af812a2013-05-10 19:23:02 +0530151
Anand Doshi8595fcf2013-02-08 19:28:14 +0530152 def initialize_taxes(self):
153 for tax in self.tax_doclist:
154 # initialize totals to 0
155 tax.tax_amount = tax.total = 0.0
156
157 # temporary fields
158 tax.tax_amount_for_current_item = tax.grand_total_for_current_item = 0.0
159
160 tax.item_wise_tax_detail = {}
161
162 self.validate_on_previous_row(tax)
163
Anand Doshi39384d32013-05-11 19:39:53 +0530164 self.round_floats_in(tax)
Anand Doshi8595fcf2013-02-08 19:28:14 +0530165
166 def calculate_net_total(self):
167 self.doc.net_total = 0
168 self.doc.net_total_import = 0
169
170 for item in self.item_doclist:
171 self.doc.net_total += item.amount
172 self.doc.net_total_import += item.import_amount
173
Anand Doshi5af812a2013-05-10 19:23:02 +0530174 self.doc.net_total = flt(self.doc.net_total, self.precision("net_total"))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530175 self.doc.net_total_import = flt(self.doc.net_total_import,
Anand Doshi5af812a2013-05-10 19:23:02 +0530176 self.precision("net_total_import"))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530177
178 def calculate_taxes(self):
179 for item in self.item_doclist:
180 item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
181 item.item_tax_amount = 0
182
183 for i, tax in enumerate(self.tax_doclist):
184 # tax_amount represents the amount of tax for the current step
185 current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map)
186
187 self.set_item_tax_amount(item, tax, current_tax_amount)
188
189 # case when net total is 0 but there is an actual type charge
190 # in this case add the actual amount to tax.tax_amount
191 # and tax.grand_total_for_current_item for the first such iteration
192 if not (current_tax_amount or self.doc.net_total or tax.tax_amount) and \
193 tax.charge_type=="Actual":
Anand Doshi39384d32013-05-11 19:39:53 +0530194 zero_net_total_adjustment = flt(tax.rate, self.precision("tax_amount", tax))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530195 current_tax_amount += zero_net_total_adjustment
196
197 # store tax_amount for current item as it will be used for
198 # charge type = 'On Previous Row Amount'
199 tax.tax_amount_for_current_item = current_tax_amount
200
201 # accumulate tax amount into tax.tax_amount
202 tax.tax_amount += tax.tax_amount_for_current_item
203
204 if tax.category == "Valuation":
205 # if just for valuation, do not add the tax amount in total
206 # hence, setting it as 0 for further steps
207 current_tax_amount = 0
208 else:
209 current_tax_amount *= tax.add_deduct_tax == "Deduct" and -1.0 or 1.0
210
211 # Calculate tax.total viz. grand total till that step
212 # note: grand_total_for_current_item contains the contribution of
213 # item's amount, previously applied tax and the current tax on that item
214 if i==0:
215 tax.grand_total_for_current_item = flt(item.amount +
Anand Doshi39384d32013-05-11 19:39:53 +0530216 current_tax_amount, self.precision("total", tax))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530217
218 else:
219 tax.grand_total_for_current_item = \
220 flt(self.tax_doclist[i-1].grand_total_for_current_item +
Anand Doshi39384d32013-05-11 19:39:53 +0530221 current_tax_amount, self.precision("total", tax))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530222
223 # in tax.total, accumulate grand total of each item
224 tax.total += tax.grand_total_for_current_item
225
226 # store tax_breakup for each item
227 # DOUBT: should valuation type amount also be stored?
228 tax.item_wise_tax_detail[item.item_code] = current_tax_amount
229
230 def calculate_totals(self):
231 if self.tax_doclist:
232 self.doc.grand_total = flt(self.tax_doclist[-1].total,
Anand Doshi5af812a2013-05-10 19:23:02 +0530233 self.precision("grand_total"))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530234 self.doc.grand_total_import = flt(
235 self.doc.grand_total / self.doc.conversion_rate,
Anand Doshi5af812a2013-05-10 19:23:02 +0530236 self.precision("grand_total_import"))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530237 else:
238 self.doc.grand_total = flt(self.doc.net_total,
Anand Doshi5af812a2013-05-10 19:23:02 +0530239 self.precision("grand_total"))
Anand Doshi4a7248e2013-02-27 18:10:30 +0530240 self.doc.grand_total_import = flt(
Anand Doshi8595fcf2013-02-08 19:28:14 +0530241 self.doc.grand_total / self.doc.conversion_rate,
Anand Doshi5af812a2013-05-10 19:23:02 +0530242 self.precision("grand_total_import"))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530243
244 self.doc.total_tax = \
245 flt(self.doc.grand_total - self.doc.net_total,
Anand Doshi5af812a2013-05-10 19:23:02 +0530246 self.precision("total_tax"))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530247
248 if self.meta.get_field("rounded_total"):
249 self.doc.rounded_total = round(self.doc.grand_total)
250
251 if self.meta.get_field("rounded_total_import"):
252 self.doc.rounded_total_import = round(self.doc.grand_total_import)
253
254 def calculate_outstanding_amount(self):
Anand Doshic99853c2013-05-14 13:35:09 +0530255 if self.doc.doctype == "Purchase Invoice" and self.doc.docstatus < 2:
Anand Doshi8595fcf2013-02-08 19:28:14 +0530256 self.doc.total_advance = flt(self.doc.total_advance,
Anand Doshi5af812a2013-05-10 19:23:02 +0530257 self.precision("total_advance"))
Anand Doshi9d794fc2013-02-27 13:34:22 +0530258 self.doc.total_amount_to_pay = flt(self.doc.grand_total - flt(self.doc.write_off_amount,
Anand Doshi5af812a2013-05-10 19:23:02 +0530259 self.precision("write_off_amount")), self.precision("total_amount_to_pay"))
Anand Doshi9d794fc2013-02-27 13:34:22 +0530260 self.doc.outstanding_amount = flt(self.doc.total_amount_to_pay - self.doc.total_advance,
Anand Doshi5af812a2013-05-10 19:23:02 +0530261 self.precision("outstanding_amount"))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530262
263 def _cleanup(self):
264 for tax in self.tax_doclist:
265 del tax.fields["grand_total_for_current_item"]
266 del tax.fields["tax_amount_for_current_item"]
267 tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail)
268
269 # except in purchase invoice, rate field is purchase_rate
270 if self.doc.doctype != "Purchase Invoice":
271 for item in self.item_doclist:
272 item.purchase_rate = item.rate
273 del item.fields["rate"]
Anand Doshia1d4b782013-02-26 18:09:47 +0530274
Anand Doshi5af812a2013-05-10 19:23:02 +0530275 # reset fieldname of rate
276 if self.doc.doctype != "Purchase Invoice":
277 df = self.meta.get_field("rate", parentfield=self.fname)
278 df.fieldname = "purchase_rate"
279
Anand Doshi8595fcf2013-02-08 19:28:14 +0530280 def validate_on_previous_row(self, tax):
281 """
282 validate if a valid row id is mentioned in case of
283 On Previous Row Amount and On Previous Row Total
284 """
285 if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"] and \
286 (not tax.row_id or cint(tax.row_id) >= tax.idx):
287 msgprint((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \
288 _("Please specify a valid") + " %(row_id_label)s") % {
289 "idx": tax.idx,
290 "taxes_doctype": tax.parenttype,
291 "row_id_label": self.meta.get_label("row_id",
292 parentfield="purchase_tax_details")
293 }, raise_exception=True)
294
295 def _load_item_tax_rate(self, item_tax_rate):
296 if not item_tax_rate:
297 return {}
298 return json.loads(item_tax_rate)
299
300 def get_current_tax_amount(self, item, tax, item_tax_map):
301 tax_rate = self._get_tax_rate(tax, item_tax_map)
302
303 if tax.charge_type == "Actual":
304 # distribute the tax amount proportionally to each item row
Anand Doshi39384d32013-05-11 19:39:53 +0530305 actual = flt(tax.rate, self.precision("tax_amount", tax))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530306 current_tax_amount = (self.doc.net_total
307 and ((item.amount / self.doc.net_total) * actual)
308 or 0)
309 elif tax.charge_type == "On Net Total":
310 current_tax_amount = (tax_rate / 100.0) * item.amount
311 elif tax.charge_type == "On Previous Row Amount":
312 current_tax_amount = (tax_rate / 100.0) * \
313 self.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item
314 elif tax.charge_type == "On Previous Row Total":
315 current_tax_amount = (tax_rate / 100.0) * \
316 self.tax_doclist[cint(tax.row_id) - 1].grand_total_for_current_item
317
Anand Doshi39384d32013-05-11 19:39:53 +0530318 return flt(current_tax_amount, self.precision("tax_amount", tax))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530319
320 def _get_tax_rate(self, tax, item_tax_map):
321 if item_tax_map.has_key(tax.account_head):
Anand Doshi39384d32013-05-11 19:39:53 +0530322 return flt(item_tax_map.get(tax.account_head), self.precision("rate", tax))
Anand Doshi8595fcf2013-02-08 19:28:14 +0530323 else:
324 return tax.rate
325
326 def set_item_tax_amount(self, item, tax, current_tax_amount):
327 """
328 item_tax_amount is the total tax amount applied on that item
329 stored for valuation
330
331 TODO: rename item_tax_amount to valuation_tax_amount
332 """
333 if tax.category in ["Valuation", "Valuation and Total"] and \
334 item.item_code in self.stock_items:
335 item.item_tax_amount += flt(current_tax_amount,
Anand Doshi39384d32013-05-11 19:39:53 +0530336 self.precision("item_tax_amount", item))
Anand Doshi4a7248e2013-02-27 18:10:30 +0530337
338 # update valuation rate
339 def update_valuation_rate(self, parentfield):
Anand Doshi5af812a2013-05-10 19:23:02 +0530340 for item in self.doclist.get({"parentfield": parentfield}):
341 item.conversion_factor = item.conversion_factor or flt(webnotes.conn.get_value(
342 "UOM Conversion Detail", {"parent": item.item_code, "uom": item.uom},
Nabin Hait0fc24542013-03-25 11:06:00 +0530343 "conversion_factor")) or 1
Anand Doshi39384d32013-05-11 19:39:53 +0530344
Anand Doshi5af812a2013-05-10 19:23:02 +0530345 if item.item_code and item.qty:
Anand Doshi39384d32013-05-11 19:39:53 +0530346 self.round_floats_in(item)
347
348 purchase_rate = item.rate if self.doc.doctype == "Purchase Invoice" else item.purchase_rate
349
Anand Doshi1bfec3a2013-02-28 19:17:46 +0530350 # if no item code, which is sometimes the case in purchase invoice,
351 # then it is not possible to track valuation against it
Anand Doshi39384d32013-05-11 19:39:53 +0530352 item.valuation_rate = flt((purchase_rate +
353 (item.item_tax_amount + item.rm_supp_cost) / item.qty) / item.conversion_factor,
354 self.precision("valuation_rate", item))
Anand Doshi4a7248e2013-02-27 18:10:30 +0530355 else:
Anand Doshi5af812a2013-05-10 19:23:02 +0530356 item.valuation_rate = 0.0
Nabin Hait54d209f2013-03-01 18:51:10 +0530357
358 def validate_for_subcontracting(self):
359 if not self.doc.is_subcontracted and self.sub_contracted_items:
360 webnotes.msgprint(_("""Please enter whether %s is made for subcontracting or purchasing,
361 in 'Is Subcontracted' field""" % self.doc.doctype), raise_exception=1)
362
363 if self.doc.doctype == "Purchase Receipt" and self.doc.is_subcontracted=="Yes" \
364 and not self.doc.supplier_warehouse:
365 webnotes.msgprint(_("Supplier Warehouse mandatory subcontracted purchase receipt"),
366 raise_exception=1)
367
368 def update_raw_materials_supplied(self, raw_material_table):
369 self.doclist = self.doc.clear_table(self.doclist, raw_material_table)
370 if self.doc.is_subcontracted=="Yes":
371 for item in self.doclist.get({"parentfield": self.fname}):
372 if item.item_code in self.sub_contracted_items:
373 self.add_bom_items(item, raw_material_table)
374
375 def add_bom_items(self, d, raw_material_table):
376 bom_items = self.get_items_from_default_bom(d.item_code)
377 raw_materials_cost = 0
378 for item in bom_items:
379 required_qty = flt(item.qty_consumed_per_unit) * flt(d.qty) * flt(d.conversion_factor)
380 rm_doclist = {
381 "parentfield": raw_material_table,
382 "doctype": self.doc.doctype + " Item Supplied",
383 "reference_name": d.name,
384 "bom_detail_no": item.name,
385 "main_item_code": d.item_code,
386 "rm_item_code": item.item_code,
387 "stock_uom": item.stock_uom,
388 "required_qty": required_qty,
389 "conversion_factor": d.conversion_factor,
390 "rate": item.rate,
391 "amount": required_qty * flt(item.rate)
392 }
393 if self.doc.doctype == "Purchase Receipt":
394 rm_doclist.update({
395 "consumed_qty": required_qty,
396 "description": item.description,
397 })
398
399 self.doclist.append(rm_doclist)
400
401 raw_materials_cost += required_qty * flt(item.rate)
402
403 if self.doc.doctype == "Purchase Receipt":
404 d.rm_supp_cost = raw_materials_cost
405
406 def get_items_from_default_bom(self, item_code):
407 # print webnotes.conn.sql("""select name from `tabBOM` where item = '_Test FG Item'""")
408 bom_items = webnotes.conn.sql("""select t2.item_code, t2.qty_consumed_per_unit,
409 t2.rate, t2.stock_uom, t2.name, t2.description
410 from `tabBOM` t1, `tabBOM Item` t2
411 where t2.parent = t1.name and t1.item = %s and t1.is_default = 1
412 and t1.docstatus = 1 and t1.is_active = 1""", item_code, as_dict=1)
413 if not bom_items:
414 msgprint(_("No default BOM exists for item: ") + item_code, raise_exception=1)
415
416 return bom_items
417
Nabin Hait5418d712013-02-27 18:11:17 +0530418 @property
419 def sub_contracted_items(self):
420 if not hasattr(self, "_sub_contracted_items"):
Nabin Haitebd51442013-04-23 15:36:26 +0530421 self._sub_contracted_items = []
Nabin Hait5418d712013-02-27 18:11:17 +0530422 item_codes = list(set(item.item_code for item in
423 self.doclist.get({"parentfield": self.fname})))
Nabin Haitebd51442013-04-23 15:36:26 +0530424 if item_codes:
425 self._sub_contracted_items = [r[0] for r in webnotes.conn.sql("""select name
426 from `tabItem` where name in (%s) and is_sub_contracted_item='Yes'""" % \
427 (", ".join((["%s"]*len(item_codes))),), item_codes)]
Nabin Hait5418d712013-02-27 18:11:17 +0530428
429 return self._sub_contracted_items
430
431 @property
432 def purchase_items(self):
433 if not hasattr(self, "_purchase_items"):
Nabin Haitebd51442013-04-23 15:36:26 +0530434 self._purchase_items = []
Nabin Hait5418d712013-02-27 18:11:17 +0530435 item_codes = list(set(item.item_code for item in
436 self.doclist.get({"parentfield": self.fname})))
Nabin Haitebd51442013-04-23 15:36:26 +0530437 if item_codes:
438 self._purchase_items = [r[0] for r in webnotes.conn.sql("""select name
439 from `tabItem` where name in (%s) and is_purchase_item='Yes'""" % \
440 (", ".join((["%s"]*len(item_codes))),), item_codes)]
Nabin Hait5418d712013-02-27 18:11:17 +0530441
Anand Doshi55d9a622013-02-27 18:14:28 +0530442 return self._purchase_items