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
=== added directory 'account_cash_discount_us'
=== added file 'account_cash_discount_us/Change Log.txt'
--- account_cash_discount_us/Change Log.txt 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/Change Log.txt 2011-10-06 15:23:28 +0000
@@ -0,0 +1,53 @@
1===============================================================================
2 Version Change Log (account_cash_discount_us)
3===============================================================================
41.15 (2011-09-16) -> Janeesh
5 * Added the onchange on amount in Pay Invoice
6
71.14 (2011-09-16) -> Arif
8 * Removed the onchange on amount in Pay Invoice
9
101.13 (2011-09-15) -> Sinoj & Arif
11 * Fixed the bug on calculation of discount on Pay Invoice
12
131.12 (2011-07-18) By Arif
14 * Added discount field in (Task ID: 362) in supplier payment
15
161.10 -> 1.11 (2011-04-14) By Jabir
17 * Update the payment amount when discount is selected and clicked on recalculate button
18
19
201.08 -> 1.09 (2011-04-14) By Jabir
21 * Add calculate button on Supplier Payment
22
231.08 -> 1.09 (2011-04-08) By Jabir
24 * Supplier discount
25
261.07 -> 1.08 (2011-02-04) By Sinoj
27 * Optimization and cleanup
28
29
301.06 -> 1.07 (2010-12-06) By jabir
31 * Removed discount wizard and changed domain filtering
32
331.05 -> 1.06 (2010-12-06) By jabir
34 * Take invoice partner instead of moveline partner
35
36 1.04 -> 1.05 (2010-11-29) By Jabir
37 * Fix placement of Cash Discount Separation Line
38
39 1.03 -> 1.04 (2010-11-29) By Sinoj
40 * Account posting updated for National account
41
42 1.02 -> 1.03 (2010-11-09) By Sinoj
43 * "Debit and Credits" wizard button moved to voucher line
44 * fields on wizard form are readonly
45 * fields on wizard are populated with default values
46 * removed
47
48 1.01 -> 1.02 (2010-11-04) By jabir
49 * Add wizard Discount and Credits
50 * Create button Discount and Credits in customer payment form
51
52 1.0 -> 1.01 (2010-11-04) By sinoj
53 * dependency changed from account_voucher_jdc to account_voucher_credits_us
0\ No newline at end of file54\ No newline at end of file
155
=== added file 'account_cash_discount_us/__init__.py'
--- account_cash_discount_us/__init__.py 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/__init__.py 2011-10-06 15:23:28 +0000
@@ -0,0 +1,26 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23
24import account_cash_discount
25# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
26
027
=== added file 'account_cash_discount_us/__openerp__.py'
--- account_cash_discount_us/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/__openerp__.py 2011-10-06 15:23:28 +0000
@@ -0,0 +1,54 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23
24{
25 "name" : "Payment Term with Cash Discount",
26 "version" : "1.15",
27 "depends" : ["account","account_voucher_credits_us","account_cash_discount"],
28 "author" : "NovaPoint Group LLC",
29 "description" : "Cash discounts, based on payment terms",
30 "website" : "http://www.novapointgroup.com/",
31 "category" : "Generic Modules/Accounting",
32 "description": """
33 This module adds cash discounts on payment terms. Cash discounts
34 for a payment term can be configured with:
35 * A number of days,
36 * A discount (%),
37 * A debit and a credit account
38 * Sales and Purchase discounts are added to product and invoice line
39 """,
40 "init_xml" : [
41 ],
42 "demo_xml" : [
43 ],
44 "update_xml" : [
45 "account_cash_discount_view.xml",
46 "product_view.xml",
47 "security/ir.model.access.csv",
48 ],
49 "active": False,
50 "installable": True,
51
52}
53# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
54
055
=== added file 'account_cash_discount_us/__terp__.py'
--- account_cash_discount_us/__terp__.py 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/__terp__.py 2011-10-06 15:23:28 +0000
@@ -0,0 +1,52 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22{
23 "name" : "Payment Term with Cash Discount",
24 "version" : "1.07",
25 "depends" : ["account","account_voucher_credits_us","account_cash_discount"],
26 "author" : "Tiny and NovaPoint Group LLC",
27 "description" : "Cash discounts, based on payment terms",
28 "website" : "http://www.novapointgroup.com/",
29 "category" : "Generic Modules/Accounting",
30 "description": """
31 This module adds cash discounts on payment terms. Cash discounts
32 for a payment term can be configured with:
33 * A number of days,
34 * A discount (%),
35 * A debit and a credit account
36 * Sales and Purchase discounts are added to product and invoice line
37 """,
38 "init_xml" : [
39 ],
40 "demo_xml" : [
41 ],
42 "update_xml" : [
43 "account_cash_discount_view.xml",
44 "product_view.xml",
45 "security/ir.model.access.csv",
46 ],
47 "active": False,
48 "installable": True,
49
50}
51# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
52
053
=== added file 'account_cash_discount_us/account_cash_discount.py'
--- account_cash_discount_us/account_cash_discount.py 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/account_cash_discount.py 2011-10-06 15:23:28 +0000
@@ -0,0 +1,941 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23from collections import defaultdict
24from mx.DateTime import RelativeDateTime
25from osv import fields, osv
26from tools.translate import _
27import decimal_precision as dp
28import mx.DateTime
29from amount_to_words import amount_to_words
30from tools.amount_to_text_en import amount_to_text
31
32def _combinations(iterable, r):
33 '''
34 @return: combination generator object
35
36 Example
37 combinations(’ABCD’, 2) --> AB AC AD BC BD CD
38 combinations(range(4), 3) --> 012 013 023 123
39 '''
40 pool = tuple(iterable)
41 n = len(pool)
42 if r > n:
43 return
44 indices = range(r)
45 yield tuple(pool[i] for i in indices)
46 while True:
47 for i in reversed(range(r)):
48 if indices[i] != i + n - r:
49 break
50 else:
51 return
52 indices[i] += 1
53 for j in range(i+1, r):
54 indices[j] = indices[j-1] + 1
55 yield tuple(pool[i] for i in indices)
56
57
58class account_payment_term(osv.osv):
59 _name = "account.payment.term"
60 _inherit = "account.payment.term"
61 _columns = {
62 'cash_discount_ids': fields.one2many('account.cash.discount', 'payment_id', 'Cash Discounts'),
63 }
64 def get_discounts(self, cr, uid, id, base_date, context={}):
65 """
66 return the list of (date,percentage) ordered by date for the
67 payment term with the corresponding id. return [] if no cash
68 discount are defined. base_date is the date from where the
69 discounts are computed.
70 """
71 res=[]
72 for pt in self.browse(cr, uid, id, context):
73
74 if not pt.cash_discount_ids:
75 continue
76
77 for d in pt.cash_discount_ids:
78 res.append(
79 ((mx.DateTime.strptime(base_date,'%Y-%m-%d') +\
80 RelativeDateTime(days=d.delay)).strftime("%Y-%m-%d"),
81 d.discount)
82 )
83
84 res.sort(cmp=lambda x,y: cmp(x[0],y[0]))
85 return res
86account_payment_term()
87
88class account_invoice(osv.osv):
89 '''
90 Add discount calculation to invoice
91 '''
92 _inherit = 'account.invoice'
93
94 def _get_discount(self, cr, uid, ids, field_name, args, context={}):
95 '''
96 Calculate the value of variable date_discount (Discount Date) and amount_discounted (Discounted Total)
97 '''
98
99 if context is None:
100 context = {}
101 for invoice in self.browse(cr, uid, ids, context):
102 res = defaultdict(list)
103 res[invoice.id] = {
104 'date_discount': invoice.date_due,
105 'amount_discounted': invoice.amount_total
106 }
107 if not invoice.date_invoice:
108 invoice_date = mx.DateTime.today().strftime("%Y-%m-%d")
109 self.write(cr, uid, [invoice.id], {'date_invoice': invoice_date}, context)
110 else:
111 invoice_date = invoice.date_invoice
112 discounts = invoice.payment_term and invoice.payment_term.get_discounts(invoice_date, context=context)
113 if discounts:
114 line_obj = self.pool.get('account.invoice.line')
115 discount_total = 0.0
116 non_discount_total = 0.0
117 for line in invoice.invoice_line:
118 if line.cash_discount:
119 discount_total += line.price_subtotal
120 line_cash_discount = round((1.0 - discounts[0][1]) * line.price_subtotal)
121 line_obj.write(cr, uid, line.id, {'cash_discount': line_cash_discount}, context)
122 else:
123 non_discount_total += line.price_subtotal
124 line_obj.write(cr, uid, line.id, {'cash_discount': 0.0}, context)
125 # assume taxes are never discountable
126 non_discount_total += invoice.amount_tax
127 # There may be more than one - return the earliest
128 res[invoice.id] = {
129 'date_discount': discounts[0][0],
130 'amount_discounted': round(((1.0 - discounts[0][1]) * discount_total) + non_discount_total,2)
131 }
132 return defaultdict(type([]),res)
133
134 _columns = {
135 'date_discount': fields.function(_get_discount, method=True, type='date', string='Discount Date', multi='all'),
136 'amount_discounted': fields.function(_get_discount, method=True, type='float', digits_compute=dp.get_precision('Account'), string='Discounted Total',
137 multi='all'),
138 }
139account_invoice()
140
141class account_invoice_pay_writeoff(osv.osv_memory):
142 """
143 Opens the write off amount pay form.
144 """
145 _name = "account.invoice.pay.writeoff"
146 _description = "Pay Invoice "
147 _columns = {
148 'writeoff_acc_id': fields.many2one('account.account', 'Write-Off account', required=True),
149 'writeoff_journal_id': fields.many2one('account.journal', 'Write-Off journal', required=True),
150 'comment': fields.char('Comment', size=64, required=True),
151 'analytic_id': fields.many2one('account.analytic.account','Analytic Account'),
152 }
153 _defaults = {
154 'comment': 'Write-Off',
155 }
156
157account_invoice_pay_writeoff()
158
159class account_invoice_pay(osv.osv_memory):
160 """
161 Generate pay invoice wizard, user can make partial or full payment for invoice.
162 """
163 _name = "account.invoice.pay"
164 _description = "Pay Invoice "
165 _columns = {
166 'amount': fields.float('Amount paid', required=True, digits_compute = dp.get_precision('Account')),
167 'name': fields.char('Entry Name', size=64, required=True),
168 'date': fields.date('Date payment', required=True),
169 'journal_id': fields.many2one('account.journal', 'Journal/Payment Mode', required=True, domain=[('type','=','cash')]),
170 'period_id': fields.many2one('account.period', 'Period', required=True),
171 }
172
173 def view_init(self, cr, uid, ids, context=None):
174 invoice = self.pool.get('account.invoice').browse(cr, uid, context['active_id'], context=context)
175 if invoice.state in ['draft', 'proforma2', 'cancel']:
176 raise osv.except_osv(_('Error !'), _('Can not pay draft/proforma/cancel invoice.'))
177 pass
178
179 def _get_period(self, cr, uid, context=None):
180 '''
181 Initialise Period
182 '''
183 ids = self.pool.get('account.period').find(cr, uid, context=context)
184 period_id = False
185 if len(ids):
186 period_id = ids[0]
187 return period_id
188
189 def _get_amount(self, cr, uid, context=None):
190 '''
191 Get default value of Amount paid
192 '''
193 return self.pool.get('account.invoice').browse(cr, uid, context['active_id'], context=context).residual
194
195 _defaults = {
196 'date': lambda *a: time.strftime('%Y-%m-%d'),
197 'period_id': _get_period,
198 'amount': _get_amount,
199 }
200account_invoice_pay()
201
202class account_voucher(osv.osv):
203 _name = 'account.voucher'
204 _inherit = 'account.voucher'
205 def calc_supp_diff(self, cr, uid, ids, context={}):
206 '''
207 Called by calculate/re-calculate action.
208 This method will update the credit lines on voucher lines.
209 If the field "auto_match" marked, this method will run a matching routine
210 '''
211 res = {'nodestroy':True}
212 amount_cash_discount = 0.0
213 amount_interest = 0.0
214
215 for vch in self.browse(cr, uid, ids):
216 for line in vch.line_dr_ids:
217 '''
218 Update the credit lines and discount lines so that matching routine can use the latest available credits and discounts
219 '''
220# line._update_debit_lines( context=context)
221 line._update_supp_discount_lines(context=context)
222
223# if vch.auto_match:
224# '''
225# Try the matching routine including the manual selection
226# '''
227# ret = self._find_exact_match(cr, uid, vch.line_cr_ids, vch.amount, mark_pay=False, use_discount=False, context=False)
228# if not ret:
229# '''
230# Try to match considering all voucher lines
231# '''
232# ret = self._find_exact_match(cr, uid, vch.line_cr_ids, vch.amount, mark_pay=True, use_discount=False, context=False)
233# if not ret:
234# '''
235# Try to match considering discount
236# '''
237# ret = self._find_exact_match(cr, uid, vch.line_cr_ids, vch.amount, mark_pay=True, use_discount=True, context=False)
238
239 return res
240
241 def _update_discounts(self, lines, vch_date):
242 date_discount = False
243 amount_discount = False
244 for line in lines:
245 if 'date_discount' in line:
246 date_discount = line['date_discount']
247 amount_discounted = line['amount_discounted']
248 else:
249 return
250 if line['amount'] >= line['amount_unreconciled']:
251 amount_discount = 0.0
252 elif vch_date <= date_discount and line['amount'] <= line['amount_unreconciled'] and line['amount'] >= amount_discounted:
253 amount_discount = max(line['amount_unreconciled'] - amount_discounted, 0.0)
254 elif vch_date <= date_discount and line['amount'] < amount_discounted:
255 amount_discount = max(line['amount_unreconciled'] - amount_discounted, 0.0)
256 line['cash_discount'] = amount_discount
257 line['amount_difference'] = line['amount_unreconciled'] - line['amount'] - amount_discount
258
259
260 def onchange_partner_id(self, cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context={}):
261 '''
262 Function to update fields in customer payment form on changing customer
263 '''
264 if context is None:
265 context = {}
266
267 currency_pool = self.pool.get('res.currency')
268 journal_pool = self.pool.get('account.journal')
269 invoice_pool = self.pool.get('account.invoice')
270 line_pool = self.pool.get('account.voucher.line')
271 move_line_pool = self.pool.get('account.move.line')
272 partner_pool = self.pool.get('res.partner')
273 company_currency = False
274
275 default = super(account_voucher, self).onchange_partner_id(cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context={})
276 if not partner_id:
277 return default
278 # we have to clear out lines, because new lines will be created by the change
279 if partner_id and not journal_id:
280 partner = partner_pool.browse(cr, uid, partner_id, context)
281 if partner._columns.has_key('payment_meth_id') and partner.payment_meth_id:
282 payment_mode_pool = self.pool.get('payment.mode')
283 payment_meth = payment_mode_pool.browse(cr, uid, partner.payment_meth_id.id, context)
284 if payment_meth:
285 default['value']['journal_id'] = payment_meth.journal.id
286 journal_id = payment_meth.journal.id
287 if ids:
288 line_ids = line_pool.search(cr, uid, [('voucher_id','=',ids[0])])
289 if line_ids:
290 line_pool.unlink(cr, uid, line_ids)
291 if journal_id:
292 journal = journal_pool.browse(cr, uid, journal_id)
293 company_currency = journal.company_id.currency_id.id
294
295 total_credit = 0.0
296 total_debit = 0.0
297 vch_date = False
298 for vch in self.browse(cr, uid, ids):
299 vch_date = vch.date
300 if default and 'value' in default and 'line_cr_ids' in default['value']:
301 for line in default['value']['line_cr_ids']:
302 invoice_id = invoice_pool.search(cr, uid, [('number', '=', line['name'])])
303 if invoice_id:
304 line['invoice_id'] = invoice_id[0]
305 invoice = invoice_pool.browse(cr, uid, invoice_id[0], )
306 date_discount = invoice.date_discount
307 amount_discounted = invoice.amount_discounted
308 line['date_discount'] = date_discount
309 line['amount_discounted'] = amount_discounted
310 else:
311 line['date_discount'] = False
312 line['amount_discounted'] = 0.0
313 line['amount'] = 0.0
314 total_credit += line['type'] == 'cr' and line['amount_unreconciled'] or 0.0
315 total_debit += line['type'] == 'dr' and line['amount_unreconciled'] or 0.0
316 # first, see if we can find an invoice matching the amount to be applied
317 found = False
318 def calc_amount(line, total):
319 return min(line['amount_unreconciled'], total)
320 lines = default['value']['line_cr_ids']
321 if len(lines) == 0:
322 return default
323# return False
324 # if only one, assign it
325 if len(lines) == 1:
326 for line in lines:
327 if line['type'] == 'cr':
328 amount = price
329 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount
330 total_credit -= amount
331 found = True
332 break
333 else:
334 amount = price
335 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount
336 total_debit -= amount
337 found = True
338 break
339 self._update_discounts(lines, vch_date)
340 if not found:
341 for line in lines:
342 if line['amount_unreconciled'] == price:
343 if line['type'] == 'cr':
344 amount = calc_amount(line, total_credit)
345 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount
346 total_credit -= amount
347 found = True
348 break
349 else:
350 amount = calc_amount(line, total_debit)
351 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount
352 total_debit -= amount
353 found = True
354 break
355 if not found:
356 # see if we can find a combination that matches
357 def search(lines, price):
358 for i in range(0, len(lines)):
359 if lines[i]['amount_unreconciled'] == price:
360 return [lines[i]]
361 for i in range(0, len(lines)):
362 for j in range(i + 1, len(lines)):
363 if lines[i]['amount_unreconciled'] + lines[j]['amount_unreconciled'] == price:
364 return [lines[i],lines[j]]
365 for i in range(0, len(lines)):
366 for j in range(i + 1, len(lines)):
367 for k in range(j + 1, len(lines)):
368 if lines[i]['amount_unreconciled'] + lines[j]['amount_unreconciled'] + lines[k]['amount_unreconciled']== price:
369 return [lines[i],lines[j],lines[k]]
370 line_ids = search(lines, price)
371
372 if line_ids: # and sum == price:
373 for line in line_ids:
374 if line['type'] == 'cr':
375 amount = calc_amount(line, line['amount_unreconciled'])
376 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount)
377 total_debit -= amount
378 found = True
379 else:
380 amount = calc_amount(line, line['amount_unreconciled'])
381 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount)
382 total_credit -= amount
383 found = True
384 if not found:
385 # see if we can find a match using discounted amount
386 def search2(lines, price):
387 for i in range(0, len(lines)):
388 if min(lines[i]['amount_unreconciled'],lines[i]['amount_discounted']) == price:
389 return [lines[i]]
390 for i in range(0, len(lines)):
391 for j in range(i + 1, len(lines)):
392 if min(lines[i]['amount_unreconciled'],lines[i]['amount_discounted']) + min(lines[j]['amount_unreconciled'],lines[j]['amount_discounted']) == price:
393 return [lines[i],lines[j]]
394 for i in range(0, len(lines)):
395 for j in range(i + 1, len(lines)):
396 for k in range(j + 1, len(lines)):
397 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:
398 return [lines[i],lines[j],lines[k]]
399 line_ids = search(lines, price)
400 lines = default['value']['line_cr_ids']
401 line_ids = search2(lines, price)
402 if line_ids:
403 for line in line_ids:
404 if line['type'] == 'cr':
405 amount = calc_amount(line, min(line['amount_unreconciled'],line['amount_discounted']))
406 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, min(line['amount_unreconciled'],line['amount_discounted']))
407 total_debit -= amount
408 found = True
409 else:
410 amount = calc_amount(line, min(line['amount_unreconciled'],line['amount_discounted']))
411 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, min(line['amount_unreconciled'],line['amount_discounted']))
412 total_credit -= amount
413 found = True
414 lines = default['value']['line_cr_ids']
415 '''
416 FIXME : removing amount from line_dr_ids (Credits on customer payment form) line.
417 and amount from line_cr_ids (Invoice and outstanding transactions on customer payment form) line
418 I do not think this this is a good solution. But it works.
419 The whole "onchange_partner_id" function need a re-thinking (may have to rewrite it completely instead of calling super ).
420 '''
421 if default:
422 for credit_line in default['value'].get('line_dr_ids',[]):
423 credit_line['amount'] = 0.0
424 for invoce_line in default['value'].get('line_cr_ids',[]):
425 invoce_line['amount'] = 0.0
426 invoce_line['amount_difference'] = invoce_line['amount_unreconciled']
427 return default
428
429 def calc_cash_discount(self, cr, uid, ids, vch, line, context={}):
430 '''
431 Calculate discount per line
432 '''
433 total_allocated = 0.0
434 for line in vch.line_ids:
435 total_allocated += line.amount
436 context.update({'total_allocated': total_allocated, 'total_amount': vch.date})
437 amount_discount = 0.0
438 if line.amount >= line.amount_unreconciled or line.amount < 0.01 :
439 amount_discount = 0.0
440 elif line.amount >= line.amount_discounted and vch.date <= line.date_discount:
441 amount_discount = line.amount_unreconciled - line.amount_discounted
442 return amount_discount
443
444
445 def onchange_amount(self, cr, uid, ids, amount, context={}):
446 if not context:
447 context = {}
448 result = {}
449 currency_format = self.pool.get('res.users').browse(cr, uid, uid).company_id.currency_format
450 if currency_format=='us':
451 amount_in_words = amount_to_words(amount)
452 else: amount_in_words = amount_to_text(amount)
453 result['amount_in_word']=amount_in_words
454 return {'value':result}
455account_voucher()
456
457class account_voucher_line(osv.osv):
458 _name = 'account.voucher.line'
459 _inherit = 'account.voucher.line'
460 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={}):
461 '''
462 Function to automatically fill the values when the pay checkbox is selected
463 '''
464 ret = {}
465 writeoff_amount = (not writeoff_amount and [0] or [writeoff_amount])[0]
466 discount_used = (not discount_used and [0] or [discount_used])[0]
467 credit_used = (not credit_used and [0] or [credit_used])[0]
468 if pay:
469 tot_amt = par_amount + line_amount
470 for credit in par_cr_ids:
471 if credit[2].get('pay'):
472 tot_amt -= (credit[2]['amount'])
473 if tot_amt < 0:
474 ret['amount'] = 0.0
475 else:
476 amount_unreconciled -= (discount_used+writeoff_amount+credit_used)
477 ret['amount'] = min(tot_amt,(amount_unreconciled<0) and 0 or amount_unreconciled)
478 else:
479 ret['amount'] = 0.0
480 return {'value':ret}
481 def recalculate_supp_values(self, cr, uid, ids, context={}):
482 '''
483 Re-calculate button action
484 '''
485 if type(ids) == type([]):
486 voucher_line = self.browse(cr,uid,ids[0])
487 else:
488 voucher_line = self.browse(cr,uid,ids)
489 if voucher_line.discount_used:
490 print "discount_useddiscount_useddiscount_useddiscount_useddiscount_useddiscount_useddiscount_useddiscount_useddiscount_useddiscount_used"
491 self.write(cr,uid,ids,{'amount':voucher_line.amount_unreconciled - voucher_line.discount_used})
492 self.pool.get('account.voucher').calc_supp_diff(cr, uid, [voucher_line.voucher_id.id])
493 return True
494
495
496
497 def _update_credit_lines(self,cr, uid, ids, context):
498 '''
499 Function to update the credit lines in payment lines
500 '''
501 credits_used_pool = self.pool.get('account.voucher.line.credits_to_use')
502 for line in self.browse(cr , uid, ids, context):
503 credits_lines_used = [x.orginal_credit_line_id.id for x in line.available_credits]
504 for credit_line in line.voucher_id.line_dr_ids :
505 if credit_line.id not in credits_lines_used and line.invoice_id and line.invoice_id.payment_term:
506 credits_used_pool.create(cr, uid, {
507 'voucher_line_id': line.id,
508 'orginal_credit_line_id':credit_line.id,
509 'use_credit': False,
510 'inv_credit': credit_line.move_line_id.id,
511 'discount_window_date': credit_line.date_original,
512 'orginal_amount': credit_line.amount_original,
513 'available_amount': credit_line.amount_unreconciled - credit_line.pending_credits,
514 'discount_amount': 0.0,
515 'gl_account' : credit_line.account_id.id,})
516 else :
517 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)
518 if to_update_credit_line_ids:
519 credits_used_pool.write(cr, uid,to_update_credit_line_ids,{'available_amount': credit_line.amount_unreconciled-credit_line.pending_credits}, context=context)
520
521 def _update_discount_lines(self,cr, uid, ids, context):
522 '''
523 Function to update the discount lines in payment lines
524 '''
525
526 discount_used_pool = self.pool.get('account.voucher.line.discount_to_use')
527 user_pool = self.pool.get('res.users')
528 user = user_pool.browse(cr, uid, uid, context)
529 for line in self.browse(cr , uid, ids, context):
530 if line.invoice_id:
531 if not line.invoice_id.date_discount or not line.voucher_id.date or line.voucher_id.date > line.invoice_id.date_discount:
532 '''
533 customer is not eligible for the discount
534 '''
535 continue
536
537 discount = line.invoice_id.amount_total - line.invoice_id.amount_discounted
538 date_discount = line.invoice_id.date_discount
539 discount_found = False
540 for discount_line in line.available_discounts:
541 #if abs(discount - discount_line.proposed_discount) < 0.01 and line.invoice_id.payment_term.id == discount_line.inv_payment_terms.id:
542 if line.invoice_id.payment_term.id == discount_line.inv_payment_terms.id:
543 discount_found = True
544 continue
545 if not discount_found and user.company_id.sales_discount_account:
546 '''
547 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.)
548 '''
549 discount_used_pool.create(cr, uid, {
550 'voucher_line_id': line.id,
551 'use_discount': False,
552 'inv_payment_terms':line.invoice_id.payment_term.id ,
553 'discount_window_date': date_discount,
554 'proposed_discount': discount,
555 'discount_amount': 0.0,
556 'gl_account':user.company_id.sales_discount_account.id
557 }, context=context)
558
559 def _update_supp_discount_lines(self,cr, uid, ids, context):
560 '''
561 Function to update the discount lines in payment lines
562 '''
563
564 discount_used_pool = self.pool.get('account.voucher.line.discount_to_use')
565 user_pool = self.pool.get('res.users')
566 user = user_pool.browse(cr, uid, uid, context)
567 for line in self.browse(cr , uid, ids, context):
568 if line.invoice_id:
569 if not line.invoice_id.date_discount or not line.voucher_id.date or line.voucher_id.date > line.invoice_id.date_discount:
570 '''
571 customer is not eligible for the discount
572 '''
573 continue
574
575 discount = line.invoice_id.amount_total - line.invoice_id.amount_discounted
576 date_discount = line.invoice_id.date_discount
577 discount_found = False
578 for discount_line in line.available_discounts:
579 #if abs(discount - discount_line.proposed_discount) < 0.01 and line.invoice_id.payment_term.id == discount_line.inv_payment_terms.id:
580 if line.invoice_id.payment_term.id == discount_line.inv_payment_terms.id:
581 discount_found = True
582 continue
583 if not discount_found and user.company_id.purchase_discount_account:
584 '''
585 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.)
586 '''
587 discount_used_pool.create(cr, uid, {
588 'voucher_line_id': line.id,
589 'use_discount': False,
590 'inv_payment_terms':line.invoice_id.payment_term.id ,
591 'discount_window_date': date_discount,
592 'proposed_discount': discount,
593 'discount_amount': 0.0,
594 'gl_account':user.company_id.purchase_discount_account.id
595 }, context=context)
596
597
598 def _compute_discount_used(self, cr, uid, ids, name, args, context=None):
599 '''
600 Function to calculate the value of variable discount used
601 '''
602 res = {}
603 for line in self.browse(cr, uid, ids):
604 res[line.id] = 0.0
605 for discount_line in line.available_discounts:
606 if discount_line.use_discount :
607 res[line.id] += discount_line.discount_amount
608 return res
609
610 def _compute_balance(self, cr, uid, ids, name, args, context=None):
611 '''
612 Function to calculate the value of variables Cash Discount, Interest and Amt Due
613 '''
614 currency_pool = self.pool.get('res.currency')
615 rs_data = super(account_voucher_line, self)._compute_balance(cr, uid, ids, name, args, context)
616 for line in self.browse(cr, uid, ids):
617 amount_cash_discount = self.calc_cash_discount(cr, uid, ids, vch, line)
618 amount_interest = self.calc_interest(vch, line, line.amount)
619 amount_unreconciled = 0.0
620 move_line = line.move_line_id or False
621 if move_line:
622 amount_unreconciled = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.amount_unreconciled - amount_cash_discount - line.writeoff)
623 rs_data[line.id] = {'cash_discount': amount_cash_discount, 'interest': amount_interest, 'amount_unreconciled': amount_unreconciled}
624 return rs_data
625
626 def _get_discount(self, cr, uid, ids, field_name, args, context={}):
627 """
628 Function to calculate the value of variable date_discount,amount_discounted,cash_discount,amount_difference
629 return the values as dictionary
630 """
631
632 if context is None:
633 context = {}
634 invoice_obj = self.pool.get('account.invoice')
635 move_line_obj = self.pool.get('account.move.line')
636 voucher_line = self.browse(cr, uid, ids)
637 vch = self.pool.get('account.voucher').browse(cr, uid, voucher_line[0].voucher_id.id)
638 res = {}
639 for line in voucher_line:
640 if line.type == 'dr':
641 res[line.id] = {
642 'date_discount': '',
643 'amount_discounted': line.amount,
644 'cash_discount': 0.0,
645 'amount_difference': line.amount_unreconciled - line.amount ,
646 }
647 continue
648 move_line = move_line_obj.browse(cr, uid, line.move_line_id.id)
649 invoice_number = move_line.name or move_line.ref
650 invoice_id = False
651 if invoice_number and invoice_number != '/':
652 invoice_id = invoice_obj.search(cr, uid, [('number', '=', str(invoice_number))])
653 if not invoice_id:
654 move = self.pool.get('account.move').browse(cr, uid, move_line.move_id.id)
655 if move:
656 invoice_number = move.name or move.ref
657 if invoice_number and invoice_number != '/':
658 invoice_id = invoice_obj.search(cr, uid, [('number', '=', str(invoice_number))])
659 if invoice_id:
660 for invoice in invoice_obj.browse(cr, uid, invoice_id, context):
661 date_discount = invoice.date_due
662 amount_discounted = invoice.amount_total
663 res[line.id] = {
664 'date_discount': invoice.date_due,
665 'amount_discounted': invoice.amount_total
666 }
667 if not invoice.date_invoice:
668 invoice_date = mx.DateTime.today().strftime("%Y-%m-%d")
669 self.write(cr, uid, [invoice.id], {'date_invoice': invoice_date}, context)
670 else:
671 invoice_date = invoice.date_invoice
672 discounts = invoice.payment_term and invoice.payment_term.get_discounts(invoice_date, context=context) or False
673 if discounts:
674 line_obj = self.pool.get('account.invoice.line')
675 discount_total = 0.0
676 non_discount_total = 0.0
677 for invline in invoice.invoice_line:
678 if invline.cash_discount:
679 discount_total += invline.price_subtotal
680 line_cash_discount = round((1.0 - discounts[0][1]) * invline.price_subtotal)
681 line_obj.write(cr, uid, invline.id, {'cash_discount': line_cash_discount}, context)
682 else:
683 non_discount_total += invline.price_subtotal
684 line_obj.write(cr, uid, invline.id, {'cash_discount': 0.0}, context)
685 # assume taxes are never discountable
686 non_discount_total += invoice.amount_tax
687 # There may be more than one - return the earliest
688 date_discount = discounts[0][0]
689 amount_discounted = round(((1.0 - discounts[0][1]) * discount_total) + non_discount_total,2)
690 amount_discount = 0.0
691 if line.amount >= line.amount_unreconciled or line.amount < 0.01:
692 amount_discount = 0.0
693 elif vch.date <= date_discount and line.amount <= line.amount_unreconciled:
694 amount_discount = max(line.amount_unreconciled - amount_discounted, 0.0)
695 elif vch.date <= date_discount and line.amount < amount_discounted:
696 amount_discount = max(line.amount_unreconciled - amount_discounted,0.0)
697 else:
698 amount_discount = 0.0
699
700 res[line.id] = {
701 'date_discount': date_discount,
702 'amount_discounted': amount_discounted,
703 'cash_discount': amount_discount,
704 '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
705 }
706 return defaultdict(type([]),res)
707 def _get_supp_discount(self, cr, uid, ids, field_name, args, context={}):
708 """
709 Function to calculate the value of variable date_discount,amount_discounted,cash_discount,amount_difference
710 return the values as dictionary
711 """
712
713 if context is None:
714 context = {}
715 invoice_obj = self.pool.get('account.invoice')
716 move_line_obj = self.pool.get('account.move.line')
717 voucher_line = self.browse(cr, uid, ids)
718 vch = self.pool.get('account.voucher').browse(cr, uid, voucher_line[0].voucher_id.id)
719 res = {}
720 for line in voucher_line:
721 if line.type == 'cr':
722 res[line.id] = {
723 'date_discount': '',
724 'amount_discounted': line.amount,
725 'cash_discount': 0.0,
726 'supp_amount_difference': line.amount_unreconciled - line.amount ,
727 'discount' : False
728 }
729 continue
730 move_line = move_line_obj.browse(cr, uid, line.move_line_id.id)
731 invoice_number = move_line.name or move_line.ref
732 invoice_id = False
733 if invoice_number and invoice_number != '/':
734 invoice_id = invoice_obj.search(cr, uid, [('number', '=', str(invoice_number))])
735 if not invoice_id:
736 move = self.pool.get('account.move').browse(cr, uid, move_line.move_id.id)
737 if move:
738 invoice_number = move.name or move.ref
739 if invoice_number and invoice_number != '/':
740 invoice_id = invoice_obj.search(cr, uid, [('number', '=', str(invoice_number))])
741 if invoice_id:
742 for invoice in invoice_obj.browse(cr, uid, invoice_id, context):
743 date_discount = invoice.date_due
744 amount_discounted = invoice.amount_total
745 res[line.id] = {
746 'date_discount': invoice.date_due,
747 'supp_amount_difference': invoice.amount_total
748 }
749 if not invoice.date_invoice:
750 invoice_date = mx.DateTime.today().strftime("%Y-%m-%d")
751 self.write(cr, uid, [invoice.id], {'date_invoice': invoice_date}, context)
752 else:
753 invoice_date = invoice.date_invoice
754 discounts = invoice.payment_term and invoice.payment_term.get_discounts(invoice_date, context=context) or False
755 if discounts:
756 line_obj = self.pool.get('account.invoice.line')
757 discount_total = 0.0
758 non_discount_total = 0.0
759 for invline in invoice.invoice_line:
760 if invline.cash_discount:
761 discount_total += invline.price_subtotal
762 line_cash_discount = round((1.0 - discounts[0][1]) * invline.price_subtotal)
763 line_obj.write(cr, uid, invline.id, {'cash_discount': line_cash_discount}, context)
764 else:
765 non_discount_total += invline.price_subtotal
766 line_obj.write(cr, uid, invline.id, {'cash_discount': 0.0}, context)
767 # assume taxes are never discountable
768 non_discount_total += invoice.amount_tax
769 # There may be more than one - return the earliest
770 date_discount = discounts[0][0]
771 amount_discounted = round(((1.0 - discounts[0][1]) * discount_total) + non_discount_total,2)
772 amount_discount = 0.0
773 if line.amount >= line.amount_unreconciled or line.amount < 0.01:
774 amount_discount = 0.0
775 elif vch.date <= date_discount and line.amount <= line.amount_unreconciled:
776 amount_discount = max(line.amount_unreconciled - amount_discounted, 0.0)
777 elif vch.date <= date_discount and line.amount < amount_discounted:
778 amount_discount = max(line.amount_unreconciled - amount_discounted,0.0)
779 else:
780 amount_discount = 0.0
781 discount=False
782 if line.available_discounts:
783# if line.discount_used:
784 discount=True
785 res[line.id] = {
786 'date_discount': date_discount,
787 'amount_discounted': amount_discounted,
788 'cash_discount': amount_discount,
789 '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
790 'discount':discount
791 }
792 return defaultdict(type([]),res)
793
794
795 _columns = {
796 'date_discount': fields.function(_get_discount, method=True, type='date', string='Discount Date',
797 multi='all'),
798 'amount_discounted': fields.function(_get_discount, method=True, type='float', digits_compute=dp.get_precision('Account'), string='Discounted Total',
799 multi='all'),
800 'cash_discount': fields.function(_get_discount, method=True, type='float', multi="all", digits_compute=dp.get_precision('Account'), string='Cash Discount',sequence=20),
801 'amount_difference': fields.function(_get_discount, method=True, multi='all', type='float', string='Unpaid Amt', digits=(16, 2) ),
802 'supp_amount_difference': fields.function(_get_supp_discount, method=True, multi='all', type='float', string='Unpaid Amt', digits=(16, 2) ),
803 'interest': fields.float(string='Interest', digits=(16,2)),
804
805 #'discount_used':fields.float('Discount used', readonly=True),
806 'discount_used': fields.function(_compute_discount_used, method=True, type='float', string='Discount Used', store=False, readonly=True,sequence=10),
807 'available_discounts':fields.one2many('account.voucher.line.discount_to_use', 'voucher_line_id', 'Available Discounts' ),
808 'discount': fields.function(_get_supp_discount, method=True, multi='all', type='boolean', string='Discount', readonly=True, sequence=20)
809 }
810 def clear_values(self, cr, uid, ids, context={}):
811 '''
812 Clear the selected credits, discounts and writeoffs from voucher line
813 '''
814 voucher_line = self.browse(cr,uid,ids[0])
815 if voucher_line._columns.has_key('writeoff_ids'):
816 for lines in self.read(cr,uid,ids,['available_credits','writeoff_ids','available_discounts']):
817 lines['writeoff_ids'] and self.pool.get('account.voucher.line.writeoff').unlink(cr,uid,lines['writeoff_ids'])
818 lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'],{
819 'use_credit':False,
820 'discount_amount':0.0})
821 lines['available_discounts'] and self.pool.get('account.voucher.line.discount_to_use').write(cr,uid,lines['available_discounts'],{
822 'use_discount':False,
823 'discount_amount':0.0})
824 else:
825 for lines in self.read(cr,uid,ids,['available_credits','writeoff_ids','available_discounts']):
826 lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'],{
827 'use_credit':False,
828 'discount_amount':0.0})
829 lines['available_discounts'] and self.pool.get('account.voucher.line.discount_to_use').write(cr,uid,lines['available_discounts'],{
830 'use_discount':False,
831 'discount_amount':0.0})
832 return True
833account_voucher_line()
834
835class product_product(osv.osv):
836 '''
837 Add new account configuration fields to product
838 '''
839 _name = "product.product"
840 _inherit = 'product.product'
841 _columns = {
842 'cash_discount': fields.boolean('Cash Discount?'),
843 'purchase_discount_account': fields.many2one('account.account', 'Purchase Discount Account', domain=[('user_type','=','COGS')]),
844 'sales_discount_account': fields.many2one('account.account', 'Sales Discount Account', domain=[('type','!=','view'),('type','!=','consolidation'),('user_type','ilike','income')]),
845 'purchase_discount_journal': fields.many2one('account.journal', 'Purchase Discount Journal', domain=[('type','!=','view'),('type','!=','consolidation'),('type','=','purchase')]),
846 'sales_discount_journal': fields.many2one('account.journal', 'Sales Discount Journal', domain=[('type','=','sale')]),
847 }
848 _defaults = {
849 'cash_discount' : lambda *a : True,
850 }
851product_product()
852
853class account_invoice_line(osv.osv):
854 '''
855 option to disable discount calculation per invoice line
856 '''
857 _name = 'account.invoice.line'
858 _inherit = 'account.invoice.line'
859 _columns = {
860 'cash_discount': fields.boolean('Cash Discount?'),
861 }
862 _defaults = {
863 'cash_discount' : lambda *a : True,
864 }
865 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):
866 '''
867 check if the discount is applicable to newly selected product
868 '''
869 result = {}
870 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)
871 if product:
872 res = self.pool.get('product.product').browse(cr, uid, product, context=context)
873 result['value']['cash_discount'] = res.cash_discount
874 else:
875 result['value']['cash_discount'] = True
876 return result
877account_invoice_line()
878
879class res_company(osv.osv):
880 '''
881 New account configuration fields on copmany form
882 '''
883 _name = 'res.company'
884 _inherit = 'res.company'
885 _columns = {
886 'purchase_discount_account': fields.many2one('account.account', 'Purchase Discount Account', domain=[('user_type','=','COGS'),('type','!=','view'),('type','!=','consolidation')]),
887 'sales_discount_account': fields.many2one('account.account', 'Sales Discount Account', domain=[('user_type','=','Income'),('type','!=','view'),('type','!=','consolidation')]),
888 'purchase_discount_journal': fields.many2one('account.journal', 'Purchase Discount Journal', domain=[('type','=','purchase')]),
889 'sales_discount_journal': fields.many2one('account.journal', 'Sales Discount Journal', domain=[('type','=','sale')]),
890 }
891res_company()
892
893class account_voucher_line_discount_to_use(osv.osv):
894 '''
895 Dynamically generated discount lines that are applicable per voucher line
896 '''
897 _name = "account.voucher.line.discount_to_use"
898 _rec_name = 'inv_credit'
899 _columns = {
900 'voucher_line_id': fields.many2one('account.voucher.line', 'Account Voucher Line', ondelete='cascade', readonly=True),
901 'use_discount': fields.boolean('Use Discount',help='Used to indicate if the cash discount should be used/taken when calculating payment.', required=True),
902 'inv_payment_terms': fields.many2one('account.payment.term', 'Invoice Payment Terms', help='Payments terms description', ),
903 '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.'),
904
905
906 '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),
907 'discount_amount': fields.float('Discount Amt',help='Enter the amount of discount to be given.', required=True),
908 'gl_account' : fields.many2one('account.account', 'G/L Account',help='Enter the General Ledger account number to record taking the cash discount.', required=True),
909 }
910 def onchage_use_discount(self, cr, uid, ids, use_discount, proposed_discount, context=None):
911 '''
912 Fill the value with proposed discount when use discount check box is clicked and remove the value when use discount is unchecked
913 '''
914 res = {}
915 if use_discount:
916 res['value'] = {'discount_amount': proposed_discount}
917 else:
918 res['value'] = {'discount_amount': 0}
919 return res
920 def onchage_discount_amount(self, cr, uid, ids, proposed_discount, discount_amount, context=None):
921 '''
922 Function to check discount amount entered in discount line of payment line
923 '''
924 res = {}
925 if discount_amount < 0:
926 res['value'] = {'discount_amount': 0, 'use_discount':False }
927 res['warning'] = {'title': 'Discount not in the limit', 'message': 'Discount should not be a negative value.'}
928 return res
929 if discount_amount > proposed_discount:
930 res['value'] = {'discount_amount': proposed_discount, 'use_discount':True }
931 res['warning'] = {'title': 'Discount not in the limit', 'message': 'Please adjust the Discount Amt value to be less than or equal the Proposed Discount.'}
932 return res
933 if discount_amount == 0.0:
934 res['value'] = { 'use_discount':False }
935 else:
936 res['value'] = { 'use_discount':True }
937 return res
938account_voucher_line_discount_to_use()
939
940# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
941
0942
=== added directory 'account_cash_discount_us/account_cash_discount_us'
=== added file 'account_cash_discount_us/account_cash_discount_us/Change Log.txt'
--- account_cash_discount_us/account_cash_discount_us/Change Log.txt 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/account_cash_discount_us/Change Log.txt 2011-10-06 15:23:28 +0000
@@ -0,0 +1,31 @@
1===============================================================================
2 Version Change Log (account_cash_discount_us)
3===============================================================================
4
51.07 -> 1.08 (2011-02-04) By Sinoj
6 * Optimization and cleanup
7
81.06 -> 1.07 (2010-12-06) By jabir
9 * Removed discount wizard and changed domain filtering
10
111.05 -> 1.06 (2010-12-06) By jabir
12 * Take invoice partner instead of moveline partner
13
14 1.04 -> 1.05 (2010-11-29) By Jabir
15 * Fix placement of Cash Discount Separation Line
16
17 1.03 -> 1.04 (2010-11-29) By Sinoj
18 * Account posting updated for National account
19
20 1.02 -> 1.03 (2010-11-09) By Sinoj
21 * "Debit and Credits" wizard button moved to voucher line
22 * fields on wizard form are readonly
23 * fields on wizard are populated with default values
24 * removed
25
26 1.01 -> 1.02 (2010-11-04) By jabir
27 * Add wizard Discount and Credits
28 * Create button Discount and Credits in customer payment form
29
30 1.0 -> 1.01 (2010-11-04) By sinoj
31 * dependency changed from account_voucher_jdc to account_voucher_credits_us
0\ No newline at end of file32\ No newline at end of file
133
=== added file 'account_cash_discount_us/account_cash_discount_us/__init__.py'
--- account_cash_discount_us/account_cash_discount_us/__init__.py 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/account_cash_discount_us/__init__.py 2011-10-06 15:23:28 +0000
@@ -0,0 +1,26 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23
24import account_cash_discount
25# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
26
027
=== added file 'account_cash_discount_us/account_cash_discount_us/__openerp__.py'
--- account_cash_discount_us/account_cash_discount_us/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/account_cash_discount_us/__openerp__.py 2011-10-06 15:23:28 +0000
@@ -0,0 +1,54 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23
24{
25 "name" : "Payment Term with Cash Discount",
26 "version" : "1.08",
27 "depends" : ["account","account_voucher_credits_us","account_cash_discount"],
28 "author" : "Tiny and NovaPoint Group LLC",
29 "description" : "Cash discounts, based on payment terms",
30 "website" : "http://www.novapointgroup.com/",
31 "category" : "Generic Modules/Accounting",
32 "description": """
33 This module adds cash discounts on payment terms. Cash discounts
34 for a payment term can be configured with:
35 * A number of days,
36 * A discount (%),
37 * A debit and a credit account
38 * Sales and Purchase discounts are added to product and invoice line
39 """,
40 "init_xml" : [
41 ],
42 "demo_xml" : [
43 ],
44 "update_xml" : [
45 "account_cash_discount_view.xml",
46 "product_view.xml",
47 "security/ir.model.access.csv",
48 ],
49 "active": False,
50 "installable": True,
51
52}
53# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
54
055
=== added file 'account_cash_discount_us/account_cash_discount_us/__terp__.py'
--- account_cash_discount_us/account_cash_discount_us/__terp__.py 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/account_cash_discount_us/__terp__.py 2011-10-06 15:23:28 +0000
@@ -0,0 +1,52 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22{
23 "name" : "Payment Term with Cash Discount",
24 "version" : "1.07",
25 "depends" : ["account","account_voucher_credits_us","account_cash_discount"],
26 "author" : "Tiny and NovaPoint Group LLC",
27 "description" : "Cash discounts, based on payment terms",
28 "website" : "http://www.novapointgroup.com/",
29 "category" : "Generic Modules/Accounting",
30 "description": """
31 This module adds cash discounts on payment terms. Cash discounts
32 for a payment term can be configured with:
33 * A number of days,
34 * A discount (%),
35 * A debit and a credit account
36 * Sales and Purchase discounts are added to product and invoice line
37 """,
38 "init_xml" : [
39 ],
40 "demo_xml" : [
41 ],
42 "update_xml" : [
43 "account_cash_discount_view.xml",
44 "product_view.xml",
45 "security/ir.model.access.csv",
46 ],
47 "active": False,
48 "installable": True,
49
50}
51# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
52
053
=== added file 'account_cash_discount_us/account_cash_discount_us/account_cash_discount.py'
--- account_cash_discount_us/account_cash_discount_us/account_cash_discount.py 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/account_cash_discount_us/account_cash_discount.py 2011-10-06 15:23:28 +0000
@@ -0,0 +1,730 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23from collections import defaultdict
24from mx.DateTime import RelativeDateTime
25from osv import fields, osv
26from tools.translate import _
27import decimal_precision as dp
28import mx.DateTime
29
30def _combinations(iterable, r):
31 '''
32 @return: combination generator object
33
34 Example
35 combinations(’ABCD’, 2) --> AB AC AD BC BD CD
36 combinations(range(4), 3) --> 012 013 023 123
37 '''
38 pool = tuple(iterable)
39 n = len(pool)
40 if r > n:
41 return
42 indices = range(r)
43 yield tuple(pool[i] for i in indices)
44 while True:
45 for i in reversed(range(r)):
46 if indices[i] != i + n - r:
47 break
48 else:
49 return
50 indices[i] += 1
51 for j in range(i+1, r):
52 indices[j] = indices[j-1] + 1
53 yield tuple(pool[i] for i in indices)
54
55
56class account_payment_term(osv.osv):
57 _name = "account.payment.term"
58 _inherit = "account.payment.term"
59 _columns = {
60 'cash_discount_ids': fields.one2many('account.cash.discount', 'payment_id', 'Cash Discounts'),
61 }
62 def get_discounts(self, cr, uid, id, base_date, context={}):
63 """
64 return the list of (date,percentage) ordered by date for the
65 payment term with the corresponding id. return [] if no cash
66 discount are defined. base_date is the date from where the
67 discounts are computed.
68 """
69 res=[]
70 for pt in self.browse(cr, uid, id, context):
71
72 if not pt.cash_discount_ids:
73 continue
74
75 for d in pt.cash_discount_ids:
76 res.append(
77 ((mx.DateTime.strptime(base_date,'%Y-%m-%d') +\
78 RelativeDateTime(days=d.delay)).strftime("%Y-%m-%d"),
79 d.discount)
80 )
81
82 res.sort(cmp=lambda x,y: cmp(x[0],y[0]))
83 return res
84account_payment_term()
85
86class account_invoice(osv.osv):
87 '''
88 Add discount calculation to invoice
89 '''
90 _inherit = 'account.invoice'
91
92 def _get_discount(self, cr, uid, ids, field_name, args, context={}):
93 '''
94 Calculate the value of variable date_discount (Discount Date) and amount_discounted (Discounted Total)
95 '''
96
97 if context is None:
98 context = {}
99 for invoice in self.browse(cr, uid, ids, context):
100 res = defaultdict(list)
101 res[invoice.id] = {
102 'date_discount': invoice.date_due,
103 'amount_discounted': invoice.amount_total
104 }
105 if not invoice.date_invoice:
106 invoice_date = mx.DateTime.today().strftime("%Y-%m-%d")
107 self.write(cr, uid, [invoice.id], {'date_invoice': invoice_date}, context)
108 else:
109 invoice_date = invoice.date_invoice
110 discounts = invoice.payment_term and invoice.payment_term.get_discounts(invoice_date, context=context)
111 if discounts:
112 line_obj = self.pool.get('account.invoice.line')
113 discount_total = 0.0
114 non_discount_total = 0.0
115 for line in invoice.invoice_line:
116 if line.cash_discount:
117 discount_total += line.price_subtotal
118 line_cash_discount = round((1.0 - discounts[0][1]) * line.price_subtotal)
119 line_obj.write(cr, uid, line.id, {'cash_discount': line_cash_discount}, context)
120 else:
121 non_discount_total += line.price_subtotal
122 line_obj.write(cr, uid, line.id, {'cash_discount': 0.0}, context)
123 # assume taxes are never discountable
124 non_discount_total += invoice.amount_tax
125 # There may be more than one - return the earliest
126 res[invoice.id] = {
127 'date_discount': discounts[0][0],
128 'amount_discounted': round(((1.0 - discounts[0][1]) * discount_total) + non_discount_total,2)
129 }
130 return defaultdict(type([]),res)
131
132 _columns = {
133 'date_discount': fields.function(_get_discount, method=True, type='date', string='Discount Date', multi='all'),
134 'amount_discounted': fields.function(_get_discount, method=True, type='float', digits_compute=dp.get_precision('Account'), string='Discounted Total',
135 multi='all'),
136 }
137account_invoice()
138
139class account_invoice_pay_writeoff(osv.osv_memory):
140 """
141 Opens the write off amount pay form.
142 """
143 _name = "account.invoice.pay.writeoff"
144 _description = "Pay Invoice "
145 _columns = {
146 'writeoff_acc_id': fields.many2one('account.account', 'Write-Off account', required=True),
147 'writeoff_journal_id': fields.many2one('account.journal', 'Write-Off journal', required=True),
148 'comment': fields.char('Comment', size=64, required=True),
149 'analytic_id': fields.many2one('account.analytic.account','Analytic Account'),
150 }
151 _defaults = {
152 'comment': 'Write-Off',
153 }
154
155account_invoice_pay_writeoff()
156
157class account_invoice_pay(osv.osv_memory):
158 """
159 Generate pay invoice wizard, user can make partial or full payment for invoice.
160 """
161 _name = "account.invoice.pay"
162 _description = "Pay Invoice "
163 _columns = {
164 'amount': fields.float('Amount paid', required=True, digits_compute = dp.get_precision('Account')),
165 'name': fields.char('Entry Name', size=64, required=True),
166 'date': fields.date('Date payment', required=True),
167 'journal_id': fields.many2one('account.journal', 'Journal/Payment Mode', required=True, domain=[('type','=','cash')]),
168 'period_id': fields.many2one('account.period', 'Period', required=True),
169 }
170
171 def view_init(self, cr, uid, ids, context=None):
172 invoice = self.pool.get('account.invoice').browse(cr, uid, context['active_id'], context=context)
173 if invoice.state in ['draft', 'proforma2', 'cancel']:
174 raise osv.except_osv(_('Error !'), _('Can not pay draft/proforma/cancel invoice.'))
175 pass
176
177 def _get_period(self, cr, uid, context=None):
178 '''
179 Initialise Period
180 '''
181 ids = self.pool.get('account.period').find(cr, uid, context=context)
182 period_id = False
183 if len(ids):
184 period_id = ids[0]
185 return period_id
186
187 def _get_amount(self, cr, uid, context=None):
188 '''
189 Get default value of Amount paid
190 '''
191 return self.pool.get('account.invoice').browse(cr, uid, context['active_id'], context=context).residual
192
193 _defaults = {
194 'date': lambda *a: time.strftime('%Y-%m-%d'),
195 'period_id': _get_period,
196 'amount': _get_amount,
197 }
198account_invoice_pay()
199
200class account_voucher(osv.osv):
201 _name = 'account.voucher'
202 _inherit = 'account.voucher'
203
204 def _update_discounts(self, lines, vch_date):
205 date_discount = False
206 amount_discount = False
207 for line in lines:
208 if 'date_discount' in line:
209 date_discount = line['date_discount']
210 amount_discounted = line['amount_discounted']
211 else:
212 return
213 if line['amount'] >= line['amount_unreconciled']:
214 amount_discount = 0.0
215 elif vch_date <= date_discount and line['amount'] <= line['amount_unreconciled'] and line['amount'] >= amount_discounted:
216 amount_discount = max(line['amount_unreconciled'] - amount_discounted, 0.0)
217 elif vch_date <= date_discount and line['amount'] < amount_discounted:
218 amount_discount = max(line['amount_unreconciled'] - amount_discounted, 0.0)
219 line['cash_discount'] = amount_discount
220 line['amount_difference'] = line['amount_unreconciled'] - line['amount'] - amount_discount
221
222
223 def onchange_partner_id(self, cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context={}):
224 '''
225 Function to update fields in customer payment form on changing customer
226 '''
227 if context is None:
228 context = {}
229
230 currency_pool = self.pool.get('res.currency')
231 journal_pool = self.pool.get('account.journal')
232 invoice_pool = self.pool.get('account.invoice')
233 line_pool = self.pool.get('account.voucher.line')
234 move_line_pool = self.pool.get('account.move.line')
235 partner_pool = self.pool.get('res.partner')
236 company_currency = False
237
238 default = super(account_voucher, self).onchange_partner_id(cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context={})
239 if not partner_id:
240 return default
241 # we have to clear out lines, because new lines will be created by the change
242 if partner_id and not journal_id:
243 partner = partner_pool.browse(cr, uid, partner_id, context)
244 if partner._columns.has_key('payment_meth_id') and partner.payment_meth_id:
245 payment_mode_pool = self.pool.get('payment.mode')
246 payment_meth = payment_mode_pool.browse(cr, uid, partner.payment_meth_id.id, context)
247 if payment_meth:
248 default['value']['journal_id'] = payment_meth.journal.id
249 journal_id = payment_meth.journal.id
250 if ids:
251 line_ids = line_pool.search(cr, uid, [('voucher_id','=',ids[0])])
252 if line_ids:
253 line_pool.unlink(cr, uid, line_ids)
254 if journal_id:
255 journal = journal_pool.browse(cr, uid, journal_id)
256 company_currency = journal.company_id.currency_id.id
257
258 total_credit = 0.0
259 total_debit = 0.0
260 vch_date = False
261 for vch in self.browse(cr, uid, ids):
262 vch_date = vch.date
263 if default and 'value' in default and 'line_cr_ids' in default['value']:
264 for line in default['value']['line_cr_ids']:
265 invoice_id = invoice_pool.search(cr, uid, [('number', '=', line['name'])])
266 if invoice_id:
267 line['invoice_id'] = invoice_id[0]
268 invoice = invoice_pool.browse(cr, uid, invoice_id[0], )
269 date_discount = invoice.date_discount
270 amount_discounted = invoice.amount_discounted
271 line['date_discount'] = date_discount
272 line['amount_discounted'] = amount_discounted
273 else:
274 line['date_discount'] = False
275 line['amount_discounted'] = 0.0
276 line['amount'] = 0.0
277 total_credit += line['type'] == 'cr' and line['amount_unreconciled'] or 0.0
278 total_debit += line['type'] == 'dr' and line['amount_unreconciled'] or 0.0
279 # first, see if we can find an invoice matching the amount to be applied
280 found = False
281 def calc_amount(line, total):
282 return min(line['amount_unreconciled'], total)
283 lines = default['value']['line_cr_ids']
284 if len(lines) == 0:
285 return default
286# return False
287 # if only one, assign it
288 if len(lines) == 1:
289 for line in lines:
290 if line['type'] == 'cr':
291 amount = price
292 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount
293 total_credit -= amount
294 found = True
295 break
296 else:
297 amount = price
298 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount
299 total_debit -= amount
300 found = True
301 break
302 self._update_discounts(lines, vch_date)
303 if not found:
304 for line in lines:
305 if line['amount_unreconciled'] == price:
306 if line['type'] == 'cr':
307 amount = calc_amount(line, total_credit)
308 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount
309 total_credit -= amount
310 found = True
311 break
312 else:
313 amount = calc_amount(line, total_debit)
314 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) or amount
315 total_debit -= amount
316 found = True
317 break
318 if not found:
319 # see if we can find a combination that matches
320 def search(lines, price):
321 for i in range(0, len(lines)):
322 if lines[i]['amount_unreconciled'] == price:
323 return [lines[i]]
324 for i in range(0, len(lines)):
325 for j in range(i + 1, len(lines)):
326 if lines[i]['amount_unreconciled'] + lines[j]['amount_unreconciled'] == price:
327 return [lines[i],lines[j]]
328 for i in range(0, len(lines)):
329 for j in range(i + 1, len(lines)):
330 for k in range(j + 1, len(lines)):
331 if lines[i]['amount_unreconciled'] + lines[j]['amount_unreconciled'] + lines[k]['amount_unreconciled']== price:
332 return [lines[i],lines[j],lines[k]]
333 line_ids = search(lines, price)
334
335 if line_ids: # and sum == price:
336 for line in line_ids:
337 if line['type'] == 'cr':
338 amount = calc_amount(line, line['amount_unreconciled'])
339 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount)
340 total_debit -= amount
341 found = True
342 else:
343 amount = calc_amount(line, line['amount_unreconciled'])
344 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount)
345 total_credit -= amount
346 found = True
347 if not found:
348 # see if we can find a match using discounted amount
349 def search2(lines, price):
350 for i in range(0, len(lines)):
351 if min(lines[i]['amount_unreconciled'],lines[i]['amount_discounted']) == price:
352 return [lines[i]]
353 for i in range(0, len(lines)):
354 for j in range(i + 1, len(lines)):
355 if min(lines[i]['amount_unreconciled'],lines[i]['amount_discounted']) + min(lines[j]['amount_unreconciled'],lines[j]['amount_discounted']) == price:
356 return [lines[i],lines[j]]
357 for i in range(0, len(lines)):
358 for j in range(i + 1, len(lines)):
359 for k in range(j + 1, len(lines)):
360 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:
361 return [lines[i],lines[j],lines[k]]
362 line_ids = search(lines, price)
363 lines = default['value']['line_cr_ids']
364 line_ids = search2(lines, price)
365 if line_ids:
366 for line in line_ids:
367 if line['type'] == 'cr':
368 amount = calc_amount(line, min(line['amount_unreconciled'],line['amount_discounted']))
369 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, min(line['amount_unreconciled'],line['amount_discounted']))
370 total_debit -= amount
371 found = True
372 else:
373 amount = calc_amount(line, min(line['amount_unreconciled'],line['amount_discounted']))
374 line['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, min(line['amount_unreconciled'],line['amount_discounted']))
375 total_credit -= amount
376 found = True
377 lines = default['value']['line_cr_ids']
378 '''
379 FIXME : removing amount from line_dr_ids (Credits on customer payment form) line.
380 and amount from line_cr_ids (Invoice and outstanding transactions on customer payment form) line
381 I do not think this this is a good solution. But it works.
382 The whole "onchange_partner_id" function need a re-thinking (may have to rewrite it completely instead of calling super ).
383 '''
384 if default:
385 for credit_line in default['value'].get('line_dr_ids',[]):
386 credit_line['amount'] = 0.0
387 for invoce_line in default['value'].get('line_cr_ids',[]):
388 invoce_line['amount'] = 0.0
389 invoce_line['amount_difference'] = invoce_line['amount_unreconciled']
390 return default
391
392 def calc_cash_discount(self, cr, uid, ids, vch, line, context={}):
393 '''
394 Calculate discount per line
395 '''
396 total_allocated = 0.0
397 for line in vch.line_ids:
398 total_allocated += line.amount
399 context.update({'total_allocated': total_allocated, 'total_amount': vch.date})
400 amount_discount = 0.0
401 if line.amount >= line.amount_unreconciled or line.amount < 0.01 :
402 amount_discount = 0.0
403 elif line.amount >= line.amount_discounted and vch.date <= line.date_discount:
404 amount_discount = line.amount_unreconciled - line.amount_discounted
405 return amount_discount
406
407account_voucher()
408
409class account_voucher_line(osv.osv):
410 _name = 'account.voucher.line'
411 _inherit = 'account.voucher.line'
412
413 def _update_credit_lines(self,cr, uid, ids, context):
414 '''
415 Function to update the credit lines in payment lines
416 '''
417 credits_used_pool = self.pool.get('account.voucher.line.credits_to_use')
418 for line in self.browse(cr , uid, ids, context):
419 credits_lines_used = [x.orginal_credit_line_id.id for x in line.available_credits]
420 for credit_line in line.voucher_id.line_dr_ids :
421 if credit_line.id not in credits_lines_used and line.invoice_id and line.invoice_id.payment_term:
422 print credit_line
423 credits_used_pool.create(cr, uid, {
424 'voucher_line_id': line.id,
425 'orginal_credit_line_id':credit_line.id,
426 'use_credit': False,
427 'inv_credit': credit_line.move_line_id.id,
428 'discount_window_date': credit_line.date_original,
429 'orginal_amount': credit_line.amount_original,
430 'available_amount': credit_line.amount_unreconciled - credit_line.pending_credits,
431 'discount_amount': 0.0,
432 'gl_account' : credit_line.account_id.id,})
433 else :
434 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)
435 if to_update_credit_line_ids:
436 credits_used_pool.write(cr, uid,to_update_credit_line_ids,{'available_amount': credit_line.amount_unreconciled-credit_line.pending_credits}, context=context)
437
438 def _update_discount_lines(self,cr, uid, ids, context):
439 '''
440 Function to update the discount lines in payment lines
441 '''
442
443 discount_used_pool = self.pool.get('account.voucher.line.discount_to_use')
444 user_pool = self.pool.get('res.users')
445 user = user_pool.browse(cr, uid, uid, context)
446 for line in self.browse(cr , uid, ids, context):
447 if line.invoice_id :
448 if not line.invoice_id.date_discount or not line.voucher_id.date or line.voucher_id.date > line.invoice_id.date_discount:
449 '''
450 customer is not eligible for the discount
451 '''
452 continue
453 discount = line.invoice_id.amount_total - line.invoice_id.amount_discounted
454 date_discount = line.invoice_id.date_discount
455 discount_found = False
456 for discount_line in line.available_discounts:
457 #if abs(discount - discount_line.proposed_discount) < 0.01 and line.invoice_id.payment_term.id == discount_line.inv_payment_terms.id:
458 if line.invoice_id.payment_term.id == discount_line.inv_payment_terms.id:
459 discount_found = True
460 continue
461 if not discount_found and user.company_id.sales_discount_account:
462 '''
463 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.)
464 '''
465 discount_used_pool.create(cr, uid, {
466 'voucher_line_id': line.id,
467 'use_discount': False,
468 'inv_payment_terms':line.invoice_id.payment_term.id ,
469 'discount_window_date': date_discount,
470 'proposed_discount': discount,
471 'discount_amount': 0.0,
472 'gl_account':user.company_id.sales_discount_account.id
473 }, context=context)
474
475
476 def _compute_discount_used(self, cr, uid, ids, name, args, context=None):
477 '''
478 Function to calculate the value of variable discount used
479 '''
480 res = {}
481 for line in self.browse(cr, uid, ids):
482 res[line.id] = 0.0
483 for discount_line in line.available_discounts:
484 if discount_line.use_discount :
485 res[line.id] += discount_line.discount_amount
486 return res
487
488 def _compute_balance(self, cr, uid, ids, name, args, context=None):
489 '''
490 Function to calculate the value of variables Cash Discount, Interest and Amt Due
491 '''
492 currency_pool = self.pool.get('res.currency')
493 rs_data = super(account_voucher_line, self)._compute_balance(cr, uid, ids, name, args, context)
494 for line in self.browse(cr, uid, ids):
495 amount_cash_discount = self.calc_cash_discount(cr, uid, ids, vch, line)
496 amount_interest = self.calc_interest(vch, line, line.amount)
497 amount_unreconciled = 0.0
498 move_line = line.move_line_id or False
499 if move_line:
500 amount_unreconciled = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.amount_unreconciled - amount_cash_discount - line.writeoff)
501 rs_data[line.id] = {'cash_discount': amount_cash_discount, 'interest': amount_interest, 'amount_unreconciled': amount_unreconciled}
502 return rs_data
503
504 def _get_discount(self, cr, uid, ids, field_name, args, context={}):
505 """
506 Function to calculate the value of variable date_discount,amount_discounted,cash_discount,amount_difference
507 return the values as dictionary
508 """
509
510 if context is None:
511 context = {}
512 invoice_obj = self.pool.get('account.invoice')
513 move_line_obj = self.pool.get('account.move.line')
514 voucher_line = self.browse(cr, uid, ids)
515 vch = self.pool.get('account.voucher').browse(cr, uid, voucher_line[0].voucher_id.id)
516 res = {}
517 for line in voucher_line:
518 if line.type == 'dr':
519 res[line.id] = {
520 'date_discount': '',
521 'amount_discounted': line.amount,
522 'cash_discount': 0.0,
523 'amount_difference': line.amount_unreconciled - line.amount
524 }
525 continue
526 move_line = move_line_obj.browse(cr, uid, line.move_line_id.id)
527 invoice_number = move_line.name or move_line.ref
528 invoice_id = False
529 if invoice_number and invoice_number != '/':
530 invoice_id = invoice_obj.search(cr, uid, [('number', '=', str(invoice_number))])
531 if not invoice_id:
532 move = self.pool.get('account.move').browse(cr, uid, move_line.move_id.id)
533 if move:
534 invoice_number = move.name or move.ref
535 if invoice_number and invoice_number != '/':
536 invoice_id = invoice_obj.search(cr, uid, [('number', '=', str(invoice_number))])
537 if invoice_id:
538 for invoice in invoice_obj.browse(cr, uid, invoice_id, context):
539 date_discount = invoice.date_due
540 amount_discounted = invoice.amount_total
541 res[line.id] = {
542 'date_discount': invoice.date_due,
543 'amount_discounted': invoice.amount_total
544 }
545 if not invoice.date_invoice:
546 invoice_date = mx.DateTime.today().strftime("%Y-%m-%d")
547 self.write(cr, uid, [invoice.id], {'date_invoice': invoice_date}, context)
548 else:
549 invoice_date = invoice.date_invoice
550 discounts = invoice.payment_term and invoice.payment_term.get_discounts(invoice_date, context=context) or False
551 if discounts:
552 line_obj = self.pool.get('account.invoice.line')
553 discount_total = 0.0
554 non_discount_total = 0.0
555 for invline in invoice.invoice_line:
556 if invline.cash_discount:
557 discount_total += invline.price_subtotal
558 line_cash_discount = round((1.0 - discounts[0][1]) * invline.price_subtotal)
559 line_obj.write(cr, uid, invline.id, {'cash_discount': line_cash_discount}, context)
560 else:
561 non_discount_total += invline.price_subtotal
562 line_obj.write(cr, uid, invline.id, {'cash_discount': 0.0}, context)
563 # assume taxes are never discountable
564 non_discount_total += invoice.amount_tax
565 # There may be more than one - return the earliest
566 date_discount = discounts[0][0]
567 amount_discounted = round(((1.0 - discounts[0][1]) * discount_total) + non_discount_total,2)
568 amount_discount = 0.0
569 if line.amount >= line.amount_unreconciled or line.amount < 0.01:
570 amount_discount = 0.0
571 elif vch.date <= date_discount and line.amount <= line.amount_unreconciled:
572 amount_discount = max(line.amount_unreconciled - amount_discounted, 0.0)
573 elif vch.date <= date_discount and line.amount < amount_discounted:
574 amount_discount = max(line.amount_unreconciled - amount_discounted,0.0)
575 else:
576 amount_discount = 0.0
577
578 res[line.id] = {
579 'date_discount': date_discount,
580 'amount_discounted': amount_discounted,
581 'cash_discount': amount_discount,
582 '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
583 }
584 return defaultdict(type([]),res)
585
586 _columns = {
587 'date_discount': fields.function(_get_discount, method=True, type='date', string='Discount Date',
588 multi='all'),
589 'amount_discounted': fields.function(_get_discount, method=True, type='float', digits_compute=dp.get_precision('Account'), string='Discounted Total',
590 multi='all'),
591 'cash_discount': fields.function(_get_discount, method=True, type='float', multi="all", digits_compute=dp.get_precision('Account'), string='Cash Discount'),
592 'amount_difference': fields.function(_get_discount, method=True, multi='all', type='float', string='Unpaid Amt', digits=(16, 2) ),
593 'interest': fields.float(string='Interest', digits=(16,2)),
594
595 #'discount_used':fields.float('Discount used', readonly=True),
596 'discount_used': fields.function(_compute_discount_used, method=True, type='float', string='Discount Used', store=False, readonly=True),
597 'available_discounts':fields.one2many('account.voucher.line.discount_to_use', 'voucher_line_id', 'Available Discounts' ),
598 }
599 def clear_values(self, cr, uid, ids, context={}):
600 '''
601 Clear the selected credits, discounts and writeoffs from voucher line
602 '''
603 voucher_line = self.browse(cr,uid,ids[0])
604 if voucher_line._columns.has_key('writeoff_ids'):
605 for lines in self.read(cr,uid,ids,['available_credits','writeoff_ids','available_discounts']):
606 lines['writeoff_ids'] and self.pool.get('account.voucher.line.writeoff').unlink(cr,uid,lines['writeoff_ids'])
607 lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'],{
608 'use_credit':False,
609 'discount_amount':0.0})
610 lines['available_discounts'] and self.pool.get('account.voucher.line.discount_to_use').write(cr,uid,lines['available_discounts'],{
611 'use_discount':False,
612 'discount_amount':0.0})
613 else:
614 for lines in self.read(cr,uid,ids,['available_credits','writeoff_ids','available_discounts']):
615 lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'],{
616 'use_credit':False,
617 'discount_amount':0.0})
618 lines['available_discounts'] and self.pool.get('account.voucher.line.discount_to_use').write(cr,uid,lines['available_discounts'],{
619 'use_discount':False,
620 'discount_amount':0.0})
621 return True
622account_voucher_line()
623
624class product_product(osv.osv):
625 '''
626 Add new account configuration fields to product
627 '''
628 _name = "product.product"
629 _inherit = 'product.product'
630 _columns = {
631 'cash_discount': fields.boolean('Cash Discount?'),
632 'purchase_discount_account': fields.many2one('account.account', 'Purchase Discount Account', domain=[('user_type','=','COGS')]),
633 'sales_discount_account': fields.many2one('account.account', 'Sales Discount Account', domain=[('type','!=','view'),('type','!=','consolidation'),('user_type','ilike','income')]),
634 'purchase_discount_journal': fields.many2one('account.journal', 'Purchase Discount Journal', domain=[('type','!=','view'),('type','!=','consolidation'),('type','=','purchase')]),
635 'sales_discount_journal': fields.many2one('account.journal', 'Sales Discount Journal', domain=[('type','=','sale')]),
636 }
637 _defaults = {
638 'cash_discount' : lambda *a : True,
639 }
640product_product()
641
642class account_invoice_line(osv.osv):
643 '''
644 option to disable discount calculation per invoice line
645 '''
646 _name = 'account.invoice.line'
647 _inherit = 'account.invoice.line'
648 _columns = {
649 'cash_discount': fields.boolean('Cash Discount?'),
650 }
651 _defaults = {
652 'cash_discount' : lambda *a : True,
653 }
654 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):
655 '''
656 check if the discount is applicable to newly selected product
657 '''
658 result = {}
659 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)
660 if product:
661 res = self.pool.get('product.product').browse(cr, uid, product, context=context)
662 result['value']['cash_discount'] = res.cash_discount
663 else:
664 result['value']['cash_discount'] = True
665 return result
666account_invoice_line()
667
668class res_company(osv.osv):
669 '''
670 New account configuration fields on copmany form
671 '''
672 _name = 'res.company'
673 _inherit = 'res.company'
674 _columns = {
675 'purchase_discount_account': fields.many2one('account.account', 'Purchase Discount Account', domain=[('user_type','=','COGS'),('type','!=','view'),('type','!=','consolidation')]),
676 'sales_discount_account': fields.many2one('account.account', 'Sales Discount Account', domain=[('user_type','=','Income'),('type','!=','view'),('type','!=','consolidation')]),
677 'purchase_discount_journal': fields.many2one('account.journal', 'Purchase Discount Journal', domain=[('type','=','purchase')]),
678 'sales_discount_journal': fields.many2one('account.journal', 'Sales Discount Journal', domain=[('type','=','sale')]),
679 }
680res_company()
681
682class account_voucher_line_discount_to_use(osv.osv):
683 '''
684 Dynamically generated discount lines that are applicable per voucher line
685 '''
686 _name = "account.voucher.line.discount_to_use"
687 _rec_name = 'inv_credit'
688 _columns = {
689 'voucher_line_id': fields.many2one('account.voucher.line', 'Account Voucher Line', ondelete='cascade', readonly=True),
690 'use_discount': fields.boolean('Use Discount',help='Used to indicate if the cash discount should be used/taken when calculating payment.', required=True),
691 'inv_payment_terms': fields.many2one('account.payment.term', 'Invoice Payment Terms', help='Payments terms description', ),
692 '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.'),
693
694
695 '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),
696 'discount_amount': fields.float('Discount Amt',help='Enter the amount of discount to be given.', required=True),
697 'gl_account' : fields.many2one('account.account', 'G/L Account',help='Enter the General Ledger account number to record taking the cash discount.', required=True),
698 }
699 def onchage_use_discount(self, cr, uid, ids, use_discount, proposed_discount, context=None):
700 '''
701 Fill the value with proposed discount when use discount check box is clicked and remove the value when use discount is unchecked
702 '''
703 res = {}
704 if use_discount:
705 res['value'] = {'discount_amount': proposed_discount}
706 else:
707 res['value'] = {'discount_amount': 0}
708 return res
709 def onchage_discount_amount(self, cr, uid, ids, proposed_discount, discount_amount, context=None):
710 '''
711 Function to check discount amount entered in discount line of payment line
712 '''
713 res = {}
714 if discount_amount < 0:
715 res['value'] = {'discount_amount': 0, 'use_discount':False }
716 res['warning'] = {'title': 'Discount not in the limit', 'message': 'Discount should not be a negative value.'}
717 return res
718 if discount_amount > proposed_discount:
719 res['value'] = {'discount_amount': proposed_discount, 'use_discount':True }
720 res['warning'] = {'title': 'Discount not in the limit', 'message': 'Please adjust the Discount Amt value to be less than or equal the Proposed Discount.'}
721 return res
722 if discount_amount == 0.0:
723 res['value'] = { 'use_discount':False }
724 else:
725 res['value'] = { 'use_discount':True }
726 return res
727account_voucher_line_discount_to_use()
728
729# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
730
0731
=== added file 'account_cash_discount_us/account_cash_discount_us/account_cash_discount_view.xml'
--- account_cash_discount_us/account_cash_discount_us/account_cash_discount_view.xml 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/account_cash_discount_us/account_cash_discount_view.xml 2011-10-06 15:23:28 +0000
@@ -0,0 +1,256 @@
1<?xml version="1.0"?>
2<openerp>
3 <data>
4
5 <!-- cash discount -->
6
7 <record id="invoice_supplier_form_jdc" model="ir.ui.view">
8 <field name="name">account.invoice.supplier.form.jdc</field>
9 <field name="model">account.invoice</field>
10 <field name="type">form</field>
11 <field name="priority">2</field>
12 <field name="inherit_id" ref="account.invoice_supplier_form"/>
13 <field name="arch" type="xml">
14 <xpath expr="/form/notebook/page/field[@name='check_total']" position="after">
15 <field name="date_discount"/>
16 <field name="amount_discounted"/>
17 </xpath>
18 </field>
19 </record>
20 <record id="invoice_form_jdc1" model="ir.ui.view">
21 <field name="name">account.invoice.form.jdc1</field>
22 <field name="model">account.invoice</field>
23 <field name="type">form</field>
24 <field name="inherit_id" ref="account.invoice_form"/>
25 <field name="arch" type="xml">
26 <xpath expr="/form/notebook/page[@string='Invoice']/field[@name='invoice_line']" position="before">
27 <group colspan="2" col="4">
28 <field name="date_discount"/>
29 <field name="amount_discounted"/>
30 </group>
31 </xpath>
32 </field>
33 </record>
34
35
36 <!--
37 Invoice Line
38 -->
39 <record id="view_invoice_line_form_discount" model="ir.ui.view">
40 <field name="name">account.invoice.line.form.discount</field>
41 <field name="model">account.invoice.line</field>
42 <field name="inherit_id" ref="account.view_invoice_line_form"/>
43 <field name="type">form</field>
44 <field name="arch" type="xml">
45 <xpath expr="/form/notebook/page/field[@name='discount']" position="after">
46 <field name="cash_discount"/>
47 </xpath>
48 </field>
49 </record>
50
51 <!--
52 Products
53 -->
54 <record id="product_normal_form_view_discount" model="ir.ui.view">
55 <field name="name">product.normal.form.discount</field>
56 <field name="model">product.product</field>
57 <field name="type">form</field>
58 <field eval="7" name="priority"/>
59 <field name="inherit_id" ref="product.product_normal_form_view"/>
60 <field name="arch" type="xml">
61 <xpath expr="/form/notebook/page[@string='Suppliers']/field[@name='seller_ids']" position="after">
62 <field name="cash_discount"/>
63 </xpath>
64 </field>
65 </record>
66
67 <!--
68 Company
69 -->
70 <record id="view_company_form_jdc2" model="ir.ui.view">
71 <field name="name">res.company.form.jdc2</field>
72 <field name="model">res.company</field>
73 <field name="type">form</field>
74 <field name="inherit_id" ref="account_voucher_credits_us.view_company_form_jdc3"/>
75 <field name="priority" eval="1"/>
76 <field name="arch" type="xml">
77 <xpath expr="/form/notebook/page[@string='Accounting']/field[@name='writeoff_account']" position="before">
78 <field name="sales_discount_account" colspan="2" />
79 <field name="purchase_discount_account" colspan="2" />
80 <field name="sales_discount_journal" colspan="2"/>
81 <field name="purchase_discount_journal" colspan="2"/>
82 </xpath>
83 </field>
84 </record>
85
86 <!-- Discount -->
87
88 <record model="ir.ui.view" id="view_account_wizard_discount_form">
89 <field name="name">account.wizard.discount.form</field>
90 <field name="model">account.wizard.discount</field>
91 <field name="type">form</field>
92 <field name="arch" type="xml">
93 <form string="Discount">
94 <field name="use_discount" select="1"/>
95 <field name="inv_payment_terms" select="1" readonly="1"/>
96 <field name="discount_window_date" select="1"/>
97 <field name="proposed_discount" select="1"/>
98 <field name="discount_amount" select="1"/>
99 <field name="gl_account" select="1"/>
100 </form>
101 </field>
102 </record>
103
104 <record model="ir.ui.view" id="view_account_wizard_discount_tree">
105 <field name="name">account.wizard.discount.tree</field>
106 <field name="model">account.wizard.discount</field>
107 <field name="type">tree</field>
108 <field name="arch" type="xml">
109 <tree string="Discount" editable="bottom">
110 <field name="use_discount" select="1"/>
111 <field name="inv_payment_terms" select="1" readonly="1"/>
112 <field name="discount_window_date" select="1"/>
113 <field name="proposed_discount" select="1"/>
114 <field name="discount_amount" select="1"/>
115 <field name="gl_account" select="1"/>
116 </tree>
117 </field>
118 </record>
119 <!-- credit -->
120
121 <record model="ir.ui.view" id="view_account_wizard_credit_form">
122 <field name="name">account.wizard.credit.form</field>
123 <field name="model">account.wizard.credit</field>
124 <field name="type">form</field>
125 <field name="arch" type="xml">
126 <form string="Credits">
127 <field name="use_credit" select="1"/>
128 <field name="inv_credit" select="1" readonly="1"/>
129 <field name="discount_window_date" select="1" readonly="1"/>
130 <field name="proposed_discount" select="1" readonly="1"/>
131 <field name="discount_amount" select="1" />
132 <field name="credit_bal" select="1" readonly="1"/>
133 <field name="gl_account" select="1" readonly="1"/>
134 </form>
135 </field>
136 </record>
137
138 <record model="ir.ui.view" id="view_account_wizard_credit_tree">
139 <field name="name">account.wizard.credit.tree</field>
140 <field name="model">account.wizard.credit</field>
141 <field name="type">tree</field>
142 <field name="arch" type="xml">
143 <tree string="Credits" editable="bottom">
144 <field name="use_credit" select="1"/>
145 <field name="inv_credit" select="1" readonly="1"/>
146 <field name="discount_window_date" select="1" readonly="1"/>
147 <field name="proposed_discount" select="1" readonly="1"/>
148 <field name="discount_amount" select="1" />
149 <field name="credit_bal" select="1" readonly="1"/>
150 <field name="gl_account" select="1" readonly="1"/>
151 </tree>
152 </field>
153 </record>
154
155
156 <!-- credit used -->
157
158 <record model="ir.ui.view" id="view_account_wizard_credit_used_form">
159 <field name="name">account.wizard.credit.used.form</field>
160 <field name="model">account.wizard.credit.used</field>
161 <field name="type">form</field>
162 <field name="arch" type="xml">
163 <form string="Previously Applied Credit">
164 <field name="date_used" select="1"/>
165 <field name="inv_credit" select="1"/>
166 <field name="discount_window_date" select="1"/>
167 <field name="proposed_discount" select="1"/>
168 <field name="amt_used" select="1"/>
169 <field name="inv_move" select="1"/>
170 <field name="gl_account" select="1"/>
171 </form>
172 </field>
173 </record>
174
175 <record model="ir.ui.view" id="view_account_wizard_credit_used_tree">
176 <field name="name">account.wizard.credit.used.tree</field>
177 <field name="model">account.wizard.credit.used</field>
178 <field name="type">tree</field>
179 <field name="arch" type="xml">
180 <tree string="Previously Applied Credit" editable="bottom">
181 <field name="date_used" select="1"/>
182 <field name="inv_credit" select="1"/>
183 <field name="discount_window_date" select="1"/>
184 <field name="proposed_discount" select="1"/>
185 <field name="amt_used" select="1"/>
186 <field name="inv_move" select="1"/>
187 <field name="gl_account" select="1"/>
188 </tree>
189 </field>
190 </record>
191
192 <!-- customer payment form modification for discount -->
193
194
195 <record model="ir.ui.view" id="view_vendor_receipt_form_2">
196 <field name="name">account.voucher.receipt.form.2</field>
197 <field name="model">account.voucher</field>
198 <field name="type">form</field>
199 <field name="inherit_id" ref="account_voucher_credits_us.view_vendor_receipt_form_1"/>
200 <field name="arch" type="xml">
201 <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">
202 <field name="discount_used"/>
203 <newline />
204 </xpath>
205 <xpath expr="/form/notebook/page[@string='Payment Information']/field/tree/field[@name='credit_used']" position="before">
206 <field name="discount_used"/>
207 <newline/>
208 </xpath>
209 <xpath expr="/form/notebook/page[@string='Payment Information']/field[@name='line_cr_ids']/form/notebook/page[@string='Credit']" position="before">
210 <page string="Discount">
211 <field name="available_discounts" nolabel="1" colspan="4" string="Avilable Discounts" view_mode="tree" />
212 </page>
213 </xpath>
214 </field>
215 </record>
216
217
218 <record model="ir.ui.view" id="view_account_voucher_line_discount_to_use_tree">
219 <field name="name">account.voucher.line.discount_to_use.tree</field>
220 <field name="model">account.voucher.line.discount_to_use</field>
221 <field name="type">tree</field>
222 <field name="arch" type="xml">
223 <tree string="Available Discounts" editable="top">
224 <field name="use_discount" width="125" on_change="onchage_use_discount(use_discount, proposed_discount)"/>
225 <field name="inv_payment_terms"/>
226 <field name="discount_window_date"/>
227 <field name="proposed_discount"/>
228 <field name="discount_amount" on_change="onchage_discount_amount(proposed_discount, discount_amount)"/>
229 <field name="gl_account"/>
230 </tree>
231 </field>
232 </record>
233
234 <record model="ir.ui.view" id="view_payment_term_form_inherited">
235 <field name="name">account.payment.term.form.inherited</field>
236 <field name="model">account.payment.term</field>
237 <field name="inherit_id" ref="account_cash_discount.view_payment_term_form"/>
238 <field name="arch" type="xml">
239 <separator string="Cash Discount" colspan="4" position="replace"/>
240 </field>
241 </record>
242 <record model="ir.ui.view" id="view_payment_term_form_inherited2">
243 <field name="name">account.payment.term.form.inherited2</field>
244 <field name="model">account.payment.term</field>
245 <field name="inherit_id" ref="view_payment_term_form_inherited"/>
246 <field name="arch" type="xml">
247 <field name="cash_discount_ids" colspan="4" position="replace">
248 <separator string="Cash Discount" colspan="4"/>
249 <field name="cash_discount_ids" colspan="4" nolabel="1"/>
250 </field>
251 </field>
252 </record>
253
254
255 </data>
256</openerp>
0257
=== added directory 'account_cash_discount_us/account_cash_discount_us/i18n'
=== added file 'account_cash_discount_us/account_cash_discount_us/i18n/account_cash_discount.pot'
--- account_cash_discount_us/account_cash_discount_us/i18n/account_cash_discount.pot 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/account_cash_discount_us/i18n/account_cash_discount.pot 2011-10-06 15:23:28 +0000
@@ -0,0 +1,85 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * account_cash_discount
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 5.0.6\n"
8"Report-Msgid-Bugs-To: support@openerp.com\n"
9"POT-Creation-Date: 2009-11-24 13:09:22+0000\n"
10"PO-Revision-Date: 2009-11-24 13:09:22+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: account_cash_discount
19#: constraint:ir.ui.view:0
20msgid "Invalid XML for View Architecture!"
21msgstr ""
22
23#. module: account_cash_discount
24#: constraint:ir.model:0
25msgid "The Object name must start with x_ and not contain any special character !"
26msgstr ""
27
28#. module: account_cash_discount
29#: field:account.cash.discount,name:0
30msgid "Name"
31msgstr ""
32
33#. module: account_cash_discount
34#: field:account.cash.discount,delay:0
35msgid "Number of Days"
36msgstr ""
37
38#. module: account_cash_discount
39#: field:account.cash.discount,discount:0
40msgid "Discount (%)"
41msgstr ""
42
43#. module: account_cash_discount
44#: field:account.cash.discount,credit_account_id:0
45msgid "Credit Account"
46msgstr ""
47
48#. module: account_cash_discount
49#: field:account.cash.discount,debit_account_id:0
50msgid "Debit Account"
51msgstr ""
52
53#. module: account_cash_discount
54#: model:ir.module.module,description:account_cash_discount.module_meta_information
55msgid "\n"
56" This module adds cash discounts on payment terms. Cash discounts\n"
57" for a payment term can be configured with:\n"
58" * A number of days,\n"
59" * A discount (%),\n"
60" * A debit and a credit account\n"
61" "
62msgstr ""
63
64#. module: account_cash_discount
65#: model:ir.module.module,shortdesc:account_cash_discount.module_meta_information
66msgid "Payement Term with Cash Discount"
67msgstr ""
68
69#. module: account_cash_discount
70#: view:account.cash.discount:0
71#: view:account.payment.term:0
72#: model:ir.model,name:account_cash_discount.model_account_cash_discount
73msgid "Cash Discount"
74msgstr ""
75
76#. module: account_cash_discount
77#: field:account.cash.discount,payment_id:0
78msgid "Associated Payment Term"
79msgstr ""
80
81#. module: account_cash_discount
82#: field:account.payment.term,cash_discount_ids:0
83msgid "Cash Discounts"
84msgstr ""
85
086
=== added file 'account_cash_discount_us/account_cash_discount_us/i18n/fr_BE.po'
--- account_cash_discount_us/account_cash_discount_us/i18n/fr_BE.po 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/account_cash_discount_us/i18n/fr_BE.po 2011-10-06 15:23:28 +0000
@@ -0,0 +1,85 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * account_cash_discount
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 5.0.6\n"
8"Report-Msgid-Bugs-To: support@openerp.com\n"
9"POT-Creation-Date: 2009-11-24 13:09:22+0000\n"
10"PO-Revision-Date: 2009-11-24 13:09:22+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: account_cash_discount
19#: constraint:ir.ui.view:0
20msgid "Invalid XML for View Architecture!"
21msgstr ""
22
23#. module: account_cash_discount
24#: constraint:ir.model:0
25msgid "The Object name must start with x_ and not contain any special character !"
26msgstr ""
27
28#. module: account_cash_discount
29#: field:account.cash.discount,name:0
30msgid "Name"
31msgstr ""
32
33#. module: account_cash_discount
34#: field:account.cash.discount,delay:0
35msgid "Number of Days"
36msgstr ""
37
38#. module: account_cash_discount
39#: field:account.cash.discount,discount:0
40msgid "Discount (%)"
41msgstr ""
42
43#. module: account_cash_discount
44#: field:account.cash.discount,credit_account_id:0
45msgid "Credit Account"
46msgstr ""
47
48#. module: account_cash_discount
49#: field:account.cash.discount,debit_account_id:0
50msgid "Debit Account"
51msgstr ""
52
53#. module: account_cash_discount
54#: model:ir.module.module,description:account_cash_discount.module_meta_information
55msgid "\n"
56" This module adds cash discounts on payment terms. Cash discounts\n"
57" for a payment term can be configured with:\n"
58" * A number of days,\n"
59" * A discount (%),\n"
60" * A debit and a credit account\n"
61" "
62msgstr ""
63
64#. module: account_cash_discount
65#: model:ir.module.module,shortdesc:account_cash_discount.module_meta_information
66msgid "Payement Term with Cash Discount"
67msgstr ""
68
69#. module: account_cash_discount
70#: view:account.cash.discount:0
71#: view:account.payment.term:0
72#: model:ir.model,name:account_cash_discount.model_account_cash_discount
73msgid "Cash Discount"
74msgstr ""
75
76#. module: account_cash_discount
77#: field:account.cash.discount,payment_id:0
78msgid "Associated Payment Term"
79msgstr ""
80
81#. module: account_cash_discount
82#: field:account.payment.term,cash_discount_ids:0
83msgid "Cash Discounts"
84msgstr ""
85
086
=== added file 'account_cash_discount_us/account_cash_discount_us/product_view.xml'
--- account_cash_discount_us/account_cash_discount_us/product_view.xml 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/account_cash_discount_us/product_view.xml 2011-10-06 15:23:28 +0000
@@ -0,0 +1,19 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4 <record id="product_normal_form_view" model="ir.ui.view">
5 <field name="name">product.normal.form.inherit2</field>
6 <field name="model">product.product</field>
7 <field name="type">form</field>
8 <field name="inherit_id" ref="account.product_normal_form_view"/>
9 <field name="arch" type="xml">
10 <xpath expr="//field[@name='property_account_expense']" position="after">
11 <newline/>
12 <field name="sales_discount_account" attrs="{'readonly':[('sale_ok','=',0)]}"/>
13 <field name="purchase_discount_account" attrs="{'readonly':[('purchase_ok','=',0)]}"/>
14 </xpath>
15 </field>
16 </record>
17 </data>
18</openerp>
19
020
=== added directory 'account_cash_discount_us/account_cash_discount_us/security'
=== added file 'account_cash_discount_us/account_cash_discount_us/security/ir.model.access.csv'
--- account_cash_discount_us/account_cash_discount_us/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/account_cash_discount_us/security/ir.model.access.csv 2011-10-06 15:23:28 +0000
@@ -0,0 +1,7 @@
1"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
2"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
3"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
4"access_account_invoice_pay","account.invoice.pay","account_cash_discount_us.model_account_invoice_pay","account.group_account_user",1,0,0,0
5"access_account_invoice_pay_manager","account.invoice.pay","account_cash_discount_us.model_account_invoice_pay","account.group_account_manager",1,1,1,1
6"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
7"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
0\ No newline at end of file8\ No newline at end of file
19
=== added directory 'account_cash_discount_us/account_cash_discount_us/wizard'
=== added file 'account_cash_discount_us/account_cash_discount_view.xml'
--- account_cash_discount_us/account_cash_discount_view.xml 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/account_cash_discount_view.xml 2011-10-06 15:23:28 +0000
@@ -0,0 +1,329 @@
1<?xml version="1.0"?>
2<openerp>
3 <data>
4
5 <!-- cash discount -->
6
7 <record id="invoice_supplier_form_jdc" model="ir.ui.view">
8 <field name="name">account.invoice.supplier.form.jdc</field>
9 <field name="model">account.invoice</field>
10 <field name="type">form</field>
11 <field name="priority">2</field>
12 <field name="inherit_id" ref="account.invoice_supplier_form"/>
13 <field name="arch" type="xml">
14 <xpath expr="/form/notebook/page/field[@name='check_total']" position="after">
15 <field name="date_discount"/>
16 <field name="amount_discounted"/>
17 </xpath>
18 </field>
19 </record>
20 <record id="invoice_form_jdc1" model="ir.ui.view">
21 <field name="name">account.invoice.form.jdc1</field>
22 <field name="model">account.invoice</field>
23 <field name="type">form</field>
24 <field name="inherit_id" ref="account.invoice_form"/>
25 <field name="arch" type="xml">
26 <xpath expr="/form/notebook/page[@string='Invoice']/field[@name='invoice_line']" position="before">
27 <group colspan="2" col="4">
28 <field name="date_discount"/>
29 <field name="amount_discounted"/>
30 </group>
31 </xpath>
32 </field>
33 </record>
34
35
36 <!--
37 Invoice Line
38 -->
39 <record id="view_invoice_line_form_discount" model="ir.ui.view">
40 <field name="name">account.invoice.line.form.discount</field>
41 <field name="model">account.invoice.line</field>
42 <field name="inherit_id" ref="account.view_invoice_line_form"/>
43 <field name="type">form</field>
44 <field name="arch" type="xml">
45 <xpath expr="/form/notebook/page/field[@name='discount']" position="after">
46 <field name="cash_discount"/>
47 </xpath>
48 </field>
49 </record>
50
51 <!--
52 Products
53 -->
54 <record id="product_normal_form_view_discount" model="ir.ui.view">
55 <field name="name">product.normal.form.discount</field>
56 <field name="model">product.product</field>
57 <field name="type">form</field>
58 <field eval="7" name="priority"/>
59 <field name="inherit_id" ref="product.product_normal_form_view"/>
60 <field name="arch" type="xml">
61 <xpath expr="/form/notebook/page[@string='Suppliers']/field[@name='seller_ids']" position="after">
62 <field name="cash_discount"/>
63 </xpath>
64 </field>
65 </record>
66
67 <!--
68 Company
69 -->
70 <record id="view_company_form_jdc2" model="ir.ui.view">
71 <field name="name">res.company.form.jdc2</field>
72 <field name="model">res.company</field>
73 <field name="type">form</field>
74 <field name="inherit_id" ref="account_voucher_credits_us.view_company_form_jdc3"/>
75 <field name="priority" eval="1"/>
76 <field name="arch" type="xml">
77 <xpath expr="/form/notebook/page[@string='Accounting']/field[@name='writeoff_account']" position="before">
78 <field name="sales_discount_account" colspan="2" />
79 <field name="purchase_discount_account" colspan="2" />
80 <field name="sales_discount_journal" colspan="2"/>
81 <field name="purchase_discount_journal" colspan="2"/>
82 </xpath>
83 </field>
84 </record>
85
86 <!-- Discount -->
87
88 <record model="ir.ui.view" id="view_account_wizard_discount_form">
89 <field name="name">account.wizard.discount.form</field>
90 <field name="model">account.wizard.discount</field>
91 <field name="type">form</field>
92 <field name="arch" type="xml">
93 <form string="Discount">
94 <field name="use_discount" select="1"/>
95 <field name="inv_payment_terms" select="1" readonly="1"/>
96 <field name="discount_window_date" select="1"/>
97 <field name="proposed_discount" select="1"/>
98 <field name="discount_amount" select="1"/>
99 <field name="gl_account" select="1"/>
100 </form>
101 </field>
102 </record>
103
104 <record model="ir.ui.view" id="view_account_wizard_discount_tree">
105 <field name="name">account.wizard.discount.tree</field>
106 <field name="model">account.wizard.discount</field>
107 <field name="type">tree</field>
108 <field name="arch" type="xml">
109 <tree string="Discount" editable="bottom">
110 <field name="use_discount" select="1"/>
111 <field name="inv_payment_terms" select="1" readonly="1"/>
112 <field name="discount_window_date" select="1"/>
113 <field name="proposed_discount" select="1"/>
114 <field name="discount_amount" select="1"/>
115 <field name="gl_account" select="1"/>
116 </tree>
117 </field>
118 </record>
119 <!-- credit -->
120
121 <record model="ir.ui.view" id="view_account_wizard_credit_form">
122 <field name="name">account.wizard.credit.form</field>
123 <field name="model">account.wizard.credit</field>
124 <field name="type">form</field>
125 <field name="arch" type="xml">
126 <form string="Credits">
127 <field name="use_credit" select="1"/>
128 <field name="inv_credit" select="1" readonly="1"/>
129 <field name="discount_window_date" select="1" readonly="1"/>
130 <field name="proposed_discount" select="1" readonly="1"/>
131 <field name="discount_amount" select="1" />
132 <field name="credit_bal" select="1" readonly="1"/>
133 <field name="gl_account" select="1" readonly="1"/>
134 </form>
135 </field>
136 </record>
137
138 <record model="ir.ui.view" id="view_account_wizard_credit_tree">
139 <field name="name">account.wizard.credit.tree</field>
140 <field name="model">account.wizard.credit</field>
141 <field name="type">tree</field>
142 <field name="arch" type="xml">
143 <tree string="Credits" editable="bottom">
144 <field name="use_credit" select="1"/>
145 <field name="inv_credit" select="1" readonly="1"/>
146 <field name="discount_window_date" select="1" readonly="1"/>
147 <field name="proposed_discount" select="1" readonly="1"/>
148 <field name="discount_amount" select="1" />
149 <field name="credit_bal" select="1" readonly="1"/>
150 <field name="gl_account" select="1" readonly="1"/>
151 </tree>
152 </field>
153 </record>
154
155
156 <!-- credit used -->
157
158 <record model="ir.ui.view" id="view_account_wizard_credit_used_form">
159 <field name="name">account.wizard.credit.used.form</field>
160 <field name="model">account.wizard.credit.used</field>
161 <field name="type">form</field>
162 <field name="arch" type="xml">
163 <form string="Previously Applied Credit">
164 <field name="date_used" select="1"/>
165 <field name="inv_credit" select="1"/>
166 <field name="discount_window_date" select="1"/>
167 <field name="proposed_discount" select="1"/>
168 <field name="amt_used" select="1"/>
169 <field name="inv_move" select="1"/>
170 <field name="gl_account" select="1"/>
171 </form>
172 </field>
173 </record>
174
175 <record model="ir.ui.view" id="view_account_wizard_credit_used_tree">
176 <field name="name">account.wizard.credit.used.tree</field>
177 <field name="model">account.wizard.credit.used</field>
178 <field name="type">tree</field>
179 <field name="arch" type="xml">
180 <tree string="Previously Applied Credit" editable="bottom">
181 <field name="date_used" select="1"/>
182 <field name="inv_credit" select="1"/>
183 <field name="discount_window_date" select="1"/>
184 <field name="proposed_discount" select="1"/>
185 <field name="amt_used" select="1"/>
186 <field name="inv_move" select="1"/>
187 <field name="gl_account" select="1"/>
188 </tree>
189 </field>
190 </record>
191
192 <!-- Supplier payment form modification for discount -->
193 <record model="ir.ui.view" id="view_vendor_payment_form_inherit">
194 <field name="name">account.voucher.payment.form.inherit</field>
195 <field name="model">account.voucher</field>
196 <field name="inherit_id" ref="account_voucher.view_vendor_payment_form"/>
197 <field name="type">form</field>
198 <field name="arch" type="xml">
199 <xpath expr="/form/group/field[@name='amount']" position="attributes" >
200 <attribute name='on_change'>onchange_amount(amount)</attribute>
201 </xpath>
202 <xpath expr="/form/group[@col='10']/button[@name='cancel_voucher']" position="after">
203 <button name="calc_supp_diff" string="Calculate" type="object" states="draft" icon="gtk-execute" />
204 </xpath>
205 <xpath expr="//field[@name='line_dr_ids']" position="replace">
206 <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">
207 <tree string="Invoices and Outstanding Transactions" editable="bottom">
208 <field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}"
209 on_change="onchange_move_line_id(move_line_id)"
210 domain="[('account_id.type','in',('receivable','payable')), ('reconcile_id','=', False), ('partner_id','=',parent.partner_id)]"
211 />
212 <field name="date_original" readonly="1"/>
213 <field name="date_due" readonly="1"/>
214 <field name="amount_original" readonly="1"/>
215 <field name="amount_unreconciled" sum="Open Balance" readonly="1"/>
216 <field name="pay" on_change="onchange_supp_pay(amount, pay, amount_unreconciled, parent.line_cr_ids, parent.amount, credit_used, discount_used, writeoff_amount)"/>
217 <field name="amount" sum="Payment"/>
218 <field name="discount" />
219 <field name="supp_amount_difference"/>
220
221 <field name="credit_used"/>
222 <field name="account_id"/>
223 <field name="discount_used" invisible="1"/>
224 <field name="writeoff_amount" invisible="1"/>
225 </tree>
226
227 <form string="Supplier Invoices and Outstanding transactions" >
228 <field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}"
229 on_change="onchange_move_line_id(move_line_id)"
230 domain="[('account_id.type','=','payable'), ('reconcile_id','=', False), ('partner_id','=',parent.partner_id)]"
231 />
232 <field name="account_id" groups="base.group_extended" domain="[('type','=','payable')]"/>
233 <field name="invoice_id"/>
234 <field name="date_original" readonly="1"/>
235 <field name="date_due" readonly="1"/>
236 <field name="amount_original" readonly="1"/>
237 <field name="amount_unreconciled" sum="Open Balance" readonly="1"/>
238 <field name="amount" sum="Payment"/>
239 <field name="supp_amount_difference"/>
240 <field name="discount_used"/>
241 <notebook tabpos="up" colspan="4" >
242 <page string="Discount">
243 <field name="available_discounts" nolabel="1" colspan="4" string="Avilable Discounts" view_mode="tree" />
244 </page>
245 <page string="Other Info" readonly="1">
246 <field name='partner_id' readonly="1"/>
247 <field name='untax_amount' readonly="1"/>
248 <field name='type' readonly="1"/>
249 <field name='account_analytic_id' readonly="1"/>
250 <field name='company_id' readonly="1"/>
251 <field name='pay' on_change="onchange_pay(amount, pay, amount_unreconciled, parent.line_dr_ids, parent.amount, credit_used, discount_used, writeoff_amount)"/>
252 </page>
253 </notebook>
254 <newline/>
255 <button name="clear_values" icon='gtk-clear' string="Clear" type="object" colspan="1"/>
256 <button name="recalculate_supp_values" icon='gtk-refresh' string="Re-Calculate" type="object" colspan="1"/>
257 </form>
258 </field>
259 </xpath>
260
261 </field>
262 </record>
263
264
265 <!-- customer payment form modification for discount -->
266
267
268 <record model="ir.ui.view" id="view_vendor_receipt_form_2">
269 <field name="name">account.voucher.receipt.form.2</field>
270 <field name="model">account.voucher</field>
271 <field name="type">form</field>
272 <field name="inherit_id" ref="account_voucher_credits_us.view_vendor_receipt_form_1"/>
273 <field name="arch" type="xml">
274 <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">
275 <field name="discount_used"/>
276 <newline />
277 </xpath>
278 <xpath expr="/form/notebook/page[@string='Payment Information']/field/tree/field[@name='credit_used']" position="before">
279 <field name="discount_used"/>
280 <newline/>
281 </xpath>
282 <xpath expr="/form/notebook/page[@string='Payment Information']/field[@name='line_cr_ids']/form/notebook/page[@string='Credit']" position="before">
283 <page string="Discount">
284 <field name="available_discounts" nolabel="1" colspan="4" string="Avilable Discounts" view_mode="tree" />
285 </page>
286 </xpath>
287 </field>
288 </record>
289
290
291 <record model="ir.ui.view" id="view_account_voucher_line_discount_to_use_tree">
292 <field name="name">account.voucher.line.discount_to_use.tree</field>
293 <field name="model">account.voucher.line.discount_to_use</field>
294 <field name="type">tree</field>
295 <field name="arch" type="xml">
296 <tree string="Available Discounts" editable="top">
297 <field name="use_discount" width="125" on_change="onchage_use_discount(use_discount, proposed_discount)"/>
298 <field name="inv_payment_terms"/>
299 <field name="discount_window_date"/>
300 <field name="proposed_discount"/>
301 <field name="discount_amount" on_change="onchage_discount_amount(proposed_discount, discount_amount)"/>
302 <field name="gl_account"/>
303 </tree>
304 </field>
305 </record>
306
307 <record model="ir.ui.view" id="view_payment_term_form_inherited">
308 <field name="name">account.payment.term.form.inherited</field>
309 <field name="model">account.payment.term</field>
310 <field name="inherit_id" ref="account_cash_discount.view_payment_term_form"/>
311 <field name="arch" type="xml">
312 <separator string="Cash Discount" colspan="4" position="replace"/>
313 </field>
314 </record>
315 <record model="ir.ui.view" id="view_payment_term_form_inherited2">
316 <field name="name">account.payment.term.form.inherited2</field>
317 <field name="model">account.payment.term</field>
318 <field name="inherit_id" ref="view_payment_term_form_inherited"/>
319 <field name="arch" type="xml">
320 <field name="cash_discount_ids" colspan="4" position="replace">
321 <separator string="Cash Discount" colspan="4"/>
322 <field name="cash_discount_ids" colspan="4" nolabel="1"/>
323 </field>
324 </field>
325 </record>
326
327
328 </data>
329</openerp>
0330
=== added file 'account_cash_discount_us/amount_to_words.py'
--- account_cash_discount_us/amount_to_words.py 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/amount_to_words.py 2011-10-06 15:23:28 +0000
@@ -0,0 +1,77 @@
1
2# can be used for numbers as large as 999 vigintillion
3# (vigintillion --> 10 to the power 60)
4# tested with Python24 vegaseat 07dec2006
5
6def int2word(n):
7 """
8 convert an integer number n into a string of English words
9 """
10 # break the number into groups of 3 digits using slicing
11 # each group representing hundred, thousand, million, billion, ...
12 if not n:
13 return 'Zero '
14 n3 = []
15 r1 = ""
16 # create numeric string
17 ns = str(n)
18 for k in range(3, 33, 3):
19 r = ns[-k:]
20 q = len(ns) - k
21 # break if end of ns has been reached
22 if q < -2:
23 break
24 else:
25 if q >= 0:
26 n3.append(int(r[:3]))
27 elif q >= -1:
28 n3.append(int(r[:2]))
29 elif q >= -2:
30 n3.append(int(r[:1]))
31 r1 = r
32 nw = ""
33 for i, x in enumerate(n3):
34 b1 = x % 10
35 b2 = (x % 100)//10
36 b3 = (x % 1000)//100
37 if x == 0:
38 continue # skip
39 else:
40 t = thousands[i]
41 if b2 == 0:
42 nw = ones[b1] + t + nw
43 elif b2 == 1:
44 nw = tens[b1] + t + nw
45 elif b2 > 1:
46 nw = twenties[b2] + ones[b1] + t + nw
47 if b3 > 0:
48 nw = ones[b3] + "hundred " + nw
49 return nw
50
51############# globals ################
52
53ones = ["", "One ","Two ","Three ","Four ", "Five ",
54 "Six ","Seven ","Eight ","Nine "]
55
56tens = ["Ten ","Eleven ","Twelve ","Thirteen ", "Fourteen ",
57 "Fifteen ","Sixteen ","Seventeen ","Eighteen ","Nineteen "]
58
59twenties = ["","","Twenty ","Thirty ","Forty ",
60 "Fifty ","Sixty ","Seventy ","Eighty ","Ninety "]
61
62thousands = ["","Thousand ","Million ", "Billion ", "Trillion ",
63 "Quadrillion ", "Quintillion ", "Sextillion ", "Septillion ","Octillion ",
64 "Nonillion ", "Decillion ", "Undecillion ", "Duodecillion ", "Tredecillion ",
65 "Quattuordecillion ", "Sexdecillion ", "Septendecillion ", "Octodecillion ",
66 "Novemdecillion ", "Vigintillion "]
67
68def amount_to_words(num):
69 # select an integer number n for testing or get it from user input
70 res=""
71 if num < 0:
72 res="Negative "
73 num=float(str(num)[1:])
74 if num==0: return 'Zero'
75 else:
76 n=str(num).split('.')
77 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'
078
=== added directory 'account_cash_discount_us/i18n'
=== added file 'account_cash_discount_us/i18n/account_cash_discount.pot'
--- account_cash_discount_us/i18n/account_cash_discount.pot 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/i18n/account_cash_discount.pot 2011-10-06 15:23:28 +0000
@@ -0,0 +1,85 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * account_cash_discount
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 5.0.6\n"
8"Report-Msgid-Bugs-To: support@openerp.com\n"
9"POT-Creation-Date: 2009-11-24 13:09:22+0000\n"
10"PO-Revision-Date: 2009-11-24 13:09:22+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: account_cash_discount
19#: constraint:ir.ui.view:0
20msgid "Invalid XML for View Architecture!"
21msgstr ""
22
23#. module: account_cash_discount
24#: constraint:ir.model:0
25msgid "The Object name must start with x_ and not contain any special character !"
26msgstr ""
27
28#. module: account_cash_discount
29#: field:account.cash.discount,name:0
30msgid "Name"
31msgstr ""
32
33#. module: account_cash_discount
34#: field:account.cash.discount,delay:0
35msgid "Number of Days"
36msgstr ""
37
38#. module: account_cash_discount
39#: field:account.cash.discount,discount:0
40msgid "Discount (%)"
41msgstr ""
42
43#. module: account_cash_discount
44#: field:account.cash.discount,credit_account_id:0
45msgid "Credit Account"
46msgstr ""
47
48#. module: account_cash_discount
49#: field:account.cash.discount,debit_account_id:0
50msgid "Debit Account"
51msgstr ""
52
53#. module: account_cash_discount
54#: model:ir.module.module,description:account_cash_discount.module_meta_information
55msgid "\n"
56" This module adds cash discounts on payment terms. Cash discounts\n"
57" for a payment term can be configured with:\n"
58" * A number of days,\n"
59" * A discount (%),\n"
60" * A debit and a credit account\n"
61" "
62msgstr ""
63
64#. module: account_cash_discount
65#: model:ir.module.module,shortdesc:account_cash_discount.module_meta_information
66msgid "Payement Term with Cash Discount"
67msgstr ""
68
69#. module: account_cash_discount
70#: view:account.cash.discount:0
71#: view:account.payment.term:0
72#: model:ir.model,name:account_cash_discount.model_account_cash_discount
73msgid "Cash Discount"
74msgstr ""
75
76#. module: account_cash_discount
77#: field:account.cash.discount,payment_id:0
78msgid "Associated Payment Term"
79msgstr ""
80
81#. module: account_cash_discount
82#: field:account.payment.term,cash_discount_ids:0
83msgid "Cash Discounts"
84msgstr ""
85
086
=== added file 'account_cash_discount_us/i18n/fr_BE.po'
--- account_cash_discount_us/i18n/fr_BE.po 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/i18n/fr_BE.po 2011-10-06 15:23:28 +0000
@@ -0,0 +1,85 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * account_cash_discount
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 5.0.6\n"
8"Report-Msgid-Bugs-To: support@openerp.com\n"
9"POT-Creation-Date: 2009-11-24 13:09:22+0000\n"
10"PO-Revision-Date: 2009-11-24 13:09:22+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: account_cash_discount
19#: constraint:ir.ui.view:0
20msgid "Invalid XML for View Architecture!"
21msgstr ""
22
23#. module: account_cash_discount
24#: constraint:ir.model:0
25msgid "The Object name must start with x_ and not contain any special character !"
26msgstr ""
27
28#. module: account_cash_discount
29#: field:account.cash.discount,name:0
30msgid "Name"
31msgstr ""
32
33#. module: account_cash_discount
34#: field:account.cash.discount,delay:0
35msgid "Number of Days"
36msgstr ""
37
38#. module: account_cash_discount
39#: field:account.cash.discount,discount:0
40msgid "Discount (%)"
41msgstr ""
42
43#. module: account_cash_discount
44#: field:account.cash.discount,credit_account_id:0
45msgid "Credit Account"
46msgstr ""
47
48#. module: account_cash_discount
49#: field:account.cash.discount,debit_account_id:0
50msgid "Debit Account"
51msgstr ""
52
53#. module: account_cash_discount
54#: model:ir.module.module,description:account_cash_discount.module_meta_information
55msgid "\n"
56" This module adds cash discounts on payment terms. Cash discounts\n"
57" for a payment term can be configured with:\n"
58" * A number of days,\n"
59" * A discount (%),\n"
60" * A debit and a credit account\n"
61" "
62msgstr ""
63
64#. module: account_cash_discount
65#: model:ir.module.module,shortdesc:account_cash_discount.module_meta_information
66msgid "Payement Term with Cash Discount"
67msgstr ""
68
69#. module: account_cash_discount
70#: view:account.cash.discount:0
71#: view:account.payment.term:0
72#: model:ir.model,name:account_cash_discount.model_account_cash_discount
73msgid "Cash Discount"
74msgstr ""
75
76#. module: account_cash_discount
77#: field:account.cash.discount,payment_id:0
78msgid "Associated Payment Term"
79msgstr ""
80
81#. module: account_cash_discount
82#: field:account.payment.term,cash_discount_ids:0
83msgid "Cash Discounts"
84msgstr ""
85
086
=== added file 'account_cash_discount_us/product_view.xml'
--- account_cash_discount_us/product_view.xml 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/product_view.xml 2011-10-06 15:23:28 +0000
@@ -0,0 +1,19 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4 <record id="product_normal_form_view" model="ir.ui.view">
5 <field name="name">product.normal.form.inherit2</field>
6 <field name="model">product.product</field>
7 <field name="type">form</field>
8 <field name="inherit_id" ref="account.product_normal_form_view"/>
9 <field name="arch" type="xml">
10 <xpath expr="//field[@name='property_account_expense']" position="after">
11 <newline/>
12 <field name="sales_discount_account" attrs="{'readonly':[('sale_ok','=',0)]}"/>
13 <field name="purchase_discount_account" attrs="{'readonly':[('purchase_ok','=',0)]}"/>
14 </xpath>
15 </field>
16 </record>
17 </data>
18</openerp>
19
020
=== added directory 'account_cash_discount_us/security'
=== added file 'account_cash_discount_us/security/ir.model.access.csv'
--- account_cash_discount_us/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
+++ account_cash_discount_us/security/ir.model.access.csv 2011-10-06 15:23:28 +0000
@@ -0,0 +1,7 @@
1"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
2"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
3"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
4"access_account_invoice_pay","account.invoice.pay","account_cash_discount_us.model_account_invoice_pay","account.group_account_user",1,0,0,0
5"access_account_invoice_pay_manager","account.invoice.pay","account_cash_discount_us.model_account_invoice_pay","account.group_account_manager",1,1,1,1
6"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
7"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
0\ No newline at end of file8\ No newline at end of file

Subscribers

People subscribed via source and target branches

to all changes: