Merge lp:~npg-team/openobject-addons/account_cash_discount_us_npg into lp:openobject-addons
- account_cash_discount_us_npg
- Merge into trunk
Proposed by
Novapoint Group
Status: | Rejected |
---|---|
Rejected by: | Fabien (Open ERP) |
Proposed branch: | lp:~npg-team/openobject-addons/account_cash_discount_us_npg |
Merge into: | lp:openobject-addons |
Diff against target: |
3188 lines (+3073/-0) 21 files modified
account_cash_discount_us/Change Log.txt (+53/-0) account_cash_discount_us/__init__.py (+26/-0) account_cash_discount_us/__openerp__.py (+54/-0) account_cash_discount_us/__terp__.py (+52/-0) account_cash_discount_us/account_cash_discount.py (+941/-0) account_cash_discount_us/account_cash_discount_us/Change Log.txt (+31/-0) account_cash_discount_us/account_cash_discount_us/__init__.py (+26/-0) account_cash_discount_us/account_cash_discount_us/__openerp__.py (+54/-0) account_cash_discount_us/account_cash_discount_us/__terp__.py (+52/-0) account_cash_discount_us/account_cash_discount_us/account_cash_discount.py (+730/-0) account_cash_discount_us/account_cash_discount_us/account_cash_discount_view.xml (+256/-0) account_cash_discount_us/account_cash_discount_us/i18n/account_cash_discount.pot (+85/-0) account_cash_discount_us/account_cash_discount_us/i18n/fr_BE.po (+85/-0) account_cash_discount_us/account_cash_discount_us/product_view.xml (+19/-0) account_cash_discount_us/account_cash_discount_us/security/ir.model.access.csv (+7/-0) account_cash_discount_us/account_cash_discount_view.xml (+329/-0) account_cash_discount_us/amount_to_words.py (+77/-0) account_cash_discount_us/i18n/account_cash_discount.pot (+85/-0) account_cash_discount_us/i18n/fr_BE.po (+85/-0) account_cash_discount_us/product_view.xml (+19/-0) account_cash_discount_us/security/ir.model.access.csv (+7/-0) |
To merge this branch: | bzr merge lp:~npg-team/openobject-addons/account_cash_discount_us_npg |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenERP Core Team | Pending | ||
Review via email: mp+78430@code.launchpad.net |
Commit message
Description of the change
NovaPoint Group has developed this module to provide the ability to process cash discounts paid on invoices. This works in conjunction with account_
To post a comment you must log in.
Unmerged revisions
- 5304. By Novapoint Group
-
[Add]: account_
cash_discount_ us module to provide cash discounts on invoices
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'account_cash_discount_us' |
2 | === added file 'account_cash_discount_us/Change Log.txt' |
3 | --- account_cash_discount_us/Change Log.txt 1970-01-01 00:00:00 +0000 |
4 | +++ account_cash_discount_us/Change Log.txt 2011-10-06 15:23:28 +0000 |
5 | @@ -0,0 +1,53 @@ |
6 | +=============================================================================== |
7 | + Version Change Log (account_cash_discount_us) |
8 | +=============================================================================== |
9 | +1.15 (2011-09-16) -> Janeesh |
10 | + * Added the onchange on amount in Pay Invoice |
11 | + |
12 | +1.14 (2011-09-16) -> Arif |
13 | + * Removed the onchange on amount in Pay Invoice |
14 | + |
15 | +1.13 (2011-09-15) -> Sinoj & Arif |
16 | + * Fixed the bug on calculation of discount on Pay Invoice |
17 | + |
18 | +1.12 (2011-07-18) By Arif |
19 | + * Added discount field in (Task ID: 362) in supplier payment |
20 | + |
21 | +1.10 -> 1.11 (2011-04-14) By Jabir |
22 | + * Update the payment amount when discount is selected and clicked on recalculate button |
23 | + |
24 | + |
25 | +1.08 -> 1.09 (2011-04-14) By Jabir |
26 | + * Add calculate button on Supplier Payment |
27 | + |
28 | +1.08 -> 1.09 (2011-04-08) By Jabir |
29 | + * Supplier discount |
30 | + |
31 | +1.07 -> 1.08 (2011-02-04) By Sinoj |
32 | + * Optimization and cleanup |
33 | + |
34 | + |
35 | +1.06 -> 1.07 (2010-12-06) By jabir |
36 | + * Removed discount wizard and changed domain filtering |
37 | + |
38 | +1.05 -> 1.06 (2010-12-06) By jabir |
39 | + * Take invoice partner instead of moveline partner |
40 | + |
41 | + 1.04 -> 1.05 (2010-11-29) By Jabir |
42 | + * Fix placement of Cash Discount Separation Line |
43 | + |
44 | + 1.03 -> 1.04 (2010-11-29) By Sinoj |
45 | + * Account posting updated for National account |
46 | + |
47 | + 1.02 -> 1.03 (2010-11-09) By Sinoj |
48 | + * "Debit and Credits" wizard button moved to voucher line |
49 | + * fields on wizard form are readonly |
50 | + * fields on wizard are populated with default values |
51 | + * removed |
52 | + |
53 | + 1.01 -> 1.02 (2010-11-04) By jabir |
54 | + * Add wizard Discount and Credits |
55 | + * Create button Discount and Credits in customer payment form |
56 | + |
57 | + 1.0 -> 1.01 (2010-11-04) By sinoj |
58 | + * dependency changed from account_voucher_jdc to account_voucher_credits_us |
59 | \ No newline at end of file |
60 | |
61 | === added file 'account_cash_discount_us/__init__.py' |
62 | --- account_cash_discount_us/__init__.py 1970-01-01 00:00:00 +0000 |
63 | +++ account_cash_discount_us/__init__.py 2011-10-06 15:23:28 +0000 |
64 | @@ -0,0 +1,26 @@ |
65 | +# -*- coding: utf-8 -*- |
66 | +############################################################################## |
67 | +# |
68 | +# OpenERP, Open Source Management Solution |
69 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
70 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
71 | +# |
72 | +# This program is free software: you can redistribute it and/or modify |
73 | +# it under the terms of the GNU General Public License as published by |
74 | +# the Free Software Foundation, either version 3 of the License, or |
75 | +# (at your option) any later version. |
76 | +# |
77 | +# This program is distributed in the hope that it will be useful, |
78 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
79 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
80 | +# GNU General Public License for more details. |
81 | +# |
82 | +# You should have received a copy of the GNU General Public License |
83 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
84 | +# |
85 | +############################################################################## |
86 | + |
87 | + |
88 | +import account_cash_discount |
89 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
90 | + |
91 | |
92 | === added file 'account_cash_discount_us/__openerp__.py' |
93 | --- account_cash_discount_us/__openerp__.py 1970-01-01 00:00:00 +0000 |
94 | +++ account_cash_discount_us/__openerp__.py 2011-10-06 15:23:28 +0000 |
95 | @@ -0,0 +1,54 @@ |
96 | +# -*- coding: utf-8 -*- |
97 | +############################################################################## |
98 | +# |
99 | +# OpenERP, Open Source Management Solution |
100 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
101 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
102 | +# |
103 | +# This program is free software: you can redistribute it and/or modify |
104 | +# it under the terms of the GNU General Public License as published by |
105 | +# the Free Software Foundation, either version 3 of the License, or |
106 | +# (at your option) any later version. |
107 | +# |
108 | +# This program is distributed in the hope that it will be useful, |
109 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
110 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
111 | +# GNU General Public License for more details. |
112 | +# |
113 | +# You should have received a copy of the GNU General Public License |
114 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
115 | +# |
116 | +############################################################################## |
117 | + |
118 | + |
119 | +{ |
120 | + "name" : "Payment Term with Cash Discount", |
121 | + "version" : "1.15", |
122 | + "depends" : ["account","account_voucher_credits_us","account_cash_discount"], |
123 | + "author" : "NovaPoint Group LLC", |
124 | + "description" : "Cash discounts, based on payment terms", |
125 | + "website" : "http://www.novapointgroup.com/", |
126 | + "category" : "Generic Modules/Accounting", |
127 | + "description": """ |
128 | + This module adds cash discounts on payment terms. Cash discounts |
129 | + for a payment term can be configured with: |
130 | + * A number of days, |
131 | + * A discount (%), |
132 | + * A debit and a credit account |
133 | + * Sales and Purchase discounts are added to product and invoice line |
134 | + """, |
135 | + "init_xml" : [ |
136 | + ], |
137 | + "demo_xml" : [ |
138 | + ], |
139 | + "update_xml" : [ |
140 | + "account_cash_discount_view.xml", |
141 | + "product_view.xml", |
142 | + "security/ir.model.access.csv", |
143 | + ], |
144 | + "active": False, |
145 | + "installable": True, |
146 | + |
147 | +} |
148 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
149 | + |
150 | |
151 | === added file 'account_cash_discount_us/__terp__.py' |
152 | --- account_cash_discount_us/__terp__.py 1970-01-01 00:00:00 +0000 |
153 | +++ account_cash_discount_us/__terp__.py 2011-10-06 15:23:28 +0000 |
154 | @@ -0,0 +1,52 @@ |
155 | +# -*- encoding: utf-8 -*- |
156 | +############################################################################## |
157 | +# |
158 | +# OpenERP, Open Source Management Solution |
159 | +# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). |
160 | +# |
161 | +# This program is free software: you can redistribute it and/or modify |
162 | +# it under the terms of the GNU Affero General Public License as |
163 | +# published by the Free Software Foundation, either version 3 of the |
164 | +# License, or (at your option) any later version. |
165 | +# |
166 | +# This program is distributed in the hope that it will be useful, |
167 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
168 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
169 | +# GNU Affero General Public License for more details. |
170 | +# |
171 | +# You should have received a copy of the GNU Affero General Public License |
172 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
173 | +# |
174 | +############################################################################## |
175 | + |
176 | +{ |
177 | + "name" : "Payment Term with Cash Discount", |
178 | + "version" : "1.07", |
179 | + "depends" : ["account","account_voucher_credits_us","account_cash_discount"], |
180 | + "author" : "Tiny and NovaPoint Group LLC", |
181 | + "description" : "Cash discounts, based on payment terms", |
182 | + "website" : "http://www.novapointgroup.com/", |
183 | + "category" : "Generic Modules/Accounting", |
184 | + "description": """ |
185 | + This module adds cash discounts on payment terms. Cash discounts |
186 | + for a payment term can be configured with: |
187 | + * A number of days, |
188 | + * A discount (%), |
189 | + * A debit and a credit account |
190 | + * Sales and Purchase discounts are added to product and invoice line |
191 | + """, |
192 | + "init_xml" : [ |
193 | + ], |
194 | + "demo_xml" : [ |
195 | + ], |
196 | + "update_xml" : [ |
197 | + "account_cash_discount_view.xml", |
198 | + "product_view.xml", |
199 | + "security/ir.model.access.csv", |
200 | + ], |
201 | + "active": False, |
202 | + "installable": True, |
203 | + |
204 | +} |
205 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
206 | + |
207 | |
208 | === added file 'account_cash_discount_us/account_cash_discount.py' |
209 | --- account_cash_discount_us/account_cash_discount.py 1970-01-01 00:00:00 +0000 |
210 | +++ account_cash_discount_us/account_cash_discount.py 2011-10-06 15:23:28 +0000 |
211 | @@ -0,0 +1,941 @@ |
212 | +# -*- coding: utf-8 -*- |
213 | +############################################################################## |
214 | +# |
215 | +# OpenERP, Open Source Management Solution |
216 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
217 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
218 | +# |
219 | +# This program is free software: you can redistribute it and/or modify |
220 | +# it under the terms of the GNU General Public License as published by |
221 | +# the Free Software Foundation, either version 3 of the License, or |
222 | +# (at your option) any later version. |
223 | +# |
224 | +# This program is distributed in the hope that it will be useful, |
225 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
226 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
227 | +# GNU General Public License for more details. |
228 | +# |
229 | +# You should have received a copy of the GNU General Public License |
230 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
231 | +# |
232 | +############################################################################## |
233 | + |
234 | +from collections import defaultdict |
235 | +from mx.DateTime import RelativeDateTime |
236 | +from osv import fields, osv |
237 | +from tools.translate import _ |
238 | +import decimal_precision as dp |
239 | +import mx.DateTime |
240 | +from amount_to_words import amount_to_words |
241 | +from tools.amount_to_text_en import amount_to_text |
242 | + |
243 | +def _combinations(iterable, r): |
244 | + ''' |
245 | + @return: combination generator object |
246 | + |
247 | + Example |
248 | + combinations(’ABCD’, 2) --> AB AC AD BC BD CD |
249 | + combinations(range(4), 3) --> 012 013 023 123 |
250 | + ''' |
251 | + pool = tuple(iterable) |
252 | + n = len(pool) |
253 | + if r > n: |
254 | + return |
255 | + indices = range(r) |
256 | + yield tuple(pool[i] for i in indices) |
257 | + while True: |
258 | + for i in reversed(range(r)): |
259 | + if indices[i] != i + n - r: |
260 | + break |
261 | + else: |
262 | + return |
263 | + indices[i] += 1 |
264 | + for j in range(i+1, r): |
265 | + indices[j] = indices[j-1] + 1 |
266 | + yield tuple(pool[i] for i in indices) |
267 | + |
268 | + |
269 | +class account_payment_term(osv.osv): |
270 | + _name = "account.payment.term" |
271 | + _inherit = "account.payment.term" |
272 | + _columns = { |
273 | + 'cash_discount_ids': fields.one2many('account.cash.discount', 'payment_id', 'Cash Discounts'), |
274 | + } |
275 | + def get_discounts(self, cr, uid, id, base_date, context={}): |
276 | + """ |
277 | + return the list of (date,percentage) ordered by date for the |
278 | + payment term with the corresponding id. return [] if no cash |
279 | + discount are defined. base_date is the date from where the |
280 | + discounts are computed. |
281 | + """ |
282 | + res=[] |
283 | + for pt in self.browse(cr, uid, id, context): |
284 | + |
285 | + if not pt.cash_discount_ids: |
286 | + continue |
287 | + |
288 | + for d in pt.cash_discount_ids: |
289 | + res.append( |
290 | + ((mx.DateTime.strptime(base_date,'%Y-%m-%d') +\ |
291 | + RelativeDateTime(days=d.delay)).strftime("%Y-%m-%d"), |
292 | + d.discount) |
293 | + ) |
294 | + |
295 | + res.sort(cmp=lambda x,y: cmp(x[0],y[0])) |
296 | + return res |
297 | +account_payment_term() |
298 | + |
299 | +class account_invoice(osv.osv): |
300 | + ''' |
301 | + Add discount calculation to invoice |
302 | + ''' |
303 | + _inherit = 'account.invoice' |
304 | + |
305 | + def _get_discount(self, cr, uid, ids, field_name, args, context={}): |
306 | + ''' |
307 | + Calculate the value of variable date_discount (Discount Date) and amount_discounted (Discounted Total) |
308 | + ''' |
309 | + |
310 | + if context is None: |
311 | + context = {} |
312 | + for invoice in self.browse(cr, uid, ids, context): |
313 | + res = defaultdict(list) |
314 | + res[invoice.id] = { |
315 | + 'date_discount': invoice.date_due, |
316 | + 'amount_discounted': invoice.amount_total |
317 | + } |
318 | + if not invoice.date_invoice: |
319 | + invoice_date = mx.DateTime.today().strftime("%Y-%m-%d") |
320 | + self.write(cr, uid, [invoice.id], {'date_invoice': invoice_date}, context) |
321 | + else: |
322 | + invoice_date = invoice.date_invoice |
323 | + discounts = invoice.payment_term and invoice.payment_term.get_discounts(invoice_date, context=context) |
324 | + if discounts: |
325 | + line_obj = self.pool.get('account.invoice.line') |
326 | + discount_total = 0.0 |
327 | + non_discount_total = 0.0 |
328 | + for line in invoice.invoice_line: |
329 | + if line.cash_discount: |
330 | + discount_total += line.price_subtotal |
331 | + line_cash_discount = round((1.0 - discounts[0][1]) * line.price_subtotal) |
332 | + line_obj.write(cr, uid, line.id, {'cash_discount': line_cash_discount}, context) |
333 | + else: |
334 | + non_discount_total += line.price_subtotal |
335 | + line_obj.write(cr, uid, line.id, {'cash_discount': 0.0}, context) |
336 | + # assume taxes are never discountable |
337 | + non_discount_total += invoice.amount_tax |
338 | + # There may be more than one - return the earliest |
339 | + res[invoice.id] = { |
340 | + 'date_discount': discounts[0][0], |
341 | + 'amount_discounted': round(((1.0 - discounts[0][1]) * discount_total) + non_discount_total,2) |
342 | + } |
343 | + return defaultdict(type([]),res) |
344 | + |
345 | + _columns = { |
346 | + 'date_discount': fields.function(_get_discount, method=True, type='date', string='Discount Date', multi='all'), |
347 | + 'amount_discounted': fields.function(_get_discount, method=True, type='float', digits_compute=dp.get_precision('Account'), string='Discounted Total', |
348 | + multi='all'), |
349 | + } |
350 | +account_invoice() |
351 | + |
352 | +class account_invoice_pay_writeoff(osv.osv_memory): |
353 | + """ |
354 | + Opens the write off amount pay form. |
355 | + """ |
356 | + _name = "account.invoice.pay.writeoff" |
357 | + _description = "Pay Invoice " |
358 | + _columns = { |
359 | + 'writeoff_acc_id': fields.many2one('account.account', 'Write-Off account', required=True), |
360 | + 'writeoff_journal_id': fields.many2one('account.journal', 'Write-Off journal', required=True), |
361 | + 'comment': fields.char('Comment', size=64, required=True), |
362 | + 'analytic_id': fields.many2one('account.analytic.account','Analytic Account'), |
363 | + } |
364 | + _defaults = { |
365 | + 'comment': 'Write-Off', |
366 | + } |
367 | + |
368 | +account_invoice_pay_writeoff() |
369 | + |
370 | +class account_invoice_pay(osv.osv_memory): |
371 | + """ |
372 | + Generate pay invoice wizard, user can make partial or full payment for invoice. |
373 | + """ |
374 | + _name = "account.invoice.pay" |
375 | + _description = "Pay Invoice " |
376 | + _columns = { |
377 | + 'amount': fields.float('Amount paid', required=True, digits_compute = dp.get_precision('Account')), |
378 | + 'name': fields.char('Entry Name', size=64, required=True), |
379 | + 'date': fields.date('Date payment', required=True), |
380 | + 'journal_id': fields.many2one('account.journal', 'Journal/Payment Mode', required=True, domain=[('type','=','cash')]), |
381 | + 'period_id': fields.many2one('account.period', 'Period', required=True), |
382 | + } |
383 | + |
384 | + def view_init(self, cr, uid, ids, context=None): |
385 | + invoice = self.pool.get('account.invoice').browse(cr, uid, context['active_id'], context=context) |
386 | + if invoice.state in ['draft', 'proforma2', 'cancel']: |
387 | + raise osv.except_osv(_('Error !'), _('Can not pay draft/proforma/cancel invoice.')) |
388 | + pass |
389 | + |
390 | + def _get_period(self, cr, uid, context=None): |
391 | + ''' |
392 | + Initialise Period |
393 | + ''' |
394 | + ids = self.pool.get('account.period').find(cr, uid, context=context) |
395 | + period_id = False |
396 | + if len(ids): |
397 | + period_id = ids[0] |
398 | + return period_id |
399 | + |
400 | + def _get_amount(self, cr, uid, context=None): |
401 | + ''' |
402 | + Get default value of Amount paid |
403 | + ''' |
404 | + return self.pool.get('account.invoice').browse(cr, uid, context['active_id'], context=context).residual |
405 | + |
406 | + _defaults = { |
407 | + 'date': lambda *a: time.strftime('%Y-%m-%d'), |
408 | + 'period_id': _get_period, |
409 | + 'amount': _get_amount, |
410 | + } |
411 | +account_invoice_pay() |
412 | + |
413 | +class account_voucher(osv.osv): |
414 | + _name = 'account.voucher' |
415 | + _inherit = 'account.voucher' |
416 | + def calc_supp_diff(self, cr, uid, ids, context={}): |
417 | + ''' |
418 | + Called by calculate/re-calculate action. |
419 | + This method will update the credit lines on voucher lines. |
420 | + If the field "auto_match" marked, this method will run a matching routine |
421 | + ''' |
422 | + res = {'nodestroy':True} |
423 | + amount_cash_discount = 0.0 |
424 | + amount_interest = 0.0 |
425 | + |
426 | + for vch in self.browse(cr, uid, ids): |
427 | + for line in vch.line_dr_ids: |
428 | + ''' |
429 | + Update the credit lines and discount lines so that matching routine can use the latest available credits and discounts |
430 | + ''' |
431 | +# line._update_debit_lines( context=context) |
432 | + line._update_supp_discount_lines(context=context) |
433 | + |
434 | +# if vch.auto_match: |
435 | +# ''' |
436 | +# Try the matching routine including the manual selection |
437 | +# ''' |
438 | +# ret = self._find_exact_match(cr, uid, vch.line_cr_ids, vch.amount, mark_pay=False, use_discount=False, context=False) |
439 | +# if not ret: |
440 | +# ''' |
441 | +# Try to match considering all voucher lines |
442 | +# ''' |
443 | +# ret = self._find_exact_match(cr, uid, vch.line_cr_ids, vch.amount, mark_pay=True, use_discount=False, context=False) |
444 | +# if not ret: |
445 | +# ''' |
446 | +# Try to match considering discount |
447 | +# ''' |
448 | +# ret = self._find_exact_match(cr, uid, vch.line_cr_ids, vch.amount, mark_pay=True, use_discount=True, context=False) |
449 | + |
450 | + return res |
451 | + |
452 | + def _update_discounts(self, lines, vch_date): |
453 | + date_discount = False |
454 | + amount_discount = False |
455 | + for line in lines: |
456 | + if 'date_discount' in line: |
457 | + date_discount = line['date_discount'] |
458 | + amount_discounted = line['amount_discounted'] |
459 | + else: |
460 | + return |
461 | + if line['amount'] >= line['amount_unreconciled']: |
462 | + amount_discount = 0.0 |
463 | + elif vch_date <= date_discount and line['amount'] <= line['amount_unreconciled'] and line['amount'] >= amount_discounted: |
464 | + amount_discount = max(line['amount_unreconciled'] - amount_discounted, 0.0) |
465 | + elif vch_date <= date_discount and line['amount'] < amount_discounted: |
466 | + amount_discount = max(line['amount_unreconciled'] - amount_discounted, 0.0) |
467 | + line['cash_discount'] = amount_discount |
468 | + line['amount_difference'] = line['amount_unreconciled'] - line['amount'] - amount_discount |
469 | + |
470 | + |
471 | + def onchange_partner_id(self, cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context={}): |
472 | + ''' |
473 | + Function to update fields in customer payment form on changing customer |
474 | + ''' |
475 | + if context is None: |
476 | + context = {} |
477 | + |
478 | + currency_pool = self.pool.get('res.currency') |
479 | + journal_pool = self.pool.get('account.journal') |
480 | + invoice_pool = self.pool.get('account.invoice') |
481 | + line_pool = self.pool.get('account.voucher.line') |
482 | + move_line_pool = self.pool.get('account.move.line') |
483 | + partner_pool = self.pool.get('res.partner') |
484 | + company_currency = False |
485 | + |
486 | + default = super(account_voucher, self).onchange_partner_id(cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context={}) |
487 | + if not partner_id: |
488 | + return default |
489 | + # we have to clear out lines, because new lines will be created by the change |
490 | + if partner_id and not journal_id: |
491 | + partner = partner_pool.browse(cr, uid, partner_id, context) |
492 | + if partner._columns.has_key('payment_meth_id') and partner.payment_meth_id: |
493 | + payment_mode_pool = self.pool.get('payment.mode') |
494 | + payment_meth = payment_mode_pool.browse(cr, uid, partner.payment_meth_id.id, context) |
495 | + if payment_meth: |
496 | + default['value']['journal_id'] = payment_meth.journal.id |
497 | + journal_id = payment_meth.journal.id |
498 | + if ids: |
499 | + line_ids = line_pool.search(cr, uid, [('voucher_id','=',ids[0])]) |
500 | + if line_ids: |
501 | + line_pool.unlink(cr, uid, line_ids) |
502 | + if journal_id: |
503 | + journal = journal_pool.browse(cr, uid, journal_id) |
504 | + company_currency = journal.company_id.currency_id.id |
505 | + |
506 | + total_credit = 0.0 |
507 | + total_debit = 0.0 |
508 | + vch_date = False |
509 | + for vch in self.browse(cr, uid, ids): |
510 | + vch_date = vch.date |
511 | + if default and 'value' in default and 'line_cr_ids' in default['value']: |
512 | + for line in default['value']['line_cr_ids']: |
513 | + invoice_id = invoice_pool.search(cr, uid, [('number', '=', line['name'])]) |
514 | + if invoice_id: |
515 | + line['invoice_id'] = invoice_id[0] |
516 | + invoice = invoice_pool.browse(cr, uid, invoice_id[0], ) |
517 | + date_discount = invoice.date_discount |
518 | + amount_discounted = invoice.amount_discounted |
519 | + line['date_discount'] = date_discount |
520 | + line['amount_discounted'] = amount_discounted |
521 | + else: |
522 | + line['date_discount'] = False |
523 | + line['amount_discounted'] = 0.0 |
524 | + line['amount'] = 0.0 |
525 | + total_credit += line['type'] == 'cr' and line['amount_unreconciled'] or 0.0 |
526 | + total_debit += line['type'] == 'dr' and line['amount_unreconciled'] or 0.0 |
527 | + # first, see if we can find an invoice matching the amount to be applied |
528 | + found = False |
529 | + def calc_amount(line, total): |
530 | + return min(line['amount_unreconciled'], total) |
531 | + lines = default['value']['line_cr_ids'] |
532 | + if len(lines) == 0: |
533 | + return default |
534 | +# return False |
535 | + # if only one, assign it |
536 | + if len(lines) == 1: |
537 | + for line in lines: |
538 | + if line['type'] == 'cr': |
539 | + amount = price |
540 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount |
541 | + total_credit -= amount |
542 | + found = True |
543 | + break |
544 | + else: |
545 | + amount = price |
546 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount |
547 | + total_debit -= amount |
548 | + found = True |
549 | + break |
550 | + self._update_discounts(lines, vch_date) |
551 | + if not found: |
552 | + for line in lines: |
553 | + if line['amount_unreconciled'] == price: |
554 | + if line['type'] == 'cr': |
555 | + amount = calc_amount(line, total_credit) |
556 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount |
557 | + total_credit -= amount |
558 | + found = True |
559 | + break |
560 | + else: |
561 | + amount = calc_amount(line, total_debit) |
562 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount |
563 | + total_debit -= amount |
564 | + found = True |
565 | + break |
566 | + if not found: |
567 | + # see if we can find a combination that matches |
568 | + def search(lines, price): |
569 | + for i in range(0, len(lines)): |
570 | + if lines[i]['amount_unreconciled'] == price: |
571 | + return [lines[i]] |
572 | + for i in range(0, len(lines)): |
573 | + for j in range(i + 1, len(lines)): |
574 | + if lines[i]['amount_unreconciled'] + lines[j]['amount_unreconciled'] == price: |
575 | + return [lines[i],lines[j]] |
576 | + for i in range(0, len(lines)): |
577 | + for j in range(i + 1, len(lines)): |
578 | + for k in range(j + 1, len(lines)): |
579 | + if lines[i]['amount_unreconciled'] + lines[j]['amount_unreconciled'] + lines[k]['amount_unreconciled']== price: |
580 | + return [lines[i],lines[j],lines[k]] |
581 | + line_ids = search(lines, price) |
582 | + |
583 | + if line_ids: # and sum == price: |
584 | + for line in line_ids: |
585 | + if line['type'] == 'cr': |
586 | + amount = calc_amount(line, line['amount_unreconciled']) |
587 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) |
588 | + total_debit -= amount |
589 | + found = True |
590 | + else: |
591 | + amount = calc_amount(line, line['amount_unreconciled']) |
592 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) |
593 | + total_credit -= amount |
594 | + found = True |
595 | + if not found: |
596 | + # see if we can find a match using discounted amount |
597 | + def search2(lines, price): |
598 | + for i in range(0, len(lines)): |
599 | + if min(lines[i]['amount_unreconciled'],lines[i]['amount_discounted']) == price: |
600 | + return [lines[i]] |
601 | + for i in range(0, len(lines)): |
602 | + for j in range(i + 1, len(lines)): |
603 | + if min(lines[i]['amount_unreconciled'],lines[i]['amount_discounted']) + min(lines[j]['amount_unreconciled'],lines[j]['amount_discounted']) == price: |
604 | + return [lines[i],lines[j]] |
605 | + for i in range(0, len(lines)): |
606 | + for j in range(i + 1, len(lines)): |
607 | + for k in range(j + 1, len(lines)): |
608 | + if min(lines[i]['amount_unreconciled'],lines[i]['amount_discounted']) + min(lines[j]['amount_unreconciled'],lines[j]['amount_discounted']) + min(lines[k]['amount_unreconciled'],lines[k]['amount_discounted']) == price: |
609 | + return [lines[i],lines[j],lines[k]] |
610 | + line_ids = search(lines, price) |
611 | + lines = default['value']['line_cr_ids'] |
612 | + line_ids = search2(lines, price) |
613 | + if line_ids: |
614 | + for line in line_ids: |
615 | + if line['type'] == 'cr': |
616 | + amount = calc_amount(line, min(line['amount_unreconciled'],line['amount_discounted'])) |
617 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, min(line['amount_unreconciled'],line['amount_discounted'])) |
618 | + total_debit -= amount |
619 | + found = True |
620 | + else: |
621 | + amount = calc_amount(line, min(line['amount_unreconciled'],line['amount_discounted'])) |
622 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, min(line['amount_unreconciled'],line['amount_discounted'])) |
623 | + total_credit -= amount |
624 | + found = True |
625 | + lines = default['value']['line_cr_ids'] |
626 | + ''' |
627 | + FIXME : removing amount from line_dr_ids (Credits on customer payment form) line. |
628 | + and amount from line_cr_ids (Invoice and outstanding transactions on customer payment form) line |
629 | + I do not think this this is a good solution. But it works. |
630 | + The whole "onchange_partner_id" function need a re-thinking (may have to rewrite it completely instead of calling super ). |
631 | + ''' |
632 | + if default: |
633 | + for credit_line in default['value'].get('line_dr_ids',[]): |
634 | + credit_line['amount'] = 0.0 |
635 | + for invoce_line in default['value'].get('line_cr_ids',[]): |
636 | + invoce_line['amount'] = 0.0 |
637 | + invoce_line['amount_difference'] = invoce_line['amount_unreconciled'] |
638 | + return default |
639 | + |
640 | + def calc_cash_discount(self, cr, uid, ids, vch, line, context={}): |
641 | + ''' |
642 | + Calculate discount per line |
643 | + ''' |
644 | + total_allocated = 0.0 |
645 | + for line in vch.line_ids: |
646 | + total_allocated += line.amount |
647 | + context.update({'total_allocated': total_allocated, 'total_amount': vch.date}) |
648 | + amount_discount = 0.0 |
649 | + if line.amount >= line.amount_unreconciled or line.amount < 0.01 : |
650 | + amount_discount = 0.0 |
651 | + elif line.amount >= line.amount_discounted and vch.date <= line.date_discount: |
652 | + amount_discount = line.amount_unreconciled - line.amount_discounted |
653 | + return amount_discount |
654 | + |
655 | + |
656 | + def onchange_amount(self, cr, uid, ids, amount, context={}): |
657 | + if not context: |
658 | + context = {} |
659 | + result = {} |
660 | + currency_format = self.pool.get('res.users').browse(cr, uid, uid).company_id.currency_format |
661 | + if currency_format=='us': |
662 | + amount_in_words = amount_to_words(amount) |
663 | + else: amount_in_words = amount_to_text(amount) |
664 | + result['amount_in_word']=amount_in_words |
665 | + return {'value':result} |
666 | +account_voucher() |
667 | + |
668 | +class account_voucher_line(osv.osv): |
669 | + _name = 'account.voucher.line' |
670 | + _inherit = 'account.voucher.line' |
671 | + def onchange_supp_pay(self, cr, uid, ids, line_amount, pay, amount_unreconciled,par_cr_ids, par_amount, credit_used, discount_used, writeoff_amount=0, context={}): |
672 | + ''' |
673 | + Function to automatically fill the values when the pay checkbox is selected |
674 | + ''' |
675 | + ret = {} |
676 | + writeoff_amount = (not writeoff_amount and [0] or [writeoff_amount])[0] |
677 | + discount_used = (not discount_used and [0] or [discount_used])[0] |
678 | + credit_used = (not credit_used and [0] or [credit_used])[0] |
679 | + if pay: |
680 | + tot_amt = par_amount + line_amount |
681 | + for credit in par_cr_ids: |
682 | + if credit[2].get('pay'): |
683 | + tot_amt -= (credit[2]['amount']) |
684 | + if tot_amt < 0: |
685 | + ret['amount'] = 0.0 |
686 | + else: |
687 | + amount_unreconciled -= (discount_used+writeoff_amount+credit_used) |
688 | + ret['amount'] = min(tot_amt,(amount_unreconciled<0) and 0 or amount_unreconciled) |
689 | + else: |
690 | + ret['amount'] = 0.0 |
691 | + return {'value':ret} |
692 | + def recalculate_supp_values(self, cr, uid, ids, context={}): |
693 | + ''' |
694 | + Re-calculate button action |
695 | + ''' |
696 | + if type(ids) == type([]): |
697 | + voucher_line = self.browse(cr,uid,ids[0]) |
698 | + else: |
699 | + voucher_line = self.browse(cr,uid,ids) |
700 | + if voucher_line.discount_used: |
701 | + print "discount_useddiscount_useddiscount_useddiscount_useddiscount_useddiscount_useddiscount_useddiscount_useddiscount_useddiscount_used" |
702 | + self.write(cr,uid,ids,{'amount':voucher_line.amount_unreconciled - voucher_line.discount_used}) |
703 | + self.pool.get('account.voucher').calc_supp_diff(cr, uid, [voucher_line.voucher_id.id]) |
704 | + return True |
705 | + |
706 | + |
707 | + |
708 | + def _update_credit_lines(self,cr, uid, ids, context): |
709 | + ''' |
710 | + Function to update the credit lines in payment lines |
711 | + ''' |
712 | + credits_used_pool = self.pool.get('account.voucher.line.credits_to_use') |
713 | + for line in self.browse(cr , uid, ids, context): |
714 | + credits_lines_used = [x.orginal_credit_line_id.id for x in line.available_credits] |
715 | + for credit_line in line.voucher_id.line_dr_ids : |
716 | + if credit_line.id not in credits_lines_used and line.invoice_id and line.invoice_id.payment_term: |
717 | + credits_used_pool.create(cr, uid, { |
718 | + 'voucher_line_id': line.id, |
719 | + 'orginal_credit_line_id':credit_line.id, |
720 | + 'use_credit': False, |
721 | + 'inv_credit': credit_line.move_line_id.id, |
722 | + 'discount_window_date': credit_line.date_original, |
723 | + 'orginal_amount': credit_line.amount_original, |
724 | + 'available_amount': credit_line.amount_unreconciled - credit_line.pending_credits, |
725 | + 'discount_amount': 0.0, |
726 | + 'gl_account' : credit_line.account_id.id,}) |
727 | + else : |
728 | + to_update_credit_line_ids = credits_used_pool.search(cr,uid,[('voucher_line_id','=',line.id),( 'orginal_credit_line_id','=',credit_line.id)], context=context) |
729 | + if to_update_credit_line_ids: |
730 | + credits_used_pool.write(cr, uid,to_update_credit_line_ids,{'available_amount': credit_line.amount_unreconciled-credit_line.pending_credits}, context=context) |
731 | + |
732 | + def _update_discount_lines(self,cr, uid, ids, context): |
733 | + ''' |
734 | + Function to update the discount lines in payment lines |
735 | + ''' |
736 | + |
737 | + discount_used_pool = self.pool.get('account.voucher.line.discount_to_use') |
738 | + user_pool = self.pool.get('res.users') |
739 | + user = user_pool.browse(cr, uid, uid, context) |
740 | + for line in self.browse(cr , uid, ids, context): |
741 | + if line.invoice_id: |
742 | + if not line.invoice_id.date_discount or not line.voucher_id.date or line.voucher_id.date > line.invoice_id.date_discount: |
743 | + ''' |
744 | + customer is not eligible for the discount |
745 | + ''' |
746 | + continue |
747 | + |
748 | + discount = line.invoice_id.amount_total - line.invoice_id.amount_discounted |
749 | + date_discount = line.invoice_id.date_discount |
750 | + discount_found = False |
751 | + for discount_line in line.available_discounts: |
752 | + #if abs(discount - discount_line.proposed_discount) < 0.01 and line.invoice_id.payment_term.id == discount_line.inv_payment_terms.id: |
753 | + if line.invoice_id.payment_term.id == discount_line.inv_payment_terms.id: |
754 | + discount_found = True |
755 | + continue |
756 | + if not discount_found and user.company_id.sales_discount_account: |
757 | + ''' |
758 | + TODO : calculate/findout the discount_window_date (The last day of the discount window. To receive discounts payments must be paid on or before this date.) |
759 | + ''' |
760 | + discount_used_pool.create(cr, uid, { |
761 | + 'voucher_line_id': line.id, |
762 | + 'use_discount': False, |
763 | + 'inv_payment_terms':line.invoice_id.payment_term.id , |
764 | + 'discount_window_date': date_discount, |
765 | + 'proposed_discount': discount, |
766 | + 'discount_amount': 0.0, |
767 | + 'gl_account':user.company_id.sales_discount_account.id |
768 | + }, context=context) |
769 | + |
770 | + def _update_supp_discount_lines(self,cr, uid, ids, context): |
771 | + ''' |
772 | + Function to update the discount lines in payment lines |
773 | + ''' |
774 | + |
775 | + discount_used_pool = self.pool.get('account.voucher.line.discount_to_use') |
776 | + user_pool = self.pool.get('res.users') |
777 | + user = user_pool.browse(cr, uid, uid, context) |
778 | + for line in self.browse(cr , uid, ids, context): |
779 | + if line.invoice_id: |
780 | + if not line.invoice_id.date_discount or not line.voucher_id.date or line.voucher_id.date > line.invoice_id.date_discount: |
781 | + ''' |
782 | + customer is not eligible for the discount |
783 | + ''' |
784 | + continue |
785 | + |
786 | + discount = line.invoice_id.amount_total - line.invoice_id.amount_discounted |
787 | + date_discount = line.invoice_id.date_discount |
788 | + discount_found = False |
789 | + for discount_line in line.available_discounts: |
790 | + #if abs(discount - discount_line.proposed_discount) < 0.01 and line.invoice_id.payment_term.id == discount_line.inv_payment_terms.id: |
791 | + if line.invoice_id.payment_term.id == discount_line.inv_payment_terms.id: |
792 | + discount_found = True |
793 | + continue |
794 | + if not discount_found and user.company_id.purchase_discount_account: |
795 | + ''' |
796 | + TODO : calculate/findout the discount_window_date (The last day of the discount window. To receive discounts payments must be paid on or before this date.) |
797 | + ''' |
798 | + discount_used_pool.create(cr, uid, { |
799 | + 'voucher_line_id': line.id, |
800 | + 'use_discount': False, |
801 | + 'inv_payment_terms':line.invoice_id.payment_term.id , |
802 | + 'discount_window_date': date_discount, |
803 | + 'proposed_discount': discount, |
804 | + 'discount_amount': 0.0, |
805 | + 'gl_account':user.company_id.purchase_discount_account.id |
806 | + }, context=context) |
807 | + |
808 | + |
809 | + def _compute_discount_used(self, cr, uid, ids, name, args, context=None): |
810 | + ''' |
811 | + Function to calculate the value of variable discount used |
812 | + ''' |
813 | + res = {} |
814 | + for line in self.browse(cr, uid, ids): |
815 | + res[line.id] = 0.0 |
816 | + for discount_line in line.available_discounts: |
817 | + if discount_line.use_discount : |
818 | + res[line.id] += discount_line.discount_amount |
819 | + return res |
820 | + |
821 | + def _compute_balance(self, cr, uid, ids, name, args, context=None): |
822 | + ''' |
823 | + Function to calculate the value of variables Cash Discount, Interest and Amt Due |
824 | + ''' |
825 | + currency_pool = self.pool.get('res.currency') |
826 | + rs_data = super(account_voucher_line, self)._compute_balance(cr, uid, ids, name, args, context) |
827 | + for line in self.browse(cr, uid, ids): |
828 | + amount_cash_discount = self.calc_cash_discount(cr, uid, ids, vch, line) |
829 | + amount_interest = self.calc_interest(vch, line, line.amount) |
830 | + amount_unreconciled = 0.0 |
831 | + move_line = line.move_line_id or False |
832 | + if move_line: |
833 | + amount_unreconciled = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.amount_unreconciled - amount_cash_discount - line.writeoff) |
834 | + rs_data[line.id] = {'cash_discount': amount_cash_discount, 'interest': amount_interest, 'amount_unreconciled': amount_unreconciled} |
835 | + return rs_data |
836 | + |
837 | + def _get_discount(self, cr, uid, ids, field_name, args, context={}): |
838 | + """ |
839 | + Function to calculate the value of variable date_discount,amount_discounted,cash_discount,amount_difference |
840 | + return the values as dictionary |
841 | + """ |
842 | + |
843 | + if context is None: |
844 | + context = {} |
845 | + invoice_obj = self.pool.get('account.invoice') |
846 | + move_line_obj = self.pool.get('account.move.line') |
847 | + voucher_line = self.browse(cr, uid, ids) |
848 | + vch = self.pool.get('account.voucher').browse(cr, uid, voucher_line[0].voucher_id.id) |
849 | + res = {} |
850 | + for line in voucher_line: |
851 | + if line.type == 'dr': |
852 | + res[line.id] = { |
853 | + 'date_discount': '', |
854 | + 'amount_discounted': line.amount, |
855 | + 'cash_discount': 0.0, |
856 | + 'amount_difference': line.amount_unreconciled - line.amount , |
857 | + } |
858 | + continue |
859 | + move_line = move_line_obj.browse(cr, uid, line.move_line_id.id) |
860 | + invoice_number = move_line.name or move_line.ref |
861 | + invoice_id = False |
862 | + if invoice_number and invoice_number != '/': |
863 | + invoice_id = invoice_obj.search(cr, uid, [('number', '=', str(invoice_number))]) |
864 | + if not invoice_id: |
865 | + move = self.pool.get('account.move').browse(cr, uid, move_line.move_id.id) |
866 | + if move: |
867 | + invoice_number = move.name or move.ref |
868 | + if invoice_number and invoice_number != '/': |
869 | + invoice_id = invoice_obj.search(cr, uid, [('number', '=', str(invoice_number))]) |
870 | + if invoice_id: |
871 | + for invoice in invoice_obj.browse(cr, uid, invoice_id, context): |
872 | + date_discount = invoice.date_due |
873 | + amount_discounted = invoice.amount_total |
874 | + res[line.id] = { |
875 | + 'date_discount': invoice.date_due, |
876 | + 'amount_discounted': invoice.amount_total |
877 | + } |
878 | + if not invoice.date_invoice: |
879 | + invoice_date = mx.DateTime.today().strftime("%Y-%m-%d") |
880 | + self.write(cr, uid, [invoice.id], {'date_invoice': invoice_date}, context) |
881 | + else: |
882 | + invoice_date = invoice.date_invoice |
883 | + discounts = invoice.payment_term and invoice.payment_term.get_discounts(invoice_date, context=context) or False |
884 | + if discounts: |
885 | + line_obj = self.pool.get('account.invoice.line') |
886 | + discount_total = 0.0 |
887 | + non_discount_total = 0.0 |
888 | + for invline in invoice.invoice_line: |
889 | + if invline.cash_discount: |
890 | + discount_total += invline.price_subtotal |
891 | + line_cash_discount = round((1.0 - discounts[0][1]) * invline.price_subtotal) |
892 | + line_obj.write(cr, uid, invline.id, {'cash_discount': line_cash_discount}, context) |
893 | + else: |
894 | + non_discount_total += invline.price_subtotal |
895 | + line_obj.write(cr, uid, invline.id, {'cash_discount': 0.0}, context) |
896 | + # assume taxes are never discountable |
897 | + non_discount_total += invoice.amount_tax |
898 | + # There may be more than one - return the earliest |
899 | + date_discount = discounts[0][0] |
900 | + amount_discounted = round(((1.0 - discounts[0][1]) * discount_total) + non_discount_total,2) |
901 | + amount_discount = 0.0 |
902 | + if line.amount >= line.amount_unreconciled or line.amount < 0.01: |
903 | + amount_discount = 0.0 |
904 | + elif vch.date <= date_discount and line.amount <= line.amount_unreconciled: |
905 | + amount_discount = max(line.amount_unreconciled - amount_discounted, 0.0) |
906 | + elif vch.date <= date_discount and line.amount < amount_discounted: |
907 | + amount_discount = max(line.amount_unreconciled - amount_discounted,0.0) |
908 | + else: |
909 | + amount_discount = 0.0 |
910 | + |
911 | + res[line.id] = { |
912 | + 'date_discount': date_discount, |
913 | + 'amount_discounted': amount_discounted, |
914 | + 'cash_discount': amount_discount, |
915 | + 'amount_difference': line.amount_unreconciled - line.amount - line.credit_used - line.discount_used - (line._columns.has_key('writeoff_amount') and line['writeoff_amount']),#- amount_discount |
916 | + } |
917 | + return defaultdict(type([]),res) |
918 | + def _get_supp_discount(self, cr, uid, ids, field_name, args, context={}): |
919 | + """ |
920 | + Function to calculate the value of variable date_discount,amount_discounted,cash_discount,amount_difference |
921 | + return the values as dictionary |
922 | + """ |
923 | + |
924 | + if context is None: |
925 | + context = {} |
926 | + invoice_obj = self.pool.get('account.invoice') |
927 | + move_line_obj = self.pool.get('account.move.line') |
928 | + voucher_line = self.browse(cr, uid, ids) |
929 | + vch = self.pool.get('account.voucher').browse(cr, uid, voucher_line[0].voucher_id.id) |
930 | + res = {} |
931 | + for line in voucher_line: |
932 | + if line.type == 'cr': |
933 | + res[line.id] = { |
934 | + 'date_discount': '', |
935 | + 'amount_discounted': line.amount, |
936 | + 'cash_discount': 0.0, |
937 | + 'supp_amount_difference': line.amount_unreconciled - line.amount , |
938 | + 'discount' : False |
939 | + } |
940 | + continue |
941 | + move_line = move_line_obj.browse(cr, uid, line.move_line_id.id) |
942 | + invoice_number = move_line.name or move_line.ref |
943 | + invoice_id = False |
944 | + if invoice_number and invoice_number != '/': |
945 | + invoice_id = invoice_obj.search(cr, uid, [('number', '=', str(invoice_number))]) |
946 | + if not invoice_id: |
947 | + move = self.pool.get('account.move').browse(cr, uid, move_line.move_id.id) |
948 | + if move: |
949 | + invoice_number = move.name or move.ref |
950 | + if invoice_number and invoice_number != '/': |
951 | + invoice_id = invoice_obj.search(cr, uid, [('number', '=', str(invoice_number))]) |
952 | + if invoice_id: |
953 | + for invoice in invoice_obj.browse(cr, uid, invoice_id, context): |
954 | + date_discount = invoice.date_due |
955 | + amount_discounted = invoice.amount_total |
956 | + res[line.id] = { |
957 | + 'date_discount': invoice.date_due, |
958 | + 'supp_amount_difference': invoice.amount_total |
959 | + } |
960 | + if not invoice.date_invoice: |
961 | + invoice_date = mx.DateTime.today().strftime("%Y-%m-%d") |
962 | + self.write(cr, uid, [invoice.id], {'date_invoice': invoice_date}, context) |
963 | + else: |
964 | + invoice_date = invoice.date_invoice |
965 | + discounts = invoice.payment_term and invoice.payment_term.get_discounts(invoice_date, context=context) or False |
966 | + if discounts: |
967 | + line_obj = self.pool.get('account.invoice.line') |
968 | + discount_total = 0.0 |
969 | + non_discount_total = 0.0 |
970 | + for invline in invoice.invoice_line: |
971 | + if invline.cash_discount: |
972 | + discount_total += invline.price_subtotal |
973 | + line_cash_discount = round((1.0 - discounts[0][1]) * invline.price_subtotal) |
974 | + line_obj.write(cr, uid, invline.id, {'cash_discount': line_cash_discount}, context) |
975 | + else: |
976 | + non_discount_total += invline.price_subtotal |
977 | + line_obj.write(cr, uid, invline.id, {'cash_discount': 0.0}, context) |
978 | + # assume taxes are never discountable |
979 | + non_discount_total += invoice.amount_tax |
980 | + # There may be more than one - return the earliest |
981 | + date_discount = discounts[0][0] |
982 | + amount_discounted = round(((1.0 - discounts[0][1]) * discount_total) + non_discount_total,2) |
983 | + amount_discount = 0.0 |
984 | + if line.amount >= line.amount_unreconciled or line.amount < 0.01: |
985 | + amount_discount = 0.0 |
986 | + elif vch.date <= date_discount and line.amount <= line.amount_unreconciled: |
987 | + amount_discount = max(line.amount_unreconciled - amount_discounted, 0.0) |
988 | + elif vch.date <= date_discount and line.amount < amount_discounted: |
989 | + amount_discount = max(line.amount_unreconciled - amount_discounted,0.0) |
990 | + else: |
991 | + amount_discount = 0.0 |
992 | + discount=False |
993 | + if line.available_discounts: |
994 | +# if line.discount_used: |
995 | + discount=True |
996 | + res[line.id] = { |
997 | + 'date_discount': date_discount, |
998 | + 'amount_discounted': amount_discounted, |
999 | + 'cash_discount': amount_discount, |
1000 | + 'supp_amount_difference': line.amount_unreconciled - line.amount - line.credit_used - line.discount_used - (line._columns.has_key('writeoff_amount') and line['writeoff_amount']),#- amount_discount |
1001 | + 'discount':discount |
1002 | + } |
1003 | + return defaultdict(type([]),res) |
1004 | + |
1005 | + |
1006 | + _columns = { |
1007 | + 'date_discount': fields.function(_get_discount, method=True, type='date', string='Discount Date', |
1008 | + multi='all'), |
1009 | + 'amount_discounted': fields.function(_get_discount, method=True, type='float', digits_compute=dp.get_precision('Account'), string='Discounted Total', |
1010 | + multi='all'), |
1011 | + 'cash_discount': fields.function(_get_discount, method=True, type='float', multi="all", digits_compute=dp.get_precision('Account'), string='Cash Discount',sequence=20), |
1012 | + 'amount_difference': fields.function(_get_discount, method=True, multi='all', type='float', string='Unpaid Amt', digits=(16, 2) ), |
1013 | + 'supp_amount_difference': fields.function(_get_supp_discount, method=True, multi='all', type='float', string='Unpaid Amt', digits=(16, 2) ), |
1014 | + 'interest': fields.float(string='Interest', digits=(16,2)), |
1015 | + |
1016 | + #'discount_used':fields.float('Discount used', readonly=True), |
1017 | + 'discount_used': fields.function(_compute_discount_used, method=True, type='float', string='Discount Used', store=False, readonly=True,sequence=10), |
1018 | + 'available_discounts':fields.one2many('account.voucher.line.discount_to_use', 'voucher_line_id', 'Available Discounts' ), |
1019 | + 'discount': fields.function(_get_supp_discount, method=True, multi='all', type='boolean', string='Discount', readonly=True, sequence=20) |
1020 | + } |
1021 | + def clear_values(self, cr, uid, ids, context={}): |
1022 | + ''' |
1023 | + Clear the selected credits, discounts and writeoffs from voucher line |
1024 | + ''' |
1025 | + voucher_line = self.browse(cr,uid,ids[0]) |
1026 | + if voucher_line._columns.has_key('writeoff_ids'): |
1027 | + for lines in self.read(cr,uid,ids,['available_credits','writeoff_ids','available_discounts']): |
1028 | + lines['writeoff_ids'] and self.pool.get('account.voucher.line.writeoff').unlink(cr,uid,lines['writeoff_ids']) |
1029 | + lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'],{ |
1030 | + 'use_credit':False, |
1031 | + 'discount_amount':0.0}) |
1032 | + lines['available_discounts'] and self.pool.get('account.voucher.line.discount_to_use').write(cr,uid,lines['available_discounts'],{ |
1033 | + 'use_discount':False, |
1034 | + 'discount_amount':0.0}) |
1035 | + else: |
1036 | + for lines in self.read(cr,uid,ids,['available_credits','writeoff_ids','available_discounts']): |
1037 | + lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'],{ |
1038 | + 'use_credit':False, |
1039 | + 'discount_amount':0.0}) |
1040 | + lines['available_discounts'] and self.pool.get('account.voucher.line.discount_to_use').write(cr,uid,lines['available_discounts'],{ |
1041 | + 'use_discount':False, |
1042 | + 'discount_amount':0.0}) |
1043 | + return True |
1044 | +account_voucher_line() |
1045 | + |
1046 | +class product_product(osv.osv): |
1047 | + ''' |
1048 | + Add new account configuration fields to product |
1049 | + ''' |
1050 | + _name = "product.product" |
1051 | + _inherit = 'product.product' |
1052 | + _columns = { |
1053 | + 'cash_discount': fields.boolean('Cash Discount?'), |
1054 | + 'purchase_discount_account': fields.many2one('account.account', 'Purchase Discount Account', domain=[('user_type','=','COGS')]), |
1055 | + 'sales_discount_account': fields.many2one('account.account', 'Sales Discount Account', domain=[('type','!=','view'),('type','!=','consolidation'),('user_type','ilike','income')]), |
1056 | + 'purchase_discount_journal': fields.many2one('account.journal', 'Purchase Discount Journal', domain=[('type','!=','view'),('type','!=','consolidation'),('type','=','purchase')]), |
1057 | + 'sales_discount_journal': fields.many2one('account.journal', 'Sales Discount Journal', domain=[('type','=','sale')]), |
1058 | + } |
1059 | + _defaults = { |
1060 | + 'cash_discount' : lambda *a : True, |
1061 | + } |
1062 | +product_product() |
1063 | + |
1064 | +class account_invoice_line(osv.osv): |
1065 | + ''' |
1066 | + option to disable discount calculation per invoice line |
1067 | + ''' |
1068 | + _name = 'account.invoice.line' |
1069 | + _inherit = 'account.invoice.line' |
1070 | + _columns = { |
1071 | + 'cash_discount': fields.boolean('Cash Discount?'), |
1072 | + } |
1073 | + _defaults = { |
1074 | + 'cash_discount' : lambda *a : True, |
1075 | + } |
1076 | + def product_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, address_invoice_id=False, currency_id=False, context=None): |
1077 | + ''' |
1078 | + check if the discount is applicable to newly selected product |
1079 | + ''' |
1080 | + result = {} |
1081 | + result = super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, fposition_id, price_unit, address_invoice_id, currency_id, context) |
1082 | + if product: |
1083 | + res = self.pool.get('product.product').browse(cr, uid, product, context=context) |
1084 | + result['value']['cash_discount'] = res.cash_discount |
1085 | + else: |
1086 | + result['value']['cash_discount'] = True |
1087 | + return result |
1088 | +account_invoice_line() |
1089 | + |
1090 | +class res_company(osv.osv): |
1091 | + ''' |
1092 | + New account configuration fields on copmany form |
1093 | + ''' |
1094 | + _name = 'res.company' |
1095 | + _inherit = 'res.company' |
1096 | + _columns = { |
1097 | + 'purchase_discount_account': fields.many2one('account.account', 'Purchase Discount Account', domain=[('user_type','=','COGS'),('type','!=','view'),('type','!=','consolidation')]), |
1098 | + 'sales_discount_account': fields.many2one('account.account', 'Sales Discount Account', domain=[('user_type','=','Income'),('type','!=','view'),('type','!=','consolidation')]), |
1099 | + 'purchase_discount_journal': fields.many2one('account.journal', 'Purchase Discount Journal', domain=[('type','=','purchase')]), |
1100 | + 'sales_discount_journal': fields.many2one('account.journal', 'Sales Discount Journal', domain=[('type','=','sale')]), |
1101 | + } |
1102 | +res_company() |
1103 | + |
1104 | +class account_voucher_line_discount_to_use(osv.osv): |
1105 | + ''' |
1106 | + Dynamically generated discount lines that are applicable per voucher line |
1107 | + ''' |
1108 | + _name = "account.voucher.line.discount_to_use" |
1109 | + _rec_name = 'inv_credit' |
1110 | + _columns = { |
1111 | + 'voucher_line_id': fields.many2one('account.voucher.line', 'Account Voucher Line', ondelete='cascade', readonly=True), |
1112 | + 'use_discount': fields.boolean('Use Discount',help='Used to indicate if the cash discount should be used/taken when calculating payment.', required=True), |
1113 | + 'inv_payment_terms': fields.many2one('account.payment.term', 'Invoice Payment Terms', help='Payments terms description', ), |
1114 | + 'discount_window_date': fields.date('Discount Window Date',help='The last day of the discount window. To receive discounts payments must be paid on or before this date.'), |
1115 | + |
1116 | + |
1117 | + 'proposed_discount': fields.float('Proposed Discount',help='This is the proposed full discount based on the Invoice Payment Terms and the Original Amount.', readonly=True), |
1118 | + 'discount_amount': fields.float('Discount Amt',help='Enter the amount of discount to be given.', required=True), |
1119 | + 'gl_account' : fields.many2one('account.account', 'G/L Account',help='Enter the General Ledger account number to record taking the cash discount.', required=True), |
1120 | + } |
1121 | + def onchage_use_discount(self, cr, uid, ids, use_discount, proposed_discount, context=None): |
1122 | + ''' |
1123 | + Fill the value with proposed discount when use discount check box is clicked and remove the value when use discount is unchecked |
1124 | + ''' |
1125 | + res = {} |
1126 | + if use_discount: |
1127 | + res['value'] = {'discount_amount': proposed_discount} |
1128 | + else: |
1129 | + res['value'] = {'discount_amount': 0} |
1130 | + return res |
1131 | + def onchage_discount_amount(self, cr, uid, ids, proposed_discount, discount_amount, context=None): |
1132 | + ''' |
1133 | + Function to check discount amount entered in discount line of payment line |
1134 | + ''' |
1135 | + res = {} |
1136 | + if discount_amount < 0: |
1137 | + res['value'] = {'discount_amount': 0, 'use_discount':False } |
1138 | + res['warning'] = {'title': 'Discount not in the limit', 'message': 'Discount should not be a negative value.'} |
1139 | + return res |
1140 | + if discount_amount > proposed_discount: |
1141 | + res['value'] = {'discount_amount': proposed_discount, 'use_discount':True } |
1142 | + res['warning'] = {'title': 'Discount not in the limit', 'message': 'Please adjust the Discount Amt value to be less than or equal the Proposed Discount.'} |
1143 | + return res |
1144 | + if discount_amount == 0.0: |
1145 | + res['value'] = { 'use_discount':False } |
1146 | + else: |
1147 | + res['value'] = { 'use_discount':True } |
1148 | + return res |
1149 | +account_voucher_line_discount_to_use() |
1150 | + |
1151 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1152 | + |
1153 | |
1154 | === added directory 'account_cash_discount_us/account_cash_discount_us' |
1155 | === added file 'account_cash_discount_us/account_cash_discount_us/Change Log.txt' |
1156 | --- account_cash_discount_us/account_cash_discount_us/Change Log.txt 1970-01-01 00:00:00 +0000 |
1157 | +++ account_cash_discount_us/account_cash_discount_us/Change Log.txt 2011-10-06 15:23:28 +0000 |
1158 | @@ -0,0 +1,31 @@ |
1159 | +=============================================================================== |
1160 | + Version Change Log (account_cash_discount_us) |
1161 | +=============================================================================== |
1162 | + |
1163 | +1.07 -> 1.08 (2011-02-04) By Sinoj |
1164 | + * Optimization and cleanup |
1165 | + |
1166 | +1.06 -> 1.07 (2010-12-06) By jabir |
1167 | + * Removed discount wizard and changed domain filtering |
1168 | + |
1169 | +1.05 -> 1.06 (2010-12-06) By jabir |
1170 | + * Take invoice partner instead of moveline partner |
1171 | + |
1172 | + 1.04 -> 1.05 (2010-11-29) By Jabir |
1173 | + * Fix placement of Cash Discount Separation Line |
1174 | + |
1175 | + 1.03 -> 1.04 (2010-11-29) By Sinoj |
1176 | + * Account posting updated for National account |
1177 | + |
1178 | + 1.02 -> 1.03 (2010-11-09) By Sinoj |
1179 | + * "Debit and Credits" wizard button moved to voucher line |
1180 | + * fields on wizard form are readonly |
1181 | + * fields on wizard are populated with default values |
1182 | + * removed |
1183 | + |
1184 | + 1.01 -> 1.02 (2010-11-04) By jabir |
1185 | + * Add wizard Discount and Credits |
1186 | + * Create button Discount and Credits in customer payment form |
1187 | + |
1188 | + 1.0 -> 1.01 (2010-11-04) By sinoj |
1189 | + * dependency changed from account_voucher_jdc to account_voucher_credits_us |
1190 | \ No newline at end of file |
1191 | |
1192 | === added file 'account_cash_discount_us/account_cash_discount_us/__init__.py' |
1193 | --- account_cash_discount_us/account_cash_discount_us/__init__.py 1970-01-01 00:00:00 +0000 |
1194 | +++ account_cash_discount_us/account_cash_discount_us/__init__.py 2011-10-06 15:23:28 +0000 |
1195 | @@ -0,0 +1,26 @@ |
1196 | +# -*- coding: utf-8 -*- |
1197 | +############################################################################## |
1198 | +# |
1199 | +# OpenERP, Open Source Management Solution |
1200 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
1201 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
1202 | +# |
1203 | +# This program is free software: you can redistribute it and/or modify |
1204 | +# it under the terms of the GNU General Public License as published by |
1205 | +# the Free Software Foundation, either version 3 of the License, or |
1206 | +# (at your option) any later version. |
1207 | +# |
1208 | +# This program is distributed in the hope that it will be useful, |
1209 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1210 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1211 | +# GNU General Public License for more details. |
1212 | +# |
1213 | +# You should have received a copy of the GNU General Public License |
1214 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
1215 | +# |
1216 | +############################################################################## |
1217 | + |
1218 | + |
1219 | +import account_cash_discount |
1220 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1221 | + |
1222 | |
1223 | === added file 'account_cash_discount_us/account_cash_discount_us/__openerp__.py' |
1224 | --- account_cash_discount_us/account_cash_discount_us/__openerp__.py 1970-01-01 00:00:00 +0000 |
1225 | +++ account_cash_discount_us/account_cash_discount_us/__openerp__.py 2011-10-06 15:23:28 +0000 |
1226 | @@ -0,0 +1,54 @@ |
1227 | +# -*- coding: utf-8 -*- |
1228 | +############################################################################## |
1229 | +# |
1230 | +# OpenERP, Open Source Management Solution |
1231 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
1232 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
1233 | +# |
1234 | +# This program is free software: you can redistribute it and/or modify |
1235 | +# it under the terms of the GNU General Public License as published by |
1236 | +# the Free Software Foundation, either version 3 of the License, or |
1237 | +# (at your option) any later version. |
1238 | +# |
1239 | +# This program is distributed in the hope that it will be useful, |
1240 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1241 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1242 | +# GNU General Public License for more details. |
1243 | +# |
1244 | +# You should have received a copy of the GNU General Public License |
1245 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
1246 | +# |
1247 | +############################################################################## |
1248 | + |
1249 | + |
1250 | +{ |
1251 | + "name" : "Payment Term with Cash Discount", |
1252 | + "version" : "1.08", |
1253 | + "depends" : ["account","account_voucher_credits_us","account_cash_discount"], |
1254 | + "author" : "Tiny and NovaPoint Group LLC", |
1255 | + "description" : "Cash discounts, based on payment terms", |
1256 | + "website" : "http://www.novapointgroup.com/", |
1257 | + "category" : "Generic Modules/Accounting", |
1258 | + "description": """ |
1259 | + This module adds cash discounts on payment terms. Cash discounts |
1260 | + for a payment term can be configured with: |
1261 | + * A number of days, |
1262 | + * A discount (%), |
1263 | + * A debit and a credit account |
1264 | + * Sales and Purchase discounts are added to product and invoice line |
1265 | + """, |
1266 | + "init_xml" : [ |
1267 | + ], |
1268 | + "demo_xml" : [ |
1269 | + ], |
1270 | + "update_xml" : [ |
1271 | + "account_cash_discount_view.xml", |
1272 | + "product_view.xml", |
1273 | + "security/ir.model.access.csv", |
1274 | + ], |
1275 | + "active": False, |
1276 | + "installable": True, |
1277 | + |
1278 | +} |
1279 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1280 | + |
1281 | |
1282 | === added file 'account_cash_discount_us/account_cash_discount_us/__terp__.py' |
1283 | --- account_cash_discount_us/account_cash_discount_us/__terp__.py 1970-01-01 00:00:00 +0000 |
1284 | +++ account_cash_discount_us/account_cash_discount_us/__terp__.py 2011-10-06 15:23:28 +0000 |
1285 | @@ -0,0 +1,52 @@ |
1286 | +# -*- encoding: utf-8 -*- |
1287 | +############################################################################## |
1288 | +# |
1289 | +# OpenERP, Open Source Management Solution |
1290 | +# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). |
1291 | +# |
1292 | +# This program is free software: you can redistribute it and/or modify |
1293 | +# it under the terms of the GNU Affero General Public License as |
1294 | +# published by the Free Software Foundation, either version 3 of the |
1295 | +# License, or (at your option) any later version. |
1296 | +# |
1297 | +# This program is distributed in the hope that it will be useful, |
1298 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1299 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1300 | +# GNU Affero General Public License for more details. |
1301 | +# |
1302 | +# You should have received a copy of the GNU Affero General Public License |
1303 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1304 | +# |
1305 | +############################################################################## |
1306 | + |
1307 | +{ |
1308 | + "name" : "Payment Term with Cash Discount", |
1309 | + "version" : "1.07", |
1310 | + "depends" : ["account","account_voucher_credits_us","account_cash_discount"], |
1311 | + "author" : "Tiny and NovaPoint Group LLC", |
1312 | + "description" : "Cash discounts, based on payment terms", |
1313 | + "website" : "http://www.novapointgroup.com/", |
1314 | + "category" : "Generic Modules/Accounting", |
1315 | + "description": """ |
1316 | + This module adds cash discounts on payment terms. Cash discounts |
1317 | + for a payment term can be configured with: |
1318 | + * A number of days, |
1319 | + * A discount (%), |
1320 | + * A debit and a credit account |
1321 | + * Sales and Purchase discounts are added to product and invoice line |
1322 | + """, |
1323 | + "init_xml" : [ |
1324 | + ], |
1325 | + "demo_xml" : [ |
1326 | + ], |
1327 | + "update_xml" : [ |
1328 | + "account_cash_discount_view.xml", |
1329 | + "product_view.xml", |
1330 | + "security/ir.model.access.csv", |
1331 | + ], |
1332 | + "active": False, |
1333 | + "installable": True, |
1334 | + |
1335 | +} |
1336 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1337 | + |
1338 | |
1339 | === added file 'account_cash_discount_us/account_cash_discount_us/account_cash_discount.py' |
1340 | --- account_cash_discount_us/account_cash_discount_us/account_cash_discount.py 1970-01-01 00:00:00 +0000 |
1341 | +++ account_cash_discount_us/account_cash_discount_us/account_cash_discount.py 2011-10-06 15:23:28 +0000 |
1342 | @@ -0,0 +1,730 @@ |
1343 | +# -*- coding: utf-8 -*- |
1344 | +############################################################################## |
1345 | +# |
1346 | +# OpenERP, Open Source Management Solution |
1347 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
1348 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
1349 | +# |
1350 | +# This program is free software: you can redistribute it and/or modify |
1351 | +# it under the terms of the GNU General Public License as published by |
1352 | +# the Free Software Foundation, either version 3 of the License, or |
1353 | +# (at your option) any later version. |
1354 | +# |
1355 | +# This program is distributed in the hope that it will be useful, |
1356 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1357 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1358 | +# GNU General Public License for more details. |
1359 | +# |
1360 | +# You should have received a copy of the GNU General Public License |
1361 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
1362 | +# |
1363 | +############################################################################## |
1364 | + |
1365 | +from collections import defaultdict |
1366 | +from mx.DateTime import RelativeDateTime |
1367 | +from osv import fields, osv |
1368 | +from tools.translate import _ |
1369 | +import decimal_precision as dp |
1370 | +import mx.DateTime |
1371 | + |
1372 | +def _combinations(iterable, r): |
1373 | + ''' |
1374 | + @return: combination generator object |
1375 | + |
1376 | + Example |
1377 | + combinations(’ABCD’, 2) --> AB AC AD BC BD CD |
1378 | + combinations(range(4), 3) --> 012 013 023 123 |
1379 | + ''' |
1380 | + pool = tuple(iterable) |
1381 | + n = len(pool) |
1382 | + if r > n: |
1383 | + return |
1384 | + indices = range(r) |
1385 | + yield tuple(pool[i] for i in indices) |
1386 | + while True: |
1387 | + for i in reversed(range(r)): |
1388 | + if indices[i] != i + n - r: |
1389 | + break |
1390 | + else: |
1391 | + return |
1392 | + indices[i] += 1 |
1393 | + for j in range(i+1, r): |
1394 | + indices[j] = indices[j-1] + 1 |
1395 | + yield tuple(pool[i] for i in indices) |
1396 | + |
1397 | + |
1398 | +class account_payment_term(osv.osv): |
1399 | + _name = "account.payment.term" |
1400 | + _inherit = "account.payment.term" |
1401 | + _columns = { |
1402 | + 'cash_discount_ids': fields.one2many('account.cash.discount', 'payment_id', 'Cash Discounts'), |
1403 | + } |
1404 | + def get_discounts(self, cr, uid, id, base_date, context={}): |
1405 | + """ |
1406 | + return the list of (date,percentage) ordered by date for the |
1407 | + payment term with the corresponding id. return [] if no cash |
1408 | + discount are defined. base_date is the date from where the |
1409 | + discounts are computed. |
1410 | + """ |
1411 | + res=[] |
1412 | + for pt in self.browse(cr, uid, id, context): |
1413 | + |
1414 | + if not pt.cash_discount_ids: |
1415 | + continue |
1416 | + |
1417 | + for d in pt.cash_discount_ids: |
1418 | + res.append( |
1419 | + ((mx.DateTime.strptime(base_date,'%Y-%m-%d') +\ |
1420 | + RelativeDateTime(days=d.delay)).strftime("%Y-%m-%d"), |
1421 | + d.discount) |
1422 | + ) |
1423 | + |
1424 | + res.sort(cmp=lambda x,y: cmp(x[0],y[0])) |
1425 | + return res |
1426 | +account_payment_term() |
1427 | + |
1428 | +class account_invoice(osv.osv): |
1429 | + ''' |
1430 | + Add discount calculation to invoice |
1431 | + ''' |
1432 | + _inherit = 'account.invoice' |
1433 | + |
1434 | + def _get_discount(self, cr, uid, ids, field_name, args, context={}): |
1435 | + ''' |
1436 | + Calculate the value of variable date_discount (Discount Date) and amount_discounted (Discounted Total) |
1437 | + ''' |
1438 | + |
1439 | + if context is None: |
1440 | + context = {} |
1441 | + for invoice in self.browse(cr, uid, ids, context): |
1442 | + res = defaultdict(list) |
1443 | + res[invoice.id] = { |
1444 | + 'date_discount': invoice.date_due, |
1445 | + 'amount_discounted': invoice.amount_total |
1446 | + } |
1447 | + if not invoice.date_invoice: |
1448 | + invoice_date = mx.DateTime.today().strftime("%Y-%m-%d") |
1449 | + self.write(cr, uid, [invoice.id], {'date_invoice': invoice_date}, context) |
1450 | + else: |
1451 | + invoice_date = invoice.date_invoice |
1452 | + discounts = invoice.payment_term and invoice.payment_term.get_discounts(invoice_date, context=context) |
1453 | + if discounts: |
1454 | + line_obj = self.pool.get('account.invoice.line') |
1455 | + discount_total = 0.0 |
1456 | + non_discount_total = 0.0 |
1457 | + for line in invoice.invoice_line: |
1458 | + if line.cash_discount: |
1459 | + discount_total += line.price_subtotal |
1460 | + line_cash_discount = round((1.0 - discounts[0][1]) * line.price_subtotal) |
1461 | + line_obj.write(cr, uid, line.id, {'cash_discount': line_cash_discount}, context) |
1462 | + else: |
1463 | + non_discount_total += line.price_subtotal |
1464 | + line_obj.write(cr, uid, line.id, {'cash_discount': 0.0}, context) |
1465 | + # assume taxes are never discountable |
1466 | + non_discount_total += invoice.amount_tax |
1467 | + # There may be more than one - return the earliest |
1468 | + res[invoice.id] = { |
1469 | + 'date_discount': discounts[0][0], |
1470 | + 'amount_discounted': round(((1.0 - discounts[0][1]) * discount_total) + non_discount_total,2) |
1471 | + } |
1472 | + return defaultdict(type([]),res) |
1473 | + |
1474 | + _columns = { |
1475 | + 'date_discount': fields.function(_get_discount, method=True, type='date', string='Discount Date', multi='all'), |
1476 | + 'amount_discounted': fields.function(_get_discount, method=True, type='float', digits_compute=dp.get_precision('Account'), string='Discounted Total', |
1477 | + multi='all'), |
1478 | + } |
1479 | +account_invoice() |
1480 | + |
1481 | +class account_invoice_pay_writeoff(osv.osv_memory): |
1482 | + """ |
1483 | + Opens the write off amount pay form. |
1484 | + """ |
1485 | + _name = "account.invoice.pay.writeoff" |
1486 | + _description = "Pay Invoice " |
1487 | + _columns = { |
1488 | + 'writeoff_acc_id': fields.many2one('account.account', 'Write-Off account', required=True), |
1489 | + 'writeoff_journal_id': fields.many2one('account.journal', 'Write-Off journal', required=True), |
1490 | + 'comment': fields.char('Comment', size=64, required=True), |
1491 | + 'analytic_id': fields.many2one('account.analytic.account','Analytic Account'), |
1492 | + } |
1493 | + _defaults = { |
1494 | + 'comment': 'Write-Off', |
1495 | + } |
1496 | + |
1497 | +account_invoice_pay_writeoff() |
1498 | + |
1499 | +class account_invoice_pay(osv.osv_memory): |
1500 | + """ |
1501 | + Generate pay invoice wizard, user can make partial or full payment for invoice. |
1502 | + """ |
1503 | + _name = "account.invoice.pay" |
1504 | + _description = "Pay Invoice " |
1505 | + _columns = { |
1506 | + 'amount': fields.float('Amount paid', required=True, digits_compute = dp.get_precision('Account')), |
1507 | + 'name': fields.char('Entry Name', size=64, required=True), |
1508 | + 'date': fields.date('Date payment', required=True), |
1509 | + 'journal_id': fields.many2one('account.journal', 'Journal/Payment Mode', required=True, domain=[('type','=','cash')]), |
1510 | + 'period_id': fields.many2one('account.period', 'Period', required=True), |
1511 | + } |
1512 | + |
1513 | + def view_init(self, cr, uid, ids, context=None): |
1514 | + invoice = self.pool.get('account.invoice').browse(cr, uid, context['active_id'], context=context) |
1515 | + if invoice.state in ['draft', 'proforma2', 'cancel']: |
1516 | + raise osv.except_osv(_('Error !'), _('Can not pay draft/proforma/cancel invoice.')) |
1517 | + pass |
1518 | + |
1519 | + def _get_period(self, cr, uid, context=None): |
1520 | + ''' |
1521 | + Initialise Period |
1522 | + ''' |
1523 | + ids = self.pool.get('account.period').find(cr, uid, context=context) |
1524 | + period_id = False |
1525 | + if len(ids): |
1526 | + period_id = ids[0] |
1527 | + return period_id |
1528 | + |
1529 | + def _get_amount(self, cr, uid, context=None): |
1530 | + ''' |
1531 | + Get default value of Amount paid |
1532 | + ''' |
1533 | + return self.pool.get('account.invoice').browse(cr, uid, context['active_id'], context=context).residual |
1534 | + |
1535 | + _defaults = { |
1536 | + 'date': lambda *a: time.strftime('%Y-%m-%d'), |
1537 | + 'period_id': _get_period, |
1538 | + 'amount': _get_amount, |
1539 | + } |
1540 | +account_invoice_pay() |
1541 | + |
1542 | +class account_voucher(osv.osv): |
1543 | + _name = 'account.voucher' |
1544 | + _inherit = 'account.voucher' |
1545 | + |
1546 | + def _update_discounts(self, lines, vch_date): |
1547 | + date_discount = False |
1548 | + amount_discount = False |
1549 | + for line in lines: |
1550 | + if 'date_discount' in line: |
1551 | + date_discount = line['date_discount'] |
1552 | + amount_discounted = line['amount_discounted'] |
1553 | + else: |
1554 | + return |
1555 | + if line['amount'] >= line['amount_unreconciled']: |
1556 | + amount_discount = 0.0 |
1557 | + elif vch_date <= date_discount and line['amount'] <= line['amount_unreconciled'] and line['amount'] >= amount_discounted: |
1558 | + amount_discount = max(line['amount_unreconciled'] - amount_discounted, 0.0) |
1559 | + elif vch_date <= date_discount and line['amount'] < amount_discounted: |
1560 | + amount_discount = max(line['amount_unreconciled'] - amount_discounted, 0.0) |
1561 | + line['cash_discount'] = amount_discount |
1562 | + line['amount_difference'] = line['amount_unreconciled'] - line['amount'] - amount_discount |
1563 | + |
1564 | + |
1565 | + def onchange_partner_id(self, cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context={}): |
1566 | + ''' |
1567 | + Function to update fields in customer payment form on changing customer |
1568 | + ''' |
1569 | + if context is None: |
1570 | + context = {} |
1571 | + |
1572 | + currency_pool = self.pool.get('res.currency') |
1573 | + journal_pool = self.pool.get('account.journal') |
1574 | + invoice_pool = self.pool.get('account.invoice') |
1575 | + line_pool = self.pool.get('account.voucher.line') |
1576 | + move_line_pool = self.pool.get('account.move.line') |
1577 | + partner_pool = self.pool.get('res.partner') |
1578 | + company_currency = False |
1579 | + |
1580 | + default = super(account_voucher, self).onchange_partner_id(cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context={}) |
1581 | + if not partner_id: |
1582 | + return default |
1583 | + # we have to clear out lines, because new lines will be created by the change |
1584 | + if partner_id and not journal_id: |
1585 | + partner = partner_pool.browse(cr, uid, partner_id, context) |
1586 | + if partner._columns.has_key('payment_meth_id') and partner.payment_meth_id: |
1587 | + payment_mode_pool = self.pool.get('payment.mode') |
1588 | + payment_meth = payment_mode_pool.browse(cr, uid, partner.payment_meth_id.id, context) |
1589 | + if payment_meth: |
1590 | + default['value']['journal_id'] = payment_meth.journal.id |
1591 | + journal_id = payment_meth.journal.id |
1592 | + if ids: |
1593 | + line_ids = line_pool.search(cr, uid, [('voucher_id','=',ids[0])]) |
1594 | + if line_ids: |
1595 | + line_pool.unlink(cr, uid, line_ids) |
1596 | + if journal_id: |
1597 | + journal = journal_pool.browse(cr, uid, journal_id) |
1598 | + company_currency = journal.company_id.currency_id.id |
1599 | + |
1600 | + total_credit = 0.0 |
1601 | + total_debit = 0.0 |
1602 | + vch_date = False |
1603 | + for vch in self.browse(cr, uid, ids): |
1604 | + vch_date = vch.date |
1605 | + if default and 'value' in default and 'line_cr_ids' in default['value']: |
1606 | + for line in default['value']['line_cr_ids']: |
1607 | + invoice_id = invoice_pool.search(cr, uid, [('number', '=', line['name'])]) |
1608 | + if invoice_id: |
1609 | + line['invoice_id'] = invoice_id[0] |
1610 | + invoice = invoice_pool.browse(cr, uid, invoice_id[0], ) |
1611 | + date_discount = invoice.date_discount |
1612 | + amount_discounted = invoice.amount_discounted |
1613 | + line['date_discount'] = date_discount |
1614 | + line['amount_discounted'] = amount_discounted |
1615 | + else: |
1616 | + line['date_discount'] = False |
1617 | + line['amount_discounted'] = 0.0 |
1618 | + line['amount'] = 0.0 |
1619 | + total_credit += line['type'] == 'cr' and line['amount_unreconciled'] or 0.0 |
1620 | + total_debit += line['type'] == 'dr' and line['amount_unreconciled'] or 0.0 |
1621 | + # first, see if we can find an invoice matching the amount to be applied |
1622 | + found = False |
1623 | + def calc_amount(line, total): |
1624 | + return min(line['amount_unreconciled'], total) |
1625 | + lines = default['value']['line_cr_ids'] |
1626 | + if len(lines) == 0: |
1627 | + return default |
1628 | +# return False |
1629 | + # if only one, assign it |
1630 | + if len(lines) == 1: |
1631 | + for line in lines: |
1632 | + if line['type'] == 'cr': |
1633 | + amount = price |
1634 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount |
1635 | + total_credit -= amount |
1636 | + found = True |
1637 | + break |
1638 | + else: |
1639 | + amount = price |
1640 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount |
1641 | + total_debit -= amount |
1642 | + found = True |
1643 | + break |
1644 | + self._update_discounts(lines, vch_date) |
1645 | + if not found: |
1646 | + for line in lines: |
1647 | + if line['amount_unreconciled'] == price: |
1648 | + if line['type'] == 'cr': |
1649 | + amount = calc_amount(line, total_credit) |
1650 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount |
1651 | + total_credit -= amount |
1652 | + found = True |
1653 | + break |
1654 | + else: |
1655 | + amount = calc_amount(line, total_debit) |
1656 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount |
1657 | + total_debit -= amount |
1658 | + found = True |
1659 | + break |
1660 | + if not found: |
1661 | + # see if we can find a combination that matches |
1662 | + def search(lines, price): |
1663 | + for i in range(0, len(lines)): |
1664 | + if lines[i]['amount_unreconciled'] == price: |
1665 | + return [lines[i]] |
1666 | + for i in range(0, len(lines)): |
1667 | + for j in range(i + 1, len(lines)): |
1668 | + if lines[i]['amount_unreconciled'] + lines[j]['amount_unreconciled'] == price: |
1669 | + return [lines[i],lines[j]] |
1670 | + for i in range(0, len(lines)): |
1671 | + for j in range(i + 1, len(lines)): |
1672 | + for k in range(j + 1, len(lines)): |
1673 | + if lines[i]['amount_unreconciled'] + lines[j]['amount_unreconciled'] + lines[k]['amount_unreconciled']== price: |
1674 | + return [lines[i],lines[j],lines[k]] |
1675 | + line_ids = search(lines, price) |
1676 | + |
1677 | + if line_ids: # and sum == price: |
1678 | + for line in line_ids: |
1679 | + if line['type'] == 'cr': |
1680 | + amount = calc_amount(line, line['amount_unreconciled']) |
1681 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) |
1682 | + total_debit -= amount |
1683 | + found = True |
1684 | + else: |
1685 | + amount = calc_amount(line, line['amount_unreconciled']) |
1686 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) |
1687 | + total_credit -= amount |
1688 | + found = True |
1689 | + if not found: |
1690 | + # see if we can find a match using discounted amount |
1691 | + def search2(lines, price): |
1692 | + for i in range(0, len(lines)): |
1693 | + if min(lines[i]['amount_unreconciled'],lines[i]['amount_discounted']) == price: |
1694 | + return [lines[i]] |
1695 | + for i in range(0, len(lines)): |
1696 | + for j in range(i + 1, len(lines)): |
1697 | + if min(lines[i]['amount_unreconciled'],lines[i]['amount_discounted']) + min(lines[j]['amount_unreconciled'],lines[j]['amount_discounted']) == price: |
1698 | + return [lines[i],lines[j]] |
1699 | + for i in range(0, len(lines)): |
1700 | + for j in range(i + 1, len(lines)): |
1701 | + for k in range(j + 1, len(lines)): |
1702 | + if min(lines[i]['amount_unreconciled'],lines[i]['amount_discounted']) + min(lines[j]['amount_unreconciled'],lines[j]['amount_discounted']) + min(lines[k]['amount_unreconciled'],lines[k]['amount_discounted']) == price: |
1703 | + return [lines[i],lines[j],lines[k]] |
1704 | + line_ids = search(lines, price) |
1705 | + lines = default['value']['line_cr_ids'] |
1706 | + line_ids = search2(lines, price) |
1707 | + if line_ids: |
1708 | + for line in line_ids: |
1709 | + if line['type'] == 'cr': |
1710 | + amount = calc_amount(line, min(line['amount_unreconciled'],line['amount_discounted'])) |
1711 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, min(line['amount_unreconciled'],line['amount_discounted'])) |
1712 | + total_debit -= amount |
1713 | + found = True |
1714 | + else: |
1715 | + amount = calc_amount(line, min(line['amount_unreconciled'],line['amount_discounted'])) |
1716 | + line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, min(line['amount_unreconciled'],line['amount_discounted'])) |
1717 | + total_credit -= amount |
1718 | + found = True |
1719 | + lines = default['value']['line_cr_ids'] |
1720 | + ''' |
1721 | + FIXME : removing amount from line_dr_ids (Credits on customer payment form) line. |
1722 | + and amount from line_cr_ids (Invoice and outstanding transactions on customer payment form) line |
1723 | + I do not think this this is a good solution. But it works. |
1724 | + The whole "onchange_partner_id" function need a re-thinking (may have to rewrite it completely instead of calling super ). |
1725 | + ''' |
1726 | + if default: |
1727 | + for credit_line in default['value'].get('line_dr_ids',[]): |
1728 | + credit_line['amount'] = 0.0 |
1729 | + for invoce_line in default['value'].get('line_cr_ids',[]): |
1730 | + invoce_line['amount'] = 0.0 |
1731 | + invoce_line['amount_difference'] = invoce_line['amount_unreconciled'] |
1732 | + return default |
1733 | + |
1734 | + def calc_cash_discount(self, cr, uid, ids, vch, line, context={}): |
1735 | + ''' |
1736 | + Calculate discount per line |
1737 | + ''' |
1738 | + total_allocated = 0.0 |
1739 | + for line in vch.line_ids: |
1740 | + total_allocated += line.amount |
1741 | + context.update({'total_allocated': total_allocated, 'total_amount': vch.date}) |
1742 | + amount_discount = 0.0 |
1743 | + if line.amount >= line.amount_unreconciled or line.amount < 0.01 : |
1744 | + amount_discount = 0.0 |
1745 | + elif line.amount >= line.amount_discounted and vch.date <= line.date_discount: |
1746 | + amount_discount = line.amount_unreconciled - line.amount_discounted |
1747 | + return amount_discount |
1748 | + |
1749 | +account_voucher() |
1750 | + |
1751 | +class account_voucher_line(osv.osv): |
1752 | + _name = 'account.voucher.line' |
1753 | + _inherit = 'account.voucher.line' |
1754 | + |
1755 | + def _update_credit_lines(self,cr, uid, ids, context): |
1756 | + ''' |
1757 | + Function to update the credit lines in payment lines |
1758 | + ''' |
1759 | + credits_used_pool = self.pool.get('account.voucher.line.credits_to_use') |
1760 | + for line in self.browse(cr , uid, ids, context): |
1761 | + credits_lines_used = [x.orginal_credit_line_id.id for x in line.available_credits] |
1762 | + for credit_line in line.voucher_id.line_dr_ids : |
1763 | + if credit_line.id not in credits_lines_used and line.invoice_id and line.invoice_id.payment_term: |
1764 | + print credit_line |
1765 | + credits_used_pool.create(cr, uid, { |
1766 | + 'voucher_line_id': line.id, |
1767 | + 'orginal_credit_line_id':credit_line.id, |
1768 | + 'use_credit': False, |
1769 | + 'inv_credit': credit_line.move_line_id.id, |
1770 | + 'discount_window_date': credit_line.date_original, |
1771 | + 'orginal_amount': credit_line.amount_original, |
1772 | + 'available_amount': credit_line.amount_unreconciled - credit_line.pending_credits, |
1773 | + 'discount_amount': 0.0, |
1774 | + 'gl_account' : credit_line.account_id.id,}) |
1775 | + else : |
1776 | + to_update_credit_line_ids = credits_used_pool.search(cr,uid,[('voucher_line_id','=',line.id),( 'orginal_credit_line_id','=',credit_line.id)], context=context) |
1777 | + if to_update_credit_line_ids: |
1778 | + credits_used_pool.write(cr, uid,to_update_credit_line_ids,{'available_amount': credit_line.amount_unreconciled-credit_line.pending_credits}, context=context) |
1779 | + |
1780 | + def _update_discount_lines(self,cr, uid, ids, context): |
1781 | + ''' |
1782 | + Function to update the discount lines in payment lines |
1783 | + ''' |
1784 | + |
1785 | + discount_used_pool = self.pool.get('account.voucher.line.discount_to_use') |
1786 | + user_pool = self.pool.get('res.users') |
1787 | + user = user_pool.browse(cr, uid, uid, context) |
1788 | + for line in self.browse(cr , uid, ids, context): |
1789 | + if line.invoice_id : |
1790 | + if not line.invoice_id.date_discount or not line.voucher_id.date or line.voucher_id.date > line.invoice_id.date_discount: |
1791 | + ''' |
1792 | + customer is not eligible for the discount |
1793 | + ''' |
1794 | + continue |
1795 | + discount = line.invoice_id.amount_total - line.invoice_id.amount_discounted |
1796 | + date_discount = line.invoice_id.date_discount |
1797 | + discount_found = False |
1798 | + for discount_line in line.available_discounts: |
1799 | + #if abs(discount - discount_line.proposed_discount) < 0.01 and line.invoice_id.payment_term.id == discount_line.inv_payment_terms.id: |
1800 | + if line.invoice_id.payment_term.id == discount_line.inv_payment_terms.id: |
1801 | + discount_found = True |
1802 | + continue |
1803 | + if not discount_found and user.company_id.sales_discount_account: |
1804 | + ''' |
1805 | + TODO : calculate/findout the discount_window_date (The last day of the discount window. To receive discounts payments must be paid on or before this date.) |
1806 | + ''' |
1807 | + discount_used_pool.create(cr, uid, { |
1808 | + 'voucher_line_id': line.id, |
1809 | + 'use_discount': False, |
1810 | + 'inv_payment_terms':line.invoice_id.payment_term.id , |
1811 | + 'discount_window_date': date_discount, |
1812 | + 'proposed_discount': discount, |
1813 | + 'discount_amount': 0.0, |
1814 | + 'gl_account':user.company_id.sales_discount_account.id |
1815 | + }, context=context) |
1816 | + |
1817 | + |
1818 | + def _compute_discount_used(self, cr, uid, ids, name, args, context=None): |
1819 | + ''' |
1820 | + Function to calculate the value of variable discount used |
1821 | + ''' |
1822 | + res = {} |
1823 | + for line in self.browse(cr, uid, ids): |
1824 | + res[line.id] = 0.0 |
1825 | + for discount_line in line.available_discounts: |
1826 | + if discount_line.use_discount : |
1827 | + res[line.id] += discount_line.discount_amount |
1828 | + return res |
1829 | + |
1830 | + def _compute_balance(self, cr, uid, ids, name, args, context=None): |
1831 | + ''' |
1832 | + Function to calculate the value of variables Cash Discount, Interest and Amt Due |
1833 | + ''' |
1834 | + currency_pool = self.pool.get('res.currency') |
1835 | + rs_data = super(account_voucher_line, self)._compute_balance(cr, uid, ids, name, args, context) |
1836 | + for line in self.browse(cr, uid, ids): |
1837 | + amount_cash_discount = self.calc_cash_discount(cr, uid, ids, vch, line) |
1838 | + amount_interest = self.calc_interest(vch, line, line.amount) |
1839 | + amount_unreconciled = 0.0 |
1840 | + move_line = line.move_line_id or False |
1841 | + if move_line: |
1842 | + amount_unreconciled = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.amount_unreconciled - amount_cash_discount - line.writeoff) |
1843 | + rs_data[line.id] = {'cash_discount': amount_cash_discount, 'interest': amount_interest, 'amount_unreconciled': amount_unreconciled} |
1844 | + return rs_data |
1845 | + |
1846 | + def _get_discount(self, cr, uid, ids, field_name, args, context={}): |
1847 | + """ |
1848 | + Function to calculate the value of variable date_discount,amount_discounted,cash_discount,amount_difference |
1849 | + return the values as dictionary |
1850 | + """ |
1851 | + |
1852 | + if context is None: |
1853 | + context = {} |
1854 | + invoice_obj = self.pool.get('account.invoice') |
1855 | + move_line_obj = self.pool.get('account.move.line') |
1856 | + voucher_line = self.browse(cr, uid, ids) |
1857 | + vch = self.pool.get('account.voucher').browse(cr, uid, voucher_line[0].voucher_id.id) |
1858 | + res = {} |
1859 | + for line in voucher_line: |
1860 | + if line.type == 'dr': |
1861 | + res[line.id] = { |
1862 | + 'date_discount': '', |
1863 | + 'amount_discounted': line.amount, |
1864 | + 'cash_discount': 0.0, |
1865 | + 'amount_difference': line.amount_unreconciled - line.amount |
1866 | + } |
1867 | + continue |
1868 | + move_line = move_line_obj.browse(cr, uid, line.move_line_id.id) |
1869 | + invoice_number = move_line.name or move_line.ref |
1870 | + invoice_id = False |
1871 | + if invoice_number and invoice_number != '/': |
1872 | + invoice_id = invoice_obj.search(cr, uid, [('number', '=', str(invoice_number))]) |
1873 | + if not invoice_id: |
1874 | + move = self.pool.get('account.move').browse(cr, uid, move_line.move_id.id) |
1875 | + if move: |
1876 | + invoice_number = move.name or move.ref |
1877 | + if invoice_number and invoice_number != '/': |
1878 | + invoice_id = invoice_obj.search(cr, uid, [('number', '=', str(invoice_number))]) |
1879 | + if invoice_id: |
1880 | + for invoice in invoice_obj.browse(cr, uid, invoice_id, context): |
1881 | + date_discount = invoice.date_due |
1882 | + amount_discounted = invoice.amount_total |
1883 | + res[line.id] = { |
1884 | + 'date_discount': invoice.date_due, |
1885 | + 'amount_discounted': invoice.amount_total |
1886 | + } |
1887 | + if not invoice.date_invoice: |
1888 | + invoice_date = mx.DateTime.today().strftime("%Y-%m-%d") |
1889 | + self.write(cr, uid, [invoice.id], {'date_invoice': invoice_date}, context) |
1890 | + else: |
1891 | + invoice_date = invoice.date_invoice |
1892 | + discounts = invoice.payment_term and invoice.payment_term.get_discounts(invoice_date, context=context) or False |
1893 | + if discounts: |
1894 | + line_obj = self.pool.get('account.invoice.line') |
1895 | + discount_total = 0.0 |
1896 | + non_discount_total = 0.0 |
1897 | + for invline in invoice.invoice_line: |
1898 | + if invline.cash_discount: |
1899 | + discount_total += invline.price_subtotal |
1900 | + line_cash_discount = round((1.0 - discounts[0][1]) * invline.price_subtotal) |
1901 | + line_obj.write(cr, uid, invline.id, {'cash_discount': line_cash_discount}, context) |
1902 | + else: |
1903 | + non_discount_total += invline.price_subtotal |
1904 | + line_obj.write(cr, uid, invline.id, {'cash_discount': 0.0}, context) |
1905 | + # assume taxes are never discountable |
1906 | + non_discount_total += invoice.amount_tax |
1907 | + # There may be more than one - return the earliest |
1908 | + date_discount = discounts[0][0] |
1909 | + amount_discounted = round(((1.0 - discounts[0][1]) * discount_total) + non_discount_total,2) |
1910 | + amount_discount = 0.0 |
1911 | + if line.amount >= line.amount_unreconciled or line.amount < 0.01: |
1912 | + amount_discount = 0.0 |
1913 | + elif vch.date <= date_discount and line.amount <= line.amount_unreconciled: |
1914 | + amount_discount = max(line.amount_unreconciled - amount_discounted, 0.0) |
1915 | + elif vch.date <= date_discount and line.amount < amount_discounted: |
1916 | + amount_discount = max(line.amount_unreconciled - amount_discounted,0.0) |
1917 | + else: |
1918 | + amount_discount = 0.0 |
1919 | + |
1920 | + res[line.id] = { |
1921 | + 'date_discount': date_discount, |
1922 | + 'amount_discounted': amount_discounted, |
1923 | + 'cash_discount': amount_discount, |
1924 | + 'amount_difference': line.amount_unreconciled - line.amount - line.credit_used - line.discount_used - (line._columns.has_key('writeoff_amount') and line['writeoff_amount'])#- amount_discount |
1925 | + } |
1926 | + return defaultdict(type([]),res) |
1927 | + |
1928 | + _columns = { |
1929 | + 'date_discount': fields.function(_get_discount, method=True, type='date', string='Discount Date', |
1930 | + multi='all'), |
1931 | + 'amount_discounted': fields.function(_get_discount, method=True, type='float', digits_compute=dp.get_precision('Account'), string='Discounted Total', |
1932 | + multi='all'), |
1933 | + 'cash_discount': fields.function(_get_discount, method=True, type='float', multi="all", digits_compute=dp.get_precision('Account'), string='Cash Discount'), |
1934 | + 'amount_difference': fields.function(_get_discount, method=True, multi='all', type='float', string='Unpaid Amt', digits=(16, 2) ), |
1935 | + 'interest': fields.float(string='Interest', digits=(16,2)), |
1936 | + |
1937 | + #'discount_used':fields.float('Discount used', readonly=True), |
1938 | + 'discount_used': fields.function(_compute_discount_used, method=True, type='float', string='Discount Used', store=False, readonly=True), |
1939 | + 'available_discounts':fields.one2many('account.voucher.line.discount_to_use', 'voucher_line_id', 'Available Discounts' ), |
1940 | + } |
1941 | + def clear_values(self, cr, uid, ids, context={}): |
1942 | + ''' |
1943 | + Clear the selected credits, discounts and writeoffs from voucher line |
1944 | + ''' |
1945 | + voucher_line = self.browse(cr,uid,ids[0]) |
1946 | + if voucher_line._columns.has_key('writeoff_ids'): |
1947 | + for lines in self.read(cr,uid,ids,['available_credits','writeoff_ids','available_discounts']): |
1948 | + lines['writeoff_ids'] and self.pool.get('account.voucher.line.writeoff').unlink(cr,uid,lines['writeoff_ids']) |
1949 | + lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'],{ |
1950 | + 'use_credit':False, |
1951 | + 'discount_amount':0.0}) |
1952 | + lines['available_discounts'] and self.pool.get('account.voucher.line.discount_to_use').write(cr,uid,lines['available_discounts'],{ |
1953 | + 'use_discount':False, |
1954 | + 'discount_amount':0.0}) |
1955 | + else: |
1956 | + for lines in self.read(cr,uid,ids,['available_credits','writeoff_ids','available_discounts']): |
1957 | + lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'],{ |
1958 | + 'use_credit':False, |
1959 | + 'discount_amount':0.0}) |
1960 | + lines['available_discounts'] and self.pool.get('account.voucher.line.discount_to_use').write(cr,uid,lines['available_discounts'],{ |
1961 | + 'use_discount':False, |
1962 | + 'discount_amount':0.0}) |
1963 | + return True |
1964 | +account_voucher_line() |
1965 | + |
1966 | +class product_product(osv.osv): |
1967 | + ''' |
1968 | + Add new account configuration fields to product |
1969 | + ''' |
1970 | + _name = "product.product" |
1971 | + _inherit = 'product.product' |
1972 | + _columns = { |
1973 | + 'cash_discount': fields.boolean('Cash Discount?'), |
1974 | + 'purchase_discount_account': fields.many2one('account.account', 'Purchase Discount Account', domain=[('user_type','=','COGS')]), |
1975 | + 'sales_discount_account': fields.many2one('account.account', 'Sales Discount Account', domain=[('type','!=','view'),('type','!=','consolidation'),('user_type','ilike','income')]), |
1976 | + 'purchase_discount_journal': fields.many2one('account.journal', 'Purchase Discount Journal', domain=[('type','!=','view'),('type','!=','consolidation'),('type','=','purchase')]), |
1977 | + 'sales_discount_journal': fields.many2one('account.journal', 'Sales Discount Journal', domain=[('type','=','sale')]), |
1978 | + } |
1979 | + _defaults = { |
1980 | + 'cash_discount' : lambda *a : True, |
1981 | + } |
1982 | +product_product() |
1983 | + |
1984 | +class account_invoice_line(osv.osv): |
1985 | + ''' |
1986 | + option to disable discount calculation per invoice line |
1987 | + ''' |
1988 | + _name = 'account.invoice.line' |
1989 | + _inherit = 'account.invoice.line' |
1990 | + _columns = { |
1991 | + 'cash_discount': fields.boolean('Cash Discount?'), |
1992 | + } |
1993 | + _defaults = { |
1994 | + 'cash_discount' : lambda *a : True, |
1995 | + } |
1996 | + def product_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, address_invoice_id=False, currency_id=False, context=None): |
1997 | + ''' |
1998 | + check if the discount is applicable to newly selected product |
1999 | + ''' |
2000 | + result = {} |
2001 | + result = super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, fposition_id, price_unit, address_invoice_id, currency_id, context) |
2002 | + if product: |
2003 | + res = self.pool.get('product.product').browse(cr, uid, product, context=context) |
2004 | + result['value']['cash_discount'] = res.cash_discount |
2005 | + else: |
2006 | + result['value']['cash_discount'] = True |
2007 | + return result |
2008 | +account_invoice_line() |
2009 | + |
2010 | +class res_company(osv.osv): |
2011 | + ''' |
2012 | + New account configuration fields on copmany form |
2013 | + ''' |
2014 | + _name = 'res.company' |
2015 | + _inherit = 'res.company' |
2016 | + _columns = { |
2017 | + 'purchase_discount_account': fields.many2one('account.account', 'Purchase Discount Account', domain=[('user_type','=','COGS'),('type','!=','view'),('type','!=','consolidation')]), |
2018 | + 'sales_discount_account': fields.many2one('account.account', 'Sales Discount Account', domain=[('user_type','=','Income'),('type','!=','view'),('type','!=','consolidation')]), |
2019 | + 'purchase_discount_journal': fields.many2one('account.journal', 'Purchase Discount Journal', domain=[('type','=','purchase')]), |
2020 | + 'sales_discount_journal': fields.many2one('account.journal', 'Sales Discount Journal', domain=[('type','=','sale')]), |
2021 | + } |
2022 | +res_company() |
2023 | + |
2024 | +class account_voucher_line_discount_to_use(osv.osv): |
2025 | + ''' |
2026 | + Dynamically generated discount lines that are applicable per voucher line |
2027 | + ''' |
2028 | + _name = "account.voucher.line.discount_to_use" |
2029 | + _rec_name = 'inv_credit' |
2030 | + _columns = { |
2031 | + 'voucher_line_id': fields.many2one('account.voucher.line', 'Account Voucher Line', ondelete='cascade', readonly=True), |
2032 | + 'use_discount': fields.boolean('Use Discount',help='Used to indicate if the cash discount should be used/taken when calculating payment.', required=True), |
2033 | + 'inv_payment_terms': fields.many2one('account.payment.term', 'Invoice Payment Terms', help='Payments terms description', ), |
2034 | + 'discount_window_date': fields.date('Discount Window Date',help='The last day of the discount window. To receive discounts payments must be paid on or before this date.'), |
2035 | + |
2036 | + |
2037 | + 'proposed_discount': fields.float('Proposed Discount',help='This is the proposed full discount based on the Invoice Payment Terms and the Original Amount.', readonly=True), |
2038 | + 'discount_amount': fields.float('Discount Amt',help='Enter the amount of discount to be given.', required=True), |
2039 | + 'gl_account' : fields.many2one('account.account', 'G/L Account',help='Enter the General Ledger account number to record taking the cash discount.', required=True), |
2040 | + } |
2041 | + def onchage_use_discount(self, cr, uid, ids, use_discount, proposed_discount, context=None): |
2042 | + ''' |
2043 | + Fill the value with proposed discount when use discount check box is clicked and remove the value when use discount is unchecked |
2044 | + ''' |
2045 | + res = {} |
2046 | + if use_discount: |
2047 | + res['value'] = {'discount_amount': proposed_discount} |
2048 | + else: |
2049 | + res['value'] = {'discount_amount': 0} |
2050 | + return res |
2051 | + def onchage_discount_amount(self, cr, uid, ids, proposed_discount, discount_amount, context=None): |
2052 | + ''' |
2053 | + Function to check discount amount entered in discount line of payment line |
2054 | + ''' |
2055 | + res = {} |
2056 | + if discount_amount < 0: |
2057 | + res['value'] = {'discount_amount': 0, 'use_discount':False } |
2058 | + res['warning'] = {'title': 'Discount not in the limit', 'message': 'Discount should not be a negative value.'} |
2059 | + return res |
2060 | + if discount_amount > proposed_discount: |
2061 | + res['value'] = {'discount_amount': proposed_discount, 'use_discount':True } |
2062 | + res['warning'] = {'title': 'Discount not in the limit', 'message': 'Please adjust the Discount Amt value to be less than or equal the Proposed Discount.'} |
2063 | + return res |
2064 | + if discount_amount == 0.0: |
2065 | + res['value'] = { 'use_discount':False } |
2066 | + else: |
2067 | + res['value'] = { 'use_discount':True } |
2068 | + return res |
2069 | +account_voucher_line_discount_to_use() |
2070 | + |
2071 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
2072 | + |
2073 | |
2074 | === added file 'account_cash_discount_us/account_cash_discount_us/account_cash_discount_view.xml' |
2075 | --- account_cash_discount_us/account_cash_discount_us/account_cash_discount_view.xml 1970-01-01 00:00:00 +0000 |
2076 | +++ account_cash_discount_us/account_cash_discount_us/account_cash_discount_view.xml 2011-10-06 15:23:28 +0000 |
2077 | @@ -0,0 +1,256 @@ |
2078 | +<?xml version="1.0"?> |
2079 | +<openerp> |
2080 | + <data> |
2081 | + |
2082 | + <!-- cash discount --> |
2083 | + |
2084 | + <record id="invoice_supplier_form_jdc" model="ir.ui.view"> |
2085 | + <field name="name">account.invoice.supplier.form.jdc</field> |
2086 | + <field name="model">account.invoice</field> |
2087 | + <field name="type">form</field> |
2088 | + <field name="priority">2</field> |
2089 | + <field name="inherit_id" ref="account.invoice_supplier_form"/> |
2090 | + <field name="arch" type="xml"> |
2091 | + <xpath expr="/form/notebook/page/field[@name='check_total']" position="after"> |
2092 | + <field name="date_discount"/> |
2093 | + <field name="amount_discounted"/> |
2094 | + </xpath> |
2095 | + </field> |
2096 | + </record> |
2097 | + <record id="invoice_form_jdc1" model="ir.ui.view"> |
2098 | + <field name="name">account.invoice.form.jdc1</field> |
2099 | + <field name="model">account.invoice</field> |
2100 | + <field name="type">form</field> |
2101 | + <field name="inherit_id" ref="account.invoice_form"/> |
2102 | + <field name="arch" type="xml"> |
2103 | + <xpath expr="/form/notebook/page[@string='Invoice']/field[@name='invoice_line']" position="before"> |
2104 | + <group colspan="2" col="4"> |
2105 | + <field name="date_discount"/> |
2106 | + <field name="amount_discounted"/> |
2107 | + </group> |
2108 | + </xpath> |
2109 | + </field> |
2110 | + </record> |
2111 | + |
2112 | + |
2113 | + <!-- |
2114 | + Invoice Line |
2115 | + --> |
2116 | + <record id="view_invoice_line_form_discount" model="ir.ui.view"> |
2117 | + <field name="name">account.invoice.line.form.discount</field> |
2118 | + <field name="model">account.invoice.line</field> |
2119 | + <field name="inherit_id" ref="account.view_invoice_line_form"/> |
2120 | + <field name="type">form</field> |
2121 | + <field name="arch" type="xml"> |
2122 | + <xpath expr="/form/notebook/page/field[@name='discount']" position="after"> |
2123 | + <field name="cash_discount"/> |
2124 | + </xpath> |
2125 | + </field> |
2126 | + </record> |
2127 | + |
2128 | + <!-- |
2129 | + Products |
2130 | + --> |
2131 | + <record id="product_normal_form_view_discount" model="ir.ui.view"> |
2132 | + <field name="name">product.normal.form.discount</field> |
2133 | + <field name="model">product.product</field> |
2134 | + <field name="type">form</field> |
2135 | + <field eval="7" name="priority"/> |
2136 | + <field name="inherit_id" ref="product.product_normal_form_view"/> |
2137 | + <field name="arch" type="xml"> |
2138 | + <xpath expr="/form/notebook/page[@string='Suppliers']/field[@name='seller_ids']" position="after"> |
2139 | + <field name="cash_discount"/> |
2140 | + </xpath> |
2141 | + </field> |
2142 | + </record> |
2143 | + |
2144 | + <!-- |
2145 | + Company |
2146 | + --> |
2147 | + <record id="view_company_form_jdc2" model="ir.ui.view"> |
2148 | + <field name="name">res.company.form.jdc2</field> |
2149 | + <field name="model">res.company</field> |
2150 | + <field name="type">form</field> |
2151 | + <field name="inherit_id" ref="account_voucher_credits_us.view_company_form_jdc3"/> |
2152 | + <field name="priority" eval="1"/> |
2153 | + <field name="arch" type="xml"> |
2154 | + <xpath expr="/form/notebook/page[@string='Accounting']/field[@name='writeoff_account']" position="before"> |
2155 | + <field name="sales_discount_account" colspan="2" /> |
2156 | + <field name="purchase_discount_account" colspan="2" /> |
2157 | + <field name="sales_discount_journal" colspan="2"/> |
2158 | + <field name="purchase_discount_journal" colspan="2"/> |
2159 | + </xpath> |
2160 | + </field> |
2161 | + </record> |
2162 | + |
2163 | + <!-- Discount --> |
2164 | + |
2165 | + <record model="ir.ui.view" id="view_account_wizard_discount_form"> |
2166 | + <field name="name">account.wizard.discount.form</field> |
2167 | + <field name="model">account.wizard.discount</field> |
2168 | + <field name="type">form</field> |
2169 | + <field name="arch" type="xml"> |
2170 | + <form string="Discount"> |
2171 | + <field name="use_discount" select="1"/> |
2172 | + <field name="inv_payment_terms" select="1" readonly="1"/> |
2173 | + <field name="discount_window_date" select="1"/> |
2174 | + <field name="proposed_discount" select="1"/> |
2175 | + <field name="discount_amount" select="1"/> |
2176 | + <field name="gl_account" select="1"/> |
2177 | + </form> |
2178 | + </field> |
2179 | + </record> |
2180 | + |
2181 | + <record model="ir.ui.view" id="view_account_wizard_discount_tree"> |
2182 | + <field name="name">account.wizard.discount.tree</field> |
2183 | + <field name="model">account.wizard.discount</field> |
2184 | + <field name="type">tree</field> |
2185 | + <field name="arch" type="xml"> |
2186 | + <tree string="Discount" editable="bottom"> |
2187 | + <field name="use_discount" select="1"/> |
2188 | + <field name="inv_payment_terms" select="1" readonly="1"/> |
2189 | + <field name="discount_window_date" select="1"/> |
2190 | + <field name="proposed_discount" select="1"/> |
2191 | + <field name="discount_amount" select="1"/> |
2192 | + <field name="gl_account" select="1"/> |
2193 | + </tree> |
2194 | + </field> |
2195 | + </record> |
2196 | + <!-- credit --> |
2197 | + |
2198 | + <record model="ir.ui.view" id="view_account_wizard_credit_form"> |
2199 | + <field name="name">account.wizard.credit.form</field> |
2200 | + <field name="model">account.wizard.credit</field> |
2201 | + <field name="type">form</field> |
2202 | + <field name="arch" type="xml"> |
2203 | + <form string="Credits"> |
2204 | + <field name="use_credit" select="1"/> |
2205 | + <field name="inv_credit" select="1" readonly="1"/> |
2206 | + <field name="discount_window_date" select="1" readonly="1"/> |
2207 | + <field name="proposed_discount" select="1" readonly="1"/> |
2208 | + <field name="discount_amount" select="1" /> |
2209 | + <field name="credit_bal" select="1" readonly="1"/> |
2210 | + <field name="gl_account" select="1" readonly="1"/> |
2211 | + </form> |
2212 | + </field> |
2213 | + </record> |
2214 | + |
2215 | + <record model="ir.ui.view" id="view_account_wizard_credit_tree"> |
2216 | + <field name="name">account.wizard.credit.tree</field> |
2217 | + <field name="model">account.wizard.credit</field> |
2218 | + <field name="type">tree</field> |
2219 | + <field name="arch" type="xml"> |
2220 | + <tree string="Credits" editable="bottom"> |
2221 | + <field name="use_credit" select="1"/> |
2222 | + <field name="inv_credit" select="1" readonly="1"/> |
2223 | + <field name="discount_window_date" select="1" readonly="1"/> |
2224 | + <field name="proposed_discount" select="1" readonly="1"/> |
2225 | + <field name="discount_amount" select="1" /> |
2226 | + <field name="credit_bal" select="1" readonly="1"/> |
2227 | + <field name="gl_account" select="1" readonly="1"/> |
2228 | + </tree> |
2229 | + </field> |
2230 | + </record> |
2231 | + |
2232 | + |
2233 | + <!-- credit used --> |
2234 | + |
2235 | + <record model="ir.ui.view" id="view_account_wizard_credit_used_form"> |
2236 | + <field name="name">account.wizard.credit.used.form</field> |
2237 | + <field name="model">account.wizard.credit.used</field> |
2238 | + <field name="type">form</field> |
2239 | + <field name="arch" type="xml"> |
2240 | + <form string="Previously Applied Credit"> |
2241 | + <field name="date_used" select="1"/> |
2242 | + <field name="inv_credit" select="1"/> |
2243 | + <field name="discount_window_date" select="1"/> |
2244 | + <field name="proposed_discount" select="1"/> |
2245 | + <field name="amt_used" select="1"/> |
2246 | + <field name="inv_move" select="1"/> |
2247 | + <field name="gl_account" select="1"/> |
2248 | + </form> |
2249 | + </field> |
2250 | + </record> |
2251 | + |
2252 | + <record model="ir.ui.view" id="view_account_wizard_credit_used_tree"> |
2253 | + <field name="name">account.wizard.credit.used.tree</field> |
2254 | + <field name="model">account.wizard.credit.used</field> |
2255 | + <field name="type">tree</field> |
2256 | + <field name="arch" type="xml"> |
2257 | + <tree string="Previously Applied Credit" editable="bottom"> |
2258 | + <field name="date_used" select="1"/> |
2259 | + <field name="inv_credit" select="1"/> |
2260 | + <field name="discount_window_date" select="1"/> |
2261 | + <field name="proposed_discount" select="1"/> |
2262 | + <field name="amt_used" select="1"/> |
2263 | + <field name="inv_move" select="1"/> |
2264 | + <field name="gl_account" select="1"/> |
2265 | + </tree> |
2266 | + </field> |
2267 | + </record> |
2268 | + |
2269 | + <!-- customer payment form modification for discount --> |
2270 | + |
2271 | + |
2272 | + <record model="ir.ui.view" id="view_vendor_receipt_form_2"> |
2273 | + <field name="name">account.voucher.receipt.form.2</field> |
2274 | + <field name="model">account.voucher</field> |
2275 | + <field name="type">form</field> |
2276 | + <field name="inherit_id" ref="account_voucher_credits_us.view_vendor_receipt_form_1"/> |
2277 | + <field name="arch" type="xml"> |
2278 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field[@name='line_cr_ids']/form/group[@string='Invoice']/group[@color='red']/field[@name='credit_used']" position="before"> |
2279 | + <field name="discount_used"/> |
2280 | + <newline /> |
2281 | + </xpath> |
2282 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field/tree/field[@name='credit_used']" position="before"> |
2283 | + <field name="discount_used"/> |
2284 | + <newline/> |
2285 | + </xpath> |
2286 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field[@name='line_cr_ids']/form/notebook/page[@string='Credit']" position="before"> |
2287 | + <page string="Discount"> |
2288 | + <field name="available_discounts" nolabel="1" colspan="4" string="Avilable Discounts" view_mode="tree" /> |
2289 | + </page> |
2290 | + </xpath> |
2291 | + </field> |
2292 | + </record> |
2293 | + |
2294 | + |
2295 | + <record model="ir.ui.view" id="view_account_voucher_line_discount_to_use_tree"> |
2296 | + <field name="name">account.voucher.line.discount_to_use.tree</field> |
2297 | + <field name="model">account.voucher.line.discount_to_use</field> |
2298 | + <field name="type">tree</field> |
2299 | + <field name="arch" type="xml"> |
2300 | + <tree string="Available Discounts" editable="top"> |
2301 | + <field name="use_discount" width="125" on_change="onchage_use_discount(use_discount, proposed_discount)"/> |
2302 | + <field name="inv_payment_terms"/> |
2303 | + <field name="discount_window_date"/> |
2304 | + <field name="proposed_discount"/> |
2305 | + <field name="discount_amount" on_change="onchage_discount_amount(proposed_discount, discount_amount)"/> |
2306 | + <field name="gl_account"/> |
2307 | + </tree> |
2308 | + </field> |
2309 | + </record> |
2310 | + |
2311 | + <record model="ir.ui.view" id="view_payment_term_form_inherited"> |
2312 | + <field name="name">account.payment.term.form.inherited</field> |
2313 | + <field name="model">account.payment.term</field> |
2314 | + <field name="inherit_id" ref="account_cash_discount.view_payment_term_form"/> |
2315 | + <field name="arch" type="xml"> |
2316 | + <separator string="Cash Discount" colspan="4" position="replace"/> |
2317 | + </field> |
2318 | + </record> |
2319 | + <record model="ir.ui.view" id="view_payment_term_form_inherited2"> |
2320 | + <field name="name">account.payment.term.form.inherited2</field> |
2321 | + <field name="model">account.payment.term</field> |
2322 | + <field name="inherit_id" ref="view_payment_term_form_inherited"/> |
2323 | + <field name="arch" type="xml"> |
2324 | + <field name="cash_discount_ids" colspan="4" position="replace"> |
2325 | + <separator string="Cash Discount" colspan="4"/> |
2326 | + <field name="cash_discount_ids" colspan="4" nolabel="1"/> |
2327 | + </field> |
2328 | + </field> |
2329 | + </record> |
2330 | + |
2331 | + |
2332 | + </data> |
2333 | +</openerp> |
2334 | |
2335 | === added directory 'account_cash_discount_us/account_cash_discount_us/i18n' |
2336 | === added file 'account_cash_discount_us/account_cash_discount_us/i18n/account_cash_discount.pot' |
2337 | --- account_cash_discount_us/account_cash_discount_us/i18n/account_cash_discount.pot 1970-01-01 00:00:00 +0000 |
2338 | +++ account_cash_discount_us/account_cash_discount_us/i18n/account_cash_discount.pot 2011-10-06 15:23:28 +0000 |
2339 | @@ -0,0 +1,85 @@ |
2340 | +# Translation of OpenERP Server. |
2341 | +# This file contains the translation of the following modules: |
2342 | +# * account_cash_discount |
2343 | +# |
2344 | +msgid "" |
2345 | +msgstr "" |
2346 | +"Project-Id-Version: OpenERP Server 5.0.6\n" |
2347 | +"Report-Msgid-Bugs-To: support@openerp.com\n" |
2348 | +"POT-Creation-Date: 2009-11-24 13:09:22+0000\n" |
2349 | +"PO-Revision-Date: 2009-11-24 13:09:22+0000\n" |
2350 | +"Last-Translator: <>\n" |
2351 | +"Language-Team: \n" |
2352 | +"MIME-Version: 1.0\n" |
2353 | +"Content-Type: text/plain; charset=UTF-8\n" |
2354 | +"Content-Transfer-Encoding: \n" |
2355 | +"Plural-Forms: \n" |
2356 | + |
2357 | +#. module: account_cash_discount |
2358 | +#: constraint:ir.ui.view:0 |
2359 | +msgid "Invalid XML for View Architecture!" |
2360 | +msgstr "" |
2361 | + |
2362 | +#. module: account_cash_discount |
2363 | +#: constraint:ir.model:0 |
2364 | +msgid "The Object name must start with x_ and not contain any special character !" |
2365 | +msgstr "" |
2366 | + |
2367 | +#. module: account_cash_discount |
2368 | +#: field:account.cash.discount,name:0 |
2369 | +msgid "Name" |
2370 | +msgstr "" |
2371 | + |
2372 | +#. module: account_cash_discount |
2373 | +#: field:account.cash.discount,delay:0 |
2374 | +msgid "Number of Days" |
2375 | +msgstr "" |
2376 | + |
2377 | +#. module: account_cash_discount |
2378 | +#: field:account.cash.discount,discount:0 |
2379 | +msgid "Discount (%)" |
2380 | +msgstr "" |
2381 | + |
2382 | +#. module: account_cash_discount |
2383 | +#: field:account.cash.discount,credit_account_id:0 |
2384 | +msgid "Credit Account" |
2385 | +msgstr "" |
2386 | + |
2387 | +#. module: account_cash_discount |
2388 | +#: field:account.cash.discount,debit_account_id:0 |
2389 | +msgid "Debit Account" |
2390 | +msgstr "" |
2391 | + |
2392 | +#. module: account_cash_discount |
2393 | +#: model:ir.module.module,description:account_cash_discount.module_meta_information |
2394 | +msgid "\n" |
2395 | +" This module adds cash discounts on payment terms. Cash discounts\n" |
2396 | +" for a payment term can be configured with:\n" |
2397 | +" * A number of days,\n" |
2398 | +" * A discount (%),\n" |
2399 | +" * A debit and a credit account\n" |
2400 | +" " |
2401 | +msgstr "" |
2402 | + |
2403 | +#. module: account_cash_discount |
2404 | +#: model:ir.module.module,shortdesc:account_cash_discount.module_meta_information |
2405 | +msgid "Payement Term with Cash Discount" |
2406 | +msgstr "" |
2407 | + |
2408 | +#. module: account_cash_discount |
2409 | +#: view:account.cash.discount:0 |
2410 | +#: view:account.payment.term:0 |
2411 | +#: model:ir.model,name:account_cash_discount.model_account_cash_discount |
2412 | +msgid "Cash Discount" |
2413 | +msgstr "" |
2414 | + |
2415 | +#. module: account_cash_discount |
2416 | +#: field:account.cash.discount,payment_id:0 |
2417 | +msgid "Associated Payment Term" |
2418 | +msgstr "" |
2419 | + |
2420 | +#. module: account_cash_discount |
2421 | +#: field:account.payment.term,cash_discount_ids:0 |
2422 | +msgid "Cash Discounts" |
2423 | +msgstr "" |
2424 | + |
2425 | |
2426 | === added file 'account_cash_discount_us/account_cash_discount_us/i18n/fr_BE.po' |
2427 | --- account_cash_discount_us/account_cash_discount_us/i18n/fr_BE.po 1970-01-01 00:00:00 +0000 |
2428 | +++ account_cash_discount_us/account_cash_discount_us/i18n/fr_BE.po 2011-10-06 15:23:28 +0000 |
2429 | @@ -0,0 +1,85 @@ |
2430 | +# Translation of OpenERP Server. |
2431 | +# This file contains the translation of the following modules: |
2432 | +# * account_cash_discount |
2433 | +# |
2434 | +msgid "" |
2435 | +msgstr "" |
2436 | +"Project-Id-Version: OpenERP Server 5.0.6\n" |
2437 | +"Report-Msgid-Bugs-To: support@openerp.com\n" |
2438 | +"POT-Creation-Date: 2009-11-24 13:09:22+0000\n" |
2439 | +"PO-Revision-Date: 2009-11-24 13:09:22+0000\n" |
2440 | +"Last-Translator: <>\n" |
2441 | +"Language-Team: \n" |
2442 | +"MIME-Version: 1.0\n" |
2443 | +"Content-Type: text/plain; charset=UTF-8\n" |
2444 | +"Content-Transfer-Encoding: \n" |
2445 | +"Plural-Forms: \n" |
2446 | + |
2447 | +#. module: account_cash_discount |
2448 | +#: constraint:ir.ui.view:0 |
2449 | +msgid "Invalid XML for View Architecture!" |
2450 | +msgstr "" |
2451 | + |
2452 | +#. module: account_cash_discount |
2453 | +#: constraint:ir.model:0 |
2454 | +msgid "The Object name must start with x_ and not contain any special character !" |
2455 | +msgstr "" |
2456 | + |
2457 | +#. module: account_cash_discount |
2458 | +#: field:account.cash.discount,name:0 |
2459 | +msgid "Name" |
2460 | +msgstr "" |
2461 | + |
2462 | +#. module: account_cash_discount |
2463 | +#: field:account.cash.discount,delay:0 |
2464 | +msgid "Number of Days" |
2465 | +msgstr "" |
2466 | + |
2467 | +#. module: account_cash_discount |
2468 | +#: field:account.cash.discount,discount:0 |
2469 | +msgid "Discount (%)" |
2470 | +msgstr "" |
2471 | + |
2472 | +#. module: account_cash_discount |
2473 | +#: field:account.cash.discount,credit_account_id:0 |
2474 | +msgid "Credit Account" |
2475 | +msgstr "" |
2476 | + |
2477 | +#. module: account_cash_discount |
2478 | +#: field:account.cash.discount,debit_account_id:0 |
2479 | +msgid "Debit Account" |
2480 | +msgstr "" |
2481 | + |
2482 | +#. module: account_cash_discount |
2483 | +#: model:ir.module.module,description:account_cash_discount.module_meta_information |
2484 | +msgid "\n" |
2485 | +" This module adds cash discounts on payment terms. Cash discounts\n" |
2486 | +" for a payment term can be configured with:\n" |
2487 | +" * A number of days,\n" |
2488 | +" * A discount (%),\n" |
2489 | +" * A debit and a credit account\n" |
2490 | +" " |
2491 | +msgstr "" |
2492 | + |
2493 | +#. module: account_cash_discount |
2494 | +#: model:ir.module.module,shortdesc:account_cash_discount.module_meta_information |
2495 | +msgid "Payement Term with Cash Discount" |
2496 | +msgstr "" |
2497 | + |
2498 | +#. module: account_cash_discount |
2499 | +#: view:account.cash.discount:0 |
2500 | +#: view:account.payment.term:0 |
2501 | +#: model:ir.model,name:account_cash_discount.model_account_cash_discount |
2502 | +msgid "Cash Discount" |
2503 | +msgstr "" |
2504 | + |
2505 | +#. module: account_cash_discount |
2506 | +#: field:account.cash.discount,payment_id:0 |
2507 | +msgid "Associated Payment Term" |
2508 | +msgstr "" |
2509 | + |
2510 | +#. module: account_cash_discount |
2511 | +#: field:account.payment.term,cash_discount_ids:0 |
2512 | +msgid "Cash Discounts" |
2513 | +msgstr "" |
2514 | + |
2515 | |
2516 | === added file 'account_cash_discount_us/account_cash_discount_us/product_view.xml' |
2517 | --- account_cash_discount_us/account_cash_discount_us/product_view.xml 1970-01-01 00:00:00 +0000 |
2518 | +++ account_cash_discount_us/account_cash_discount_us/product_view.xml 2011-10-06 15:23:28 +0000 |
2519 | @@ -0,0 +1,19 @@ |
2520 | +<?xml version="1.0" encoding="utf-8"?> |
2521 | +<openerp> |
2522 | + <data> |
2523 | + <record id="product_normal_form_view" model="ir.ui.view"> |
2524 | + <field name="name">product.normal.form.inherit2</field> |
2525 | + <field name="model">product.product</field> |
2526 | + <field name="type">form</field> |
2527 | + <field name="inherit_id" ref="account.product_normal_form_view"/> |
2528 | + <field name="arch" type="xml"> |
2529 | + <xpath expr="//field[@name='property_account_expense']" position="after"> |
2530 | + <newline/> |
2531 | + <field name="sales_discount_account" attrs="{'readonly':[('sale_ok','=',0)]}"/> |
2532 | + <field name="purchase_discount_account" attrs="{'readonly':[('purchase_ok','=',0)]}"/> |
2533 | + </xpath> |
2534 | + </field> |
2535 | + </record> |
2536 | + </data> |
2537 | +</openerp> |
2538 | + |
2539 | |
2540 | === added directory 'account_cash_discount_us/account_cash_discount_us/security' |
2541 | === added file 'account_cash_discount_us/account_cash_discount_us/security/ir.model.access.csv' |
2542 | --- account_cash_discount_us/account_cash_discount_us/security/ir.model.access.csv 1970-01-01 00:00:00 +0000 |
2543 | +++ account_cash_discount_us/account_cash_discount_us/security/ir.model.access.csv 2011-10-06 15:23:28 +0000 |
2544 | @@ -0,0 +1,7 @@ |
2545 | +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" |
2546 | +"access_account_invoice_pay_writeoff","account.invoice.pay.writeoff","account_cash_discount_us.model_account_invoice_pay_writeoff","account.group_account_user",1,0,0,0 |
2547 | +"access_account_invoice_pay_writeoff_manager","account.invoice.pay.writeoff","account_cash_discount_us.model_account_invoice_pay_writeoff","account.group_account_manager",1,1,1,1 |
2548 | +"access_account_invoice_pay","account.invoice.pay","account_cash_discount_us.model_account_invoice_pay","account.group_account_user",1,0,0,0 |
2549 | +"access_account_invoice_pay_manager","account.invoice.pay","account_cash_discount_us.model_account_invoice_pay","account.group_account_manager",1,1,1,1 |
2550 | +"access_account_voucher_line_discount_to_use","account.voucher.line.discount_to_usey","account_cash_discount_us.model_account_voucher_line_discount_to_use","account.group_account_user",1,0,0,0 |
2551 | +"access_account_voucher_line_discount_to_use_manager","account.voucher.line.discount_to_use","account_cash_discount_us.model_account_voucher_line_discount_to_use","account.group_account_manager",1,1,1,1 |
2552 | \ No newline at end of file |
2553 | |
2554 | === added directory 'account_cash_discount_us/account_cash_discount_us/wizard' |
2555 | === added file 'account_cash_discount_us/account_cash_discount_view.xml' |
2556 | --- account_cash_discount_us/account_cash_discount_view.xml 1970-01-01 00:00:00 +0000 |
2557 | +++ account_cash_discount_us/account_cash_discount_view.xml 2011-10-06 15:23:28 +0000 |
2558 | @@ -0,0 +1,329 @@ |
2559 | +<?xml version="1.0"?> |
2560 | +<openerp> |
2561 | + <data> |
2562 | + |
2563 | + <!-- cash discount --> |
2564 | + |
2565 | + <record id="invoice_supplier_form_jdc" model="ir.ui.view"> |
2566 | + <field name="name">account.invoice.supplier.form.jdc</field> |
2567 | + <field name="model">account.invoice</field> |
2568 | + <field name="type">form</field> |
2569 | + <field name="priority">2</field> |
2570 | + <field name="inherit_id" ref="account.invoice_supplier_form"/> |
2571 | + <field name="arch" type="xml"> |
2572 | + <xpath expr="/form/notebook/page/field[@name='check_total']" position="after"> |
2573 | + <field name="date_discount"/> |
2574 | + <field name="amount_discounted"/> |
2575 | + </xpath> |
2576 | + </field> |
2577 | + </record> |
2578 | + <record id="invoice_form_jdc1" model="ir.ui.view"> |
2579 | + <field name="name">account.invoice.form.jdc1</field> |
2580 | + <field name="model">account.invoice</field> |
2581 | + <field name="type">form</field> |
2582 | + <field name="inherit_id" ref="account.invoice_form"/> |
2583 | + <field name="arch" type="xml"> |
2584 | + <xpath expr="/form/notebook/page[@string='Invoice']/field[@name='invoice_line']" position="before"> |
2585 | + <group colspan="2" col="4"> |
2586 | + <field name="date_discount"/> |
2587 | + <field name="amount_discounted"/> |
2588 | + </group> |
2589 | + </xpath> |
2590 | + </field> |
2591 | + </record> |
2592 | + |
2593 | + |
2594 | + <!-- |
2595 | + Invoice Line |
2596 | + --> |
2597 | + <record id="view_invoice_line_form_discount" model="ir.ui.view"> |
2598 | + <field name="name">account.invoice.line.form.discount</field> |
2599 | + <field name="model">account.invoice.line</field> |
2600 | + <field name="inherit_id" ref="account.view_invoice_line_form"/> |
2601 | + <field name="type">form</field> |
2602 | + <field name="arch" type="xml"> |
2603 | + <xpath expr="/form/notebook/page/field[@name='discount']" position="after"> |
2604 | + <field name="cash_discount"/> |
2605 | + </xpath> |
2606 | + </field> |
2607 | + </record> |
2608 | + |
2609 | + <!-- |
2610 | + Products |
2611 | + --> |
2612 | + <record id="product_normal_form_view_discount" model="ir.ui.view"> |
2613 | + <field name="name">product.normal.form.discount</field> |
2614 | + <field name="model">product.product</field> |
2615 | + <field name="type">form</field> |
2616 | + <field eval="7" name="priority"/> |
2617 | + <field name="inherit_id" ref="product.product_normal_form_view"/> |
2618 | + <field name="arch" type="xml"> |
2619 | + <xpath expr="/form/notebook/page[@string='Suppliers']/field[@name='seller_ids']" position="after"> |
2620 | + <field name="cash_discount"/> |
2621 | + </xpath> |
2622 | + </field> |
2623 | + </record> |
2624 | + |
2625 | + <!-- |
2626 | + Company |
2627 | + --> |
2628 | + <record id="view_company_form_jdc2" model="ir.ui.view"> |
2629 | + <field name="name">res.company.form.jdc2</field> |
2630 | + <field name="model">res.company</field> |
2631 | + <field name="type">form</field> |
2632 | + <field name="inherit_id" ref="account_voucher_credits_us.view_company_form_jdc3"/> |
2633 | + <field name="priority" eval="1"/> |
2634 | + <field name="arch" type="xml"> |
2635 | + <xpath expr="/form/notebook/page[@string='Accounting']/field[@name='writeoff_account']" position="before"> |
2636 | + <field name="sales_discount_account" colspan="2" /> |
2637 | + <field name="purchase_discount_account" colspan="2" /> |
2638 | + <field name="sales_discount_journal" colspan="2"/> |
2639 | + <field name="purchase_discount_journal" colspan="2"/> |
2640 | + </xpath> |
2641 | + </field> |
2642 | + </record> |
2643 | + |
2644 | + <!-- Discount --> |
2645 | + |
2646 | + <record model="ir.ui.view" id="view_account_wizard_discount_form"> |
2647 | + <field name="name">account.wizard.discount.form</field> |
2648 | + <field name="model">account.wizard.discount</field> |
2649 | + <field name="type">form</field> |
2650 | + <field name="arch" type="xml"> |
2651 | + <form string="Discount"> |
2652 | + <field name="use_discount" select="1"/> |
2653 | + <field name="inv_payment_terms" select="1" readonly="1"/> |
2654 | + <field name="discount_window_date" select="1"/> |
2655 | + <field name="proposed_discount" select="1"/> |
2656 | + <field name="discount_amount" select="1"/> |
2657 | + <field name="gl_account" select="1"/> |
2658 | + </form> |
2659 | + </field> |
2660 | + </record> |
2661 | + |
2662 | + <record model="ir.ui.view" id="view_account_wizard_discount_tree"> |
2663 | + <field name="name">account.wizard.discount.tree</field> |
2664 | + <field name="model">account.wizard.discount</field> |
2665 | + <field name="type">tree</field> |
2666 | + <field name="arch" type="xml"> |
2667 | + <tree string="Discount" editable="bottom"> |
2668 | + <field name="use_discount" select="1"/> |
2669 | + <field name="inv_payment_terms" select="1" readonly="1"/> |
2670 | + <field name="discount_window_date" select="1"/> |
2671 | + <field name="proposed_discount" select="1"/> |
2672 | + <field name="discount_amount" select="1"/> |
2673 | + <field name="gl_account" select="1"/> |
2674 | + </tree> |
2675 | + </field> |
2676 | + </record> |
2677 | + <!-- credit --> |
2678 | + |
2679 | + <record model="ir.ui.view" id="view_account_wizard_credit_form"> |
2680 | + <field name="name">account.wizard.credit.form</field> |
2681 | + <field name="model">account.wizard.credit</field> |
2682 | + <field name="type">form</field> |
2683 | + <field name="arch" type="xml"> |
2684 | + <form string="Credits"> |
2685 | + <field name="use_credit" select="1"/> |
2686 | + <field name="inv_credit" select="1" readonly="1"/> |
2687 | + <field name="discount_window_date" select="1" readonly="1"/> |
2688 | + <field name="proposed_discount" select="1" readonly="1"/> |
2689 | + <field name="discount_amount" select="1" /> |
2690 | + <field name="credit_bal" select="1" readonly="1"/> |
2691 | + <field name="gl_account" select="1" readonly="1"/> |
2692 | + </form> |
2693 | + </field> |
2694 | + </record> |
2695 | + |
2696 | + <record model="ir.ui.view" id="view_account_wizard_credit_tree"> |
2697 | + <field name="name">account.wizard.credit.tree</field> |
2698 | + <field name="model">account.wizard.credit</field> |
2699 | + <field name="type">tree</field> |
2700 | + <field name="arch" type="xml"> |
2701 | + <tree string="Credits" editable="bottom"> |
2702 | + <field name="use_credit" select="1"/> |
2703 | + <field name="inv_credit" select="1" readonly="1"/> |
2704 | + <field name="discount_window_date" select="1" readonly="1"/> |
2705 | + <field name="proposed_discount" select="1" readonly="1"/> |
2706 | + <field name="discount_amount" select="1" /> |
2707 | + <field name="credit_bal" select="1" readonly="1"/> |
2708 | + <field name="gl_account" select="1" readonly="1"/> |
2709 | + </tree> |
2710 | + </field> |
2711 | + </record> |
2712 | + |
2713 | + |
2714 | + <!-- credit used --> |
2715 | + |
2716 | + <record model="ir.ui.view" id="view_account_wizard_credit_used_form"> |
2717 | + <field name="name">account.wizard.credit.used.form</field> |
2718 | + <field name="model">account.wizard.credit.used</field> |
2719 | + <field name="type">form</field> |
2720 | + <field name="arch" type="xml"> |
2721 | + <form string="Previously Applied Credit"> |
2722 | + <field name="date_used" select="1"/> |
2723 | + <field name="inv_credit" select="1"/> |
2724 | + <field name="discount_window_date" select="1"/> |
2725 | + <field name="proposed_discount" select="1"/> |
2726 | + <field name="amt_used" select="1"/> |
2727 | + <field name="inv_move" select="1"/> |
2728 | + <field name="gl_account" select="1"/> |
2729 | + </form> |
2730 | + </field> |
2731 | + </record> |
2732 | + |
2733 | + <record model="ir.ui.view" id="view_account_wizard_credit_used_tree"> |
2734 | + <field name="name">account.wizard.credit.used.tree</field> |
2735 | + <field name="model">account.wizard.credit.used</field> |
2736 | + <field name="type">tree</field> |
2737 | + <field name="arch" type="xml"> |
2738 | + <tree string="Previously Applied Credit" editable="bottom"> |
2739 | + <field name="date_used" select="1"/> |
2740 | + <field name="inv_credit" select="1"/> |
2741 | + <field name="discount_window_date" select="1"/> |
2742 | + <field name="proposed_discount" select="1"/> |
2743 | + <field name="amt_used" select="1"/> |
2744 | + <field name="inv_move" select="1"/> |
2745 | + <field name="gl_account" select="1"/> |
2746 | + </tree> |
2747 | + </field> |
2748 | + </record> |
2749 | + |
2750 | + <!-- Supplier payment form modification for discount --> |
2751 | + <record model="ir.ui.view" id="view_vendor_payment_form_inherit"> |
2752 | + <field name="name">account.voucher.payment.form.inherit</field> |
2753 | + <field name="model">account.voucher</field> |
2754 | + <field name="inherit_id" ref="account_voucher.view_vendor_payment_form"/> |
2755 | + <field name="type">form</field> |
2756 | + <field name="arch" type="xml"> |
2757 | + <xpath expr="/form/group/field[@name='amount']" position="attributes" > |
2758 | + <attribute name='on_change'>onchange_amount(amount)</attribute> |
2759 | + </xpath> |
2760 | + <xpath expr="/form/group[@col='10']/button[@name='cancel_voucher']" position="after"> |
2761 | + <button name="calc_supp_diff" string="Calculate" type="object" states="draft" icon="gtk-execute" /> |
2762 | + </xpath> |
2763 | + <xpath expr="//field[@name='line_dr_ids']" position="replace"> |
2764 | + <field name="line_dr_ids" default_get="{'journal_id':journal_id, 'type':type, 'partner_id':partner_id}" colspan="4" nolabel="1" height="140" string="Payment Modification"> |
2765 | + <tree string="Invoices and Outstanding Transactions" editable="bottom"> |
2766 | + <field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}" |
2767 | + on_change="onchange_move_line_id(move_line_id)" |
2768 | + domain="[('account_id.type','in',('receivable','payable')), ('reconcile_id','=', False), ('partner_id','=',parent.partner_id)]" |
2769 | + /> |
2770 | + <field name="date_original" readonly="1"/> |
2771 | + <field name="date_due" readonly="1"/> |
2772 | + <field name="amount_original" readonly="1"/> |
2773 | + <field name="amount_unreconciled" sum="Open Balance" readonly="1"/> |
2774 | + <field name="pay" on_change="onchange_supp_pay(amount, pay, amount_unreconciled, parent.line_cr_ids, parent.amount, credit_used, discount_used, writeoff_amount)"/> |
2775 | + <field name="amount" sum="Payment"/> |
2776 | + <field name="discount" /> |
2777 | + <field name="supp_amount_difference"/> |
2778 | + |
2779 | + <field name="credit_used"/> |
2780 | + <field name="account_id"/> |
2781 | + <field name="discount_used" invisible="1"/> |
2782 | + <field name="writeoff_amount" invisible="1"/> |
2783 | + </tree> |
2784 | + |
2785 | + <form string="Supplier Invoices and Outstanding transactions" > |
2786 | + <field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}" |
2787 | + on_change="onchange_move_line_id(move_line_id)" |
2788 | + domain="[('account_id.type','=','payable'), ('reconcile_id','=', False), ('partner_id','=',parent.partner_id)]" |
2789 | + /> |
2790 | + <field name="account_id" groups="base.group_extended" domain="[('type','=','payable')]"/> |
2791 | + <field name="invoice_id"/> |
2792 | + <field name="date_original" readonly="1"/> |
2793 | + <field name="date_due" readonly="1"/> |
2794 | + <field name="amount_original" readonly="1"/> |
2795 | + <field name="amount_unreconciled" sum="Open Balance" readonly="1"/> |
2796 | + <field name="amount" sum="Payment"/> |
2797 | + <field name="supp_amount_difference"/> |
2798 | + <field name="discount_used"/> |
2799 | + <notebook tabpos="up" colspan="4" > |
2800 | + <page string="Discount"> |
2801 | + <field name="available_discounts" nolabel="1" colspan="4" string="Avilable Discounts" view_mode="tree" /> |
2802 | + </page> |
2803 | + <page string="Other Info" readonly="1"> |
2804 | + <field name='partner_id' readonly="1"/> |
2805 | + <field name='untax_amount' readonly="1"/> |
2806 | + <field name='type' readonly="1"/> |
2807 | + <field name='account_analytic_id' readonly="1"/> |
2808 | + <field name='company_id' readonly="1"/> |
2809 | + <field name='pay' on_change="onchange_pay(amount, pay, amount_unreconciled, parent.line_dr_ids, parent.amount, credit_used, discount_used, writeoff_amount)"/> |
2810 | + </page> |
2811 | + </notebook> |
2812 | + <newline/> |
2813 | + <button name="clear_values" icon='gtk-clear' string="Clear" type="object" colspan="1"/> |
2814 | + <button name="recalculate_supp_values" icon='gtk-refresh' string="Re-Calculate" type="object" colspan="1"/> |
2815 | + </form> |
2816 | + </field> |
2817 | + </xpath> |
2818 | + |
2819 | + </field> |
2820 | + </record> |
2821 | + |
2822 | + |
2823 | + <!-- customer payment form modification for discount --> |
2824 | + |
2825 | + |
2826 | + <record model="ir.ui.view" id="view_vendor_receipt_form_2"> |
2827 | + <field name="name">account.voucher.receipt.form.2</field> |
2828 | + <field name="model">account.voucher</field> |
2829 | + <field name="type">form</field> |
2830 | + <field name="inherit_id" ref="account_voucher_credits_us.view_vendor_receipt_form_1"/> |
2831 | + <field name="arch" type="xml"> |
2832 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field[@name='line_cr_ids']/form/group[@string='Invoice']/group[@color='red']/field[@name='credit_used']" position="before"> |
2833 | + <field name="discount_used"/> |
2834 | + <newline /> |
2835 | + </xpath> |
2836 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field/tree/field[@name='credit_used']" position="before"> |
2837 | + <field name="discount_used"/> |
2838 | + <newline/> |
2839 | + </xpath> |
2840 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field[@name='line_cr_ids']/form/notebook/page[@string='Credit']" position="before"> |
2841 | + <page string="Discount"> |
2842 | + <field name="available_discounts" nolabel="1" colspan="4" string="Avilable Discounts" view_mode="tree" /> |
2843 | + </page> |
2844 | + </xpath> |
2845 | + </field> |
2846 | + </record> |
2847 | + |
2848 | + |
2849 | + <record model="ir.ui.view" id="view_account_voucher_line_discount_to_use_tree"> |
2850 | + <field name="name">account.voucher.line.discount_to_use.tree</field> |
2851 | + <field name="model">account.voucher.line.discount_to_use</field> |
2852 | + <field name="type">tree</field> |
2853 | + <field name="arch" type="xml"> |
2854 | + <tree string="Available Discounts" editable="top"> |
2855 | + <field name="use_discount" width="125" on_change="onchage_use_discount(use_discount, proposed_discount)"/> |
2856 | + <field name="inv_payment_terms"/> |
2857 | + <field name="discount_window_date"/> |
2858 | + <field name="proposed_discount"/> |
2859 | + <field name="discount_amount" on_change="onchage_discount_amount(proposed_discount, discount_amount)"/> |
2860 | + <field name="gl_account"/> |
2861 | + </tree> |
2862 | + </field> |
2863 | + </record> |
2864 | + |
2865 | + <record model="ir.ui.view" id="view_payment_term_form_inherited"> |
2866 | + <field name="name">account.payment.term.form.inherited</field> |
2867 | + <field name="model">account.payment.term</field> |
2868 | + <field name="inherit_id" ref="account_cash_discount.view_payment_term_form"/> |
2869 | + <field name="arch" type="xml"> |
2870 | + <separator string="Cash Discount" colspan="4" position="replace"/> |
2871 | + </field> |
2872 | + </record> |
2873 | + <record model="ir.ui.view" id="view_payment_term_form_inherited2"> |
2874 | + <field name="name">account.payment.term.form.inherited2</field> |
2875 | + <field name="model">account.payment.term</field> |
2876 | + <field name="inherit_id" ref="view_payment_term_form_inherited"/> |
2877 | + <field name="arch" type="xml"> |
2878 | + <field name="cash_discount_ids" colspan="4" position="replace"> |
2879 | + <separator string="Cash Discount" colspan="4"/> |
2880 | + <field name="cash_discount_ids" colspan="4" nolabel="1"/> |
2881 | + </field> |
2882 | + </field> |
2883 | + </record> |
2884 | + |
2885 | + |
2886 | + </data> |
2887 | +</openerp> |
2888 | |
2889 | === added file 'account_cash_discount_us/amount_to_words.py' |
2890 | --- account_cash_discount_us/amount_to_words.py 1970-01-01 00:00:00 +0000 |
2891 | +++ account_cash_discount_us/amount_to_words.py 2011-10-06 15:23:28 +0000 |
2892 | @@ -0,0 +1,77 @@ |
2893 | + |
2894 | +# can be used for numbers as large as 999 vigintillion |
2895 | +# (vigintillion --> 10 to the power 60) |
2896 | +# tested with Python24 vegaseat 07dec2006 |
2897 | + |
2898 | +def int2word(n): |
2899 | + """ |
2900 | + convert an integer number n into a string of English words |
2901 | + """ |
2902 | + # break the number into groups of 3 digits using slicing |
2903 | + # each group representing hundred, thousand, million, billion, ... |
2904 | + if not n: |
2905 | + return 'Zero ' |
2906 | + n3 = [] |
2907 | + r1 = "" |
2908 | + # create numeric string |
2909 | + ns = str(n) |
2910 | + for k in range(3, 33, 3): |
2911 | + r = ns[-k:] |
2912 | + q = len(ns) - k |
2913 | + # break if end of ns has been reached |
2914 | + if q < -2: |
2915 | + break |
2916 | + else: |
2917 | + if q >= 0: |
2918 | + n3.append(int(r[:3])) |
2919 | + elif q >= -1: |
2920 | + n3.append(int(r[:2])) |
2921 | + elif q >= -2: |
2922 | + n3.append(int(r[:1])) |
2923 | + r1 = r |
2924 | + nw = "" |
2925 | + for i, x in enumerate(n3): |
2926 | + b1 = x % 10 |
2927 | + b2 = (x % 100)//10 |
2928 | + b3 = (x % 1000)//100 |
2929 | + if x == 0: |
2930 | + continue # skip |
2931 | + else: |
2932 | + t = thousands[i] |
2933 | + if b2 == 0: |
2934 | + nw = ones[b1] + t + nw |
2935 | + elif b2 == 1: |
2936 | + nw = tens[b1] + t + nw |
2937 | + elif b2 > 1: |
2938 | + nw = twenties[b2] + ones[b1] + t + nw |
2939 | + if b3 > 0: |
2940 | + nw = ones[b3] + "hundred " + nw |
2941 | + return nw |
2942 | + |
2943 | +############# globals ################ |
2944 | + |
2945 | +ones = ["", "One ","Two ","Three ","Four ", "Five ", |
2946 | + "Six ","Seven ","Eight ","Nine "] |
2947 | + |
2948 | +tens = ["Ten ","Eleven ","Twelve ","Thirteen ", "Fourteen ", |
2949 | + "Fifteen ","Sixteen ","Seventeen ","Eighteen ","Nineteen "] |
2950 | + |
2951 | +twenties = ["","","Twenty ","Thirty ","Forty ", |
2952 | + "Fifty ","Sixty ","Seventy ","Eighty ","Ninety "] |
2953 | + |
2954 | +thousands = ["","Thousand ","Million ", "Billion ", "Trillion ", |
2955 | + "Quadrillion ", "Quintillion ", "Sextillion ", "Septillion ","Octillion ", |
2956 | + "Nonillion ", "Decillion ", "Undecillion ", "Duodecillion ", "Tredecillion ", |
2957 | + "Quattuordecillion ", "Sexdecillion ", "Septendecillion ", "Octodecillion ", |
2958 | + "Novemdecillion ", "Vigintillion "] |
2959 | + |
2960 | +def amount_to_words(num): |
2961 | + # select an integer number n for testing or get it from user input |
2962 | + res="" |
2963 | + if num < 0: |
2964 | + res="Negative " |
2965 | + num=float(str(num)[1:]) |
2966 | + if num==0: return 'Zero' |
2967 | + else: |
2968 | + n=str(num).split('.') |
2969 | + return res+int2word(int(n[0]))+'and '+(len(n)>1 and int(n[1]) and str((num - int(num))*100).split('.')[0] or 'no')+'/100s' |
2970 | |
2971 | === added directory 'account_cash_discount_us/i18n' |
2972 | === added file 'account_cash_discount_us/i18n/account_cash_discount.pot' |
2973 | --- account_cash_discount_us/i18n/account_cash_discount.pot 1970-01-01 00:00:00 +0000 |
2974 | +++ account_cash_discount_us/i18n/account_cash_discount.pot 2011-10-06 15:23:28 +0000 |
2975 | @@ -0,0 +1,85 @@ |
2976 | +# Translation of OpenERP Server. |
2977 | +# This file contains the translation of the following modules: |
2978 | +# * account_cash_discount |
2979 | +# |
2980 | +msgid "" |
2981 | +msgstr "" |
2982 | +"Project-Id-Version: OpenERP Server 5.0.6\n" |
2983 | +"Report-Msgid-Bugs-To: support@openerp.com\n" |
2984 | +"POT-Creation-Date: 2009-11-24 13:09:22+0000\n" |
2985 | +"PO-Revision-Date: 2009-11-24 13:09:22+0000\n" |
2986 | +"Last-Translator: <>\n" |
2987 | +"Language-Team: \n" |
2988 | +"MIME-Version: 1.0\n" |
2989 | +"Content-Type: text/plain; charset=UTF-8\n" |
2990 | +"Content-Transfer-Encoding: \n" |
2991 | +"Plural-Forms: \n" |
2992 | + |
2993 | +#. module: account_cash_discount |
2994 | +#: constraint:ir.ui.view:0 |
2995 | +msgid "Invalid XML for View Architecture!" |
2996 | +msgstr "" |
2997 | + |
2998 | +#. module: account_cash_discount |
2999 | +#: constraint:ir.model:0 |
3000 | +msgid "The Object name must start with x_ and not contain any special character !" |
3001 | +msgstr "" |
3002 | + |
3003 | +#. module: account_cash_discount |
3004 | +#: field:account.cash.discount,name:0 |
3005 | +msgid "Name" |
3006 | +msgstr "" |
3007 | + |
3008 | +#. module: account_cash_discount |
3009 | +#: field:account.cash.discount,delay:0 |
3010 | +msgid "Number of Days" |
3011 | +msgstr "" |
3012 | + |
3013 | +#. module: account_cash_discount |
3014 | +#: field:account.cash.discount,discount:0 |
3015 | +msgid "Discount (%)" |
3016 | +msgstr "" |
3017 | + |
3018 | +#. module: account_cash_discount |
3019 | +#: field:account.cash.discount,credit_account_id:0 |
3020 | +msgid "Credit Account" |
3021 | +msgstr "" |
3022 | + |
3023 | +#. module: account_cash_discount |
3024 | +#: field:account.cash.discount,debit_account_id:0 |
3025 | +msgid "Debit Account" |
3026 | +msgstr "" |
3027 | + |
3028 | +#. module: account_cash_discount |
3029 | +#: model:ir.module.module,description:account_cash_discount.module_meta_information |
3030 | +msgid "\n" |
3031 | +" This module adds cash discounts on payment terms. Cash discounts\n" |
3032 | +" for a payment term can be configured with:\n" |
3033 | +" * A number of days,\n" |
3034 | +" * A discount (%),\n" |
3035 | +" * A debit and a credit account\n" |
3036 | +" " |
3037 | +msgstr "" |
3038 | + |
3039 | +#. module: account_cash_discount |
3040 | +#: model:ir.module.module,shortdesc:account_cash_discount.module_meta_information |
3041 | +msgid "Payement Term with Cash Discount" |
3042 | +msgstr "" |
3043 | + |
3044 | +#. module: account_cash_discount |
3045 | +#: view:account.cash.discount:0 |
3046 | +#: view:account.payment.term:0 |
3047 | +#: model:ir.model,name:account_cash_discount.model_account_cash_discount |
3048 | +msgid "Cash Discount" |
3049 | +msgstr "" |
3050 | + |
3051 | +#. module: account_cash_discount |
3052 | +#: field:account.cash.discount,payment_id:0 |
3053 | +msgid "Associated Payment Term" |
3054 | +msgstr "" |
3055 | + |
3056 | +#. module: account_cash_discount |
3057 | +#: field:account.payment.term,cash_discount_ids:0 |
3058 | +msgid "Cash Discounts" |
3059 | +msgstr "" |
3060 | + |
3061 | |
3062 | === added file 'account_cash_discount_us/i18n/fr_BE.po' |
3063 | --- account_cash_discount_us/i18n/fr_BE.po 1970-01-01 00:00:00 +0000 |
3064 | +++ account_cash_discount_us/i18n/fr_BE.po 2011-10-06 15:23:28 +0000 |
3065 | @@ -0,0 +1,85 @@ |
3066 | +# Translation of OpenERP Server. |
3067 | +# This file contains the translation of the following modules: |
3068 | +# * account_cash_discount |
3069 | +# |
3070 | +msgid "" |
3071 | +msgstr "" |
3072 | +"Project-Id-Version: OpenERP Server 5.0.6\n" |
3073 | +"Report-Msgid-Bugs-To: support@openerp.com\n" |
3074 | +"POT-Creation-Date: 2009-11-24 13:09:22+0000\n" |
3075 | +"PO-Revision-Date: 2009-11-24 13:09:22+0000\n" |
3076 | +"Last-Translator: <>\n" |
3077 | +"Language-Team: \n" |
3078 | +"MIME-Version: 1.0\n" |
3079 | +"Content-Type: text/plain; charset=UTF-8\n" |
3080 | +"Content-Transfer-Encoding: \n" |
3081 | +"Plural-Forms: \n" |
3082 | + |
3083 | +#. module: account_cash_discount |
3084 | +#: constraint:ir.ui.view:0 |
3085 | +msgid "Invalid XML for View Architecture!" |
3086 | +msgstr "" |
3087 | + |
3088 | +#. module: account_cash_discount |
3089 | +#: constraint:ir.model:0 |
3090 | +msgid "The Object name must start with x_ and not contain any special character !" |
3091 | +msgstr "" |
3092 | + |
3093 | +#. module: account_cash_discount |
3094 | +#: field:account.cash.discount,name:0 |
3095 | +msgid "Name" |
3096 | +msgstr "" |
3097 | + |
3098 | +#. module: account_cash_discount |
3099 | +#: field:account.cash.discount,delay:0 |
3100 | +msgid "Number of Days" |
3101 | +msgstr "" |
3102 | + |
3103 | +#. module: account_cash_discount |
3104 | +#: field:account.cash.discount,discount:0 |
3105 | +msgid "Discount (%)" |
3106 | +msgstr "" |
3107 | + |
3108 | +#. module: account_cash_discount |
3109 | +#: field:account.cash.discount,credit_account_id:0 |
3110 | +msgid "Credit Account" |
3111 | +msgstr "" |
3112 | + |
3113 | +#. module: account_cash_discount |
3114 | +#: field:account.cash.discount,debit_account_id:0 |
3115 | +msgid "Debit Account" |
3116 | +msgstr "" |
3117 | + |
3118 | +#. module: account_cash_discount |
3119 | +#: model:ir.module.module,description:account_cash_discount.module_meta_information |
3120 | +msgid "\n" |
3121 | +" This module adds cash discounts on payment terms. Cash discounts\n" |
3122 | +" for a payment term can be configured with:\n" |
3123 | +" * A number of days,\n" |
3124 | +" * A discount (%),\n" |
3125 | +" * A debit and a credit account\n" |
3126 | +" " |
3127 | +msgstr "" |
3128 | + |
3129 | +#. module: account_cash_discount |
3130 | +#: model:ir.module.module,shortdesc:account_cash_discount.module_meta_information |
3131 | +msgid "Payement Term with Cash Discount" |
3132 | +msgstr "" |
3133 | + |
3134 | +#. module: account_cash_discount |
3135 | +#: view:account.cash.discount:0 |
3136 | +#: view:account.payment.term:0 |
3137 | +#: model:ir.model,name:account_cash_discount.model_account_cash_discount |
3138 | +msgid "Cash Discount" |
3139 | +msgstr "" |
3140 | + |
3141 | +#. module: account_cash_discount |
3142 | +#: field:account.cash.discount,payment_id:0 |
3143 | +msgid "Associated Payment Term" |
3144 | +msgstr "" |
3145 | + |
3146 | +#. module: account_cash_discount |
3147 | +#: field:account.payment.term,cash_discount_ids:0 |
3148 | +msgid "Cash Discounts" |
3149 | +msgstr "" |
3150 | + |
3151 | |
3152 | === added file 'account_cash_discount_us/product_view.xml' |
3153 | --- account_cash_discount_us/product_view.xml 1970-01-01 00:00:00 +0000 |
3154 | +++ account_cash_discount_us/product_view.xml 2011-10-06 15:23:28 +0000 |
3155 | @@ -0,0 +1,19 @@ |
3156 | +<?xml version="1.0" encoding="utf-8"?> |
3157 | +<openerp> |
3158 | + <data> |
3159 | + <record id="product_normal_form_view" model="ir.ui.view"> |
3160 | + <field name="name">product.normal.form.inherit2</field> |
3161 | + <field name="model">product.product</field> |
3162 | + <field name="type">form</field> |
3163 | + <field name="inherit_id" ref="account.product_normal_form_view"/> |
3164 | + <field name="arch" type="xml"> |
3165 | + <xpath expr="//field[@name='property_account_expense']" position="after"> |
3166 | + <newline/> |
3167 | + <field name="sales_discount_account" attrs="{'readonly':[('sale_ok','=',0)]}"/> |
3168 | + <field name="purchase_discount_account" attrs="{'readonly':[('purchase_ok','=',0)]}"/> |
3169 | + </xpath> |
3170 | + </field> |
3171 | + </record> |
3172 | + </data> |
3173 | +</openerp> |
3174 | + |
3175 | |
3176 | === added directory 'account_cash_discount_us/security' |
3177 | === added file 'account_cash_discount_us/security/ir.model.access.csv' |
3178 | --- account_cash_discount_us/security/ir.model.access.csv 1970-01-01 00:00:00 +0000 |
3179 | +++ account_cash_discount_us/security/ir.model.access.csv 2011-10-06 15:23:28 +0000 |
3180 | @@ -0,0 +1,7 @@ |
3181 | +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" |
3182 | +"access_account_invoice_pay_writeoff","account.invoice.pay.writeoff","account_cash_discount_us.model_account_invoice_pay_writeoff","account.group_account_user",1,0,0,0 |
3183 | +"access_account_invoice_pay_writeoff_manager","account.invoice.pay.writeoff","account_cash_discount_us.model_account_invoice_pay_writeoff","account.group_account_manager",1,1,1,1 |
3184 | +"access_account_invoice_pay","account.invoice.pay","account_cash_discount_us.model_account_invoice_pay","account.group_account_user",1,0,0,0 |
3185 | +"access_account_invoice_pay_manager","account.invoice.pay","account_cash_discount_us.model_account_invoice_pay","account.group_account_manager",1,1,1,1 |
3186 | +"access_account_voucher_line_discount_to_use","account.voucher.line.discount_to_usey","account_cash_discount_us.model_account_voucher_line_discount_to_use","account.group_account_user",1,0,0,0 |
3187 | +"access_account_voucher_line_discount_to_use_manager","account.voucher.line.discount_to_use","account_cash_discount_us.model_account_voucher_line_discount_to_use","account.group_account_manager",1,1,1,1 |
3188 | \ No newline at end of file |