Merge lp:~therp-nl/account-invoicing/7.0-account_cash_discount into lp:~account-core-editors/account-invoicing/7.0
- 7.0-account_cash_discount
- Merge into 7.0
Status: | Needs review |
---|---|
Proposed branch: | lp:~therp-nl/account-invoicing/7.0-account_cash_discount |
Merge into: | lp:~account-core-editors/account-invoicing/7.0 |
Diff against target: |
1160 lines (+1080/-0) 15 files modified
account_cash_discount/__init__.py (+25/-0) account_cash_discount/__openerp__.py (+84/-0) account_cash_discount/i18n/account_cash_discount.pot (+142/-0) account_cash_discount/i18n/de.po (+133/-0) account_cash_discount/model/__init__.py (+24/-0) account_cash_discount/model/account_invoice.py (+251/-0) account_cash_discount/model/account_payment_term.py (+59/-0) account_cash_discount/model/account_payment_term_cash_discount.py (+87/-0) account_cash_discount/model/account_voucher.py (+75/-0) account_cash_discount/security/ir.model.access.csv (+3/-0) account_cash_discount/view/account_invoice.xml (+24/-0) account_cash_discount/view/account_move_line_reconcile.xml (+26/-0) account_cash_discount/view/account_payment_term.xml (+49/-0) account_cash_discount/wizard/__init__.py (+22/-0) account_cash_discount/wizard/account_move_line_reconcile.py (+76/-0) |
To merge this branch: | bzr merge lp:~therp-nl/account-invoicing/7.0-account_cash_discount |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Pedro Manuel Baeza | Needs Resubmitting | ||
Review via email: mp+203359@code.launchpad.net |
Commit message
Description of the change
This started as a port of http://
I've been unhappy with the way the original module did its work (too much SQL, deleting moves and recreating them), so by now, it's actually a rewrite.
- 27. By Holger Brunn (Therp)
-
[ADD] cope with user configurable deviations from exact discount price
[ADD] use discount_{expense, income} _account_ id
[RFR] make discount_{expense, income} _account_ id regular fields - 28. By Holger Brunn (Therp)
-
[ADD] translation
- 29. By Holger Brunn (Therp)
-
[ADD] handle refunds with cash discounts
Erwin van der Ploeg (BAS Solutions) (erwin-bassolutions-deactivatedaccount) wrote : | # |
Erwin van der Ploeg (BAS Solutions) (erwin-bassolutions-deactivatedaccount) wrote : | # |
Hi Holger. I did some testing on the sales site and it looks ok
- First of all you example is not correct, You say: "On 01/20/2014, you charged EUR 80 to a customer, with 20% tax, totalling in EUR 100". If the amount is 80 and tax is 20%, then the total is 96,-
- Second. In the Netherlands it is not allowed to make a correction on the tax. If you want to correct tax, you have to provide the customer with a new invoice.
Example: 100 + 20% vat = 120 (early payment discount = 5%). The to pay amount = (100-5%) + 20 = 115.
- 30. By Holger Brunn (Therp)
-
[FIX] wrong numbers in example
Holger Brunn (Therp) (hbrunn) wrote : | # |
Erwin, thanks a lot for having a look!
I corrected the example.
Support for payment orders will happen sooner or later, but currently I think it will be rather later than sooner.
This module is meant to deal with the situation in Austria and Germany, there you are legally required to jump through this hoops. For the Dutch situation, a simple write-off is enough I think.
Pedro Manuel Baeza (pedro.baeza) wrote : | # |
This project is now hosted on https:/
Unmerged revisions
- 30. By Holger Brunn (Therp)
-
[FIX] wrong numbers in example
- 29. By Holger Brunn (Therp)
-
[ADD] handle refunds with cash discounts
- 28. By Holger Brunn (Therp)
-
[ADD] translation
- 27. By Holger Brunn (Therp)
-
[ADD] cope with user configurable deviations from exact discount price
[ADD] use discount_{expense, income} _account_ id
[RFR] make discount_{expense, income} _account_ id regular fields - 26. By Holger Brunn (Therp)
-
[ADD] account_
cash_discount
Preview Diff
1 | === added directory 'account_cash_discount' |
2 | === added file 'account_cash_discount/__init__.py' |
3 | --- account_cash_discount/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ account_cash_discount/__init__.py 2014-05-26 08:47:02 +0000 |
5 | @@ -0,0 +1,25 @@ |
6 | +# -*- coding: utf-8 -*- |
7 | +############################################################################## |
8 | +# |
9 | +# OpenERP, Open Source Management Solution |
10 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
11 | +# Copyright (C) 2010-2012 Camptocamp Austria (<http://www.camptocamp.at>) |
12 | +# Copyright (C) 2014 Therp BV (<http://www.therp.nl>) |
13 | +# |
14 | +# This program is free software: you can redistribute it and/or modify |
15 | +# it under the terms of the GNU Affero General Public License as |
16 | +# published by the Free Software Foundation, either version 3 of the |
17 | +# License, or (at your option) any later version. |
18 | +# |
19 | +# This program is distributed in the hope that it will be useful, |
20 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | +# GNU Affero General Public License for more details. |
23 | +# |
24 | +# You should have received a copy of the GNU Affero General Public License |
25 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
26 | +# |
27 | +############################################################################## |
28 | +import model |
29 | +import wizard |
30 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
31 | |
32 | === added file 'account_cash_discount/__openerp__.py' |
33 | --- account_cash_discount/__openerp__.py 1970-01-01 00:00:00 +0000 |
34 | +++ account_cash_discount/__openerp__.py 2014-05-26 08:47:02 +0000 |
35 | @@ -0,0 +1,84 @@ |
36 | +# -*- coding: utf-8 -*- |
37 | +############################################################################## |
38 | +# |
39 | +# OpenERP, Open Source Management Solution |
40 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
41 | +# Copyright (C) 2010-2012 Camptocamp Austria (<http://www.camptocamp.at>) |
42 | +# Copyright (C) 2014 Therp BV (<http://www.therp.nl>) |
43 | +# |
44 | +# This program is free software: you can redistribute it and/or modify |
45 | +# it under the terms of the GNU Affero General Public License as |
46 | +# published by the Free Software Foundation, either version 3 of the |
47 | +# License, or (at your option) any later version. |
48 | +# |
49 | +# This program is distributed in the hope that it will be useful, |
50 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
51 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
52 | +# GNU Affero General Public License for more details. |
53 | +# |
54 | +# You should have received a copy of the GNU Affero General Public License |
55 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
56 | +# |
57 | +############################################################################## |
58 | + |
59 | + |
60 | +{ |
61 | + 'name': 'Cash discount', |
62 | + 'version': '0.9', |
63 | + 'category': 'Accounting & Finance', |
64 | + 'description': """ |
65 | +Cash Discount (Austria and Germany style) |
66 | +========================================= |
67 | + |
68 | +Usage |
69 | +----- |
70 | + |
71 | +Define your discounts as part of your payment terms. Keep in mind that other |
72 | +computation lines than 'balance' won't make much sense, so only fill in one |
73 | +computation line of type 'balance' indicating your payment date. |
74 | + |
75 | +When paying your invoice, fill in the exact amount for the discounted invoice. |
76 | +If the payment date and the amount matches a discount, the invoice will be |
77 | +marked as paid and some correction move lines will be created to reflect the |
78 | +invoice being paid with a discount. |
79 | + |
80 | +If you manually reconcile move lines, you'll be offered a button to book the |
81 | +writeoff amount as cash discount if a matching cash discount can be found. |
82 | + |
83 | +Example |
84 | +------- |
85 | + |
86 | +On 01/20/2014, you charged EUR 80 to a customer, with 25% tax, totalling in |
87 | +EUR 100. Further, you set up a payment term for this invoice that includes |
88 | +5% discount if paid within a week. |
89 | + |
90 | +If you fill in EUR 95 and payment date 01/22/2014 when paying the invoice, the |
91 | +following happens: |
92 | + |
93 | +- the invoice is marked as paid |
94 | +- on the invoice's 'Other info' tag, you'll find a field 'Cash discount |
95 | + correction' with the following lines: |
96 | + |
97 | + - EUR 1 as debit on your tax account |
98 | + - EUR 4 as debit on your income account |
99 | + - EUR 5 as credit on your customer's account |
100 | + |
101 | +TODO |
102 | +---- |
103 | + |
104 | +- cash discounts don't show up on invoice report |
105 | +- multi currency not tested |
106 | +- no automatic reconciliation |
107 | +""", |
108 | + 'author': 'Therp BV', |
109 | + 'depends': [ 'account_voucher' ], |
110 | + 'data': [ |
111 | + 'view/account_move_line_reconcile.xml', |
112 | + 'view/account_payment_term.xml', |
113 | + 'view/account_invoice.xml', |
114 | + 'security/ir.model.access.csv', |
115 | + ], |
116 | + 'installable': True, |
117 | + 'auto_install': False, |
118 | +} |
119 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
120 | |
121 | === added directory 'account_cash_discount/i18n' |
122 | === added file 'account_cash_discount/i18n/account_cash_discount.pot' |
123 | --- account_cash_discount/i18n/account_cash_discount.pot 1970-01-01 00:00:00 +0000 |
124 | +++ account_cash_discount/i18n/account_cash_discount.pot 2014-05-26 08:47:02 +0000 |
125 | @@ -0,0 +1,142 @@ |
126 | +# Translation of OpenERP Server. |
127 | +# This file contains the translation of the following modules: |
128 | +# * account_cash_discount |
129 | +# |
130 | +msgid "" |
131 | +msgstr "" |
132 | +"Project-Id-Version: OpenERP Server 7.0\n" |
133 | +"Report-Msgid-Bugs-To: \n" |
134 | +"POT-Creation-Date: 2014-02-18 15:41+0000\n" |
135 | +"PO-Revision-Date: 2014-02-18 15:41+0000\n" |
136 | +"Last-Translator: <>\n" |
137 | +"Language-Team: \n" |
138 | +"MIME-Version: 1.0\n" |
139 | +"Content-Type: text/plain; charset=UTF-8\n" |
140 | +"Content-Transfer-Encoding: \n" |
141 | +"Plural-Forms: \n" |
142 | + |
143 | +#. module: account_cash_discount |
144 | +#: code:addons/account_cash_discount/model/account_invoice.py:130 |
145 | +#: code:addons/account_cash_discount/model/account_invoice.py:144 |
146 | +#, python-format |
147 | +msgid "Cash discount writeoff" |
148 | +msgstr "" |
149 | + |
150 | +#. module: account_cash_discount |
151 | +#: view:account.invoice:0 |
152 | +msgid "Note: This invoice was paid with a cash discount as detailed in the cash discount correction move on the 'Other info' tab" |
153 | +msgstr "" |
154 | + |
155 | +#. module: account_cash_discount |
156 | +#: field:account.payment.term.cash.discount,allowed_deviation:0 |
157 | +msgid "Allowed deviation" |
158 | +msgstr "" |
159 | + |
160 | +#. module: account_cash_discount |
161 | +#: help:account.payment.term.cash.discount,discount_expense_account_id:0 |
162 | +msgid "This account will be used to post the cash discount expense" |
163 | +msgstr "" |
164 | + |
165 | +#. module: account_cash_discount |
166 | +#: field:account.move.line.reconcile,invoice_has_cash_discount:0 |
167 | +msgid "Cash discount on invoice" |
168 | +msgstr "" |
169 | + |
170 | +#. module: account_cash_discount |
171 | +#: model:ir.model,name:account_cash_discount.model_account_move_line_reconcile |
172 | +msgid "Account move line reconcile" |
173 | +msgstr "" |
174 | + |
175 | +#. module: account_cash_discount |
176 | +#: code:addons/account_cash_discount/model/account_payment_term.py:45 |
177 | +#, python-format |
178 | +msgid "When working with cash discounts, you can only have one computation line of type \"balance\"!" |
179 | +msgstr "" |
180 | + |
181 | +#. module: account_cash_discount |
182 | +#: field:account.payment.term.cash.discount,discount_income_account_id:0 |
183 | +msgid "Discount Income Account" |
184 | +msgstr "" |
185 | + |
186 | +#. module: account_cash_discount |
187 | +#: help:account.payment.term.cash.discount,discount_income_account_id:0 |
188 | +msgid "This account will be used to post the cash discount income" |
189 | +msgstr "" |
190 | + |
191 | +#. module: account_cash_discount |
192 | +#: field:account.payment.term.cash.discount,discount:0 |
193 | +msgid "Discount" |
194 | +msgstr "" |
195 | + |
196 | +#. module: account_cash_discount |
197 | +#: field:account.invoice,cash_discount_move_id:0 |
198 | +msgid "Cash discount correction move" |
199 | +msgstr "" |
200 | + |
201 | +#. module: account_cash_discount |
202 | +#: view:account.move.line.reconcile:0 |
203 | +msgid "Book difference as cash discount" |
204 | +msgstr "" |
205 | + |
206 | +#. module: account_cash_discount |
207 | +#: field:account.payment.term.cash.discount,payment_term_id:0 |
208 | +msgid "Payment term" |
209 | +msgstr "" |
210 | + |
211 | +#. module: account_cash_discount |
212 | +#: field:account.payment.term.cash.discount,days:0 |
213 | +msgid "Days" |
214 | +msgstr "" |
215 | + |
216 | +#. module: account_cash_discount |
217 | +#: code:addons/account_cash_discount/model/account_payment_term.py:45 |
218 | +#, python-format |
219 | +msgid "Error" |
220 | +msgstr "" |
221 | + |
222 | +#. module: account_cash_discount |
223 | +#: field:account.payment.term.cash.discount,discount_expense_account_id:0 |
224 | +msgid "Discount Expense Account" |
225 | +msgstr "" |
226 | + |
227 | +#. module: account_cash_discount |
228 | +#: field:account.payment.term,cash_discount_ids:0 |
229 | +#: model:ir.model,name:account_cash_discount.model_account_payment_term_cash_discount |
230 | +msgid "Cash discount" |
231 | +msgstr "" |
232 | + |
233 | +#. module: account_cash_discount |
234 | +#: view:account.move.line.reconcile:0 |
235 | +msgid "Reconcile" |
236 | +msgstr "" |
237 | + |
238 | +#. module: account_cash_discount |
239 | +#: model:ir.model,name:account_cash_discount.model_account_voucher |
240 | +msgid "Accounting Voucher" |
241 | +msgstr "" |
242 | + |
243 | +#. module: account_cash_discount |
244 | +#: view:account.payment.term:0 |
245 | +#: model:ir.model,name:account_cash_discount.model_account_payment_term |
246 | +msgid "Payment Term" |
247 | +msgstr "" |
248 | + |
249 | +#. module: account_cash_discount |
250 | +#: help:account.payment.term.cash.discount,allowed_deviation:0 |
251 | +msgid "The amount a payment can deviate from the computed amount and still be accepted as payment within this discount.\n" |
252 | +"Think of rounding errors as use case for this" |
253 | +msgstr "" |
254 | + |
255 | +#. module: account_cash_discount |
256 | +#: code:addons/account_cash_discount/model/account_invoice.py:64 |
257 | +#: code:addons/account_cash_discount/model/account_invoice.py:188 |
258 | +#, python-format |
259 | +msgid "Cash discount for %s" |
260 | +msgstr "" |
261 | + |
262 | +#. module: account_cash_discount |
263 | +#: field:account.move.line.reconcile,invoice_id:0 |
264 | +#: model:ir.model,name:account_cash_discount.model_account_invoice |
265 | +msgid "Invoice" |
266 | +msgstr "" |
267 | + |
268 | |
269 | === added file 'account_cash_discount/i18n/de.po' |
270 | --- account_cash_discount/i18n/de.po 1970-01-01 00:00:00 +0000 |
271 | +++ account_cash_discount/i18n/de.po 2014-05-26 08:47:02 +0000 |
272 | @@ -0,0 +1,133 @@ |
273 | +# Translation of OpenERP Server. |
274 | +# This file contains the translation of the following modules: |
275 | +# * account_cash_discount |
276 | +# |
277 | +msgid "" |
278 | +msgstr "" |
279 | +"Project-Id-Version: OpenERP Server 7.0\n" |
280 | +"Report-Msgid-Bugs-To: \n" |
281 | +"POT-Creation-Date: 2014-02-18 15:41+0000\n" |
282 | +"PO-Revision-Date: 2014-02-18 15:41+0000\n" |
283 | +"Last-Translator: <>\n" |
284 | +"Language-Team: \n" |
285 | +"MIME-Version: 1.0\n" |
286 | +"Content-Type: text/plain; charset=UTF-8\n" |
287 | +"Content-Transfer-Encoding: \n" |
288 | +"Plural-Forms: \n" |
289 | + |
290 | +#. module: account_cash_discount |
291 | +#: code:addons/account_cash_discount/model/account_invoice.py:130 |
292 | +#: code:addons/account_cash_discount/model/account_invoice.py:144 |
293 | +#, python-format |
294 | +msgid "Cash discount writeoff" |
295 | +msgstr "Skontoabschreibung" |
296 | + |
297 | +#. module: account_cash_discount |
298 | +#: view:account.invoice:0 |
299 | +msgid "Note: This invoice was paid with a cash discount as detailed in the cash discount correction move on the 'Other info' tab" |
300 | +msgstr "Achtung: Diese Rechnung wurde unter Einbehalt von Skonto bezahlt. Die ensprechenden Buchungen finden sich im 'Weitere Info'-Reiter." |
301 | + |
302 | +#. module: account_cash_discount |
303 | +#: field:account.payment.term.cash.discount,allowed_deviation:0 |
304 | +msgid "Allowed deviation" |
305 | +msgstr "Erlaubte Abweichung" |
306 | + |
307 | +#. module: account_cash_discount |
308 | +#: help:account.payment.term.cash.discount,discount_expense_account_id:0 |
309 | +msgid "This account will be used to post the cash discount expense" |
310 | +msgstr "Skontoausgaben werden auf dieses Konto gebucht" |
311 | + |
312 | +#. module: account_cash_discount |
313 | +#: field:account.move.line.reconcile,invoice_has_cash_discount:0 |
314 | +msgid "Cash discount on invoice" |
315 | +msgstr "Rechnung mit Skonto" |
316 | + |
317 | +#. module: account_cash_discount |
318 | +#: model:ir.model,name:account_cash_discount.model_account_move_line_reconcile |
319 | +msgid "Account move line reconcile" |
320 | +msgstr "Buchen OP Ausgleich" |
321 | + |
322 | +#. module: account_cash_discount |
323 | +#: code:addons/account_cash_discount/model/account_payment_term.py:45 |
324 | +#, python-format |
325 | +msgid "When working with cash discounts, you can only have one computation line of type \"balance\"!" |
326 | +msgstr "Skontobezahlungen können nur eine Berechnung vom Typ \"Saldo\" beinhalten!" |
327 | + |
328 | +#. module: account_cash_discount |
329 | +#: field:account.payment.term.cash.discount,discount_income_account_id:0 |
330 | +msgid "Discount Income Account" |
331 | +msgstr "Skonto-Erlöskonto" |
332 | + |
333 | +#. module: account_cash_discount |
334 | +#: help:account.payment.term.cash.discount,discount_income_account_id:0 |
335 | +msgid "This account will be used to post the cash discount income" |
336 | +msgstr "Skontoerlöse werden auf dieses Konto gebucht" |
337 | + |
338 | +#. module: account_cash_discount |
339 | +#: field:account.payment.term.cash.discount,discount:0 |
340 | +msgid "Discount" |
341 | +msgstr "Skonto" |
342 | + |
343 | +#. module: account_cash_discount |
344 | +#: field:account.invoice,cash_discount_move_id:0 |
345 | +msgid "Cash discount correction move" |
346 | +msgstr "Skonto-Buchungssatz" |
347 | + |
348 | +#. module: account_cash_discount |
349 | +#: view:account.move.line.reconcile:0 |
350 | +msgid "Book difference as cash discount" |
351 | +msgstr "Differenz als Skonto buchen" |
352 | + |
353 | +#. module: account_cash_discount |
354 | +#: field:account.payment.term.cash.discount,payment_term_id:0 |
355 | +msgid "Payment term" |
356 | +msgstr "Zahlungsbedingung" |
357 | + |
358 | +#. module: account_cash_discount |
359 | +#: field:account.payment.term.cash.discount,days:0 |
360 | +msgid "Days" |
361 | +msgstr "Tage" |
362 | + |
363 | +#. module: account_cash_discount |
364 | +#: code:addons/account_cash_discount/model/account_payment_term.py:45 |
365 | +#, python-format |
366 | +msgid "Error" |
367 | +msgstr "Fehler" |
368 | + |
369 | +#. module: account_cash_discount |
370 | +#: field:account.payment.term.cash.discount,discount_expense_account_id:0 |
371 | +msgid "Discount Expense Account" |
372 | +msgstr "Skonto-Aufwandskonto" |
373 | + |
374 | +#. module: account_cash_discount |
375 | +#: field:account.payment.term,cash_discount_ids:0 |
376 | +#: model:ir.model,name:account_cash_discount.model_account_payment_term_cash_discount |
377 | +msgid "Cash discount" |
378 | +msgstr "Skonto" |
379 | + |
380 | +#. module: account_cash_discount |
381 | +#: view:account.payment.term:0 |
382 | +#: model:ir.model,name:account_cash_discount.model_account_payment_term |
383 | +msgid "Payment Term" |
384 | +msgstr "Zahlungsbedingung" |
385 | + |
386 | +#. module: account_cash_discount |
387 | +#: help:account.payment.term.cash.discount,allowed_deviation:0 |
388 | +msgid "The amount a payment can deviate from the computed amount and still be accepted as payment within this discount.\n" |
389 | +"Think of rounding errors as use case for this" |
390 | +msgstr "Der Betrag um den eine Zahlung vom berechneten Betrag abweichen darf um noch als Zahlung innerhalb des Skontos angesehen zu werden.\n" |
391 | +"Dies vereinfact die Handhabung von Rundungsunterschieden." |
392 | + |
393 | +#. module: account_cash_discount |
394 | +#: code:addons/account_cash_discount/model/account_invoice.py:64 |
395 | +#: code:addons/account_cash_discount/model/account_invoice.py:188 |
396 | +#, python-format |
397 | +msgid "Cash discount for %s" |
398 | +msgstr "Skonto für %s" |
399 | + |
400 | +#. module: account_cash_discount |
401 | +#: field:account.move.line.reconcile,invoice_id:0 |
402 | +#: model:ir.model,name:account_cash_discount.model_account_invoice |
403 | +msgid "Invoice" |
404 | +msgstr "Rechnung" |
405 | + |
406 | |
407 | === added directory 'account_cash_discount/model' |
408 | === added file 'account_cash_discount/model/__init__.py' |
409 | --- account_cash_discount/model/__init__.py 1970-01-01 00:00:00 +0000 |
410 | +++ account_cash_discount/model/__init__.py 2014-05-26 08:47:02 +0000 |
411 | @@ -0,0 +1,24 @@ |
412 | +# -*- coding: utf-8 -*- |
413 | +############################################################################## |
414 | +# |
415 | +# OpenERP, Open Source Management Solution |
416 | +# This module copyright (C) 2014 Therp BV (<http://therp.nl>). |
417 | +# |
418 | +# This program is free software: you can redistribute it and/or modify |
419 | +# it under the terms of the GNU Affero General Public License as |
420 | +# published by the Free Software Foundation, either version 3 of the |
421 | +# License, or (at your option) any later version. |
422 | +# |
423 | +# This program is distributed in the hope that it will be useful, |
424 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
425 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
426 | +# GNU Affero General Public License for more details. |
427 | +# |
428 | +# You should have received a copy of the GNU Affero General Public License |
429 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
430 | +# |
431 | +############################################################################## |
432 | +import account_voucher |
433 | +import account_invoice |
434 | +import account_payment_term |
435 | +import account_payment_term_cash_discount |
436 | |
437 | === added file 'account_cash_discount/model/account_invoice.py' |
438 | --- account_cash_discount/model/account_invoice.py 1970-01-01 00:00:00 +0000 |
439 | +++ account_cash_discount/model/account_invoice.py 2014-05-26 08:47:02 +0000 |
440 | @@ -0,0 +1,251 @@ |
441 | +# -*- coding: utf-8 -*- |
442 | +############################################################################## |
443 | +# |
444 | +# OpenERP, Open Source Management Solution |
445 | +# This module copyright (C) 2014 Therp BV (<http://therp.nl>). |
446 | +# |
447 | +# This program is free software: you can redistribute it and/or modify |
448 | +# it under the terms of the GNU Affero General Public License as |
449 | +# published by the Free Software Foundation, either version 3 of the |
450 | +# License, or (at your option) any later version. |
451 | +# |
452 | +# This program is distributed in the hope that it will be useful, |
453 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
454 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
455 | +# GNU Affero General Public License for more details. |
456 | +# |
457 | +# You should have received a copy of the GNU Affero General Public License |
458 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
459 | +# |
460 | +############################################################################## |
461 | +import datetime |
462 | +from openerp.osv import orm, fields |
463 | +from openerp.tools.translate import _ |
464 | +from openerp.tools import float_round, float_is_zero, float_compare,\ |
465 | + DEFAULT_SERVER_DATE_FORMAT |
466 | + |
467 | + |
468 | +class AccountInvoice(orm.Model): |
469 | + _inherit = 'account.invoice' |
470 | + |
471 | + _columns = { |
472 | + 'cash_discount_move_id': fields.many2one( |
473 | + 'account.move', string='Cash discount correction move'), |
474 | + } |
475 | + |
476 | + def create_cash_discount_move_lines( |
477 | + self, cr, uid, ids, discount, payment_move_lines, date=None, |
478 | + post_move=True, context=None): |
479 | + '''create correction entries for invoices eligible to a cash discount, |
480 | + given by the appropriate payment.term.line |
481 | + |
482 | + :param discount: the discount |
483 | + :type discount: browse_record('payment.term.line') |
484 | + :param payment_move_lines: the payment move lines to create correction |
485 | + entries for |
486 | + :type payment_move_lines: browse_record_list('account.move.line') |
487 | + :param date: the date to post the move to |
488 | + :type date: string |
489 | + |
490 | + :returns: list of created account.move.lines' ids |
491 | + ''' |
492 | + if date is None: |
493 | + date = datetime.datetime.now().strftime(DEFAULT_SERVER_DATE_FORMAT) |
494 | + |
495 | + account_move_line = self.pool.get('account.move.line') |
496 | + account_move = self.pool.get('account.move') |
497 | + precision = self.pool.get('decimal.precision').precision_get( |
498 | + cr, uid, 'Account') |
499 | + result = [] |
500 | + for this in self.browse(cr, uid, ids, context=context): |
501 | + discount_move_id = account_move.create( |
502 | + cr, uid, |
503 | + { |
504 | + 'name': _('Cash discount for %s') % this.move_id.name, |
505 | + 'period_id': self.pool.get('account.period').find( |
506 | + cr, uid, dt=date, context=context)[0], |
507 | + 'journal_id': this.journal_id.id, |
508 | + 'date': date, |
509 | + }, |
510 | + context=context) |
511 | + |
512 | + #prepare to correct potential rounding errors |
513 | + total_debit_payment = total_credit_payment = 0 |
514 | + for payment_move_line in payment_move_lines: |
515 | + total_debit_payment += payment_move_line.debit |
516 | + total_credit_payment += payment_move_line.credit |
517 | + total_debit_invoice = total_credit_invoice = 0 |
518 | + #create correction entries |
519 | + total_debit_correction = total_credit_correction = 0 |
520 | + for move_line in this.move_id.line_id: |
521 | + line_data = self.create_cash_discount_move_line_dict( |
522 | + discount_move_id, move_line, discount, precision) |
523 | + line_id = account_move_line.create(cr, uid, line_data, |
524 | + context=context) |
525 | + result.append(line_id) |
526 | + total_debit_correction += line_data['debit'] |
527 | + total_credit_correction += line_data['credit'] |
528 | + total_debit_invoice += move_line.debit |
529 | + total_credit_invoice += move_line.credit |
530 | + |
531 | + #add rounding error to a matching correction entry |
532 | + if not float_is_zero( |
533 | + total_debit_correction - total_credit_correction, |
534 | + precision): |
535 | + error_credit = max(0, float_round( |
536 | + total_debit_correction - total_credit_correction, |
537 | + precision)) |
538 | + error_debit = max(0, float_round( |
539 | + total_credit_correction - total_debit_correction, |
540 | + precision)) |
541 | + |
542 | + for correction_line in account_move_line.browse( |
543 | + cr, uid, result, context=context): |
544 | + if correction_line.credit and error_credit: |
545 | + correction_line.write( |
546 | + {'credit': correction_line.credit + error_credit}) |
547 | + total_credit_correction += error_credit |
548 | + error_credit = 0 |
549 | + if correction_line.debit and error_debit: |
550 | + correction_line.write( |
551 | + {'debit': correction_line.debit + error_debit}) |
552 | + total_debit_correction += error_debit |
553 | + error_debit = 0 |
554 | + if not error_credit and not error_debit: |
555 | + break |
556 | + |
557 | + #write off differences within deviation margin |
558 | + writeoff_debit = total_debit_correction + total_debit_payment\ |
559 | + - total_debit_invoice |
560 | + writeoff_credit = total_credit_correction + total_credit_payment\ |
561 | + - total_credit_invoice |
562 | + |
563 | + if float_compare(writeoff_debit, writeoff_credit, precision) == 0\ |
564 | + and float_compare(abs(writeoff_debit), |
565 | + discount.allowed_deviation, |
566 | + precision) == -1: |
567 | + line_id = account_move_line.create( |
568 | + cr, uid, |
569 | + { |
570 | + 'name': _('Cash discount writeoff'), |
571 | + 'debit': abs(writeoff_debit), |
572 | + 'move_id': discount_move_id, |
573 | + 'partner_id': this.partner_id.id, |
574 | + 'account_id': this.account_id.id |
575 | + if writeoff_debit > 0 |
576 | + else discount.discount_expense_account_id.id, |
577 | + }, |
578 | + context=context) |
579 | + result.append(line_id) |
580 | + |
581 | + line_id = account_move_line.create( |
582 | + cr, uid, |
583 | + { |
584 | + 'name': _('Cash discount writeoff'), |
585 | + 'credit': abs(writeoff_credit), |
586 | + 'move_id': discount_move_id, |
587 | + 'partner_id': this.partner_id.id, |
588 | + 'account_id': this.account_id.id |
589 | + if writeoff_credit < 0 |
590 | + else discount.discount_income_account_id.id, |
591 | + }, |
592 | + context=context) |
593 | + result.append(line_id) |
594 | + |
595 | + this.write({'cash_discount_move_id': discount_move_id}) |
596 | + if post_move: |
597 | + account_move.post(cr, uid, [discount_move_id], context=context) |
598 | + return result |
599 | + |
600 | + def create_cash_discount_move_line_dict(self, move_id, move_line, |
601 | + discount, precision): |
602 | + '''return a dict suitable to create a correction entry for specified |
603 | + cash discount |
604 | + |
605 | + :param move_id: the move to append correction entries to |
606 | + :type move: int |
607 | + :param move_line: the move to append correction entries to |
608 | + :type move_line: browse_record('account.move') |
609 | + :param discount: the discount |
610 | + :type discount: browse_record('payment.term.line') |
611 | + |
612 | + :returns: dict that can be fed to account_move_line.create |
613 | + ''' |
614 | + |
615 | + account_id = move_line.account_id.id |
616 | + if move_line.account_id.id in [ |
617 | + l.account_id.id for l in move_line.invoice.invoice_line]: |
618 | + if move_line.credit: |
619 | + account_id = discount.discount_expense_account_id.id\ |
620 | + or account_id |
621 | + if move_line.debit: |
622 | + account_id = discount.discount_income_account_id.id\ |
623 | + or account_id |
624 | + |
625 | + data = self.pool.get('account.move.line').copy_data( |
626 | + move_line._cr, move_line._uid, move_line.id, |
627 | + default={ |
628 | + 'name': _('Cash discount for %s') % move_line.name, |
629 | + 'debit': float_round( |
630 | + move_line.credit * discount.discount / 100, |
631 | + precision), |
632 | + 'credit': float_round( |
633 | + move_line.debit * discount.discount / 100, |
634 | + precision), |
635 | + 'tax_amount': float_round( |
636 | + -move_line.tax_amount * discount.discount / 100, |
637 | + precision), |
638 | + 'amount_currency': float_round( |
639 | + -move_line.amount_currency * discount.discount / 100, |
640 | + precision), |
641 | + 'move_id': move_id, |
642 | + 'account_id': account_id, |
643 | + }, |
644 | + context=move_line._context) |
645 | + return data |
646 | + |
647 | + def copy_data(self, cr, uid, id, default=None, context=None): |
648 | + '''reset cash_discount_move_id''' |
649 | + if default is None: |
650 | + default = {} |
651 | + default.setdefault('cash_discount_move_id', False) |
652 | + |
653 | + return super(AccountInvoice, self).copy_data( |
654 | + cr, uid, id, default=default, context=None) |
655 | + |
656 | + def get_matching_cash_discount(self, cr, uid, ids, amount, |
657 | + payment_date=None, context=None): |
658 | + '''return a cash discount that matches the amount paid and payment |
659 | + date''' |
660 | + result = False |
661 | + for this in self.browse(cr, uid, ids, context=context): |
662 | + if not this.payment_term or\ |
663 | + not this.payment_term.cash_discount_ids: |
664 | + continue |
665 | + for discount in this.payment_term.cash_discount_ids: |
666 | + if discount.matches(amount, this.date_invoice, |
667 | + this.amount_total, |
668 | + payment_date=payment_date): |
669 | + return discount |
670 | + return result |
671 | + |
672 | + def _prepare_refund(self, cr, uid, invoice, date=None, period_id=None, |
673 | + description=None, journal_id=None, context=None): |
674 | + result = super(AccountInvoice, self)._prepare_refund( |
675 | + cr, uid, invoice, date=date, period_id=period_id, |
676 | + description=description, journal_id=journal_id, context=context) |
677 | + if invoice.cash_discount_move_id: |
678 | + result['payment_term'] = False |
679 | + for discount_move in invoice.cash_discount_move_id.line_id: |
680 | + if not discount_move.account_id == invoice.account_id: |
681 | + continue |
682 | + result['invoice_line'].append( |
683 | + (0, 0, |
684 | + { |
685 | + 'name': discount_move.name, |
686 | + 'account_id': discount_move.account_id.id, |
687 | + 'price_unit': -(discount_move.credit or |
688 | + -discount_move.debit), |
689 | + })) |
690 | + |
691 | + return result |
692 | |
693 | === added file 'account_cash_discount/model/account_payment_term.py' |
694 | --- account_cash_discount/model/account_payment_term.py 1970-01-01 00:00:00 +0000 |
695 | +++ account_cash_discount/model/account_payment_term.py 2014-05-26 08:47:02 +0000 |
696 | @@ -0,0 +1,59 @@ |
697 | +# -*- coding: utf-8 -*- |
698 | +############################################################################## |
699 | +# |
700 | +# OpenERP, Open Source Management Solution |
701 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
702 | +# Copyright (C) 2012-2012 Camptocamp Austria (<http://www.camptocamp.at>) |
703 | +# Copyright (C) 2014 Therp BV (<http://www.therp.nl>) |
704 | +# |
705 | +# This program is free software: you can redistribute it and/or modify |
706 | +# it under the terms of the GNU Affero General Public License as |
707 | +# published by the Free Software Foundation, either version 3 of the |
708 | +# License, or (at your option) any later version. |
709 | +# |
710 | +# This program is distributed in the hope that it will be useful, |
711 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
712 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
713 | +# GNU Affero General Public License for more details. |
714 | +# |
715 | +# You should have received a copy of the GNU Affero General Public License |
716 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
717 | +# |
718 | +############################################################################## |
719 | +from openerp.osv import fields, orm |
720 | +from openerp.tools.translate import _ |
721 | + |
722 | + |
723 | +class AccountPaymentTerm(orm.Model): |
724 | + _inherit = "account.payment.term" |
725 | + _columns = { |
726 | + 'cash_discount_ids': fields.one2many( |
727 | + 'account.payment.term.cash.discount', 'payment_term_id', |
728 | + 'Cash discount'), |
729 | + } |
730 | + |
731 | + def _check_validity(self, cr, uid, ids, context=None): |
732 | + for this in self.browse( |
733 | + cr, uid, ids if isinstance(ids, list) else [ids], |
734 | + context=context): |
735 | + if not this.cash_discount_ids: |
736 | + continue |
737 | + for payment_term_line in this.line_ids: |
738 | + if payment_term_line.value == 'balance': |
739 | + continue |
740 | + raise orm.except_orm( |
741 | + _('Error'), _('When working with cash discounts, you can ' |
742 | + 'only have one computation line of type ' |
743 | + '"balance"!')) |
744 | + |
745 | + def create(self, cr, uid, vals, context=None): |
746 | + result = super(AccountPaymentTerm, self).create( |
747 | + cr, uid, vals, context=context) |
748 | + self._check_validity(cr, uid, result, context=context) |
749 | + return result |
750 | + |
751 | + def write(self, cr, uid, ids, vals, context=None): |
752 | + result = super(AccountPaymentTerm, self).write( |
753 | + cr, uid, ids, vals, context=context) |
754 | + self._check_validity(cr, uid, ids, context=context) |
755 | + return result |
756 | |
757 | === added file 'account_cash_discount/model/account_payment_term_cash_discount.py' |
758 | --- account_cash_discount/model/account_payment_term_cash_discount.py 1970-01-01 00:00:00 +0000 |
759 | +++ account_cash_discount/model/account_payment_term_cash_discount.py 2014-05-26 08:47:02 +0000 |
760 | @@ -0,0 +1,87 @@ |
761 | +# -*- coding: utf-8 -*- |
762 | +############################################################################## |
763 | +# |
764 | +# OpenERP, Open Source Management Solution |
765 | +# This module copyright (C) 2014 Therp BV (<http://therp.nl>). |
766 | +# |
767 | +# This program is free software: you can redistribute it and/or modify |
768 | +# it under the terms of the GNU Affero General Public License as |
769 | +# published by the Free Software Foundation, either version 3 of the |
770 | +# License, or (at your option) any later version. |
771 | +# |
772 | +# This program is distributed in the hope that it will be useful, |
773 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
774 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
775 | +# GNU Affero General Public License for more details. |
776 | +# |
777 | +# You should have received a copy of the GNU Affero General Public License |
778 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
779 | +# |
780 | +############################################################################## |
781 | +import datetime |
782 | +from openerp.osv.orm import Model |
783 | +from openerp.osv import fields |
784 | +from openerp.tools import float_compare, DEFAULT_SERVER_DATE_FORMAT |
785 | + |
786 | +class AccountPaymentTermCashDiscount(Model): |
787 | + _name = 'account.payment.term.cash.discount' |
788 | + _description= 'Cash discount' |
789 | + _rec_name = 'days' |
790 | + _order = 'days' |
791 | + |
792 | + _columns = { |
793 | + 'payment_term_id': fields.many2one( |
794 | + 'account.payment.term', 'Payment term', required=True), |
795 | + 'days': fields.integer('Days', required=True), |
796 | + 'discount': fields.float('Discount', required=True), |
797 | + 'allowed_deviation': fields.float( |
798 | + 'Allowed deviation', |
799 | + help="The amount a payment can deviate from the computed amount " |
800 | + "and still be accepted as payment within this discount.\n" |
801 | + "Think of rounding errors as use case for this"), |
802 | + 'discount_income_account_id': fields.many2one( |
803 | + 'account.account', string='Discount Income Account', |
804 | + help="This account will be used to post the cash discount income"), |
805 | + 'discount_expense_account_id': fields.many2one( |
806 | + 'account.account', |
807 | + string='Discount Expense Account', |
808 | + help="This account will be used to post the cash discount expense") |
809 | + } |
810 | + |
811 | + def matches(self, cr, uid, ids, amount, invoice_date, invoice_amount, |
812 | + payment_date=None, context=None): |
813 | + '''determine if an amount paid at a certain date matches an invoiced |
814 | + amount from a certain date |
815 | + |
816 | + :param amount: the amount paid |
817 | + :type amount: float |
818 | + :param invoice_date: the invoice's date |
819 | + :type invoice_date: string |
820 | + :param invoice_amount: the invoiced amount |
821 | + :type invoice_amount: float |
822 | + :param payment_date: the date of payment, today if None |
823 | + :type payment_date: string |
824 | + ''' |
825 | + precision = self.pool.get('decimal.precision').precision_get( |
826 | + cr, uid, 'Account') |
827 | + |
828 | + if not payment_date: |
829 | + payment_date = datetime.datetime.now().strftime( |
830 | + DEFAULT_SERVER_DATE_FORMAT) |
831 | + |
832 | + for this in self.browse(cr, uid, ids, context=context): |
833 | + date = ( |
834 | + datetime.datetime.strptime( |
835 | + invoice_date, DEFAULT_SERVER_DATE_FORMAT) + |
836 | + datetime.timedelta(days=this.days))\ |
837 | + .strftime(DEFAULT_SERVER_DATE_FORMAT) |
838 | + |
839 | + return date >= payment_date and float_compare( |
840 | + amount, |
841 | + (1 - this.discount / 100) * invoice_amount |
842 | + - this.allowed_deviation, |
843 | + precision) == 1 and float_compare( |
844 | + amount, |
845 | + (1 - this.discount / 100) * invoice_amount |
846 | + + this.allowed_deviation, |
847 | + precision) == -1 |
848 | |
849 | === added file 'account_cash_discount/model/account_voucher.py' |
850 | --- account_cash_discount/model/account_voucher.py 1970-01-01 00:00:00 +0000 |
851 | +++ account_cash_discount/model/account_voucher.py 2014-05-26 08:47:02 +0000 |
852 | @@ -0,0 +1,75 @@ |
853 | +# -*- coding: utf-8 -*- |
854 | +############################################################################## |
855 | +# |
856 | +# OpenERP, Open Source Management Solution |
857 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
858 | +# Copyright (C) 2012-2012 Camptocamp Austria (<http://www.camptocamp.at>) |
859 | +# Copyright (C) 2014 Therp BV (<http://www.therp.nl>) |
860 | +# |
861 | +# This program is free software: you can redistribute it and/or modify |
862 | +# it under the terms of the GNU Affero General Public License as |
863 | +# published by the Free Software Foundation, either version 3 of the |
864 | +# License, or (at your option) any later version. |
865 | +# |
866 | +# This program is distributed in the hope that it will be useful, |
867 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
868 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
869 | +# GNU Affero General Public License for more details. |
870 | +# |
871 | +# You should have received a copy of the GNU Affero General Public License |
872 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
873 | +# |
874 | +############################################################################## |
875 | + |
876 | +from openerp.osv import fields, orm |
877 | + |
878 | + |
879 | +class AccountVoucher(orm.Model): |
880 | + _inherit = 'account.voucher' |
881 | + |
882 | + def voucher_move_line_create( |
883 | + self, cr, uid, voucher_id, line_total, move_id, company_currency, |
884 | + current_currency, context=None): |
885 | + total, ids_list = super(AccountVoucher, self).voucher_move_line_create( |
886 | + cr, uid, voucher_id, line_total, move_id, company_currency, |
887 | + current_currency) |
888 | + '''add correction entries to payment if the payment amount matches a |
889 | + cash discount amount and is in time for that''' |
890 | + |
891 | + account_move_line = self.pool.get('account.move.line') |
892 | + |
893 | + precision = self.pool.get('decimal.precision').precision_get( |
894 | + cr, uid, 'Account') |
895 | + voucher = self.browse(cr, uid, voucher_id, context=context) |
896 | + move = self.pool.get('account.move').browse( |
897 | + cr, uid, move_id, context=context) |
898 | + |
899 | + for ids in ids_list: |
900 | + move_lines = account_move_line.browse(cr, uid, ids, |
901 | + context=context) |
902 | + for move_line in move_lines: |
903 | + #only act on move liness with invoices whose payment term is a |
904 | + #cash discount |
905 | + if move_line.invoice and move_line.invoice.payment_term and\ |
906 | + move_line.invoice.payment_term.cash_discount_ids: |
907 | + |
908 | + #find a cash discount that matches current payment |
909 | + discount = move_line.invoice.get_matching_cash_discount( |
910 | + voucher.amount, payment_date=voucher.date) |
911 | + if not discount: |
912 | + continue |
913 | + |
914 | + discount_move_line_ids = move_line.invoice\ |
915 | + .create_cash_discount_move_lines( |
916 | + payment_move_lines=move.line_id, |
917 | + discount=discount, date=move.date) |
918 | + |
919 | + #put correction entries into list with matching |
920 | + #original ones to have them reconciled at once |
921 | + for discount_move_line in account_move_line.browse( |
922 | + cr, uid, discount_move_line_ids, context=context): |
923 | + if discount_move_line.account_id == \ |
924 | + move_line.account_id: |
925 | + ids.append(discount_move_line.id) |
926 | + |
927 | + return total, ids_list |
928 | |
929 | === added directory 'account_cash_discount/security' |
930 | === added file 'account_cash_discount/security/ir.model.access.csv' |
931 | --- account_cash_discount/security/ir.model.access.csv 1970-01-01 00:00:00 +0000 |
932 | +++ account_cash_discount/security/ir.model.access.csv 2014-05-26 08:47:02 +0000 |
933 | @@ -0,0 +1,3 @@ |
934 | +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" |
935 | +crud_cash_discount_line,"CRUD cash discount",model_account_payment_term_cash_discount,account.group_account_manager,1,1,1,1 |
936 | +r_cash_discount_line,"R cash discount",model_account_payment_term_cash_discount,account.group_account_user,1,0,0,0 |
937 | |
938 | === added directory 'account_cash_discount/view' |
939 | === added file 'account_cash_discount/view/account_invoice.xml' |
940 | --- account_cash_discount/view/account_invoice.xml 1970-01-01 00:00:00 +0000 |
941 | +++ account_cash_discount/view/account_invoice.xml 2014-05-26 08:47:02 +0000 |
942 | @@ -0,0 +1,24 @@ |
943 | +<?xml version="1.0" encoding="UTF-8"?> |
944 | +<openerp> |
945 | + <data> |
946 | + <record id="invoice_form" model="ir.ui.view"> |
947 | + <field name="model">account.invoice</field> |
948 | + <field name="inherit_id" ref="account.invoice_form" /> |
949 | + <field name="arch" type="xml"> |
950 | + <data> |
951 | + <field name="move_id" position="after"> |
952 | + <field name="cash_discount_move_id" |
953 | + groups="account.group_account_user" |
954 | + readonly="1" |
955 | + attrs="{'invisible': [('cash_discount_move_id', '=', False)]}"/> |
956 | + </field> |
957 | + <field name="residual" position="after"> |
958 | + <div attrs="{'invisible': [('cash_discount_move_id', '=', False)]}" colspan="2"> |
959 | + Note: This invoice was paid with a cash discount as detailed in the cash discount correction move on the 'Other info' tab |
960 | + </div> |
961 | + </field> |
962 | + </data> |
963 | + </field> |
964 | + </record> |
965 | + </data> |
966 | +</openerp> |
967 | |
968 | === added file 'account_cash_discount/view/account_move_line_reconcile.xml' |
969 | --- account_cash_discount/view/account_move_line_reconcile.xml 1970-01-01 00:00:00 +0000 |
970 | +++ account_cash_discount/view/account_move_line_reconcile.xml 2014-05-26 08:47:02 +0000 |
971 | @@ -0,0 +1,26 @@ |
972 | +<?xml version="1.0" encoding="UTF-8"?> |
973 | +<openerp> |
974 | + <data> |
975 | + <record id="view_account_move_line_reconcile_full" model="ir.ui.view"> |
976 | + <field name="model">account.move.line.reconcile</field> |
977 | + <field name="inherit_id" ref="account.view_account_move_line_reconcile_full" /> |
978 | + <field name="arch" type="xml"> |
979 | + <data> |
980 | + <footer position="before"> |
981 | + <group attrs="{'invisible': [('invoice_has_cash_discount', '=', False)]}"> |
982 | + <field name="invoice_id" readonly="1" /> |
983 | + <field name="invoice_has_cash_discount" invisible="1" /> |
984 | + </group> |
985 | + </footer> |
986 | + <button string="Reconcile" position="after"> |
987 | + <button string="Book difference as cash discount" |
988 | + type="object" |
989 | + name="reconcile_with_cash_discount" |
990 | + attrs="{'invisible': [('invoice_has_cash_discount', '=', False)]}" |
991 | + /> |
992 | + </button> |
993 | + </data> |
994 | + </field> |
995 | + </record> |
996 | + </data> |
997 | +</openerp> |
998 | |
999 | === added file 'account_cash_discount/view/account_payment_term.xml' |
1000 | --- account_cash_discount/view/account_payment_term.xml 1970-01-01 00:00:00 +0000 |
1001 | +++ account_cash_discount/view/account_payment_term.xml 2014-05-26 08:47:02 +0000 |
1002 | @@ -0,0 +1,49 @@ |
1003 | +<?xml version="1.0" encoding="utf-8"?> |
1004 | +<openerp> |
1005 | + <data> |
1006 | + |
1007 | + <record id="view_payment_term_disc_tree" model="ir.ui.view"> |
1008 | + <field name="name">account.payment.term.disc.tree</field> |
1009 | + <field name="model">account.payment.term</field> |
1010 | + <field name="type">tree</field> |
1011 | + <field name="arch" type="xml"> |
1012 | + <tree string="Payment Term"> |
1013 | + <field name="name"/> |
1014 | + <field name="active"/> |
1015 | + </tree> |
1016 | + </field> |
1017 | + </record> |
1018 | + |
1019 | + |
1020 | + <record id="view_payment_term_disc_form" model="ir.ui.view"> |
1021 | + <field name="name">account.payment.term.disc.form</field> |
1022 | + <field name="model">account.payment.term</field> |
1023 | + <field name="inherit_id" ref="account.view_payment_term_form"/> |
1024 | + <field name="type">form</field> |
1025 | + <field name="arch" type="xml"> |
1026 | + <field name="line_ids" position="after"> |
1027 | + <div class="oe_horizontal_separator oe_clear"><label for="cash_discount_ids" /></div> |
1028 | + <field name="cash_discount_ids"> |
1029 | + <tree> |
1030 | + <field name="days" /> |
1031 | + <field name="discount" /> |
1032 | + <field name="allowed_deviation" /> |
1033 | + </tree> |
1034 | + <form> |
1035 | + <group> |
1036 | + <field name="days" /> |
1037 | + <field name="discount" /> |
1038 | + <field name="allowed_deviation" /> |
1039 | + </group> |
1040 | + <group> |
1041 | + <field name="discount_expense_account_id" /> |
1042 | + <field name="discount_income_account_id" /> |
1043 | + </group> |
1044 | + </form> |
1045 | + </field> |
1046 | + </field> |
1047 | + </field> |
1048 | + </record> |
1049 | + </data> |
1050 | +</openerp> |
1051 | + |
1052 | |
1053 | === added directory 'account_cash_discount/wizard' |
1054 | === added file 'account_cash_discount/wizard/__init__.py' |
1055 | --- account_cash_discount/wizard/__init__.py 1970-01-01 00:00:00 +0000 |
1056 | +++ account_cash_discount/wizard/__init__.py 2014-05-26 08:47:02 +0000 |
1057 | @@ -0,0 +1,22 @@ |
1058 | +# -*- coding: utf-8 -*- |
1059 | +############################################################################## |
1060 | +# |
1061 | +# OpenERP, Open Source Management Solution |
1062 | +# This module copyright (C) 2014 Therp BV (<http://therp.nl>). |
1063 | +# |
1064 | +# This program is free software: you can redistribute it and/or modify |
1065 | +# it under the terms of the GNU Affero General Public License as |
1066 | +# published by the Free Software Foundation, either version 3 of the |
1067 | +# License, or (at your option) any later version. |
1068 | +# |
1069 | +# This program is distributed in the hope that it will be useful, |
1070 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1071 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1072 | +# GNU Affero General Public License for more details. |
1073 | +# |
1074 | +# You should have received a copy of the GNU Affero General Public License |
1075 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1076 | +# |
1077 | +############################################################################## |
1078 | +import account_move_line_reconcile |
1079 | +import account_move_line_reconcile |
1080 | |
1081 | === added file 'account_cash_discount/wizard/account_move_line_reconcile.py' |
1082 | --- account_cash_discount/wizard/account_move_line_reconcile.py 1970-01-01 00:00:00 +0000 |
1083 | +++ account_cash_discount/wizard/account_move_line_reconcile.py 2014-05-26 08:47:02 +0000 |
1084 | @@ -0,0 +1,76 @@ |
1085 | +# -*- coding: utf-8 -*- |
1086 | +############################################################################## |
1087 | +# |
1088 | +# OpenERP, Open Source Management Solution |
1089 | +# This module copyright (C) 2014 Therp BV (<http://therp.nl>). |
1090 | +# |
1091 | +# This program is free software: you can redistribute it and/or modify |
1092 | +# it under the terms of the GNU Affero General Public License as |
1093 | +# published by the Free Software Foundation, either version 3 of the |
1094 | +# License, or (at your option) any later version. |
1095 | +# |
1096 | +# This program is distributed in the hope that it will be useful, |
1097 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1098 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1099 | +# GNU Affero General Public License for more details. |
1100 | +# |
1101 | +# You should have received a copy of the GNU Affero General Public License |
1102 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1103 | +# |
1104 | +############################################################################## |
1105 | +from openerp.osv.orm import Model |
1106 | +from openerp.osv import fields |
1107 | + |
1108 | +class AccountMoveLineReconcile(Model): |
1109 | + _inherit = 'account.move.line.reconcile' |
1110 | + |
1111 | + _columns = { |
1112 | + 'invoice_id': fields.many2one('account.invoice', 'Invoice'), |
1113 | + 'invoice_has_cash_discount': fields.boolean('Cash discount on invoice') |
1114 | + } |
1115 | + |
1116 | + def default_get(self, cr, uid, fields, context=None): |
1117 | + result = super(AccountMoveLineReconcile, self).default_get( |
1118 | + cr, uid, fields, context=context) |
1119 | + for move_line in self.pool.get('account.move.line').browse( |
1120 | + cr, uid, context.get('active_ids', []), context=context): |
1121 | + if move_line.invoice: |
1122 | + if move_line.invoice.id != result.get('invoice_id'): |
1123 | + result['invoice_id'] = move_line.invoice.id |
1124 | + result['invoice_has_cash_discount'] = bool( |
1125 | + move_line.invoice.get_matching_cash_discount( |
1126 | + result.get('credit')) or |
1127 | + move_line.invoice.get_matching_cash_discount( |
1128 | + result.get('debit'))) |
1129 | + else: |
1130 | + result['invoice_id'] = False |
1131 | + result['invoice_has_cash_discount'] = False |
1132 | + return result |
1133 | + |
1134 | + def reconcile_with_cash_discount(self, cr, uid, ids, context=None): |
1135 | + account_move_line = self.pool.get('account.move.line') |
1136 | + for this in self.browse(cr, uid, ids, context=context): |
1137 | + discount = this.invoice_id.get_matching_cash_discount(this.credit)\ |
1138 | + or this.invoice_id.get_matching_cash_discount(this.debit) |
1139 | + if not discount: |
1140 | + continue |
1141 | + payment_move_lines = [ |
1142 | + l for ml in account_move_line.browse( |
1143 | + cr, uid, context.get('active_ids', []), |
1144 | + context=context) |
1145 | + for l in ml.move_id.line_id |
1146 | + if not l.invoice] |
1147 | + correction_move_line_ids = this.invoice_id\ |
1148 | + .create_cash_discount_move_lines(discount, |
1149 | + payment_move_lines) |
1150 | + reconcile_ids = context.get('active_ids', []) |
1151 | + for correction_move_line in account_move_line.browse( |
1152 | + cr, uid, correction_move_line_ids, context=context): |
1153 | + for payment_move_line in payment_move_lines: |
1154 | + if payment_move_line.account_id ==\ |
1155 | + correction_move_line.account_id: |
1156 | + reconcile_ids.append(correction_move_line.id) |
1157 | + break |
1158 | + return self.trans_rec_reconcile_full( |
1159 | + cr, uid, [this.id], dict(context, active_ids=reconcile_ids)) |
1160 | + pass |
Hi Holger, good work. Question. Is there any integration between this cash discount and payment orders? When i make a payment order on time then discount can be extracted. When im passed my discount days it can't. Curious if this exists or is in planning. Thanks.