Merge lp:~npg-team/openobject-addons/account_cash_discount_us_npg into lp:openobject-addons

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
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+78430@code.launchpad.net

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_voucher_credits_us.(merge proposal made for this module)

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

Subscribers

People subscribed via source and target branches

to all changes: