blob: ac06b2e168155eacbc45b01d44eaca82033dca88 [file] [log] [blame]
Nabin Hait0feebc12013-06-03 16:45:38 +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
19from webnotes.utils import flt, cstr
20from webnotes import msgprint
21
22from webnotes.model.controller import DocListController
23
24class StatusUpdater(DocListController):
25 """
26 Updates the status of the calling records
27 Delivery Note: Update Delivered Qty, Update Percent and Validate over delivery
28 Sales Invoice: Update Billed Amt, Update Percent and Validate over billing
29 Installation Note: Update Installed Qty, Update Percent Qty and Validate over installation
30 """
31
32 def update_prevdoc_status(self):
33 self.update_qty()
34 self.validate_qty()
35
36 def validate_qty(self):
37 """
38 Validates qty at row level
39 """
40 self.tolerance = {}
41 self.global_tolerance = None
42
43 for args in self.status_updater:
44 # get unique transactions to update
45 for d in self.doclist:
46 if d.doctype == args['source_dt'] and d.fields.get(args["join_field"]):
47 args['name'] = d.fields[args['join_field']]
48
49 # get all qty where qty > target_field
50 item = webnotes.conn.sql("""select item_code, `%(target_ref_field)s`,
51 `%(target_field)s`, parenttype, parent from `tab%(target_dt)s`
52 where `%(target_ref_field)s` < `%(target_field)s`
53 and name="%(name)s" and docstatus=1""" % args, as_dict=1)
54 if item:
55 item = item[0]
56 item['idx'] = d.idx
57 item['target_ref_field'] = args['target_ref_field'].replace('_', ' ')
58
59 if not item[args['target_ref_field']]:
60 msgprint("""As %(target_ref_field)s for item: %(item_code)s in \
61 %(parenttype)s: %(parent)s is zero, system will not check \
62 over-delivery or over-billed""" % item)
63 elif args.get('no_tolerance'):
64 item['reduce_by'] = item[args['target_field']] - \
65 item[args['target_ref_field']]
66 if item['reduce_by'] > .01:
67 msgprint("""
68 Row #%(idx)s: Max %(target_ref_field)s allowed for <b>Item \
69 %(item_code)s</b> against <b>%(parenttype)s %(parent)s</b> \
70 is <b>""" % item + cstr(item[args['target_ref_field']]) +
71 """</b>.<br>You must reduce the %(target_ref_field)s by \
72 %(reduce_by)s""" % item, raise_exception=1)
73
74 else:
75 self.check_overflow_with_tolerance(item, args)
76
77 def check_overflow_with_tolerance(self, item, args):
78 """
79 Checks if there is overflow condering a relaxation tolerance
80 """
81
82 # check if overflow is within tolerance
83 tolerance = self.get_tolerance_for(item['item_code'])
84 overflow_percent = ((item[args['target_field']] - item[args['target_ref_field']]) /
85 item[args['target_ref_field']]) * 100
86
87 if overflow_percent - tolerance > 0.01:
88 item['max_allowed'] = flt(item[args['target_ref_field']] * (100+tolerance)/100)
89 item['reduce_by'] = item[args['target_field']] - item['max_allowed']
90
91 msgprint("""
92 Row #%(idx)s: Max %(target_ref_field)s allowed for <b>Item %(item_code)s</b> \
93 against <b>%(parenttype)s %(parent)s</b> is <b>%(max_allowed)s</b>.
94
95 If you want to increase your overflow tolerance, please increase tolerance %% in \
96 Global Defaults or Item master.
97
98 Or, you must reduce the %(target_ref_field)s by %(reduce_by)s
99
100 Also, please check if the order item has already been billed in the Sales Order""" %
101 item, raise_exception=1)
102
103 def get_tolerance_for(self, item_code):
104 """
105 Returns the tolerance for the item, if not set, returns global tolerance
106 """
107 if self.tolerance.get(item_code): return self.tolerance[item_code]
108
109 tolerance = flt(webnotes.conn.get_value('Item',item_code,'tolerance') or 0)
110
111 if not tolerance:
112 if self.global_tolerance == None:
113 self.global_tolerance = flt(webnotes.conn.get_value('Global Defaults', None,
114 'tolerance'))
115 tolerance = self.global_tolerance
116
117 self.tolerance[item_code] = tolerance
118 return tolerance
119
120
121 def update_qty(self, change_modified=True):
122 """
123 Updates qty at row level
124 """
125 for args in self.status_updater:
126 # condition to include current record (if submit or no if cancel)
127 if self.doc.docstatus == 1:
128 args['cond'] = ' or parent="%s"' % self.doc.name
129 else:
130 args['cond'] = ' and parent!="%s"' % self.doc.name
131
132 args['modified_cond'] = ''
133 if change_modified:
134 args['modified_cond'] = ', modified = now()'
135
136 # update quantities in child table
137 for d in self.doclist:
138 if d.doctype == args['source_dt']:
139 # updates qty in the child table
140 args['detail_id'] = d.fields.get(args['join_field'])
141
142 args['second_source_condition'] = ""
143 if args.get('second_source_dt') and args.get('second_source_field') \
144 and args.get('second_join_field'):
145 args['second_source_condition'] = """ + (select sum(%(second_source_field)s)
146 from `tab%(second_source_dt)s`
147 where `%(second_join_field)s`="%(detail_id)s"
148 and (docstatus=1))""" % args
149
150 if args['detail_id']:
151 webnotes.conn.sql("""update `tab%(target_dt)s`
152 set %(target_field)s = (select sum(%(source_field)s)
153 from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s"
154 and (docstatus=1 %(cond)s)) %(second_source_condition)s
155 where name='%(detail_id)s'""" % args)
156
157 # get unique transactions to update
158 for name in set([d.fields.get(args['percent_join_field']) for d in self.doclist
159 if d.doctype == args['source_dt']]):
160 if name:
161 args['name'] = name
162
163 # update percent complete in the parent table
164 webnotes.conn.sql("""update `tab%(target_parent_dt)s`
165 set %(target_parent_field)s = (select sum(if(%(target_ref_field)s >
166 ifnull(%(target_field)s, 0), %(target_field)s,
167 %(target_ref_field)s))/sum(%(target_ref_field)s)*100
168 from `tab%(target_dt)s` where parent="%(name)s") %(modified_cond)s
169 where name='%(name)s'""" % args)
170
171 # update field
172 if args.get('status_field'):
173 webnotes.conn.sql("""update `tab%(target_parent_dt)s`
174 set %(status_field)s = if(ifnull(%(target_parent_field)s,0)<0.001,
175 'Not %(keyword)s', if(%(target_parent_field)s>=99.99,
176 'Fully %(keyword)s', 'Partly %(keyword)s'))
177 where name='%(name)s'""" % args)