Merge lp:~npg-team/openobject-addons/account_voucher_credits_us_npg into lp:openobject-addons
- account_voucher_credits_us_npg
- Merge into trunk
Status: | Rejected |
---|---|
Rejected by: | Fabien (Open ERP) |
Proposed branch: | lp:~npg-team/openobject-addons/account_voucher_credits_us_npg |
Merge into: | lp:openobject-addons |
Diff against target: |
4025 lines (+3893/-0) 25 files modified
account_voucher_credits_us/Change Log.txt (+70/-0) account_voucher_credits_us/__init__.py (+27/-0) account_voucher_credits_us/__openerp__.py (+47/-0) account_voucher_credits_us/account_voucher_credits_us/Change Log.txt (+40/-0) account_voucher_credits_us/account_voucher_credits_us/__init__.py (+18/-0) account_voucher_credits_us/account_voucher_credits_us/__openerp__.py (+32/-0) account_voucher_credits_us/account_voucher_credits_us/test/account_voucher.yml (+97/-0) account_voucher_credits_us/account_voucher_credits_us/test/account_voucher_report.yml (+25/-0) account_voucher_credits_us/account_voucher_credits_us/test/sales_payment.yml (+89/-0) account_voucher_credits_us/account_voucher_credits_us/test/sales_receipt.yml (+74/-0) account_voucher_credits_us/account_voucher_credits_us/voucher.py (+1275/-0) account_voucher_credits_us/account_voucher_credits_us/voucher_payment_receipt_view.xml (+213/-0) account_voucher_credits_us/account_voucher_credits_us/wizard/__init__.py (+25/-0) account_voucher_credits_us/account_voucher_credits_us/wizard/account_post_voucher.py (+73/-0) account_voucher_credits_us/account_voucher_credits_us/wizard/account_post_voucher.xml (+40/-0) account_voucher_credits_us/security/ir.model.access.csv (+2/-0) account_voucher_credits_us/test/account_voucher.yml (+97/-0) account_voucher_credits_us/test/account_voucher_report.yml (+25/-0) account_voucher_credits_us/test/sales_payment.yml (+89/-0) account_voucher_credits_us/test/sales_receipt.yml (+74/-0) account_voucher_credits_us/voucher.py (+1100/-0) account_voucher_credits_us/voucher_payment_receipt_view.xml (+220/-0) account_voucher_credits_us/wizard/__init__.py (+26/-0) account_voucher_credits_us/wizard/account_post_voucher.py (+75/-0) account_voucher_credits_us/wizard/account_post_voucher.xml (+40/-0) |
To merge this branch: | bzr merge lp:~npg-team/openobject-addons/account_voucher_credits_us_npg |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Olivier Dony (Odoo) | policy + quick technical scan | Disapprove | |
Review via email: mp+78431@code.launchpad.net |
Commit message
Description of the change
NovaPoint Group has developed this module to provide an improved ability to manage credit memos and apply them against invoices. Allows users to split credit memos and provides significantly more flexibility than the base OpenERP. Accountants have the control and option to use credit memos as they/or their customers direct. Credit memos can be allocated against a single outstanding invoice, partial allocation, against multiple invoices, etc. With this development users have complete control.
Fabien (Open ERP) (fp-tinyerp) wrote : | # |
Olivier Dony (Odoo) (odo-openerp) wrote : | # |
Hello,
I would like to explain a little bit more why this merge proposal was rejected, in 2 parts: our policy for merge proposals, then some specific hints.
1. Merge Proposal Acceptance Policy
=======
There may have been contradicting messages about how and when it is useful to make a merge proposal.
We would like to state this policy very clearly, especially now that extra-addons have been deprecated due to the introduction of OpenERP Apps. So we have now added an official Merge Proposal Acceptance Policy to our contributor documentation, please have a look: http://
2. Remarks specific to this merge proposal
=======
In approximate order of importance:
- if this module is specific to the US (which it seems to be) and would be a dependency of l10n_us, it should be named l10n_us_xxx, shouldn't it?
- it looks like this module is a general purpose extra feature that could be a great extra feature on OpenERP Apps as explained in the policy, but does not need to be included in official addons now
- the size of the merge proposal diff is very large (+3900 lines) compared to its scope:
+ DUPLICATED COPY OF THE MODULE in account_
+ lots of copy/pasted code from original addons, are they all really necessary? You duplicated almost the whole account_voucher module! It was certainly possible to avoid that, this is *very* bad practice
- invalid/deprecated XML attributes in views: group.color, field.view_mode, etc.
- oversized methods, e.g. your account_
- you included YAML tests that seem to test and demo the module (good!), but you copy/pasted some existing tests without changing the record IDs.. this is brittle and not likely to work for very long, if it ever does.
- "hook" methods are discouraged in OpenERP, and should be replaced by smaller, overridable API methods as much as possible (e.g. your "_update_discount" hook method)
- use of deprecated API: as of v6.0 it is possible to make multiple XPATH alteration to an inherited form within a single view, you don't need to make multiple views for that
- non-i18n compatible text in warning (missing _() call): e.g. account_
- unclear description of the module in the module manifest
- remaining typos in labels/text, e.g. "Avilable Credits"
- multiple leftover "print" debugging statements
- remaining commented out code and TODOs, should be cleaned up
I hope this helps,
Thanks!
Unmerged revisions
- 5304. By Novapoint Group
-
[Add]: account_
voucher_ credits_ us to manage credit memos against invoices
Preview Diff
1 | === added directory 'account_voucher_credits_us' |
2 | === added file 'account_voucher_credits_us/Change Log.txt' |
3 | --- account_voucher_credits_us/Change Log.txt 1970-01-01 00:00:00 +0000 |
4 | +++ account_voucher_credits_us/Change Log.txt 2011-10-06 15:24:58 +0000 |
5 | @@ -0,0 +1,70 @@ |
6 | +=============================================================================== |
7 | + Version Change Log (account_voucher_credits_us) |
8 | +=============================================================================== |
9 | +1.17 (2011-09-29) -> Arif |
10 | + * Hide Post button in Credit Card Pay Invoice |
11 | + |
12 | +1.16 (2011-09-16) -> Arif |
13 | + * Added dicount check box on customer pay invoice |
14 | + * Removed the onchange on amount in Pay Invoice |
15 | + |
16 | +1.15 (2011-09-15) -> Sinoj & Arif |
17 | + * Fixed the bug on calculation of discount on Pay Invoice |
18 | + |
19 | +1.13 -> 1.14 (2011-05-24) By Jabir |
20 | + * Fixed credits are not using on customer payment if no amount is entered Paid Amount |
21 | + |
22 | +1.12 -> 1.13 (2011-04-18) By Jabir |
23 | + * Created configuration on company to set default payment term for supplier |
24 | + |
25 | +1.11 -> 1.12 (2011-02-07) By Jabir |
26 | + * Supplier discount support |
27 | +1.10 -> 1.11 (2011-02-07) By Jabir |
28 | + * Fixed the wrong account posting for journal with type bank and cash |
29 | + |
30 | +1.09 -> 1.10 (2011-02-07) By Jabir |
31 | + * Removed default focus from Calculate button |
32 | + |
33 | +1.08 -> 1.09 (2011-02-07) By Jabir |
34 | + * Add write function on account.move.line to make ids list if it is not |
35 | + |
36 | +1.07 -> 1.08 (2011-02-04) By Sinoj |
37 | + * Optimization and cleanup |
38 | + |
39 | +1.06 -> 1.07 (2010-12-06) By jabir |
40 | + * Remove payment_meth_id from account_voucher_credits_us and add code to check whether this variable exist before using it |
41 | + |
42 | +1.05 -> 1.06 (2010-12-06) By jabir |
43 | + * Change the domain of writeoff_account and remove extra whitespace and comments in voucher.py |
44 | + |
45 | +1.04 -> 1.05 (2010-12-06) By jabir |
46 | + * Take invoice partner instead of voucher partner |
47 | + |
48 | +1.03 -> 1.04 (2010-11-24) By jabir |
49 | + * Fixed unable to open new customer payment form issue occur due to trunk update |
50 | + * Fixed onchange_pay function error occuring when writeoff or discount module uninstalled |
51 | + |
52 | +1.02 -> 1.03 (2010-11-24) By jabir |
53 | + * Select credit and debit lines of child partner along with its when a customer is selected |
54 | + * Automatically fill payment amount when Pay is checked in voucher lines |
55 | + |
56 | +1.01 -> 1.02 (2010-11-12) By jabir |
57 | + * Add all the feature in module account_voucher_jdc in this module |
58 | + =============================================================================== |
59 | + Version Change Log (account_voucher_jdc) |
60 | + =============================================================================== |
61 | + 1.01 -> 1.02 (2010-11-09) By sinoj |
62 | + * in "account.voucher.line", label string "Discount and Credit" changed to "Discount and Credits" |
63 | + |
64 | + 1.0 -> 1.01 (2010-11-03) By sinoj |
65 | + * in "account.voucher.line", label string for amount_original changed from "Original Amount" to "Original Amt." |
66 | + * in "account.voucher.line", label string for amount_unreconciled changed from "Open Balance" to "Amount Due" |
67 | + * in "account.voucher.line", label string for amount changed from "Amount" to "Payment Amt" |
68 | + * in "account.voucher.line", label string for date_original changed from "Date" to "Invoice Date" |
69 | + * in "account.voucher.line", label string for account_id changed from "Account" to "G/L Account" |
70 | + * in "account.voucher.line", New boolean field Pay |
71 | + |
72 | +=============================================================================== |
73 | + Version Change Log (account_voucher_credits_jdc) |
74 | +=============================================================================== |
75 | + account_voucher_jdc 1.0 -> account_voucher_credits_jdc 0.01 (2010-11-03) By sinoj |
76 | |
77 | === added file 'account_voucher_credits_us/__init__.py' |
78 | --- account_voucher_credits_us/__init__.py 1970-01-01 00:00:00 +0000 |
79 | +++ account_voucher_credits_us/__init__.py 2011-10-06 15:24:58 +0000 |
80 | @@ -0,0 +1,27 @@ |
81 | +# -*- coding: utf-8 -*- |
82 | +############################################################################## |
83 | +# |
84 | +# OpenERP, Open Source Management Solution |
85 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
86 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
87 | +# |
88 | +# This program is free software: you can redistribute it and/or modify |
89 | +# it under the terms of the GNU General Public License as published by |
90 | +# the Free Software Foundation, either version 3 of the License, or |
91 | +# (at your option) any later version. |
92 | +# |
93 | +# This program is distributed in the hope that it will be useful, |
94 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
95 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
96 | +# GNU General Public License for more details. |
97 | +# |
98 | +# You should have received a copy of the GNU General Public License |
99 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
100 | +# |
101 | +############################################################################## |
102 | + |
103 | +import voucher |
104 | +import wizard |
105 | + |
106 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
107 | + |
108 | |
109 | === added file 'account_voucher_credits_us/__openerp__.py' |
110 | --- account_voucher_credits_us/__openerp__.py 1970-01-01 00:00:00 +0000 |
111 | +++ account_voucher_credits_us/__openerp__.py 2011-10-06 15:24:58 +0000 |
112 | @@ -0,0 +1,47 @@ |
113 | +# -*- coding: utf-8 -*- |
114 | +############################################################################## |
115 | +# |
116 | +# OpenERP, Open Source Management Solution |
117 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
118 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
119 | +# |
120 | +# This program is free software: you can redistribute it and/or modify |
121 | +# it under the terms of the GNU General Public License as published by |
122 | +# the Free Software Foundation, either version 3 of the License, or |
123 | +# (at your option) any later version. |
124 | +# |
125 | +# This program is distributed in the hope that it will be useful, |
126 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
127 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
128 | +# GNU General Public License for more details. |
129 | +# |
130 | +# You should have received a copy of the GNU General Public License |
131 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
132 | +# |
133 | +############################################################################## |
134 | + |
135 | +{ |
136 | + "name" : "Voucher modifications for US", |
137 | + "version" : "1.17", |
138 | + "author" : 'NovaPoint Group LLC', |
139 | + "description": """ |
140 | +This module will add new functionality to better manage credits and how and when they apply to Sales Payments. |
141 | +The result of this development will enable users to designate which credit(s) will apply to each individual invoice, and how much of an individual credit amount to apply. |
142 | + """, |
143 | + "category" : "US Localisation/Account", |
144 | + "website" : "http://www.novapointgroup.com/", |
145 | + "depends" : ["account", "account_voucher",], |
146 | + "init_xml" : [], |
147 | + |
148 | + "demo_xml" : [], |
149 | + |
150 | + "update_xml" : [ |
151 | + "voucher_payment_receipt_view.xml", |
152 | + "wizard/account_post_voucher.xml", |
153 | + "security/ir.model.access.csv"], |
154 | + "test" : [], |
155 | + "active": False, |
156 | + "installable": True, |
157 | + } |
158 | + |
159 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
160 | |
161 | === added directory 'account_voucher_credits_us/account_voucher_credits_us' |
162 | === added file 'account_voucher_credits_us/account_voucher_credits_us/Change Log.txt' |
163 | --- account_voucher_credits_us/account_voucher_credits_us/Change Log.txt 1970-01-01 00:00:00 +0000 |
164 | +++ account_voucher_credits_us/account_voucher_credits_us/Change Log.txt 2011-10-06 15:24:58 +0000 |
165 | @@ -0,0 +1,40 @@ |
166 | + |
167 | +=============================================================================== |
168 | + Version Change Log (account_voucher_credits_us) |
169 | +=============================================================================== |
170 | +1.06 -> 1.07 (2010-12-06) By jabir |
171 | + * Remove payment_meth_id from account_voucher_credits_us and add code to check whether this variable exist before using it |
172 | +1.05 -> 1.06 (2010-12-06) By jabir |
173 | + * Change the domain of writeoff_account and remove extra whitespace and comments in voucher.py |
174 | +1.04 -> 1.05 (2010-12-06) By jabir |
175 | + * Take invoice partner instead of voucher partner |
176 | +1.03 -> 1.04 (2010-11-24) By jabir |
177 | + * Fixed unable to open new customer payment form issue occur due to trunk update |
178 | + * Fixed onchange_pay function error occuring when writeoff or discount module uninstalled |
179 | + |
180 | +1.02 -> 1.03 (2010-11-24) By jabir |
181 | + * Select credit and debit lines of child partner along with its when a customer is selected |
182 | + * Automatically fill payment amount when Pay is checked in voucher lines |
183 | + |
184 | +1.01 -> 1.02 (2010-11-12) By jabir |
185 | + * Add all the feature in module account_voucher_jdc in this module |
186 | + =============================================================================== |
187 | + Version Change Log (account_voucher_jdc) |
188 | + =============================================================================== |
189 | + 1.01 -> 1.02 (2010-11-09) By sinoj |
190 | + * in "account.voucher.line", label string "Discount and Credit" changed to "Discount and Credits" |
191 | + |
192 | + 1.0 -> 1.01 (2010-11-03) By sinoj |
193 | + * in "account.voucher.line", label string for amount_original changed from "Original Amount" to "Original Amt." |
194 | + * in "account.voucher.line", label string for amount_unreconciled changed from "Open Balance" to "Amount Due" |
195 | + * in "account.voucher.line", label string for amount changed from "Amount" to "Payment Amt" |
196 | + * in "account.voucher.line", label string for date_original changed from "Date" to "Invoice Date" |
197 | + * in "account.voucher.line", label string for account_id changed from "Account" to "G/L Account" |
198 | + * in "account.voucher.line", New boolean field Pay |
199 | + |
200 | +=============================================================================== |
201 | + Version Change Log (account_voucher_credits_jdc) |
202 | +=============================================================================== |
203 | + account_voucher_jdc 1.0 -> account_voucher_credits_jdc 0.01 (2010-11-03) By sinoj |
204 | + |
205 | + |
206 | |
207 | === added file 'account_voucher_credits_us/account_voucher_credits_us/__init__.py' |
208 | --- account_voucher_credits_us/account_voucher_credits_us/__init__.py 1970-01-01 00:00:00 +0000 |
209 | +++ account_voucher_credits_us/account_voucher_credits_us/__init__.py 2011-10-06 15:24:58 +0000 |
210 | @@ -0,0 +1,18 @@ |
211 | +# -*- encoding: utf-8 -*- |
212 | +############################################################################## |
213 | +# |
214 | +# Copyright (c) 2010 ZestyBeanz Technologies Pvt. Ltd. |
215 | +# (http://wwww.zbeanztech.com) All Rights Reserved. |
216 | +# sinoj@zbeanztech.com |
217 | +# |
218 | +############################################################################## |
219 | + |
220 | +''' |
221 | + TODO : Add access rules for all objects in the module |
222 | + |
223 | +''' |
224 | +import voucher |
225 | +import wizard |
226 | + |
227 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
228 | + |
229 | |
230 | === added file 'account_voucher_credits_us/account_voucher_credits_us/__openerp__.py' |
231 | --- account_voucher_credits_us/account_voucher_credits_us/__openerp__.py 1970-01-01 00:00:00 +0000 |
232 | +++ account_voucher_credits_us/account_voucher_credits_us/__openerp__.py 2011-10-06 15:24:58 +0000 |
233 | @@ -0,0 +1,32 @@ |
234 | +# -*- encoding: utf-8 -*- |
235 | +############################################################################## |
236 | +# |
237 | +# Copyright (c) 2010 ZestyBeanz Technologies Pvt. Ltd. |
238 | +# (http://wwww.zbeanztech.com) All Rights Reserved. |
239 | +# sinoj@zbeanztech.com |
240 | +# |
241 | +############################################################################## |
242 | +{ |
243 | + "name" : "Voucher modifications for US", |
244 | + "version" : "0.07", |
245 | + "author" : 'Voucher and NovaPoint Group LLC', |
246 | + "description": """ |
247 | +This module will add new functionality to better manage credits and how and when they apply to Sales Payments. |
248 | +The result of this development will enable users to designate which credit(s) will apply to each individual invoice, and how much of an individual credit amount to apply. |
249 | + """, |
250 | + "category" : "Generic Modules/Accounting", |
251 | + "website" : "http://www.novapointgroup.com/", |
252 | + "depends" : ["account", "account_voucher",], |
253 | + "init_xml" : [], |
254 | + |
255 | + "demo_xml" : [], |
256 | + |
257 | + "update_xml" : [ |
258 | + "voucher_payment_receipt_view.xml", |
259 | + "wizard/account_post_voucher.xml",], |
260 | + "test" : [], |
261 | + "active": False, |
262 | + "installable": True, |
263 | + } |
264 | + |
265 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
266 | |
267 | === added directory 'account_voucher_credits_us/account_voucher_credits_us/test' |
268 | === added file 'account_voucher_credits_us/account_voucher_credits_us/test/account_voucher.yml' |
269 | --- account_voucher_credits_us/account_voucher_credits_us/test/account_voucher.yml 1970-01-01 00:00:00 +0000 |
270 | +++ account_voucher_credits_us/account_voucher_credits_us/test/account_voucher.yml 2011-10-06 15:24:58 +0000 |
271 | @@ -0,0 +1,97 @@ |
272 | + |
273 | +- |
274 | + In order to check account voucher module in OpenERP I create a customer voucher |
275 | +- |
276 | + !record {model: account.voucher, id: account_voucher_voucherforaxelor0}: |
277 | + account_id: account.cash |
278 | + company_id: base.main_company |
279 | + currency_id: base.EUR |
280 | + journal_id: account.bank_journal |
281 | + name: Voucher for Axelor |
282 | + narration: Basic Pc |
283 | + line_ids: |
284 | + - account_id: account.a_recv |
285 | + amount: 1000.0 |
286 | + name: Voucher for Axelor |
287 | + partner_id: base.res_partner_desertic_hispafuentes |
288 | + period_id: account.period_6 |
289 | + reference_type: none |
290 | + |
291 | +- |
292 | + I check that Initially customer voucher is in the "Draft" state |
293 | +- |
294 | + !assert {model: account.voucher, id: account_voucher_voucherforaxelor0}: |
295 | + - state == 'draft' |
296 | +- |
297 | + I compute the voucher to calculate the taxes by clicking Cpmpute button |
298 | +- |
299 | + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_voucherforaxelor0} |
300 | +- |
301 | + I check that the voucher state is now "proforma" |
302 | +- |
303 | + !assert {model: account.voucher, id: account_voucher_voucherforaxelor0}: |
304 | + - state == 'proforma' |
305 | +- |
306 | + I create voucher by clicking on Create button |
307 | +- |
308 | + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_voucherforaxelor0} |
309 | +- |
310 | + I clicked on Validate Button |
311 | +- |
312 | + !assert {model: account.voucher, id: account_voucher_voucherforaxelor0}: |
313 | + - state == 'posted' |
314 | + |
315 | +- |
316 | + I check that Moves get created for this voucher |
317 | +- |
318 | + !python {model: account.voucher}: | |
319 | + acc_id=self.browse(cr, uid, ref("account_voucher_voucherforaxelor0")) |
320 | + assert(acc_id.move_id) |
321 | + |
322 | + |
323 | +- |
324 | + Now I create a Vendor Voucher |
325 | +- |
326 | + !record {model: account.voucher, id: account_voucher_voucheraxelor0}: |
327 | + account_id: account.cash |
328 | + company_id: base.main_company |
329 | + currency_id: base.EUR |
330 | + journal_id: account.bank_journal |
331 | + name: Voucher Axelor |
332 | + narration: Basic PC |
333 | + line_ids: |
334 | + - account_id: account.cash |
335 | + amount: 1000.0 |
336 | + name: Voucher Axelor |
337 | + period_id: account.period_6 |
338 | + reference_type: none |
339 | + |
340 | +- |
341 | + I check that Initially vendor voucher is in the "Draft" state |
342 | +- |
343 | + !assert {model: account.voucher, id: account_voucher_voucheraxelor0}: |
344 | + - state == 'draft' |
345 | +- |
346 | + I change the state of voucher to "proforma" by clicking PRO-FORMA button |
347 | +- |
348 | + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_voucheraxelor0} |
349 | +- |
350 | + I check that the voucher state is now "proforma" |
351 | +- |
352 | + !assert {model: account.voucher, id: account_voucher_voucheraxelor0}: |
353 | + - state == 'proforma' |
354 | +- |
355 | + I create voucher by clicking on Create button |
356 | +- |
357 | + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_voucheraxelor0} |
358 | +- |
359 | + I check that the voucher state is "posted" |
360 | +- |
361 | + !assert {model: account.voucher, id: account_voucher_voucheraxelor0}: |
362 | + - state == 'posted' |
363 | +- |
364 | + I check that moves get created for this voucher |
365 | +- |
366 | + !python {model: account.voucher}: | |
367 | + acc_id=self.browse(cr, uid, ref("account_voucher_voucheraxelor0")) |
368 | + assert(acc_id.move_id) |
369 | |
370 | === added file 'account_voucher_credits_us/account_voucher_credits_us/test/account_voucher_report.yml' |
371 | --- account_voucher_credits_us/account_voucher_credits_us/test/account_voucher_report.yml 1970-01-01 00:00:00 +0000 |
372 | +++ account_voucher_credits_us/account_voucher_credits_us/test/account_voucher_report.yml 2011-10-06 15:24:58 +0000 |
373 | @@ -0,0 +1,25 @@ |
374 | +- |
375 | + Demo for Account Voucher |
376 | +- |
377 | + !record {model: account.voucher, id: account_voucher_voucheraxelor0}: |
378 | + account_id: account.cash |
379 | + company_id: base.main_company |
380 | + currency_id: base.EUR |
381 | + journal_id: account.bank_journal |
382 | + name: Voucher Axelor |
383 | + narration: Basic PC |
384 | + amount: 1000.0 |
385 | + line_ids: |
386 | + - account_id: account.cash |
387 | + amount: 1000.0 |
388 | + name: Voucher Axelor |
389 | + period_id: account.period_6 |
390 | + |
391 | +- |
392 | + In order to test the PDF reports defined on a account_voucher, we will print account voucher Report |
393 | +- |
394 | + !python {model: account.voucher}: | |
395 | + import netsvc, tools, os |
396 | + (data, format) = netsvc.LocalService('report.voucher.cash_receipt.drcr').create(cr, uid, [ref("account_voucher_voucheraxelor0")], {}, {}) |
397 | + if tools.config['test_report_directory']: |
398 | + file(os.path.join(tools.config['test_report_directory'], 'account_voucher-report.'+format), 'wb+').write(data) |
399 | |
400 | === added file 'account_voucher_credits_us/account_voucher_credits_us/test/sales_payment.yml' |
401 | --- account_voucher_credits_us/account_voucher_credits_us/test/sales_payment.yml 1970-01-01 00:00:00 +0000 |
402 | +++ account_voucher_credits_us/account_voucher_credits_us/test/sales_payment.yml 2011-10-06 15:24:58 +0000 |
403 | @@ -0,0 +1,89 @@ |
404 | +- |
405 | + In order to test account voucher i will create an invoice and pay it through account voucher. |
406 | +- |
407 | + I create a new Partner |
408 | +- |
409 | + !record {model: res.partner, id: res_partner_micropc0}: |
410 | + address: |
411 | + - country_id: base.be |
412 | + name: Jenifer |
413 | + street: 69 rue de Chimay |
414 | + type: default |
415 | + zip: '5478' |
416 | + category_id: |
417 | + - base.res_partner_category_8 |
418 | + credit_limit: 0.0 |
419 | + name: Micro PC |
420 | + property_account_payable: account.a_pay |
421 | + property_account_receivable: account.a_recv |
422 | + |
423 | +- |
424 | + Create an invoice for the partner |
425 | +- |
426 | + !record {model: account.invoice, id: account_invoice_0}: |
427 | + account_id: account.a_recv |
428 | + address_contact_id: base.res_partner_address_7 |
429 | + address_invoice_id: base.res_partner_address_7 |
430 | + company_id: base.main_company |
431 | + currency_id: base.EUR |
432 | + invoice_line: |
433 | + - account_id: account.a_sale |
434 | + name: '[PC1] Basic PC' |
435 | + price_unit: 450.0 |
436 | + quantity: 1.0 |
437 | + product_id: product.product_product_pc1 |
438 | + uos_id: product.product_uom_unit |
439 | + journal_id: account.sales_journal |
440 | + partner_id: res_partner_micropc0 |
441 | + |
442 | +- |
443 | + I check that the customer invoice is in draft state |
444 | +- |
445 | + !assert {model: account.invoice, id: account_invoice_0}: |
446 | + - state == 'draft' |
447 | + |
448 | +- |
449 | + I make the invoice in Open state |
450 | +- |
451 | + !workflow {model: account.invoice, action: invoice_open, ref: account_invoice_0} |
452 | + |
453 | +- |
454 | + I check that a payment entry gets created in the account.move.line |
455 | +- |
456 | + !python {model: account.invoice}: | |
457 | + acc_id=self.browse(cr, uid, ref("account_invoice_0")) |
458 | + assert(acc_id.move_id) |
459 | + |
460 | +- |
461 | + I will create and post an account voucher for the partner. |
462 | +- |
463 | + !python {model: account.voucher}: | |
464 | + import netsvc |
465 | + vals = {} |
466 | + journal_id = self.default_get(cr, uid, ['journal_id']).get('journal_id',None) |
467 | + res = self.onchange_partner_id(cr, uid, [], ref("res_partner_micropc0"), journal_id, price=0.0, ttype='receipt') |
468 | + vals = { |
469 | + 'account_id': ref('account.cash'), |
470 | + 'amount': 450.0, |
471 | + 'company_id': ref('base.main_company'), |
472 | + 'currency_id': ref('base.EUR'), |
473 | + 'journal_id': ref('account.bank_journal'), |
474 | + 'partner_id': ref('res_partner_micropc0'), |
475 | + 'period_id': ref('account.period_8'), |
476 | + 'type': 'receipt', |
477 | + } |
478 | + if not res['value']['line_cr_ids']: |
479 | + res['value']['line_cr_ids'] = [{'type': 'cr', 'account_id': ref('account.a_recv'),}] |
480 | + res['value']['line_cr_ids'][0]['amount'] = 450.0 |
481 | + vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']] |
482 | + id = self.create(cr, uid, vals) |
483 | + voucher_id = self.browse(cr, uid, id) |
484 | + assert (voucher_id.state=='draft'), "Voucher is not in draft state" |
485 | + wf_service = netsvc.LocalService("workflow") |
486 | + wf_service.trg_validate(uid, 'account.voucher', voucher_id.id, 'proforma_voucher', cr) |
487 | + |
488 | +- |
489 | + Finally i will Confirm the state of the invoice is paid |
490 | +- |
491 | + !assert {model: account.invoice, id: account_invoice_0}: |
492 | + - state == 'paid' |
493 | |
494 | === added file 'account_voucher_credits_us/account_voucher_credits_us/test/sales_receipt.yml' |
495 | --- account_voucher_credits_us/account_voucher_credits_us/test/sales_receipt.yml 1970-01-01 00:00:00 +0000 |
496 | +++ account_voucher_credits_us/account_voucher_credits_us/test/sales_receipt.yml 2011-10-06 15:24:58 +0000 |
497 | @@ -0,0 +1,74 @@ |
498 | + |
499 | +- |
500 | + In order to test sales receipt i will create a sale receipt and pay it through sales payment |
501 | +- |
502 | + First of all I create a voucher |
503 | +- |
504 | + !record {model: account.voucher, id: account_voucher_chinaexport_0}: |
505 | + account_id: account.a_recv |
506 | + amount: 30000.0 |
507 | + company_id: base.main_company |
508 | + journal_id: account.sales_journal |
509 | + line_cr_ids: |
510 | + - account_id: account.a_sale |
511 | + amount: 30000.0 |
512 | + partner_id: base.res_partner_3 |
513 | + period_id: account.period_8 |
514 | + tax_amount: 0.0 |
515 | + type: sale |
516 | + |
517 | +- |
518 | + I check that the voucher state is Draft |
519 | +- |
520 | + !assert {model: account.voucher, id: account_voucher_chinaexport_0}: |
521 | + - state == 'draft' |
522 | + |
523 | +- |
524 | + I clicked on post button to post the voucher |
525 | +- |
526 | + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_chinaexport_0} |
527 | + |
528 | +- |
529 | + Check the voucher state is Posted |
530 | +- |
531 | + !assert {model: account.voucher, id: account_voucher_chinaexport_0}: |
532 | + - state == 'posted' |
533 | + |
534 | +- |
535 | + I create a voucher record for the same partner |
536 | +- |
537 | + !record {model: account.voucher, id: account_voucher_chinaexport_1}: |
538 | + account_id: account.cash |
539 | + amount: 30000.0 |
540 | + company_id: base.main_company |
541 | + currency_id: base.EUR |
542 | + journal_id: account.bank_journal |
543 | + line_cr_ids: |
544 | + - account_id: account.a_recv |
545 | + amount: 0.0 |
546 | + name: 2010/003 |
547 | + type: cr |
548 | + - account_id: account.a_recv |
549 | + amount: 30000.0 |
550 | + name: 2010/003 |
551 | + type: cr |
552 | + partner_id: base.res_partner_3 |
553 | + period_id: account.period_8 |
554 | + type: receipt |
555 | + |
556 | +- |
557 | + Check the voucher state is draft |
558 | +- |
559 | + !assert {model: account.voucher, id: account_voucher_chinaexport_1}: |
560 | + - state == 'draft' |
561 | + |
562 | +- |
563 | + I clicked on Post button to post the voucher |
564 | +- |
565 | + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_chinaexport_1} |
566 | + |
567 | +- |
568 | + Check the voucher state is Posted |
569 | +- |
570 | + !assert {model: account.voucher, id: account_voucher_chinaexport_1}: |
571 | + - state == 'posted' |
572 | |
573 | === added file 'account_voucher_credits_us/account_voucher_credits_us/voucher.py' |
574 | --- account_voucher_credits_us/account_voucher_credits_us/voucher.py 1970-01-01 00:00:00 +0000 |
575 | +++ account_voucher_credits_us/account_voucher_credits_us/voucher.py 2011-10-06 15:24:58 +0000 |
576 | @@ -0,0 +1,1275 @@ |
577 | +# -*- coding: utf-8 -*- |
578 | +############################################################################## |
579 | +# |
580 | +# OpenERP, Open Source Management Solution |
581 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
582 | +# |
583 | +# This program is free software: you can redistribute it and/or modify |
584 | +# it under the terms of the GNU Affero General Public License as |
585 | +# published by the Free Software Foundation, either version 3 of the |
586 | +# License, or (at your option) any later version. |
587 | +# |
588 | +# This program is distributed in the hope that it will be useful, |
589 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
590 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
591 | +# GNU Affero General Public License for more details. |
592 | +# |
593 | +# You should have received a copy of the GNU Affero General Public License |
594 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
595 | +# |
596 | +############################################################################## |
597 | + |
598 | +import time |
599 | +import netsvc |
600 | +from osv import fields |
601 | +from osv import osv |
602 | +from tools.translate import _ |
603 | +def _combinations(iterable, r): |
604 | + ''' |
605 | + @return: combination generator object |
606 | + |
607 | + Example |
608 | + combinations(’ABCD’, 2) --> AB AC AD BC BD CD |
609 | + combinations(range(4), 3) --> 012 013 023 123 |
610 | + ''' |
611 | + pool = tuple(iterable) |
612 | + n = len(pool) |
613 | + if r > n: |
614 | + return |
615 | + indices = range(r) |
616 | + yield tuple(pool[i] for i in indices) |
617 | + while True: |
618 | + for i in reversed(range(r)): |
619 | + if indices[i] != i + n - r: |
620 | + break |
621 | + else: |
622 | + return |
623 | + indices[i] += 1 |
624 | + for j in range(i+1, r): |
625 | + indices[j] = indices[j-1] + 1 |
626 | + yield tuple(pool[i] for i in indices) |
627 | + |
628 | + |
629 | +class res_company(osv.osv): |
630 | + _name = 'res.company' |
631 | + _inherit = 'res.company' |
632 | + |
633 | + _columns = { |
634 | + 'writeoff_account': fields.many2one('account.account', 'Writeoff Account', domain=[('type','!=','view'),('type','!=','consolidation')], |
635 | + help="This is the designated write-off gl account that will be used when writing off remaining amounts in customer payment."), |
636 | + } |
637 | +res_company() |
638 | + |
639 | + |
640 | +class account_cash_discount(osv.osv): |
641 | + _name = "account.cash.discount" |
642 | + _description = "Cash Discount" #A reduction in the price if payment is made within a stipulated period. |
643 | + _columns = { |
644 | + 'name': fields.char('Name', size=32), |
645 | + 'delay': fields.integer('Number of Days', required=True), |
646 | + 'discount': fields.float('Discount (%)', digits=(16,6),required=True), |
647 | + 'payment_id': fields.many2one('account.payment.term','Associated Payment Term'), |
648 | + 'credit_account_id': fields.many2one('account.account', 'Credit Account'), |
649 | + 'debit_account_id': fields.many2one('account.account', 'Debit Account'), |
650 | + } |
651 | +account_cash_discount() |
652 | + |
653 | + |
654 | + |
655 | +class account_move_line(osv.osv): |
656 | + _inherit = 'account.move.line' |
657 | + def _unreconciled(self, cr, uid, ids, prop, unknow_none, context): |
658 | + ''' |
659 | + Function to calculate the value of variable Unreconciled Amount |
660 | + ''' |
661 | + res={} |
662 | + for line in self.browse(cr, uid, ids, context=context): |
663 | + res[line.id] = line.debit - line.credit |
664 | + if line.reconcile_partial_id: |
665 | + res[line.id] = 0 |
666 | + for partial in line.reconcile_partial_id.line_partial_ids: |
667 | + res[line.id] += partial.debit - partial.credit |
668 | + res[line.id] = abs(res[line.id]) |
669 | + return res |
670 | + |
671 | + _columns = { |
672 | + 'amount_unreconciled': fields.function(_unreconciled, method=True, string='Unreconciled Amount'), |
673 | + } |
674 | +account_move_line() |
675 | + |
676 | +class account_voucher_line(osv.osv): |
677 | + _inherit = 'account.voucher.line' |
678 | + |
679 | + |
680 | + def _update_credit_lines(self,cr, uid, ids, context): |
681 | + credits_used_pool = self.pool.get('account.voucher.line.credits_to_use') |
682 | + for line in self.browse(cr , uid, ids, context): |
683 | + credits_lines_used = [x.orginal_credit_line_id.id for x in line.available_credits] |
684 | + for credit_line in line.voucher_id.line_dr_ids : |
685 | + if credit_line.id not in credits_lines_used and line.invoice_id and line.invoice_id.payment_term: |
686 | + print credit_line |
687 | + credits_used_pool.create(cr, uid, { |
688 | + 'voucher_line_id': line.id, |
689 | + 'orginal_credit_line_id':credit_line.id, |
690 | + 'use_credit': False, |
691 | + 'inv_credit': credit_line.move_line_id.id, |
692 | + 'discount_window_date': credit_line.date_original, |
693 | + 'orginal_amount': credit_line.amount_original, |
694 | + 'available_amount': credit_line.amount_unreconciled - credit_line.pending_credits, |
695 | + 'discount_amount': 0.0, |
696 | + 'gl_account' : credit_line.account_id.id,}) |
697 | + else : |
698 | + 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) |
699 | + credits_used_pool.write(cr, uid,to_update_credit_line_ids,{'available_amount': credit_line.amount_unreconciled-credit_line.pending_credits}, context=context) |
700 | + |
701 | +account_voucher_line() |
702 | + |
703 | +class account_voucher(osv.osv): |
704 | + def _get_type(self, cr, uid, ids, context={}): |
705 | + ''' |
706 | + Initialise the variable Default Type |
707 | + ''' |
708 | + return context.get('type', False) |
709 | + |
710 | + def _get_period(self, cr, uid, context={}): |
711 | + ''' |
712 | + Initialise the variable Period |
713 | + ''' |
714 | + |
715 | + if context.get('period_id', False): |
716 | + return context.get('period_id') |
717 | + periods = self.pool.get('account.period').find(cr, uid) |
718 | + return periods and periods[0] or False |
719 | + |
720 | + def _get_journal(self, cr, uid, context={}): |
721 | + ''' |
722 | + Initialise the variable Journal |
723 | + ''' |
724 | + journal_pool = self.pool.get('account.journal') |
725 | + if context.get('journal_id', False): |
726 | + return context.get('journal_id') |
727 | + if not context.get('journal_id', False) and context.get('search_default_journal_id', False): |
728 | + return context.get('search_default_journal_id') |
729 | + |
730 | + ttype = context.get('type', 'bank') |
731 | + res = journal_pool.search(cr, uid, [('type', '=', ttype)], limit=1) |
732 | + return res and res[0] or False |
733 | + |
734 | + def _get_tax(self, cr, uid, context={}): |
735 | + ''' |
736 | + Initialise the variable Tax |
737 | + ''' |
738 | + journal_pool = self.pool.get('account.journal') |
739 | + journal_id = context.get('journal_id', False) |
740 | + if not journal_id: |
741 | + ttype = context.get('type', 'bank') |
742 | + res = journal_pool.search(cr, uid, [('type', '=', ttype)], limit=1) |
743 | + if not res: |
744 | + return False |
745 | + journal_id = res[0] |
746 | + |
747 | + if not journal_id: |
748 | + return False |
749 | + journal = journal_pool.browse(cr, uid, journal_id) |
750 | + account_id = journal.default_credit_account_id or journal.default_debit_account_id |
751 | + if account_id and account_id.tax_ids: |
752 | + tax_id = account_id.tax_ids[0].id |
753 | + return tax_id |
754 | + return False |
755 | + |
756 | + def _get_currency(self, cr, uid, context): |
757 | + ''' |
758 | + Initialise the variable Currency |
759 | + ''' |
760 | + journal_pool = self.pool.get('account.journal') |
761 | + journal_id = context.get('journal_id', False) |
762 | + if journal_id: |
763 | + journal = journal_pool.browse(cr, uid, journal_id) |
764 | + currency_id = journal.company_id.currency_id.id |
765 | + if journal.currency: |
766 | + currency_id = journal.currency.id |
767 | + return False |
768 | + |
769 | + def _get_partner(self, cr, uid, context={}): |
770 | + ''' |
771 | + Initialise the variable Partner |
772 | + ''' |
773 | + return context.get('partner_id', False) |
774 | + |
775 | + def _get_reference(self, cr, uid, context={}): |
776 | + ''' |
777 | + Initialise the variable Ref # |
778 | + ''' |
779 | + return context.get('reference', False) |
780 | + |
781 | + def _get_narration(self, cr, uid, context={}): |
782 | + ''' |
783 | + Initialise the field Notes |
784 | + ''' |
785 | + return context.get('narration', False) |
786 | + |
787 | + |
788 | + def _find_exact_match(self, cr, uid, lines, amount, mark_pay=False, use_discount=False, context=False): |
789 | + ''' |
790 | + accept voucher lines as list of dict and amount to match |
791 | + return : update lines if it found an exact match |
792 | + ''' |
793 | + total_amount = 0.0 |
794 | + discount_available = {} |
795 | + total_discount_available = 0.0 |
796 | + for line in lines: |
797 | + if mark_pay or line.pay == True: |
798 | + if use_discount: |
799 | + discount_available[line.id] = 0.0 |
800 | + for discount_line in line.available_discounts: |
801 | + discount_available[line.id] += discount_line.proposed_discount |
802 | + total_discount_available += discount_line.proposed_discount |
803 | + total_amount += line.amount_unreconciled - line.credit_used - (line._columns.has_key('writeoff_amount') and line.writeoff_amount) |
804 | + else: |
805 | + total_amount += line.amount_unreconciled - line.credit_used - line.discount_used- (line._columns.has_key('writeoff_amount') and line.writeoff_amount) |
806 | + if abs(amount - total_amount) < 0.01 : |
807 | + ''' |
808 | + Unchecking all the lines other than matched line |
809 | + ''' |
810 | + line_ids = self.read(cr,uid,lines[0].voucher_id.id,['line_ids'])['line_ids'] |
811 | + self.pool.get('account.voucher.line').write(cr,uid,line_ids,{'pay':False}) |
812 | + for line in lines: |
813 | + if mark_pay or line.pay == True: |
814 | + line.write({'amount':line.amount_unreconciled - line.credit_used - line.discount_used - (line._columns.has_key('writeoff_amount') and line.writeoff_amount), 'pay':True }) |
815 | + else: |
816 | + line.write({'amount':0.0, 'pay':False }) |
817 | + return True |
818 | + if use_discount and total_amount>amount and (total_amount - amount ) <=total_discount_available: #It is possible to match using Discount |
819 | + ''' |
820 | + Unchecking all the lines other than matched line and uncheck all discount lines |
821 | + ''' |
822 | + line_ids = self.read(cr,uid,lines[0].voucher_id.id,['line_ids'])['line_ids'] |
823 | + self.pool.get('account.voucher.line').write(cr,uid,line_ids,{'pay':False}) |
824 | + for line_id in line_ids: |
825 | + discount_ids = self.pool.get('account.voucher.line').read(cr,uid,line_id,['available_discounts'])['available_discounts'] |
826 | + self.pool.get("account.voucher.line.discount_to_use").write(cr,uid,discount_ids,{'use_discount':False, 'discount_amount':0.0}) |
827 | + discount_to_use = total_amount - amount |
828 | + for line in lines: |
829 | + if discount_to_use > 0.0: |
830 | + for discount_line in line.available_discounts: |
831 | + discount_line.write({'use_discount':True,'discount_amount':min(discount_to_use, discount_line.proposed_discount)}) |
832 | + discount_to_use = discount_to_use - min(discount_to_use, discount_line.proposed_discount) |
833 | + line = self.pool.get('account.voucher.line').browse(cr, uid, line.id,context=context) |
834 | + line.write({'amount':line.amount_unreconciled - line.credit_used - line.discount_used - (line._columns.has_key('writeoff_amount') and line.writeoff_amount), 'pay':True }) |
835 | + return True |
836 | + if len(lines) > 1: |
837 | + for combination in _combinations(lines,len(lines)-1 ): |
838 | + if self._find_exact_match(cr, uid, combination, amount, mark_pay, context=False): |
839 | + return True |
840 | + return False |
841 | + def calc_diff(self, cr, uid, ids, context={}): |
842 | + res = {'nodestroy':True} |
843 | + amount_cash_discount = 0.0 |
844 | + amount_interest = 0.0 |
845 | + for vch in self.browse(cr, uid, ids): |
846 | + for line in vch.line_cr_ids: |
847 | + line._update_credit_lines( context=context) |
848 | + if vch.auto_match: |
849 | + ret = self._find_exact_match(cr, uid, vch.line_cr_ids, vch.amount, mark_pay=False, use_discount=False, context=False) |
850 | + if not ret: |
851 | + ret = self._find_exact_match(cr, uid, vch.line_cr_ids, vch.amount, mark_pay=True, use_discount=False, context=False) |
852 | + if not ret: |
853 | + ret = self._find_exact_match(cr, uid, vch.line_cr_ids, vch.amount, mark_pay=True, use_discount=True, context=False) |
854 | + return res |
855 | + |
856 | + _name = 'account.voucher' |
857 | + _inherit = 'account.voucher' |
858 | + _description = 'Accounting Voucher' |
859 | + _order = "date desc, id desc" |
860 | + _rec_name = 'number' |
861 | + _columns = { |
862 | + 'type':fields.selection([ |
863 | + ('sale','Sale'), |
864 | + ('purchase','Purchase'), |
865 | + ('payment','Payment'), |
866 | + ('receipt','Receipt'), |
867 | + ],'Default Type', readonly=True, states={'draft':[('readonly',False)]}), |
868 | + 'name':fields.char('Memo', size=256, readonly=True, states={'draft':[('readonly',False)]}), |
869 | + 'date':fields.date('Date', readonly=True, states={'draft':[('readonly',False)]}, help="Effective date for accounting entries"), |
870 | + 'journal_id':fields.many2one('account.journal', 'Journal', required=True, readonly=True, states={'draft':[('readonly',False)]}), |
871 | + 'account_id':fields.many2one('account.account', 'Account', required=True, readonly=True, states={'draft':[('readonly',False)]}), |
872 | + 'line_ids':fields.one2many('account.voucher.line','voucher_id','Voucher Lines', readonly=True, states={'draft':[('readonly',False)]}), |
873 | + 'line_cr_ids':fields.one2many('account.voucher.line','voucher_id','Credits', |
874 | + domain=[('type','=','cr')], context={'default_type':'cr'}, readonly=True, states={'draft':[('readonly',False)]}), |
875 | + 'line_dr_ids':fields.one2many('account.voucher.line','voucher_id','Debits', |
876 | + domain=[('type','=','dr')], context={'default_type':'dr'}, readonly=True, states={'draft':[('readonly',False)]}), |
877 | + 'period_id': fields.many2one('account.period', 'Period', required=True, readonly=True, states={'draft':[('readonly',False)]}), |
878 | + 'narration':fields.text('Notes', readonly=True, states={'draft':[('readonly',False)]}), |
879 | + 'currency_id':fields.many2one('res.currency', 'Currency', readonly=True, states={'draft':[('readonly',False)]}), |
880 | +# 'currency_id': fields.related('journal_id','currency', type='many2one', relation='res.currency', string='Currency', store=True, readonly=True, states={'draft':[('readonly',False)]}), |
881 | + 'company_id': fields.many2one('res.company', 'Company', required=True, readonly=True, states={'draft':[('readonly',False)]}), |
882 | + 'state':fields.selection( |
883 | + [('draft','Draft'), |
884 | + ('proforma','Pro-forma'), |
885 | + ('posted','Posted'), |
886 | + ('cancel','Cancelled') |
887 | + ], 'State', readonly=True, size=32, |
888 | + help=' * The \'Draft\' state is used when a user is encoding a new and unconfirmed Voucher. \ |
889 | + \n* The \'Pro-forma\' when voucher is in Pro-forma state,voucher does not have an voucher number. \ |
890 | + \n* The \'Posted\' state is used when user create voucher,a voucher number is generated and voucher entries are created in account \ |
891 | + \n* The \'Cancelled\' state is used when user cancel voucher.'), |
892 | + 'amount': fields.float('Total', digits=(16, 2), required=True, readonly=True, states={'draft':[('readonly',False)]}), |
893 | + 'tax_amount':fields.float('Tax Amount', digits=(14,2), readonly=True, states={'draft':[('readonly',False)]}), |
894 | + 'reference': fields.char('Ref #', size=64, readonly=True, states={'draft':[('readonly',False)]}, help="Transaction reference number."), |
895 | + 'number': fields.related('move_id', 'name', type="char", readonly=True, string='Number'), |
896 | + 'move_id':fields.many2one('account.move', 'Account Entry'), |
897 | + 'move_ids': fields.related('move_id','line_id', type='one2many', relation='account.move.line', string='Journal Items', readonly=True), |
898 | + 'partner_id':fields.many2one('res.partner', 'Partner', change_default=1, readonly=True, states={'draft':[('readonly',False)]}), |
899 | + 'audit': fields.related('move_id','to_check', type='boolean', relation='account.move', string='Audit Complete ?'), |
900 | + 'pay_now':fields.selection([ |
901 | + ('pay_now','Pay Directly'), |
902 | + ('pay_later','Pay Later or Group Funds'), |
903 | + ],'Payment', select=True, readonly=True, states={'draft':[('readonly',False)]}), |
904 | + 'tax_id':fields.many2one('account.tax', 'Tax', readonly=True, states={'draft':[('readonly',False)]}), |
905 | + 'pre_line':fields.boolean('Previous Payments ?', required=False), |
906 | + 'date_due': fields.date('Due Date', readonly=True, states={'draft':[('readonly',False)]}), |
907 | + 'auto_match':fields.boolean('Use Automatic Matching') |
908 | + } |
909 | + _defaults = { |
910 | + 'period_id': _get_period, |
911 | + 'partner_id': _get_partner, |
912 | + 'journal_id':_get_journal, |
913 | + 'currency_id': _get_currency, |
914 | + 'reference': _get_reference, |
915 | + 'narration':_get_narration, |
916 | + 'type':_get_type, |
917 | + 'state': lambda *a: 'draft', |
918 | + 'pay_now':lambda *a: 'pay_later', |
919 | + 'name': lambda *a: '', |
920 | + 'date' : lambda *a: time.strftime('%Y-%m-%d'), |
921 | + 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.voucher',context=c), |
922 | + 'tax_id': _get_tax, |
923 | + } |
924 | + |
925 | + |
926 | + def compute_tax(self, cr, uid, ids, context={}): |
927 | + tax_pool = self.pool.get('account.tax') |
928 | + partner_pool = self.pool.get('res.partner') |
929 | + position_pool = self.pool.get('account.fiscal.position') |
930 | + voucher_line_pool = self.pool.get('account.voucher.line') |
931 | + voucher_pool = self.pool.get('account.voucher') |
932 | + |
933 | + for voucher in voucher_pool.browse(cr, uid, ids, context): |
934 | + voucher_amount = 0.0 |
935 | + for line in voucher.line_ids: |
936 | + voucher_amount += line.untax_amount or line.amount |
937 | + line.amount = line.untax_amount or line.amount |
938 | + voucher_line_pool.write(cr, uid, [line.id], {'amount':line.amount, 'untax_amount':line.untax_amount}) |
939 | + |
940 | + if not voucher.tax_id: |
941 | + self.write(cr, uid, [voucher.id], {'amount':voucher_amount, 'tax_amount':0.0}) |
942 | + continue |
943 | + |
944 | + tax = [tax_pool.browse(cr, uid, voucher.tax_id.id)] |
945 | + partner = partner_pool.browse(cr, uid, voucher.partner_id.id) or False |
946 | + taxes = position_pool.map_tax(cr, uid, partner and partner.property_account_position or False, tax) |
947 | + tax = tax_pool.browse(cr, uid, taxes) |
948 | + |
949 | + total = voucher_amount |
950 | + total_tax = 0.0 |
951 | + |
952 | + if not tax[0].price_include: |
953 | + for tax_line in tax_pool.compute_all(cr, uid, tax, voucher_amount, 1).get('taxes',[]): |
954 | + total_tax += tax_line.get('amount') |
955 | + total += total_tax |
956 | + else: |
957 | + line_ids2 = [] |
958 | + for line in voucher.line_ids: |
959 | + line_total = 0.0 |
960 | + line_tax = 0.0 |
961 | + |
962 | + for tax_line in tax_pool.compute_all(cr, uid, tax, line.untax_amount or line.amount, 1).get('taxes',[]): |
963 | + line_tax += tax_line.get('amount') |
964 | + line_total += tax_line.get('price_unit') |
965 | + total_tax += line_tax |
966 | + untax_amount = line.untax_amount or line.amount |
967 | + voucher_line_pool.write(cr, uid, [line.id], {'amount':line_total, 'untax_amount':untax_amount}) |
968 | + |
969 | + self.write(cr, uid, [voucher.id], {'amount':total, 'tax_amount':total_tax}) |
970 | + return True |
971 | + |
972 | + def onchange_price(self, cr, uid, ids, line_ids, tax_id, partner_id=False, context={}): |
973 | + tax_pool = self.pool.get('account.tax') |
974 | + partner_pool = self.pool.get('res.partner') |
975 | + position_pool = self.pool.get('account.fiscal.position') |
976 | + voucher_line_pool = self.pool.get('account.voucher.line') |
977 | + res = { |
978 | + 'tax_amount':False, |
979 | + 'amount':False, |
980 | + } |
981 | + voucher_total_tax = 0.0 |
982 | + voucher_total = 0.0 |
983 | + voucher_line_ids = [] |
984 | + |
985 | + total = 0.0 |
986 | + total_tax = 0.0 |
987 | + |
988 | + for line in line_ids: |
989 | + line_amount = 0.0 |
990 | + line_amount = line[2].get('amount') |
991 | + voucher_line_ids += [line[1]] |
992 | + voucher_total += line_amount |
993 | + |
994 | + total = voucher_total |
995 | + total_tax = 0.0 |
996 | + if tax_id: |
997 | + tax = [tax_pool.browse(cr, uid, tax_id)] |
998 | + if partner_id: |
999 | + partner = partner_pool.browse(cr, uid, partner_id) or False |
1000 | + taxes = position_pool.map_tax(cr, uid, partner and partner.property_account_position or False, tax) |
1001 | + tax = tax_pool.browse(cr, uid, taxes) |
1002 | + |
1003 | + if not tax[0].price_include: |
1004 | + for tax_line in tax_pool.compute_all(cr, uid, tax, voucher_total, 1).get('taxes',[]): |
1005 | + total_tax += tax_line.get('amount') |
1006 | + total += total_tax |
1007 | + |
1008 | + res.update({ |
1009 | + 'amount':total or voucher_total, |
1010 | + 'tax_amount':total_tax |
1011 | + }) |
1012 | + return { |
1013 | + 'value':res |
1014 | + } |
1015 | + |
1016 | + def onchange_term_id(self, cr, uid, ids, term_id, amount): |
1017 | + term_pool = self.pool.get('account.payment.term') |
1018 | + terms = False |
1019 | + due_date = False |
1020 | + default = {'date_due':False} |
1021 | + if term_id and amount: |
1022 | + terms = term_pool.compute(cr, uid, term_id, amount) |
1023 | + if terms: |
1024 | + due_date = terms[-1][0] |
1025 | + default.update({ |
1026 | + 'date_due':due_date |
1027 | + }) |
1028 | + return {'value':default} |
1029 | + |
1030 | + def onchange_journal_voucher(self, cr, uid, ids, line_ids=False, tax_id=False, price=0.0, partner_id=False, journal_id=False, ttype=False, context={}): |
1031 | + """price |
1032 | + Returns a dict that contains new values and context |
1033 | + |
1034 | + @param partner_id: latest value from user input for field partner_id |
1035 | + @param args: other arguments |
1036 | + @param context: context arguments, like lang, time zone |
1037 | + |
1038 | + @return: Returns a dict which contains new values, and context |
1039 | + """ |
1040 | + default = { |
1041 | + 'value':{}, |
1042 | + } |
1043 | + |
1044 | + if not partner_id or not journal_id: |
1045 | + return default |
1046 | + |
1047 | + partner_pool = self.pool.get('res.partner') |
1048 | + journal_pool = self.pool.get('account.journal') |
1049 | + |
1050 | + journal = journal_pool.browse(cr, uid, journal_id) |
1051 | + partner = partner_pool.browse(cr, uid, partner_id) |
1052 | + account_id = False |
1053 | + tr_type = False |
1054 | + if journal.type in ('sale','sale_refund'): |
1055 | + account_id = partner.property_account_receivable.id |
1056 | + tr_type = 'sale' |
1057 | + elif journal.type in ('purchase', 'purchase_refund','expense'): |
1058 | + account_id = partner.property_account_payable.id |
1059 | + tr_type = 'purchase' |
1060 | + else: |
1061 | + account_id = journal.default_credit_account_id.id or journal.default_debit_account_id.id |
1062 | + tr_type = 'receipt' |
1063 | + |
1064 | + default['value']['account_id'] = account_id |
1065 | + default['value']['type'] = ttype or tr_type |
1066 | + |
1067 | + vals = self.onchange_journal(cr, uid, ids, journal_id, line_ids, tax_id, partner_id, context) |
1068 | + default['value'].update(vals.get('value')) |
1069 | + |
1070 | + return default |
1071 | + |
1072 | + def onchange_partner_id(self, cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, context={}): |
1073 | + """price |
1074 | + Returns a dict that contains new values and context |
1075 | + |
1076 | + @param partner_id: latest value from user input for field partner_id |
1077 | + @param args: other arguments |
1078 | + @param context: context arguments, like lang, time zone |
1079 | + |
1080 | + @return: Returns a dict which contains new values, and context |
1081 | + """ |
1082 | + currency_pool = self.pool.get('res.currency') |
1083 | + move_pool = self.pool.get('account.move') |
1084 | + line_pool = self.pool.get('account.voucher.line') |
1085 | + move_line_pool = self.pool.get('account.move.line') |
1086 | + partner_pool = self.pool.get('res.partner') |
1087 | + journal_pool = self.pool.get('account.journal') |
1088 | + default = { |
1089 | + 'value':{'line_ids':[], 'line_dr_ids':[], 'line_cr_ids':[], 'pre_line': False, 'currency_id':currency_id, 'journal_id': False}, |
1090 | + } |
1091 | + if partner_id and not journal_id: |
1092 | + partner = partner_pool.browse(cr, uid, partner_id, context) |
1093 | + if partner._columns.has_key('payment_meth_id') and partner.payment_meth_id: |
1094 | + payment_mode_pool = self.pool.get('payment.mode') |
1095 | + payment_meth = payment_mode_pool.browse(cr, uid, partner.payment_meth_id.id, context) |
1096 | + if payment_meth: |
1097 | + default['value']['journal_id'] = payment_meth.journal.id |
1098 | + journal_id = payment_meth.journal.id |
1099 | + if not journal_id: |
1100 | + return {} |
1101 | + |
1102 | + vals = self.onchange_journal(cr, uid, ids, journal_id, [], False, partner_id, context) |
1103 | + vals = vals.get('value') |
1104 | + currency_id = vals.get('currency_id', currency_id) |
1105 | + |
1106 | + if not partner_id: |
1107 | + return default |
1108 | + |
1109 | + if not partner_id and ids: |
1110 | + line_ids = line_pool.search(cr, uid, [('voucher_id','=',ids[0])]) |
1111 | + if line_ids: |
1112 | + line_pool.unlink(cr, uid, line_ids) |
1113 | + return default |
1114 | + |
1115 | + journal = journal_pool.browse(cr, uid, journal_id) |
1116 | + partner = partner_pool.browse(cr, uid, partner_id) |
1117 | + account_id = False |
1118 | + if journal.type in ('sale','sale_refund'): |
1119 | + account_id = partner.property_account_receivable.id |
1120 | + elif journal.type in ('purchase', 'purchase_refund','expense'): |
1121 | + account_id = partner.property_account_payable.id |
1122 | + elif journal.type in ('cash', 'bank'): |
1123 | + account_id = journal.default_debit_account_id.id |
1124 | + else: |
1125 | + account_id = journal.default_credit_account_id.id or journal.default_debit_account_id.id |
1126 | + |
1127 | + if journal and not default['value']['currency_id']: |
1128 | + default['value']['currency_id'] = journal.company_id.currency_id.id |
1129 | + default['value']['account_id'] = account_id |
1130 | + if journal.type not in ('cash', 'bank'): |
1131 | + return default |
1132 | + |
1133 | + total_credit = 0.0 |
1134 | + total_debit = 0.0 |
1135 | + account_type = 'receivable' |
1136 | + if ttype == 'payment': |
1137 | + account_type = 'payable' |
1138 | + total_debit = price or 0.0 |
1139 | + else: |
1140 | + total_credit = price or 0.0 |
1141 | + account_type = 'receivable' |
1142 | + |
1143 | + if partner._columns.has_key('nat_acc_parent') and partner.nat_acc_parent: |
1144 | + partner_ids = partner_pool.search(cr,uid,[('parent_id','child_of',[partner_id])]) |
1145 | + else: |
1146 | + partner_ids = [partner_id] |
1147 | + ids = move_line_pool.search(cr, uid, [('account_id.type','=', account_type), ('reconcile_id','=', False), ('partner_id','in',partner_ids)], context=context) |
1148 | + ids.reverse() |
1149 | + moves = move_line_pool.browse(cr, uid, ids) |
1150 | + |
1151 | + company_currency = journal.company_id.currency_id.id |
1152 | + if company_currency != currency_id and ttype == 'payment': |
1153 | + total_debit = currency_pool.compute(cr, uid, currency_id, company_currency, total_debit) |
1154 | + elif company_currency != currency_id and ttype == 'receipt': |
1155 | + total_credit = currency_pool.compute(cr, uid, currency_id, company_currency, total_credit) |
1156 | + |
1157 | + for line in moves: |
1158 | + if line.credit and line.reconcile_partial_id and ttype == 'receipt': |
1159 | + continue |
1160 | + if line.debit and line.reconcile_partial_id and ttype == 'payment': |
1161 | + continue |
1162 | + total_credit += line.credit or 0.0 |
1163 | + total_debit += line.debit or 0.0 |
1164 | + |
1165 | + for line in moves: |
1166 | + if line.credit and line.reconcile_partial_id and ttype == 'receipt': |
1167 | + continue |
1168 | + if line.debit and line.reconcile_partial_id and ttype == 'payment': |
1169 | + continue |
1170 | + |
1171 | + original_amount = line.credit or line.debit or 0.0 |
1172 | + rs = { |
1173 | + 'name':line.move_id.name, |
1174 | + 'type': line.credit and 'dr' or 'cr', |
1175 | + 'move_line_id':line.id, |
1176 | + 'account_id':line.account_id.id, |
1177 | + 'amount_original':currency_pool.compute(cr, uid, company_currency, currency_id, original_amount), |
1178 | + 'date_original':line.date, |
1179 | + 'date_due':line.date_maturity, |
1180 | + 'amount_unreconciled':currency_pool.compute(cr, uid, company_currency, currency_id, line.amount_unreconciled) |
1181 | + } |
1182 | + |
1183 | + def calc_amount(line, total): |
1184 | + return min(line.amount_unreconciled, total) |
1185 | + |
1186 | + if line.credit: |
1187 | + amount = calc_amount(line, total_debit) |
1188 | + rs['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) |
1189 | + total_debit -= amount |
1190 | + else: |
1191 | + amount = calc_amount(line, total_credit) |
1192 | + rs['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount) |
1193 | + total_credit -= amount |
1194 | + |
1195 | + default['value']['line_ids'].append(rs) |
1196 | + if rs['type'] == 'cr': |
1197 | + default['value']['line_cr_ids'].append(rs) |
1198 | + else: |
1199 | + default['value']['line_dr_ids'].append(rs) |
1200 | + |
1201 | + if ttype == 'payment' and len(default['value']['line_cr_ids']) > 0: |
1202 | + default['value']['pre_line'] = 1 |
1203 | + elif ttype == 'receipt' and len(default['value']['line_dr_ids']) > 0: |
1204 | + default['value']['pre_line'] = 1 |
1205 | + for credit_line in default['value']['line_dr_ids']: |
1206 | + credit_line['amount'] = 0.0 |
1207 | + for invoice_line in default['value']['line_cr_ids']: |
1208 | + invoice_line['amount'] = 0.0 |
1209 | + invoice_line['amount_difference'] = invoice_line['amount_unreconciled'] |
1210 | + |
1211 | + return default |
1212 | + |
1213 | + def onchange_date(self, cr, user, ids, date, context={}): |
1214 | + """ |
1215 | + @param date: latest value from user input for field date |
1216 | + @param args: other arguments |
1217 | + @param context: context arguments, like lang, time zone |
1218 | + @return: Returns a dict which contains new values, and context |
1219 | + """ |
1220 | + period_pool = self.pool.get('account.period') |
1221 | + pids = period_pool.search(cr, user, [('date_start','<=',date), ('date_stop','>=',date)]) |
1222 | + if not pids: |
1223 | + return {} |
1224 | + return { |
1225 | + 'value':{ |
1226 | + 'period_id':pids[0] |
1227 | + } |
1228 | + } |
1229 | + |
1230 | + def onchange_journal(self, cr, uid, ids, journal_id, line_ids, tax_id, partner_id, context={}): |
1231 | + if not journal_id: |
1232 | + return False |
1233 | + journal_pool = self.pool.get('account.journal') |
1234 | + journal = journal_pool.browse(cr, uid, journal_id) |
1235 | + account_id = journal.default_credit_account_id or journal.default_debit_account_id |
1236 | + tax_id = False |
1237 | + if account_id and account_id.tax_ids: |
1238 | + tax_id = account_id.tax_ids[0].id |
1239 | + |
1240 | + vals = self.onchange_price(cr, uid, ids, line_ids, tax_id, partner_id, context) |
1241 | + vals['value'].update({'tax_id':tax_id}) |
1242 | + currency_id = journal.company_id.currency_id.id |
1243 | + if journal.currency: |
1244 | + currency_id = journal.currency.id |
1245 | + vals['value'].update({'currency_id':currency_id}) |
1246 | + return vals |
1247 | + |
1248 | + def action_cancel_draft(self, cr, uid, ids, context={}): |
1249 | + wf_service = netsvc.LocalService("workflow") |
1250 | + for voucher_id in ids: |
1251 | + wf_service.trg_create(uid, 'account.voucher', voucher_id, cr) |
1252 | + self.write(cr, uid, ids, {'state':'draft'}) |
1253 | + return True |
1254 | + |
1255 | + def cancel_voucher(self, cr, uid, ids, context={}): |
1256 | + reconcile_pool = self.pool.get('account.move.reconcile') |
1257 | + move_pool = self.pool.get('account.move') |
1258 | + voucher_line_pool = self.pool.get('account.voucher.line') |
1259 | + |
1260 | + for voucher in self.browse(cr, uid, ids): |
1261 | + recs = [] |
1262 | + for line in voucher.move_ids: |
1263 | + if line.reconcile_id: |
1264 | + recs += [line.reconcile_id.id] |
1265 | + if line.reconcile_partial_id: |
1266 | + recs += [line.reconcile_partial_id.id] |
1267 | + |
1268 | + reconcile_pool.unlink(cr, uid, recs) |
1269 | + |
1270 | + if voucher.move_id: |
1271 | + move_pool.button_cancel(cr, uid, [voucher.move_id.id]) |
1272 | + move_pool.unlink(cr, uid, [voucher.move_id.id]) |
1273 | + res = { |
1274 | + 'state':'cancel', |
1275 | + 'move_id':False, |
1276 | + } |
1277 | + self.write(cr, uid, ids, res) |
1278 | + return True |
1279 | + |
1280 | + def unlink(self, cr, uid, ids, context=None): |
1281 | + for t in self.read(cr, uid, ids, ['state'], context=context): |
1282 | + if t['state'] not in ('draft', 'cancel'): |
1283 | + raise osv.except_osv(_('Invalid action !'), _('Cannot delete Voucher(s) which are already opened or paid !')) |
1284 | + return super(account_voucher, self).unlink(cr, uid, ids, context=context) |
1285 | + |
1286 | + # TODO: may be we can remove this method if not used anyware |
1287 | + def onchange_payment(self, cr, uid, ids, pay_now, journal_id, partner_id, ttype='sale'): |
1288 | + res = {} |
1289 | + if not partner_id: |
1290 | + return res |
1291 | + res = {'account_id':False} |
1292 | + partner_pool = self.pool.get('res.partner') |
1293 | + journal_pool = self.pool.get('account.journal') |
1294 | + if pay_now == 'pay_later': |
1295 | + partner = partner_pool.browse(cr, uid, partner_id) |
1296 | + journal = journal_pool.browse(cr, uid, journal_id) |
1297 | + if journal.type in ('sale','sale_refund'): |
1298 | + account_id = partner.property_account_receivable.id |
1299 | + elif journal.type in ('purchase', 'purchase_refund','expense'): |
1300 | + account_id = partner.property_account_payable.id |
1301 | + elif journal.type in ('cash', 'bank'): |
1302 | + account_id = journal.default_debit_account_id.id |
1303 | + else: |
1304 | + account_id = journal.default_credit_account_id.id or journal.default_debit_account_id.id |
1305 | + res['account_id'] = account_id |
1306 | + return {'value':res} |
1307 | + |
1308 | + def calc_cash_discount(self, vch, line, amount=0): |
1309 | + # hook method for cash discount |
1310 | + return 0.0 |
1311 | + |
1312 | + def calc_interest(self, vch, line, amount=0): |
1313 | + # hook method for interest posting |
1314 | + return 0.0 |
1315 | + |
1316 | + def action_move_line_create(self, cr, uid, ids, context=None): |
1317 | + |
1318 | + def _get_payment_term_lines(term_id, amount): |
1319 | + term_pool = self.pool.get('account.payment.term') |
1320 | + if term_id and amount: |
1321 | + terms = term_pool.compute(cr, uid, term_id, amount) |
1322 | + return terms |
1323 | + return False |
1324 | + if not context: |
1325 | + context = {} |
1326 | + move_pool = self.pool.get('account.move') |
1327 | + move_line_pool = self.pool.get('account.move.line') |
1328 | + analytic_pool = self.pool.get('account.analytic.line') |
1329 | + currency_pool = self.pool.get('res.currency') |
1330 | + invoice_pool = self.pool.get('account.invoice') |
1331 | + company_pool = self.pool.get('res.company') |
1332 | + for vch in self.browse(cr, uid, ids): |
1333 | + if vch.move_id: |
1334 | + continue |
1335 | + |
1336 | + if 'force_name' in context and context['force_name']: |
1337 | + name = context['force_name'] |
1338 | + elif vch.journal_id.sequence_id: |
1339 | + name = self.pool.get('ir.sequence').get_id(cr, uid, vch.journal_id.sequence_id.id) |
1340 | + else: |
1341 | + raise osv.except_osv(_('Error !'), _('Please define a sequence on the journal !')) |
1342 | + |
1343 | + move = { |
1344 | + 'name' : name, |
1345 | + 'journal_id': vch.journal_id.id, |
1346 | + 'narration' : vch.narration, |
1347 | + 'date':vch.date, |
1348 | + 'ref':vch.reference, |
1349 | + 'period_id': vch.period_id and vch.period_id.id or False |
1350 | + } |
1351 | + move_id = move_pool.create(cr, uid, move) |
1352 | + |
1353 | + #create the first line manually |
1354 | + company_currency = vch.journal_id.company_id.currency_id.id |
1355 | + debit = 0.0 |
1356 | + credit = 0.0 |
1357 | + # TODO: is there any other alternative then the voucher type ?? |
1358 | + # -for sale, purchase we have but for the payment and receipt we do not have as based on the bank/cash journal we can not know its payment or receipt |
1359 | + if vch.type in ('purchase', 'payment'): |
1360 | + credit = currency_pool.compute(cr, uid, vch.currency_id.id, company_currency, vch.amount) |
1361 | + elif vch.type in ('sale', 'receipt'): |
1362 | + debit = currency_pool.compute(cr, uid, vch.currency_id.id, company_currency, vch.amount) |
1363 | + if debit < 0: |
1364 | + credit = -debit |
1365 | + debit = 0.0 |
1366 | + if credit < 0: |
1367 | + debit = -credit |
1368 | + credit = 0.0 |
1369 | + |
1370 | + move_line = { |
1371 | + 'name':vch.name or '/', |
1372 | + 'debit':debit, |
1373 | + 'credit':credit, |
1374 | + 'account_id':vch.account_id.id, |
1375 | + 'move_id':move_id , |
1376 | + 'journal_id':vch.journal_id.id, |
1377 | + 'period_id':vch.period_id.id, |
1378 | + 'partner_id':vch.partner_id.id, |
1379 | + 'currency_id':vch.currency_id.id, |
1380 | + 'amount_currency':vch.amount, |
1381 | + 'date':vch.date, |
1382 | + 'date_maturity':vch.date_due |
1383 | + } |
1384 | + |
1385 | + if (debit == 0.0 or credit == 0.0 or debit+credit > 0) and (debit > 0.0 or credit > 0.0): |
1386 | + master_line = move_line_pool.create(cr, uid, move_line) |
1387 | + company = company_pool.browse(cr, uid, vch.company_id.id, context) |
1388 | + rec_list_ids = [] |
1389 | + line_total = debit - credit |
1390 | + if vch.type == 'sale': |
1391 | + line_total = line_total - currency_pool.compute(cr, uid, vch.currency_id.id, company_currency, vch.tax_amount) |
1392 | + elif vch.type == 'purchase': |
1393 | + line_total = line_total + currency_pool.compute(cr, uid, vch.currency_id.id, company_currency, vch.tax_amount) |
1394 | + |
1395 | + writeoff_ids = [] |
1396 | + for line in vch.line_ids: |
1397 | + if not line.amount: |
1398 | + continue |
1399 | + amount_cash_discount = 0.0#self.calc_cash_discount(line, line.amount) |
1400 | + amount_writeoff = 0.0#calc_writeoff(line, amount_cash_discount) |
1401 | + amount_interest = 0.0#calc_interest(line, amount_cash_discount + amount_writeoff) |
1402 | + amount_currency = currency_pool.compute(cr, uid, vch.currency_id.id, company_currency, line.amount) |
1403 | + amount = amount_currency |
1404 | + |
1405 | + move_line = { |
1406 | + 'journal_id':vch.journal_id.id, |
1407 | + 'period_id':vch.period_id.id, |
1408 | + 'name':line.name and line.name or '/', |
1409 | + 'account_id':line.account_id.id, |
1410 | + 'move_id':move_id, |
1411 | + 'partner_id':vch.partner_id.id, |
1412 | + 'currency_id':vch.currency_id.id, |
1413 | + 'amount_currency':amount, |
1414 | + 'analytic_account_id':line.account_analytic_id and line.account_analytic_id.id or False, |
1415 | + 'quantity':1, |
1416 | + 'credit':0.0, |
1417 | + 'debit':0.0, |
1418 | + 'date':vch.date |
1419 | + } |
1420 | + if line.invoice_id: |
1421 | + move_line['partner_id'] = line.invoice_id.partner_id.id |
1422 | + if amount < 0: |
1423 | + amount = -amount |
1424 | + if line.type == 'dr': |
1425 | + line.type = 'cr' |
1426 | + else: |
1427 | + line.type = 'dr' |
1428 | + |
1429 | + if (line.type=='dr'): |
1430 | + line_total += amount |
1431 | + move_line['debit'] = amount |
1432 | + else: |
1433 | + line_total -= (amount+line.credit_used) |
1434 | + move_line['credit'] = (amount+line.credit_used) |
1435 | + |
1436 | + if vch.tax_id and vch.type in ('sale', 'purchase'): |
1437 | + move_line.update({ |
1438 | + 'account_tax_id':vch.tax_id.id, |
1439 | + }) |
1440 | + master_line = move_line_pool.create(cr, uid, move_line) |
1441 | + if line.move_line_id.id: |
1442 | + rec_ids = [master_line, line.move_line_id.id] |
1443 | + rec_list_ids.append(rec_ids) |
1444 | + if not self.pool.get('res.currency').is_zero(cr, uid, vch.currency_id, line_total): |
1445 | + diff = line_total |
1446 | + move_line = { |
1447 | + 'name':name, |
1448 | + 'account_id':False, |
1449 | + 'move_id':move_id , |
1450 | + 'partner_id':vch.partner_id.id, |
1451 | + 'date':vch.date, |
1452 | + 'credit':diff>0 and diff or 0.0, |
1453 | + 'debit':diff<0 and -diff or 0.0, |
1454 | + } |
1455 | + account_id = False |
1456 | + if vch.type in ('sale', 'receipt'): |
1457 | + account_id = vch.partner_id.property_account_receivable.id |
1458 | + else: |
1459 | + account_id = vch.partner_id.property_account_payable.id |
1460 | + move_line['account_id'] = account_id |
1461 | + move_line_id = move_line_pool.create(cr, uid, move_line) |
1462 | + if line.move_line_id.id: |
1463 | + rec_ids = [move_line, line.move_line_id.id] |
1464 | + rec_list_ids.append(rec_ids) |
1465 | + |
1466 | + self.write(cr, uid, [vch.id], { |
1467 | + 'move_id': move_id, |
1468 | + 'state':'posted' |
1469 | + }) |
1470 | + move_pool.post(cr, uid, [move_id], context={}) |
1471 | + for rec_ids in rec_list_ids: |
1472 | + if len(rec_ids) >= 2: |
1473 | + move_line_pool.reconcile_partial(cr, uid, rec_ids) |
1474 | + return True |
1475 | + |
1476 | + def copy(self, cr, uid, id, default={}, context=None): |
1477 | + default.update({ |
1478 | + 'state':'draft', |
1479 | + 'number':False, |
1480 | + 'move_id':False, |
1481 | + 'line_cr_ids':False, |
1482 | + 'line_dr_ids':False, |
1483 | + 'reference':False |
1484 | + }) |
1485 | + if 'date' not in default: |
1486 | + default['date'] = time.strftime('%Y-%m-%d') |
1487 | + return super(account_voucher, self).copy(cr, uid, id, default, context) |
1488 | + |
1489 | + |
1490 | +account_voucher() |
1491 | + |
1492 | +class account_voucher_line(osv.osv): |
1493 | + _name = 'account.voucher.line' |
1494 | + _inherit = 'account.voucher.line' |
1495 | + _description = 'Voucher Lines' |
1496 | + _order = "date_due" |
1497 | + |
1498 | + def write(self, cr, user, ids, vals, context=None): |
1499 | + ''' |
1500 | + Add invoice and description in payment modification line |
1501 | + ''' |
1502 | + if type(ids) == type([]): |
1503 | + move = self.browse(cr, user,ids[0]).move_line_id |
1504 | + else: |
1505 | + move = self.browse(cr, user,ids).move_line_id |
1506 | + if move: |
1507 | + vals['invoice_id'] = move.invoice and move.invoice.id |
1508 | + vals['name'] = move.invoice and move.invoice.number |
1509 | + |
1510 | + return super(account_voucher_line, self).write(cr, user, ids, vals, context) |
1511 | + |
1512 | + def create(self, cr, user, vals, context=None): |
1513 | + ''' |
1514 | + Add invoice and description in payment modification line |
1515 | + ''' |
1516 | + if vals.has_key('move_line_id') and vals['move_line_id']: |
1517 | + move = self.pool.get('account.move.line').browse(cr, user,vals['move_line_id']) |
1518 | + vals['invoice_id'] = move.invoice and move.invoice.id |
1519 | + vals['name'] = move.invoice and move.invoice.number |
1520 | + return super(account_voucher_line, self).create(cr, user, vals, context) |
1521 | + |
1522 | + def calc_amt(self, cr, uid, ids, context={}): |
1523 | + ''' |
1524 | + Function to calculate Pending Credits Used |
1525 | + ''' |
1526 | + res = {} |
1527 | + result = 0.0 |
1528 | + |
1529 | + for id in ids: |
1530 | + res[id] = result |
1531 | + return res |
1532 | + |
1533 | + def _credits_calc(self, cr, uid, ids, name, args, context): |
1534 | + credits_used_pool = self.pool.get('account.voucher.line.credits_to_use') |
1535 | + res={} |
1536 | + for line in self.browse(cr, uid, ids): |
1537 | + credits_used_ids = credits_used_pool.search(cr, uid, [('orginal_credit_line_id','=',line.id)]) |
1538 | + res[line.id] = 0.0 |
1539 | + if line.voucher_id.state != 'draft': |
1540 | + continue |
1541 | + for credit_used in credits_used_pool.browse(cr, uid, credits_used_ids, context=context): |
1542 | + if credit_used.use_credit: |
1543 | + res[line.id] += credit_used.discount_amount |
1544 | + return res |
1545 | + def _compute_credit_used(self, cr, uid, ids, name, args, context=None): |
1546 | + res = {} |
1547 | + for line in self.browse(cr, uid, ids): |
1548 | + res[line.id] = 0.0 |
1549 | + for credit_line in line.available_credits: |
1550 | + if credit_line.use_credit : |
1551 | + res[line.id] += credit_line.discount_amount |
1552 | + return res |
1553 | + |
1554 | + def _compute_balance(self, cr, uid, ids, name, args, context=None): |
1555 | + currency_pool = self.pool.get('res.currency') |
1556 | + rs_data = {} |
1557 | + for line in self.browse(cr, uid, ids): |
1558 | + res = {} |
1559 | + company_currency = line.voucher_id.journal_id.company_id.currency_id.id |
1560 | + voucher_currency = line.voucher_id.currency_id.id |
1561 | + move_line = line.move_line_id or False |
1562 | + if not move_line: |
1563 | + res['amount_original'] = 0.0 |
1564 | + res['amount_unreconciled'] = 0.0 |
1565 | + |
1566 | + elif move_line and move_line.credit > 0: |
1567 | + res['amount_original'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.credit) |
1568 | + else: |
1569 | + res['amount_original'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.debit) |
1570 | + |
1571 | + if move_line: |
1572 | + res['amount_unreconciled'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.amount_unreconciled - line.pending_credits ) |
1573 | + if line.amount > 0.0: |
1574 | + res['amount_difference'] = res['amount_unreconciled'] - line.amount - line.credit_used |
1575 | + else: |
1576 | + res['amount_difference'] = 0.0 |
1577 | + rs_data[line.id] = res |
1578 | + return rs_data |
1579 | + |
1580 | + def _get_due_date(self, cr, uid, ids, context=None): |
1581 | + result = {} |
1582 | + for line in self.pool.get('account.move.line').browse(cr, uid, ids, context=context): |
1583 | +# result[line.invoice_id.id] = True ##Changed by Jabir to fix error when clicking Post button from Customer Payment form. 2010/11/24 |
1584 | + result[line.invoice.id] = True |
1585 | + return result.keys() |
1586 | + def _compute_discount_used(self, cr, uid, ids, name, args, context=None): |
1587 | + res = {} |
1588 | + for id in ids: |
1589 | + res[id] = 0.0 |
1590 | + return res |
1591 | + def _calc_writeoff(self, cr, uid, ids, name, args, context): |
1592 | + res={} |
1593 | + for id in ids: |
1594 | + res[id] = 0.0 |
1595 | + return res |
1596 | + |
1597 | + |
1598 | + def _order_compute_credit_used(self, cr, uid, ids, context=None): |
1599 | + """ Compute which all records to update |
1600 | + @return: List of ids |
1601 | + """ |
1602 | + operation_ids = [] |
1603 | + for credits_to_use in self.pool.get('account.voucher.line.credits_to_use').browse(cr,uid,ids,context=context): |
1604 | + operation_ids.append(credits_to_use.voucher_line_id and credits_to_use.voucher_line_id.id) |
1605 | + return operation_ids |
1606 | + |
1607 | + def _get_voucher_line_ids(self, cr, uid, ids, context=None): |
1608 | + result = [] |
1609 | + for vch_lines in self.pool.get('account.voucher').read(cr, uid, ids, ['line_ids'], context=context): |
1610 | + result +=vch_lines['line_ids'] |
1611 | + return result |
1612 | + _columns = { |
1613 | + 'voucher_id':fields.many2one('account.voucher', 'Voucher', required=1, ondelete='cascade'), |
1614 | + 'invoice_id': fields.many2one('account.invoice', 'Invoice'), |
1615 | + 'name':fields.char('Description', size=256), |
1616 | + 'account_id':fields.many2one('account.account','G/L Account', required=True), |
1617 | + 'partner_id':fields.related('voucher_id', 'partner_id', type='many2one', relation='res.partner', string='Partner'), |
1618 | + 'untax_amount':fields.float('Untax Amount'), |
1619 | + 'amount':fields.float('Payment Amt', digits=(14,2), required=True), |
1620 | + 'type':fields.selection([('dr','Debit'),('cr','Credit')], 'Cr/Dr'), |
1621 | + 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account'), |
1622 | + 'move_line_id': fields.many2one('account.move.line', 'Invoice'), |
1623 | + 'date_original': fields.related('move_line_id','date', type='date', relation='account.move.line', string='Invoice Date', readonly=True), |
1624 | + 'date_due': fields.related('move_line_id','date_maturity', type='date', relation='account.move.line', string='Due Date', readonly=True , store={ |
1625 | + 'account.voucher.line': (lambda self, cr, uid, ids, c={}: ids, ['move_line_id'], 20), |
1626 | + 'account.move.line': (_get_due_date, ['date_maturity'], 20), |
1627 | + }), |
1628 | + 'amount_original': fields.function(_compute_balance, method=True, multi='dc', type='float', string='Original Amt', store=True, readonly=True), |
1629 | + 'amount_unreconciled': fields.function(_compute_balance, method=True, multi='dc', type='float', string='Amt Due', store=True, readonly=True), |
1630 | + 'company_id': fields.related('voucher_id','company_id',type='many2one', relation='res.company', string='Company', store={ |
1631 | + 'account.voucher': (_get_voucher_line_ids, ['company_id'], 20), |
1632 | + }), |
1633 | + 'credit_used': fields.function(_compute_credit_used, method=True, type='float', string='Credit Used', |
1634 | + store={'account.voucher.line.credits_to_use':(_order_compute_credit_used,['use_credit','discount_amount'], 10)}, readonly=True), |
1635 | + 'amount_difference': fields.function(_compute_balance, method=True, multi='dc', type='float', string='Unpaid Amt', digits=(16, 2) ), |
1636 | + 'writeoff': fields.boolean("Writeoff"), |
1637 | + 'pay': fields.boolean("Pay", required=True), |
1638 | + 'pending_credits':fields.function(_credits_calc, method=True, string='Pending Credits Used', type='float'), |
1639 | + 'available_credits':fields.one2many('account.voucher.line.credits_to_use', 'voucher_line_id', 'Available credits' ), |
1640 | + 'discount_used': fields.function(_compute_discount_used, method=True, type='float', string='Discount Used', store=False, readonly=True), |
1641 | + 'writeoff_amount':fields.function(_calc_writeoff, method=True, string='Write-off Amt', type='float', store=False,), |
1642 | + 'discount_used': fields.function(_compute_discount_used, method=True, type='float', string='Discount Used', store=False, readonly=True), |
1643 | + } |
1644 | + _defaults = { |
1645 | + 'name': lambda *a: '' |
1646 | + } |
1647 | + |
1648 | + def default_get(self, cr, user, fields_list, context=None): |
1649 | + """ |
1650 | + Returns default values for fields |
1651 | + @param fields_list: list of fields, for which default values are required to be read |
1652 | + @param context: context arguments, like lang, time zone |
1653 | + |
1654 | + @return: Returns a dict that contains default values for fields |
1655 | + """ |
1656 | + journal_id = context.get('journal_id', False) |
1657 | + partner_id = context.get('partner_id', False) |
1658 | + journal_pool = self.pool.get('account.journal') |
1659 | + partner_pool = self.pool.get('res.partner') |
1660 | + values = super(account_voucher_line, self).default_get(cr, user, fields_list, context=context) |
1661 | + if (not journal_id) or ('account_id' not in fields_list): |
1662 | + return values |
1663 | + journal = journal_pool.browse(cr, user, journal_id) |
1664 | + account_id = False |
1665 | + ttype = 'cr' |
1666 | + if journal.type in ('sale', 'sale_refund'): |
1667 | + account_id = journal.default_credit_account_id and journal.default_credit_account_id.id or False |
1668 | + ttype = 'cr' |
1669 | + elif journal.type in ('purchase', 'expense', 'purchase_refund'): |
1670 | + account_id = journal.default_debit_account_id and journal.default_debit_account_id.id or False |
1671 | + ttype = 'dr' |
1672 | + elif partner_id: |
1673 | + partner = partner_pool.browse(cr, user, partner_id, context=context) |
1674 | + if context.get('type') == 'payment': |
1675 | + ttype = 'dr' |
1676 | + account_id = partner.property_account_payable.id |
1677 | + elif context.get('type') == 'receipt': |
1678 | + account_id = partner.property_account_receivable.id |
1679 | + |
1680 | + if (not account_id) and 'account_id' in fields_list: |
1681 | + raise osv.except_osv(_('Invalid Error !'), _('Unable to locate account. Please change partner or payment method and try again !')) |
1682 | + values.update({ |
1683 | + 'account_id':account_id, |
1684 | + 'type':ttype |
1685 | + }) |
1686 | + return values |
1687 | + |
1688 | + def recalculate_values(self, cr, uid, ids, context={}): |
1689 | + if type(ids) == type([]): |
1690 | + voucher_line = self.browse(cr,uid,ids[0]) |
1691 | + else: |
1692 | + voucher_line = self.browse(cr,uid,ids) |
1693 | + self.pool.get('account.voucher').calc_diff(cr, uid, [voucher_line.voucher_id.id]) |
1694 | + return True |
1695 | + def clear_values(self, cr, uid, ids, context={}): |
1696 | + ''' |
1697 | + Clear all selected discounts, credits and writeoffs and manually entered values |
1698 | + ''' |
1699 | + voucher_line = self.browse(cr,uid,ids[0]) |
1700 | + if voucher_line._columns.has_key('writeoff_ids'): |
1701 | + if voucher_line._columns.has_key('available_discounts'): |
1702 | + for lines in self.read(cr,uid,ids,['available_credits','writeoff_ids','available_discounts']): |
1703 | + lines['writeoff_ids'] and self.pool.get('account.voucher.line.writeoff').unlink(cr,uid,lines['writeoff_ids']) |
1704 | + lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'], |
1705 | + {'use_credit':False, 'discount_amount':0.0}) |
1706 | + lines['available_discounts'] and self.pool.get('account.voucher.line.discount_to_use').write(cr,uid,lines['available_discounts'], |
1707 | + {'use_discount':False, 'discount_amount':0.0}) |
1708 | + else: |
1709 | + for lines in self.read(cr,uid,ids,['available_credits','writeoff_ids']): |
1710 | + lines['writeoff_ids'] and self.pool.get('account.voucher.line.writeoff').unlink(cr,uid,lines['writeoff_ids']) |
1711 | + lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'], |
1712 | + {'use_credit':False, 'discount_amount':0.0}) |
1713 | + elif voucher_line._columns.has_key('available_discounts'): |
1714 | + for lines in self.read(cr,uid,ids,['available_credits','available_discounts']): |
1715 | + lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'], |
1716 | + {'use_credit':False, 'discount_amount':0.0}) |
1717 | + lines['available_discounts'] and self.pool.get('account.voucher.line.discount_to_use').write(cr,uid,lines['available_discounts'], |
1718 | + {'use_discount':False, 'discount_amount':0.0}) |
1719 | + else: |
1720 | + for lines in self.read(cr,uid,ids,['available_credits']): |
1721 | + lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'], |
1722 | + {'use_credit':False, 'discount_amount':0.0}) |
1723 | + return True |
1724 | + |
1725 | + def onchange_pay(self, cr, uid, ids, pay, amount_unreconciled,par_cr_ids, par_amount, credit_used, discount_used=0, writeoff_amount=0,context={}): |
1726 | + ''' |
1727 | + Function to automativally fill the values when the pay checkbox is selected |
1728 | + ''' |
1729 | + ret = {} |
1730 | + writeoff_amount = (not writeoff_amount and [0] or [writeoff_amount])[0] |
1731 | + discount_used = (not discount_used and [0] or [discount_used])[0] |
1732 | + credit_used = (not credit_used and [0] or [credit_used])[0] |
1733 | + if pay: |
1734 | + tot_amt = par_amount |
1735 | + for credit in par_cr_ids: |
1736 | + if credit[2]['pay']: |
1737 | + tot_amt -= (credit[2]['amount']) |
1738 | + if tot_amt < 0: |
1739 | + ret['amount'] = 0.0 |
1740 | + else: |
1741 | + amount_unreconciled -= (discount_used+writeoff_amount+credit_used) |
1742 | + ret['amount'] = min(tot_amt,(amount_unreconciled<0) and 0 or amount_unreconciled) |
1743 | + else: |
1744 | + ret['amount'] = 0.0 |
1745 | + return {'value':ret} |
1746 | + |
1747 | + |
1748 | +account_voucher_line() |
1749 | + |
1750 | +class account_bank_statement(osv.osv): |
1751 | + _inherit = 'account.bank.statement' |
1752 | + |
1753 | + def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, next_number, context=None): |
1754 | + st_line = self.pool.get('account.bank.statement.line').browse(cr, uid, st_line_id, context=context) |
1755 | + if st_line.voucher_id: |
1756 | + res = self.pool.get('account.voucher').proforma_voucher(cr, uid, [st_line.voucher_id.id], context={'force_name': next_number}) |
1757 | + return self.pool.get('account.move.line').write(cr, uid, [x.id for x in st_line.voucher_id.move_ids], {'statement_id': st_line.statement_id.id}, context=context) |
1758 | + return super(account_bank_statement, self).create_move_from_st_line(cr, uid, st_line, company_currency_id, next_number, context=context) |
1759 | +account_bank_statement() |
1760 | + |
1761 | +class account_bank_statement_line(osv.osv): |
1762 | + _inherit = 'account.bank.statement.line' |
1763 | + |
1764 | + def _amount_reconciled(self, cursor, user, ids, name, args, context=None): |
1765 | + ''' |
1766 | + Function to calculate the value of variable Amount reconciled |
1767 | + ''' |
1768 | + if not ids: |
1769 | + return {} |
1770 | + res_currency_obj = self.pool.get('res.currency') |
1771 | + res = {} |
1772 | + company_currency_id = False |
1773 | + |
1774 | + for line in self.browse(cursor, user, ids, context=context): |
1775 | + if not company_currency_id: |
1776 | + company_currency_id = line.company_id.id |
1777 | + if line.voucher_id: |
1778 | + res[line.id] = res_currency_obj.compute(cursor, user, |
1779 | + company_currency_id, line.statement_id.currency.id, |
1780 | + line.voucher_id.amount, context=context) |
1781 | + else: |
1782 | + res[line.id] = 0.0 |
1783 | + return res |
1784 | + |
1785 | + _columns = { |
1786 | + 'amount_reconciled': fields.function(_amount_reconciled, |
1787 | + string='Amount reconciled', method=True, type='float'), |
1788 | + 'voucher_id': fields.many2one('account.voucher', 'Payment'), |
1789 | + |
1790 | + } |
1791 | + |
1792 | +account_bank_statement_line() |
1793 | + |
1794 | +class account_voucher_line_credits_to_use(osv.osv): |
1795 | + _name = "account.voucher.line.credits_to_use" |
1796 | + _rec_name = 'inv_credit' |
1797 | + |
1798 | + def _credit_balance(self, cr, uid, ids, name, args, context=None): |
1799 | + ''' |
1800 | + Function to calculate the value of variable Credit Balance |
1801 | + ''' |
1802 | + res = {} |
1803 | + for line in self.browse(cr, uid, ids, context=context): |
1804 | + if line.use_credit: |
1805 | + res[line.id] = line.available_amount - line.discount_amount |
1806 | + else: |
1807 | + res[line.id] = line.available_amount |
1808 | + return res |
1809 | + |
1810 | + _columns = { |
1811 | + 'voucher_line_id': fields.many2one('account.voucher.line', 'Account Voucher line', ondelete='cascade', readonly=True), |
1812 | + 'orginal_credit_line_id': fields.many2one('account.voucher.line', 'Account Voucher Credit Line', ondelete='cascade', readonly=True), |
1813 | + 'use_credit': fields.boolean('Use Credit',help='Used to indicate if credit should used against the invoice.', required=True), |
1814 | + 'inv_credit': fields.many2one('account.move.line', 'Invoice', help='Invoice of the credit', readonly=True), |
1815 | + 'discount_window_date': fields.date('Date',help='Date of the original credit', readonly=True), |
1816 | + 'orginal_amount': fields.float('Original Credit Amt', readonly=True), |
1817 | + 'available_amount': fields.float('Credit Amt Available', readonly=True), |
1818 | + 'discount_amount': fields.float('Amt to Use',help='Enter the amount of discount to be given.', required=True), |
1819 | + 'gl_account' : fields.many2one('account.account', 'G/L Account',help='Enter the General Ledger account number to record taking the cash discount.', required=True,readonly=True), |
1820 | + 'credit_bal': fields.function(_credit_balance, string='Credit Balance', method=True, type='float', store=False), |
1821 | + } |
1822 | + def onchage_use_credit(self, cr, uid, ids, use_credit, available_amount, amount_difference, context=None): |
1823 | + ''' |
1824 | + Function to automatically fill or remove the discount amount when use credit checkbox checked or unchecked |
1825 | + ''' |
1826 | + res = {} |
1827 | + if use_credit: |
1828 | + res['value'] = {'discount_amount': min(available_amount, amount_difference)} |
1829 | + else: |
1830 | + res['value'] = {'discount_amount': 0} |
1831 | + return res |
1832 | + def onchage_discount_amount(self, cr, uid, ids, available_amount, discount_amount, context=None): |
1833 | + ''' |
1834 | + Function to validate the discount amount |
1835 | + ''' |
1836 | + res = {} |
1837 | + if discount_amount < 0: |
1838 | + res['value'] = {'discount_amount': 0, 'use_credit':False } |
1839 | + res['warning'] = {'title': 'Credit not in the limit', 'message': 'Credit should not be a negative value.'} |
1840 | + return res |
1841 | + if discount_amount > available_amount: |
1842 | + res['value'] = {'discount_amount': available_amount, 'use_credit':True } |
1843 | + res['warning'] = {'title': 'Credit not in the limit', 'message': 'Please adjust the Credit Amt value to be less than or equal the Credit Available.'} |
1844 | + return res |
1845 | + if discount_amount == 0.0: |
1846 | + res['value'] = { 'use_credit':False } |
1847 | + else: |
1848 | + res['value'] = { 'use_credit':True } |
1849 | + return res |
1850 | +account_voucher_line_credits_to_use() |
1851 | + |
1852 | |
1853 | === added file 'account_voucher_credits_us/account_voucher_credits_us/voucher_payment_receipt_view.xml' |
1854 | --- account_voucher_credits_us/account_voucher_credits_us/voucher_payment_receipt_view.xml 1970-01-01 00:00:00 +0000 |
1855 | +++ account_voucher_credits_us/account_voucher_credits_us/voucher_payment_receipt_view.xml 2011-10-06 15:24:58 +0000 |
1856 | @@ -0,0 +1,213 @@ |
1857 | +<?xml version="1.0" encoding="UTF-8"?> |
1858 | +<openerp> |
1859 | + <data> |
1860 | + <record model="ir.ui.view" id="view_vendor_receipt_form_1"> |
1861 | + <field name="name">account.voucher.receipt.form.1</field> |
1862 | + <field name="model">account.voucher</field> |
1863 | + <field name="type">form</field> |
1864 | + <field name="inherit_id" ref="account_voucher.view_vendor_receipt_form"/> |
1865 | + <field name="arch" type="xml"> |
1866 | + |
1867 | + <xpath expr="/form/group/field[@name='amount']" position="replace"> |
1868 | + <field name="amount" string="Paid Amount" /> |
1869 | + </xpath> |
1870 | + <xpath expr="/form/group[@col='10']/button[@name='cancel_voucher']" position="after"> |
1871 | + <button name="calc_diff" string="Calculate" type="object" states="draft" icon="gtk-execute" default_focus="1" /> |
1872 | + </xpath> |
1873 | + <xpath expr="/form/notebook/page[@string='Payment Information']/group[@colspan='1']/group[@colspan='1']/field[@name='number']" position="after"> |
1874 | + <field name="auto_match" /> |
1875 | + </xpath> |
1876 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field[@name='line_dr_ids']/tree" position="replace"> |
1877 | + <tree string="Credits" editable="bottom"> |
1878 | + <field name="move_line_id"/> |
1879 | + <field name="date_original" readonly="1"/> |
1880 | + <field name="amount_original" readonly="1"/> |
1881 | + <field name="amount" sum="Total Amt Used" string="Amt Used" /> |
1882 | + <field name="pending_credits" sum="Total Pending Credit Used" readonly="1"/> |
1883 | + <field name="amount_unreconciled" string="Amt Available" readonly="1"/> |
1884 | + <field name="account_id" groups="base.group_extended" domain="[('type','=','receivable')]"/> |
1885 | + </tree> |
1886 | + <form string="Credits"> |
1887 | + <field name="move_line_id" /> |
1888 | + <field name="date_original" readonly="1"/> |
1889 | + <field name="amount_original" readonly="1"/> |
1890 | + <field name="amount" string="Amount Used" readonly="False"/> |
1891 | + <field name="pending_credits" readonly="1" sum="Total Credit Used"/> |
1892 | + <field name="amount_unreconciled" string="Amount Available" readonly="1"/> |
1893 | + <field name="account_id" groups="base.group_extended" domain="[('type','=','receivable')]"/> |
1894 | + </form> |
1895 | + </xpath> |
1896 | + |
1897 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field[@name='line_cr_ids']" position="replace"> |
1898 | + <field name="line_cr_ids" default_get="{'journal_id':journal_id, 'type':type, 'partner_id':partner_id}" colspan="4" nolabel="1" height="140" string="Payment Modification"> |
1899 | + <tree string="Invoices and Outstanding Transactions" editable="bottom"> |
1900 | + <field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}" |
1901 | + on_change="onchange_move_line_id(move_line_id)" |
1902 | + domain="[('account_id.type','in',('receivable','payable')), ('reconcile_id','=', False), ('partner_id','=',parent.partner_id)]" |
1903 | + /> |
1904 | + <field name="date_original" readonly="1"/> |
1905 | + <field name="date_due" readonly="1"/> |
1906 | + <field name="amount_original" readonly="1"/> |
1907 | + <field name="amount_unreconciled" sum="Open Balance" readonly="1"/> |
1908 | + <field name="pay" on_change="onchange_pay(pay, amount_unreconciled, parent.line_cr_ids, parent.amount, credit_used, discount_used, writeoff_amount)"/> |
1909 | + <field name="amount" sum="Payment"/> |
1910 | + <field name="amount_difference"/> |
1911 | + <field name="credit_used"/> |
1912 | + <field name="account_id"/> |
1913 | + </tree> |
1914 | + |
1915 | + |
1916 | + <form > |
1917 | + <group string="Invoice" colspan="4" col="4" > |
1918 | + <group colspan="2" cols="2"> |
1919 | + <field name="name" readonly="True"/> |
1920 | + <newline/> |
1921 | + <field name="invoice_id" readonly="True"/> |
1922 | + <newline/> |
1923 | + <field name="date_original" readonly="True"/> |
1924 | + </group> |
1925 | + |
1926 | + <group color="red" colspan="2" cols="2" > |
1927 | + <field name="amount_original"/> |
1928 | + <newline/> |
1929 | + <field name="amount_unreconciled"/> |
1930 | + <newline/> |
1931 | + <field name='amount' /> |
1932 | + <newline/> |
1933 | + <field name="credit_used"/> |
1934 | + <newline /> |
1935 | + <field name="amount_difference"/> |
1936 | + <!--field name="discount_used"/> |
1937 | + <field name="tot_disc_amt"/> |
1938 | + <newline/> |
1939 | + <field name="tot_cred_amt"/> |
1940 | + <newline/> |
1941 | + <field name="tot_dis_cred_amt"/> |
1942 | + <newline/> |
1943 | + <field name="rem_due"/--> |
1944 | + </group> |
1945 | + </group> |
1946 | + <notebook tabpos="up" colspan="4" > |
1947 | + <page string="Credit"> |
1948 | + <field name="available_credits" nolabel="1" colspan="4" string="Avilable Credits" view_mode="tree" > |
1949 | + </field> |
1950 | + </page> |
1951 | + <page string="Other Info" readonly="1"> |
1952 | + <field name='account_id'/> |
1953 | + <field name='partner_id' readonly="1"/> |
1954 | + <field name='untax_amount' readonly="1"/> |
1955 | + <field name='type' readonly="1"/> |
1956 | + <field name='account_analytic_id' readonly="1"/> |
1957 | + <field name='date_due' readonly="1"/> |
1958 | + <field name='company_id' readonly="1"/> |
1959 | + <field name='pay' on_change="onchange_pay(pay, amount_unreconciled, parent.line_cr_ids, parent.amount, credit_used, discount_used, writeoff_amount)"/> |
1960 | + </page> |
1961 | + </notebook> |
1962 | + <group colspan="1" cols="1"> |
1963 | + <label/><label/> |
1964 | + <button name="clear_values" icon='gtk-clear' string="Clear" type="object" colspan="1"/> |
1965 | + <button name="recalculate_values" icon='gtk-refresh' string="Re-Calculate" type="object" colspan="1"/> |
1966 | + </group> |
1967 | + </form> |
1968 | + |
1969 | + </field> |
1970 | + </xpath> |
1971 | + |
1972 | + </field> |
1973 | + </record> |
1974 | + |
1975 | + |
1976 | + <record model="ir.ui.view" id="view_account_voucher_line_credits_to_use_tree"> |
1977 | + <field name="name">account.voucher.line.credits_to_use.tree</field> |
1978 | + <field name="model">account.voucher.line.credits_to_use</field> |
1979 | + <field name="type">tree</field> |
1980 | + <field name="arch" type="xml"> |
1981 | + <tree string="Available Credits" editable="top" > |
1982 | + <field name="use_credit" width="100" on_change="onchage_use_credit(use_credit, available_amount, parent.amount_difference)"/> |
1983 | + <field name="inv_credit"/> |
1984 | + <field name="discount_window_date"/> |
1985 | + <field name="orginal_amount"/> |
1986 | + <field name="available_amount"/> |
1987 | + <field name="discount_amount" on_change="onchage_discount_amount(available_amount, discount_amount)"/> |
1988 | + <field name="credit_bal"/> |
1989 | + <field name="gl_account"/> |
1990 | + </tree> |
1991 | + </field> |
1992 | + </record> |
1993 | + |
1994 | + <record model="ir.ui.view" id="view_vendor_receipt_form_2"> |
1995 | + <field name="name">account.voucher.receipt.form.2</field> |
1996 | + <field name="model">account.voucher</field> |
1997 | + <field name="type">form</field> |
1998 | + <field name="inherit_id" ref="account_voucher.view_vendor_receipt_form"/> |
1999 | + <field name="arch" type="xml"> |
2000 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field/tree/field[@name='move_line_id']" position="replace"> |
2001 | + <field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}" |
2002 | + domain="[('account_id.type','in',('receivable','payable')), ('reconcile_id','=', False), ('partner_id','=',parent.partner_id)]" |
2003 | + /> |
2004 | + </xpath> |
2005 | + </field> |
2006 | + </record> |
2007 | + <record model="ir.ui.view" id="view_vendor_receipt_form_3"> |
2008 | + <field name="name">account.voucher.receipt.form.3</field> |
2009 | + <field name="model">account.voucher</field> |
2010 | + <field name="type">form</field> |
2011 | + <field name="inherit_id" ref="account_voucher.view_vendor_receipt_form"/> |
2012 | + <field name="arch" type="xml"> |
2013 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field/tree/field[@name='account_id']" position="replace"> |
2014 | + <field name="account_id" groups="base.group_extended" domain="[('type','=','receivable')]"/> |
2015 | + </xpath> |
2016 | + </field> |
2017 | + </record> |
2018 | + <record model="ir.ui.view" id="view_vendor_receipt_form_4"> |
2019 | + <field name="name">account.voucher.receipt.form.4</field> |
2020 | + <field name="model">account.voucher</field> |
2021 | + <field name="type">form</field> |
2022 | + <field name="inherit_id" ref="account_voucher.view_vendor_receipt_form"/> |
2023 | + <field name="arch" type="xml"> |
2024 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field/tree/field[@name='amount']" position="replace"> |
2025 | + <field name="amount" sum="Payment" /> |
2026 | + </xpath> |
2027 | + </field> |
2028 | + </record> |
2029 | + |
2030 | + <record id="action_proforma_voucher" model="ir.actions.act_window"> |
2031 | + <field name="name">Post Voucher</field> |
2032 | + <field name="type">ir.actions.act_window</field> |
2033 | + <field name="res_model">account.post.voucher</field> |
2034 | + <field name="view_type">form</field> |
2035 | + <field name="view_mode">form</field> |
2036 | + <field name="target">new</field> |
2037 | + </record> |
2038 | + <record model="ir.ui.view" id="view_vendor_receipt_form_5"> |
2039 | + <field name="name">account.voucher.receipt.form.5</field> |
2040 | + <field name="model">account.voucher</field> |
2041 | + <field name="type">form</field> |
2042 | + <field name="inherit_id" ref="account_voucher.view_vendor_receipt_form"/> |
2043 | + <field name="arch" type="xml"> |
2044 | + <xpath expr="/form/group[@col='10']/button[@name='proforma_voucher']" position="replace"> |
2045 | + <button name="%(action_proforma_voucher)d" string="Post" states="draft" type="action" icon="terp-camera_test"/> |
2046 | + </xpath> |
2047 | + </field> |
2048 | + </record> |
2049 | + <!-- |
2050 | + Company |
2051 | + --> |
2052 | + <record id="view_company_form_jdc3" model="ir.ui.view"> |
2053 | + <field name="name">res.company.form.jdc3</field> |
2054 | + <field name="model">res.company</field> |
2055 | + <field name="type">form</field> |
2056 | + <field name="inherit_id" ref="base.view_company_form"/> |
2057 | + <field name="priority" eval="1"/> |
2058 | + <field name="arch" type="xml"> |
2059 | + <xpath expr="/form/notebook" position="inside"> |
2060 | + <page string="Accounting"> |
2061 | + <field name="writeoff_account" colspan="2"/> |
2062 | + </page> |
2063 | + </xpath> |
2064 | + </field> |
2065 | + </record> |
2066 | + |
2067 | + |
2068 | + </data> |
2069 | +</openerp> |
2070 | |
2071 | === added directory 'account_voucher_credits_us/account_voucher_credits_us/wizard' |
2072 | === added file 'account_voucher_credits_us/account_voucher_credits_us/wizard/__init__.py' |
2073 | --- account_voucher_credits_us/account_voucher_credits_us/wizard/__init__.py 1970-01-01 00:00:00 +0000 |
2074 | +++ account_voucher_credits_us/account_voucher_credits_us/wizard/__init__.py 2011-10-06 15:24:58 +0000 |
2075 | @@ -0,0 +1,25 @@ |
2076 | +# -*- encoding: utf-8 -*- |
2077 | +############################################################################## |
2078 | +# |
2079 | +# OpenERP, Open Source Management Solution |
2080 | +# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). |
2081 | +# |
2082 | +# This program is free software: you can redistribute it and/or modify |
2083 | +# it under the terms of the GNU Affero General Public License as |
2084 | +# published by the Free Software Foundation, either version 3 of the |
2085 | +# License, or (at your option) any later version. |
2086 | +# |
2087 | +# This program is distributed in the hope that it will be useful, |
2088 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2089 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2090 | +# GNU Affero General Public License for more details. |
2091 | +# |
2092 | +# You should have received a copy of the GNU Affero General Public License |
2093 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2094 | +# |
2095 | +############################################################################## |
2096 | + |
2097 | +import account_post_voucher |
2098 | + |
2099 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
2100 | + |
2101 | |
2102 | === added file 'account_voucher_credits_us/account_voucher_credits_us/wizard/account_post_voucher.py' |
2103 | --- account_voucher_credits_us/account_voucher_credits_us/wizard/account_post_voucher.py 1970-01-01 00:00:00 +0000 |
2104 | +++ account_voucher_credits_us/account_voucher_credits_us/wizard/account_post_voucher.py 2011-10-06 15:24:58 +0000 |
2105 | @@ -0,0 +1,73 @@ |
2106 | +# -*- coding: utf-8 -*- |
2107 | +############################################################################## |
2108 | +# |
2109 | +# OpenERP, Open Source Management Solution |
2110 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
2111 | +# |
2112 | +# This program is free software: you can redistribute it and/or modify |
2113 | +# it under the terms of the GNU Affero General Public License as |
2114 | +# published by the Free Software Foundation, either version 3 of the |
2115 | +# License, or (at your option) any later version. |
2116 | +# |
2117 | +# This program is distributed in the hope that it will be useful, |
2118 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2119 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2120 | +# GNU Affero General Public License for more details. |
2121 | +# |
2122 | +# You should have received a copy of the GNU Affero General Public License |
2123 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2124 | +# |
2125 | +############################################################################## |
2126 | +from osv import fields, osv |
2127 | + |
2128 | +class account_post_voucher(osv.osv_memory): |
2129 | + _name = 'account.post.voucher' |
2130 | + _description = 'Account Pay Voucher' |
2131 | + |
2132 | + _columns = { |
2133 | + 'total_paid': fields.float('Total Received'), |
2134 | + 'total_allocated': fields.float('Total Allocated'), |
2135 | + 'ok_to_go': fields.float('OK to Go'), |
2136 | + } |
2137 | + |
2138 | + def _get_total_paid(self, cr, uid, context={}): |
2139 | + obj_voucher = self.pool.get('account.voucher') |
2140 | + return obj_voucher.browse(cr, uid, context['active_id'], context).amount |
2141 | + |
2142 | + def _get_total_allocated(self, cr, uid, context={}): |
2143 | + obj_voucher = self.pool.get('account.voucher') |
2144 | + voucher = obj_voucher.browse(cr, uid, context['active_id'], context) |
2145 | + total_allocated = 0.0 |
2146 | + for line in voucher.line_cr_ids: |
2147 | + total_allocated += line.amount |
2148 | + return total_allocated |
2149 | + |
2150 | + def _get_ok_to_go(self,cr, uid, context={}): |
2151 | + obj_voucher = self.pool.get('account.voucher') |
2152 | + voucher = obj_voucher.browse(cr, uid, context['active_id'], context) |
2153 | + total_allocated = 0.0 |
2154 | + for line in voucher.line_cr_ids: |
2155 | + total_allocated += line.amount |
2156 | + return total_allocated - voucher.amount |
2157 | + |
2158 | + _defaults = { |
2159 | + 'total_paid': _get_total_paid, |
2160 | + 'total_allocated': _get_total_allocated, |
2161 | + 'ok_to_go': _get_ok_to_go, |
2162 | + } |
2163 | + def onchange_ok_to_go(self,cr, uid, ids, ok_to_go, context={}): |
2164 | + if ok_to_go > 0.0: |
2165 | + return {'warning': {'title': 'Overallocated invoices', 'message': 'Reduce allocations to match Total Receipt'}} |
2166 | + else: |
2167 | + return {} |
2168 | + def launch_wizard(self, cr, uid, ids, context=None): |
2169 | + """ |
2170 | + Don't allow post if total_allocated > total_paid. |
2171 | + """ |
2172 | + obj_voucher = self.pool.get('account.voucher') |
2173 | + obj_voucher.action_move_line_create(cr, uid, context['active_ids'], context) |
2174 | + return {} |
2175 | + |
2176 | +account_post_voucher() |
2177 | + |
2178 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
2179 | |
2180 | === added file 'account_voucher_credits_us/account_voucher_credits_us/wizard/account_post_voucher.xml' |
2181 | --- account_voucher_credits_us/account_voucher_credits_us/wizard/account_post_voucher.xml 1970-01-01 00:00:00 +0000 |
2182 | +++ account_voucher_credits_us/account_voucher_credits_us/wizard/account_post_voucher.xml 2011-10-06 15:24:58 +0000 |
2183 | @@ -0,0 +1,40 @@ |
2184 | +<?xml version="1.0" encoding="utf-8"?> |
2185 | +<openerp> |
2186 | + <data> |
2187 | + |
2188 | + <record id="account_voucher_post_view" model="ir.ui.view"> |
2189 | + <field name="name">account.post.voucher.form</field> |
2190 | + <field name="model">account.post.voucher</field> |
2191 | + <field name="type">form</field> |
2192 | + <field name="arch" type="xml"> |
2193 | + <form string="Post Voucher"> |
2194 | + <group colspan="2" col="4"> |
2195 | + <field name="total_paid" readonly="True"/> |
2196 | + <field name="total_allocated" readonly="True"/> |
2197 | + <field name="ok_to_go" invisible="True" on_change="onchange_ok_to_go(ok_to_go)"/> |
2198 | + </group> |
2199 | + <group height="100" width="320"> |
2200 | + <separator string="Confirm Amounts?"/> |
2201 | + <newline/> |
2202 | + <group colspan="2" col="4"> |
2203 | + <button special="cancel" string="Cancel" icon="gtk-cancel"/> |
2204 | + <button name="launch_wizard" string="Yes" type="object" attrs="{'invisible':[('ok_to_go', '>', 0.0)]}" icon="gtk-ok" default_focus="1"/> |
2205 | + </group> |
2206 | + </group> |
2207 | + </form> |
2208 | + </field> |
2209 | + </record> |
2210 | + |
2211 | + <record id="action_proforma_voucher" model="ir.actions.act_window"> |
2212 | + <field name="name">Post Voucher</field> |
2213 | + <field name="type">ir.actions.act_window</field> |
2214 | + <field name="res_model">account.post.voucher</field> |
2215 | + <field name="view_type">form</field> |
2216 | + <field name="view_mode">form</field> |
2217 | + <field name="view_id" ref="account_voucher_post_view"/> |
2218 | + <field name="target">new</field> |
2219 | + </record> |
2220 | + |
2221 | + |
2222 | + </data> |
2223 | +</openerp> |
2224 | |
2225 | === added directory 'account_voucher_credits_us/security' |
2226 | === added file 'account_voucher_credits_us/security/ir.model.access.csv' |
2227 | --- account_voucher_credits_us/security/ir.model.access.csv 1970-01-01 00:00:00 +0000 |
2228 | +++ account_voucher_credits_us/security/ir.model.access.csv 2011-10-06 15:24:58 +0000 |
2229 | @@ -0,0 +1,2 @@ |
2230 | +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" |
2231 | +"access_account_voucher_line_credits_to_use","account.voucher.line.credits_to_use","model_account_voucher_line_credits_to_use","base.group_user",1,1,1,1 |
2232 | \ No newline at end of file |
2233 | |
2234 | === added directory 'account_voucher_credits_us/test' |
2235 | === added file 'account_voucher_credits_us/test/account_voucher.yml' |
2236 | --- account_voucher_credits_us/test/account_voucher.yml 1970-01-01 00:00:00 +0000 |
2237 | +++ account_voucher_credits_us/test/account_voucher.yml 2011-10-06 15:24:58 +0000 |
2238 | @@ -0,0 +1,97 @@ |
2239 | + |
2240 | +- |
2241 | + In order to check account voucher module in OpenERP I create a customer voucher |
2242 | +- |
2243 | + !record {model: account.voucher, id: account_voucher_voucherforaxelor0}: |
2244 | + account_id: account.cash |
2245 | + company_id: base.main_company |
2246 | + currency_id: base.EUR |
2247 | + journal_id: account.bank_journal |
2248 | + name: Voucher for Axelor |
2249 | + narration: Basic Pc |
2250 | + line_ids: |
2251 | + - account_id: account.a_recv |
2252 | + amount: 1000.0 |
2253 | + name: Voucher for Axelor |
2254 | + partner_id: base.res_partner_desertic_hispafuentes |
2255 | + period_id: account.period_6 |
2256 | + reference_type: none |
2257 | + |
2258 | +- |
2259 | + I check that Initially customer voucher is in the "Draft" state |
2260 | +- |
2261 | + !assert {model: account.voucher, id: account_voucher_voucherforaxelor0}: |
2262 | + - state == 'draft' |
2263 | +- |
2264 | + I compute the voucher to calculate the taxes by clicking Cpmpute button |
2265 | +- |
2266 | + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_voucherforaxelor0} |
2267 | +- |
2268 | + I check that the voucher state is now "proforma" |
2269 | +- |
2270 | + !assert {model: account.voucher, id: account_voucher_voucherforaxelor0}: |
2271 | + - state == 'proforma' |
2272 | +- |
2273 | + I create voucher by clicking on Create button |
2274 | +- |
2275 | + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_voucherforaxelor0} |
2276 | +- |
2277 | + I clicked on Validate Button |
2278 | +- |
2279 | + !assert {model: account.voucher, id: account_voucher_voucherforaxelor0}: |
2280 | + - state == 'posted' |
2281 | + |
2282 | +- |
2283 | + I check that Moves get created for this voucher |
2284 | +- |
2285 | + !python {model: account.voucher}: | |
2286 | + acc_id=self.browse(cr, uid, ref("account_voucher_voucherforaxelor0")) |
2287 | + assert(acc_id.move_id) |
2288 | + |
2289 | + |
2290 | +- |
2291 | + Now I create a Vendor Voucher |
2292 | +- |
2293 | + !record {model: account.voucher, id: account_voucher_voucheraxelor0}: |
2294 | + account_id: account.cash |
2295 | + company_id: base.main_company |
2296 | + currency_id: base.EUR |
2297 | + journal_id: account.bank_journal |
2298 | + name: Voucher Axelor |
2299 | + narration: Basic PC |
2300 | + line_ids: |
2301 | + - account_id: account.cash |
2302 | + amount: 1000.0 |
2303 | + name: Voucher Axelor |
2304 | + period_id: account.period_6 |
2305 | + reference_type: none |
2306 | + |
2307 | +- |
2308 | + I check that Initially vendor voucher is in the "Draft" state |
2309 | +- |
2310 | + !assert {model: account.voucher, id: account_voucher_voucheraxelor0}: |
2311 | + - state == 'draft' |
2312 | +- |
2313 | + I change the state of voucher to "proforma" by clicking PRO-FORMA button |
2314 | +- |
2315 | + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_voucheraxelor0} |
2316 | +- |
2317 | + I check that the voucher state is now "proforma" |
2318 | +- |
2319 | + !assert {model: account.voucher, id: account_voucher_voucheraxelor0}: |
2320 | + - state == 'proforma' |
2321 | +- |
2322 | + I create voucher by clicking on Create button |
2323 | +- |
2324 | + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_voucheraxelor0} |
2325 | +- |
2326 | + I check that the voucher state is "posted" |
2327 | +- |
2328 | + !assert {model: account.voucher, id: account_voucher_voucheraxelor0}: |
2329 | + - state == 'posted' |
2330 | +- |
2331 | + I check that moves get created for this voucher |
2332 | +- |
2333 | + !python {model: account.voucher}: | |
2334 | + acc_id=self.browse(cr, uid, ref("account_voucher_voucheraxelor0")) |
2335 | + assert(acc_id.move_id) |
2336 | |
2337 | === added file 'account_voucher_credits_us/test/account_voucher_report.yml' |
2338 | --- account_voucher_credits_us/test/account_voucher_report.yml 1970-01-01 00:00:00 +0000 |
2339 | +++ account_voucher_credits_us/test/account_voucher_report.yml 2011-10-06 15:24:58 +0000 |
2340 | @@ -0,0 +1,25 @@ |
2341 | +- |
2342 | + Demo for Account Voucher |
2343 | +- |
2344 | + !record {model: account.voucher, id: account_voucher_voucheraxelor0}: |
2345 | + account_id: account.cash |
2346 | + company_id: base.main_company |
2347 | + currency_id: base.EUR |
2348 | + journal_id: account.bank_journal |
2349 | + name: Voucher Axelor |
2350 | + narration: Basic PC |
2351 | + amount: 1000.0 |
2352 | + line_ids: |
2353 | + - account_id: account.cash |
2354 | + amount: 1000.0 |
2355 | + name: Voucher Axelor |
2356 | + period_id: account.period_6 |
2357 | + |
2358 | +- |
2359 | + In order to test the PDF reports defined on a account_voucher, we will print account voucher Report |
2360 | +- |
2361 | + !python {model: account.voucher}: | |
2362 | + import netsvc, tools, os |
2363 | + (data, format) = netsvc.LocalService('report.voucher.cash_receipt.drcr').create(cr, uid, [ref("account_voucher_voucheraxelor0")], {}, {}) |
2364 | + if tools.config['test_report_directory']: |
2365 | + file(os.path.join(tools.config['test_report_directory'], 'account_voucher-report.'+format), 'wb+').write(data) |
2366 | |
2367 | === added file 'account_voucher_credits_us/test/sales_payment.yml' |
2368 | --- account_voucher_credits_us/test/sales_payment.yml 1970-01-01 00:00:00 +0000 |
2369 | +++ account_voucher_credits_us/test/sales_payment.yml 2011-10-06 15:24:58 +0000 |
2370 | @@ -0,0 +1,89 @@ |
2371 | +- |
2372 | + In order to test account voucher i will create an invoice and pay it through account voucher. |
2373 | +- |
2374 | + I create a new Partner |
2375 | +- |
2376 | + !record {model: res.partner, id: res_partner_micropc0}: |
2377 | + address: |
2378 | + - country_id: base.be |
2379 | + name: Jenifer |
2380 | + street: 69 rue de Chimay |
2381 | + type: default |
2382 | + zip: '5478' |
2383 | + category_id: |
2384 | + - base.res_partner_category_8 |
2385 | + credit_limit: 0.0 |
2386 | + name: Micro PC |
2387 | + property_account_payable: account.a_pay |
2388 | + property_account_receivable: account.a_recv |
2389 | + |
2390 | +- |
2391 | + Create an invoice for the partner |
2392 | +- |
2393 | + !record {model: account.invoice, id: account_invoice_0}: |
2394 | + account_id: account.a_recv |
2395 | + address_contact_id: base.res_partner_address_7 |
2396 | + address_invoice_id: base.res_partner_address_7 |
2397 | + company_id: base.main_company |
2398 | + currency_id: base.EUR |
2399 | + invoice_line: |
2400 | + - account_id: account.a_sale |
2401 | + name: '[PC1] Basic PC' |
2402 | + price_unit: 450.0 |
2403 | + quantity: 1.0 |
2404 | + product_id: product.product_product_pc1 |
2405 | + uos_id: product.product_uom_unit |
2406 | + journal_id: account.sales_journal |
2407 | + partner_id: res_partner_micropc0 |
2408 | + |
2409 | +- |
2410 | + I check that the customer invoice is in draft state |
2411 | +- |
2412 | + !assert {model: account.invoice, id: account_invoice_0}: |
2413 | + - state == 'draft' |
2414 | + |
2415 | +- |
2416 | + I make the invoice in Open state |
2417 | +- |
2418 | + !workflow {model: account.invoice, action: invoice_open, ref: account_invoice_0} |
2419 | + |
2420 | +- |
2421 | + I check that a payment entry gets created in the account.move.line |
2422 | +- |
2423 | + !python {model: account.invoice}: | |
2424 | + acc_id=self.browse(cr, uid, ref("account_invoice_0")) |
2425 | + assert(acc_id.move_id) |
2426 | + |
2427 | +- |
2428 | + I will create and post an account voucher for the partner. |
2429 | +- |
2430 | + !python {model: account.voucher}: | |
2431 | + import netsvc |
2432 | + vals = {} |
2433 | + journal_id = self.default_get(cr, uid, ['journal_id']).get('journal_id',None) |
2434 | + res = self.onchange_partner_id(cr, uid, [], ref("res_partner_micropc0"), journal_id, price=0.0, ttype='receipt') |
2435 | + vals = { |
2436 | + 'account_id': ref('account.cash'), |
2437 | + 'amount': 450.0, |
2438 | + 'company_id': ref('base.main_company'), |
2439 | + 'currency_id': ref('base.EUR'), |
2440 | + 'journal_id': ref('account.bank_journal'), |
2441 | + 'partner_id': ref('res_partner_micropc0'), |
2442 | + 'period_id': ref('account.period_8'), |
2443 | + 'type': 'receipt', |
2444 | + } |
2445 | + if not res['value']['line_cr_ids']: |
2446 | + res['value']['line_cr_ids'] = [{'type': 'cr', 'account_id': ref('account.a_recv'),}] |
2447 | + res['value']['line_cr_ids'][0]['amount'] = 450.0 |
2448 | + vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']] |
2449 | + id = self.create(cr, uid, vals) |
2450 | + voucher_id = self.browse(cr, uid, id) |
2451 | + assert (voucher_id.state=='draft'), "Voucher is not in draft state" |
2452 | + wf_service = netsvc.LocalService("workflow") |
2453 | + wf_service.trg_validate(uid, 'account.voucher', voucher_id.id, 'proforma_voucher', cr) |
2454 | + |
2455 | +- |
2456 | + Finally i will Confirm the state of the invoice is paid |
2457 | +- |
2458 | + !assert {model: account.invoice, id: account_invoice_0}: |
2459 | + - state == 'paid' |
2460 | |
2461 | === added file 'account_voucher_credits_us/test/sales_receipt.yml' |
2462 | --- account_voucher_credits_us/test/sales_receipt.yml 1970-01-01 00:00:00 +0000 |
2463 | +++ account_voucher_credits_us/test/sales_receipt.yml 2011-10-06 15:24:58 +0000 |
2464 | @@ -0,0 +1,74 @@ |
2465 | + |
2466 | +- |
2467 | + In order to test sales receipt i will create a sale receipt and pay it through sales payment |
2468 | +- |
2469 | + First of all I create a voucher |
2470 | +- |
2471 | + !record {model: account.voucher, id: account_voucher_chinaexport_0}: |
2472 | + account_id: account.a_recv |
2473 | + amount: 30000.0 |
2474 | + company_id: base.main_company |
2475 | + journal_id: account.sales_journal |
2476 | + line_cr_ids: |
2477 | + - account_id: account.a_sale |
2478 | + amount: 30000.0 |
2479 | + partner_id: base.res_partner_3 |
2480 | + period_id: account.period_8 |
2481 | + tax_amount: 0.0 |
2482 | + type: sale |
2483 | + |
2484 | +- |
2485 | + I check that the voucher state is Draft |
2486 | +- |
2487 | + !assert {model: account.voucher, id: account_voucher_chinaexport_0}: |
2488 | + - state == 'draft' |
2489 | + |
2490 | +- |
2491 | + I clicked on post button to post the voucher |
2492 | +- |
2493 | + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_chinaexport_0} |
2494 | + |
2495 | +- |
2496 | + Check the voucher state is Posted |
2497 | +- |
2498 | + !assert {model: account.voucher, id: account_voucher_chinaexport_0}: |
2499 | + - state == 'posted' |
2500 | + |
2501 | +- |
2502 | + I create a voucher record for the same partner |
2503 | +- |
2504 | + !record {model: account.voucher, id: account_voucher_chinaexport_1}: |
2505 | + account_id: account.cash |
2506 | + amount: 30000.0 |
2507 | + company_id: base.main_company |
2508 | + currency_id: base.EUR |
2509 | + journal_id: account.bank_journal |
2510 | + line_cr_ids: |
2511 | + - account_id: account.a_recv |
2512 | + amount: 0.0 |
2513 | + name: 2010/003 |
2514 | + type: cr |
2515 | + - account_id: account.a_recv |
2516 | + amount: 30000.0 |
2517 | + name: 2010/003 |
2518 | + type: cr |
2519 | + partner_id: base.res_partner_3 |
2520 | + period_id: account.period_8 |
2521 | + type: receipt |
2522 | + |
2523 | +- |
2524 | + Check the voucher state is draft |
2525 | +- |
2526 | + !assert {model: account.voucher, id: account_voucher_chinaexport_1}: |
2527 | + - state == 'draft' |
2528 | + |
2529 | +- |
2530 | + I clicked on Post button to post the voucher |
2531 | +- |
2532 | + !workflow {model: account.voucher, action: proforma_voucher, ref: account_voucher_chinaexport_1} |
2533 | + |
2534 | +- |
2535 | + Check the voucher state is Posted |
2536 | +- |
2537 | + !assert {model: account.voucher, id: account_voucher_chinaexport_1}: |
2538 | + - state == 'posted' |
2539 | |
2540 | === added file 'account_voucher_credits_us/voucher.py' |
2541 | --- account_voucher_credits_us/voucher.py 1970-01-01 00:00:00 +0000 |
2542 | +++ account_voucher_credits_us/voucher.py 2011-10-06 15:24:58 +0000 |
2543 | @@ -0,0 +1,1100 @@ |
2544 | +# -*- coding: utf-8 -*- |
2545 | +############################################################################## |
2546 | +# |
2547 | +# OpenERP, Open Source Management Solution |
2548 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
2549 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
2550 | +# |
2551 | +# This program is free software: you can redistribute it and/or modify |
2552 | +# it under the terms of the GNU General Public License as published by |
2553 | +# the Free Software Foundation, either version 3 of the License, or |
2554 | +# (at your option) any later version. |
2555 | +# |
2556 | +# This program is distributed in the hope that it will be useful, |
2557 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2558 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2559 | +# GNU General Public License for more details. |
2560 | +# |
2561 | +# You should have received a copy of the GNU General Public License |
2562 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
2563 | +# |
2564 | +############################################################################## |
2565 | + |
2566 | +import time |
2567 | +import netsvc |
2568 | +from osv import fields |
2569 | +from osv import osv |
2570 | +from tools.translate import _ |
2571 | +def _combinations(iterable, r): |
2572 | + ''' |
2573 | + @return: combination generator object |
2574 | + |
2575 | + Example |
2576 | + combinations(’ABCD’, 2) --> AB AC AD BC BD CD |
2577 | + combinations(range(4), 3) --> 012 013 023 123 |
2578 | + ''' |
2579 | + pool = tuple(iterable) |
2580 | + n = len(pool) |
2581 | + if r > n: |
2582 | + return |
2583 | + indices = range(r) |
2584 | + yield tuple(pool[i] for i in indices) |
2585 | + while True: |
2586 | + for i in reversed(range(r)): |
2587 | + if indices[i] != i + n - r: |
2588 | + break |
2589 | + else: |
2590 | + return |
2591 | + indices[i] += 1 |
2592 | + for j in range(i+1, r): |
2593 | + indices[j] = indices[j-1] + 1 |
2594 | + yield tuple(pool[i] for i in indices) |
2595 | + |
2596 | + |
2597 | +class account_move_line(osv.osv): |
2598 | + ''' |
2599 | + Show unreconciled amount on partial reconciled/none reconciled move line |
2600 | + ''' |
2601 | + _inherit = 'account.move.line' |
2602 | + def _unreconciled(self, cr, uid, ids, prop, unknow_none, context): |
2603 | + ''' |
2604 | + Calculate Amount yet to reconcile |
2605 | + ''' |
2606 | + res={} |
2607 | + for line in self.browse(cr, uid, ids, context=context): |
2608 | + res[line.id] = line.debit - line.credit |
2609 | + if line.reconcile_partial_id: |
2610 | + res[line.id] = 0 |
2611 | + for partial in line.reconcile_partial_id.line_partial_ids: |
2612 | + res[line.id] += partial.debit - partial.credit |
2613 | + res[line.id] = abs(res[line.id]) |
2614 | + return res |
2615 | + |
2616 | + def write(self, cr, uid, ids, vals, context=None, check=True, update_check=True): |
2617 | + if type(ids)!=type([]): |
2618 | + ids = [ids] |
2619 | + return super(account_move_line, self).write(cr, uid, ids, vals, context=context, check=check, update_check=update_check) |
2620 | + |
2621 | + _columns = { |
2622 | + 'amount_unreconciled': fields.function(_unreconciled, method=True, string='Unreconciled Amount'), |
2623 | + } |
2624 | +account_move_line() |
2625 | + |
2626 | +class account_voucher(osv.osv): |
2627 | + |
2628 | + |
2629 | + def default_get(self, cr, user, fields_list, context=None): |
2630 | + """ |
2631 | + Returns default values for fields |
2632 | + @param fields_list: list of fields, for which default values are required to be read |
2633 | + @param context: context arguments, like lang, time zone |
2634 | + |
2635 | + @return: Returns a dict that contains default values for fields |
2636 | + """ |
2637 | + values = super(account_voucher, self).default_get(cr, user, fields_list, context=context) |
2638 | + if values.get('type') == 'payment': |
2639 | + company = self.pool.get('res.users').browse(cr, user, user, context=context).company_id |
2640 | + if company.def_supp_journal: |
2641 | + values['journal_id'] = company.def_supp_journal.id |
2642 | + return values |
2643 | + |
2644 | + |
2645 | + def _find_exact_match(self, cr, uid, lines, amount, mark_pay=False, use_discount=False, context=False): |
2646 | + ''' |
2647 | + Accept voucher lines as list of dict and amount to match |
2648 | + return : update lines if it found an exact match |
2649 | + ''' |
2650 | + total_amount = 0.0 |
2651 | + discount_available = {} |
2652 | + total_discount_available = 0.0 |
2653 | + for line in lines: |
2654 | + if mark_pay or line.pay == True: |
2655 | + if use_discount: |
2656 | + discount_available[line.id] = 0.0 |
2657 | + for discount_line in line.available_discounts: |
2658 | + discount_available[line.id] += discount_line.proposed_discount |
2659 | + total_discount_available += discount_line.proposed_discount |
2660 | + total_amount += line.amount_unreconciled - line.credit_used - (line._columns.has_key('writeoff_amount') and line.writeoff_amount) |
2661 | + else: |
2662 | + total_amount += line.amount_unreconciled - line.credit_used - line.discount_used- (line._columns.has_key('writeoff_amount') and line.writeoff_amount) |
2663 | + if abs(amount - total_amount) < 0.01 : |
2664 | + ''' |
2665 | + Unchecking all the lines other than matched line |
2666 | + ''' |
2667 | + line_ids = self.read(cr,uid,lines[0].voucher_id.id,['line_ids'])['line_ids'] |
2668 | + self.pool.get('account.voucher.line').write(cr,uid,line_ids,{'pay':False}) |
2669 | + for line in lines: |
2670 | + if mark_pay or line.pay == True: |
2671 | + line.write({'amount':line.amount_unreconciled - line.credit_used - line.discount_used - (line._columns.has_key('writeoff_amount') and line.writeoff_amount), 'pay':True }) |
2672 | + else: |
2673 | + line.write({'amount':0.0, 'pay':False }) |
2674 | + return True |
2675 | + if use_discount and total_amount>amount and (total_amount - amount ) <=total_discount_available: #It is possible to match using Discount |
2676 | + ''' |
2677 | + Unchecking all the lines other than matched line and uncheck all discount lines |
2678 | + ''' |
2679 | + line_ids = self.read(cr,uid,lines[0].voucher_id.id,['line_ids'])['line_ids'] |
2680 | + self.pool.get('account.voucher.line').write(cr,uid,line_ids,{'pay':False}) |
2681 | + for line_id in line_ids: |
2682 | + discount_ids = self.pool.get('account.voucher.line').read(cr,uid,line_id,['available_discounts'])['available_discounts'] |
2683 | + self.pool.get("account.voucher.line.discount_to_use").write(cr,uid,discount_ids,{'use_discount':False, 'discount_amount':0.0}) |
2684 | + discount_to_use = total_amount - amount |
2685 | + for line in lines: |
2686 | + if discount_to_use > 0.0: |
2687 | + for discount_line in line.available_discounts: |
2688 | + discount_line.write({'use_discount':True,'discount_amount':min(discount_to_use, discount_line.proposed_discount)}) |
2689 | + discount_to_use = discount_to_use - min(discount_to_use, discount_line.proposed_discount) |
2690 | + line = self.pool.get('account.voucher.line').browse(cr, uid, line.id,context=context) |
2691 | + line.write({'amount':line.amount_unreconciled - line.credit_used - line.discount_used - (line._columns.has_key('writeoff_amount') and line.writeoff_amount), 'pay':True }) |
2692 | + return True |
2693 | + if len(lines) > 1: |
2694 | + for combination in _combinations(lines,len(lines)-1 ): |
2695 | + if self._find_exact_match(cr, uid, combination, amount, mark_pay, context=False): |
2696 | + return True |
2697 | + return False |
2698 | + |
2699 | + def calc_diff(self, cr, uid, ids, context={}): |
2700 | + ''' |
2701 | + Called by calculate/re-calculate action. |
2702 | + This method will update the credit lines on voucher lines. |
2703 | + If the field "auto_match" marked, this method will run a matching routine |
2704 | + ''' |
2705 | + res = {'nodestroy':True} |
2706 | + amount_cash_discount = 0.0 |
2707 | + amount_interest = 0.0 |
2708 | + for vch in self.browse(cr, uid, ids): |
2709 | + for line in vch.line_cr_ids: |
2710 | + ''' |
2711 | + Update the credit lines and discount lines so that matching routine can use the latest available credits and discounts |
2712 | + ''' |
2713 | + line._update_credit_lines( context=context) |
2714 | + line._update_discount_lines(context=context) |
2715 | + |
2716 | + if vch.auto_match: |
2717 | + ''' |
2718 | + Try the matching routine including the manual selection |
2719 | + ''' |
2720 | + ret = self._find_exact_match(cr, uid, vch.line_cr_ids, vch.amount, mark_pay=False, use_discount=False, context=False) |
2721 | + if not ret: |
2722 | + ''' |
2723 | + Try to match considering all voucher lines |
2724 | + ''' |
2725 | + ret = self._find_exact_match(cr, uid, vch.line_cr_ids, vch.amount, mark_pay=True, use_discount=False, context=False) |
2726 | + if not ret: |
2727 | + ''' |
2728 | + Try to match considering discount |
2729 | + ''' |
2730 | + ret = self._find_exact_match(cr, uid, vch.line_cr_ids, vch.amount, mark_pay=True, use_discount=True, context=False) |
2731 | + return res |
2732 | + |
2733 | + def onchange_date(self, cr, user, ids, partner_id, journal_id, price, currency_id, ttype, date, context={}): |
2734 | + """ |
2735 | + @param date: latest value from user input for field date |
2736 | + @param args: other arguments |
2737 | + @param context: context arguments, like lang, time zone |
2738 | + @return: Returns a dict which contains new values, and context |
2739 | + """ |
2740 | + period_pool = self.pool.get('account.period') |
2741 | + pids = period_pool.search(cr, user, [('date_start','<=',date), ('date_stop','>=',date)]) |
2742 | + if not pids: |
2743 | + return {} |
2744 | + return { |
2745 | + 'value':{ |
2746 | + 'period_id':pids[0] |
2747 | + } |
2748 | + } |
2749 | + |
2750 | + def _update_discounts(self, lines, vch_date): |
2751 | + # hook method for account_cash_discount_us module |
2752 | + return True |
2753 | + |
2754 | + _inherit = 'account.voucher' |
2755 | + _columns = { |
2756 | + 'number': fields.related('move_id', 'name', type="char", readonly=True, string='Number'), |
2757 | + 'auto_match':fields.boolean('Use Automatic Matching') |
2758 | + } |
2759 | + |
2760 | + def onchange_partner_id(self, cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context={}): |
2761 | + """price |
2762 | + Returns a dict that contains new values and context |
2763 | + |
2764 | + @param partner_id: latest value from user input for field partner_id |
2765 | + @param args: other arguments |
2766 | + @param context: context arguments, like lang, time zone |
2767 | + |
2768 | + @return: Returns a dict which contains new values, and context |
2769 | + """ |
2770 | + ''' |
2771 | + function ported from account_voucher_jds module |
2772 | + This function is redefined and do not use functionality provided by account_voucher module |
2773 | + Possible issue is that the latest function from updated account_voucher module will have no effect if this module is installed |
2774 | + ''' |
2775 | + if context is None: |
2776 | + context = {} |
2777 | + currency_pool = self.pool.get('res.currency') |
2778 | + move_pool = self.pool.get('account.move') |
2779 | + line_pool = self.pool.get('account.voucher.line') |
2780 | + move_line_pool = self.pool.get('account.move.line') |
2781 | + partner_pool = self.pool.get('res.partner') |
2782 | + journal_pool = self.pool.get('account.journal') |
2783 | + default = { |
2784 | + 'value':{'line_ids':[], 'line_dr_ids':[], 'line_cr_ids':[], 'pre_line': False, 'currency_id':currency_id, 'journal_id': False}, |
2785 | + } |
2786 | + if partner_id and not journal_id: |
2787 | + partner = partner_pool.browse(cr, uid, partner_id, context) |
2788 | + if partner._columns.has_key('payment_meth_id') and partner.payment_meth_id: |
2789 | + payment_mode_pool = self.pool.get('payment.mode') |
2790 | + payment_meth = payment_mode_pool.browse(cr, uid, partner.payment_meth_id.id, context) |
2791 | + if payment_meth: |
2792 | + default['value']['journal_id'] = payment_meth.journal.id |
2793 | + journal_id = payment_meth.journal.id |
2794 | + if not journal_id: |
2795 | + return {} |
2796 | + context_multi_currency = context.copy() |
2797 | + if date: |
2798 | + context_multi_currency.update({'date': date}) |
2799 | + |
2800 | + vals = self.onchange_journal(cr, uid, ids, journal_id, [], False, partner_id, context) |
2801 | + vals = vals.get('value') |
2802 | + currency_id = vals.get('currency_id', currency_id) |
2803 | + |
2804 | + if not partner_id: |
2805 | + return default |
2806 | + |
2807 | + if not partner_id and ids: |
2808 | + line_ids = line_pool.search(cr, uid, [('voucher_id','=',ids[0])]) |
2809 | + if line_ids: |
2810 | + line_pool.unlink(cr, uid, line_ids) |
2811 | + return default |
2812 | + |
2813 | + journal = journal_pool.browse(cr, uid, journal_id, context=context) |
2814 | + partner = partner_pool.browse(cr, uid, partner_id, context=context) |
2815 | + account_id = False |
2816 | + if journal.type in ('sale','sale_refund'): |
2817 | + account_id = partner.property_account_receivable.id |
2818 | + elif journal.type in ('purchase', 'purchase_refund','expense'): |
2819 | + account_id = partner.property_account_payable.id |
2820 | + elif journal.type in ('cash', 'bank'): |
2821 | + account_id = journal.default_debit_account_id.id |
2822 | + else: |
2823 | + account_id = journal.default_credit_account_id.id or journal.default_debit_account_id.id |
2824 | + |
2825 | + if journal and not default['value']['currency_id']: |
2826 | + default['value']['currency_id'] = journal.company_id.currency_id.id |
2827 | + default['value']['account_id'] = account_id |
2828 | + if journal.type not in ('cash', 'bank'): |
2829 | + return default |
2830 | + |
2831 | + total_credit = 0.0 |
2832 | + total_debit = 0.0 |
2833 | + account_type = 'receivable' |
2834 | + if ttype == 'payment': |
2835 | + account_type = 'payable' |
2836 | + total_debit = price or 0.0 |
2837 | + else: |
2838 | + total_credit = price or 0.0 |
2839 | + account_type = 'receivable' |
2840 | + |
2841 | + if partner._columns.has_key('nat_acc_parent') and partner.nat_acc_parent: |
2842 | + partner_ids = partner_pool.search(cr,uid,[('parent_id','child_of',[partner_id])]) |
2843 | + else: |
2844 | + partner_ids = [partner_id] |
2845 | + ids = move_line_pool.search(cr, uid, [('account_id.type','=', account_type), ('reconcile_id','=', False), ('partner_id','in',partner_ids)], context=context) |
2846 | + ids.reverse() |
2847 | + moves = move_line_pool.browse(cr, uid, ids) |
2848 | + |
2849 | + company_currency = journal.company_id.currency_id.id |
2850 | + if company_currency != currency_id and ttype == 'payment': |
2851 | + total_debit = currency_pool.compute(cr, uid, currency_id, company_currency, total_debit, context=context_multi_currency) |
2852 | + elif company_currency != currency_id and ttype == 'receipt': |
2853 | + total_credit = currency_pool.compute(cr, uid, currency_id, company_currency, total_credit, context=context_multi_currency) |
2854 | + |
2855 | + for line in moves: |
2856 | + if line.credit and line.reconcile_partial_id and ttype == 'receipt': |
2857 | + continue |
2858 | + if line.debit and line.reconcile_partial_id and ttype == 'payment': |
2859 | + continue |
2860 | + total_credit += line.credit or 0.0 |
2861 | + total_debit += line.debit or 0.0 |
2862 | + |
2863 | + for line in moves: |
2864 | + if line.credit and line.reconcile_partial_id and ttype == 'receipt': |
2865 | + continue |
2866 | + if line.debit and line.reconcile_partial_id and ttype == 'payment': |
2867 | + continue |
2868 | + |
2869 | + original_amount = line.credit or line.debit or 0.0 |
2870 | + rs = { |
2871 | + 'name':line.move_id.name, |
2872 | + 'type': line.credit and 'dr' or 'cr', |
2873 | + 'move_line_id':line.id, |
2874 | + 'account_id':line.account_id.id, |
2875 | + 'amount_original':currency_pool.compute(cr, uid, company_currency, currency_id, original_amount, context=context_multi_currency), |
2876 | + 'date_original':line.date, |
2877 | + 'date_due':line.date_maturity, |
2878 | + 'amount_unreconciled':currency_pool.compute(cr, uid, company_currency, currency_id, line.amount_unreconciled, context=context_multi_currency) |
2879 | + } |
2880 | + |
2881 | + def calc_amount(line, total): |
2882 | + return min(line.amount_unreconciled, total) |
2883 | + |
2884 | + if line.credit: |
2885 | + amount = calc_amount(line, total_debit) |
2886 | + rs['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount, context=context_multi_currency) |
2887 | + total_debit -= amount |
2888 | + else: |
2889 | + amount = calc_amount(line, total_credit) |
2890 | + rs['amount'] = currency_pool.compute(cr, uid, company_currency, currency_id, amount, context=context_multi_currency) |
2891 | + total_credit -= amount |
2892 | + |
2893 | + default['value']['line_ids'].append(rs) |
2894 | + if rs['type'] == 'cr': |
2895 | + default['value']['line_cr_ids'].append(rs) |
2896 | + else: |
2897 | + default['value']['line_dr_ids'].append(rs) |
2898 | + |
2899 | + if ttype == 'payment' and len(default['value']['line_cr_ids']) > 0: |
2900 | + default['value']['pre_line'] = 1 |
2901 | + elif ttype == 'receipt' and len(default['value']['line_dr_ids']) > 0: |
2902 | + default['value']['pre_line'] = 1 |
2903 | + for credit_line in default['value']['line_dr_ids']: |
2904 | + credit_line['amount'] = 0.0 |
2905 | + for invoice_line in default['value']['line_cr_ids']: |
2906 | + invoice_line['amount'] = 0.0 |
2907 | + invoice_line['amount_difference'] = invoice_line['amount_unreconciled'] |
2908 | + |
2909 | + return default |
2910 | + |
2911 | + def calc_cash_discount(self, vch, line, amount=0): |
2912 | + # hook method for cash discount |
2913 | + return 0.0 |
2914 | + |
2915 | + def calc_interest(self, vch, line, amount=0): |
2916 | + # hook method for interest posting |
2917 | + return 0.0 |
2918 | + |
2919 | + def action_move_line_create(self, cr, uid, ids, context=None): |
2920 | + ''' |
2921 | + Function overridden from account voucher module |
2922 | + account posting include amount after currency conversion |
2923 | + TODO : Function need more analysis and testing |
2924 | + ''' |
2925 | + |
2926 | + def _get_payment_term_lines(term_id, amount): |
2927 | + term_pool = self.pool.get('account.payment.term') |
2928 | + if term_id and amount: |
2929 | + terms = term_pool.compute(cr, uid, term_id, amount) |
2930 | + return terms |
2931 | + return False |
2932 | + if not context: |
2933 | + context = {} |
2934 | + move_pool = self.pool.get('account.move') |
2935 | + move_line_pool = self.pool.get('account.move.line') |
2936 | + analytic_pool = self.pool.get('account.analytic.line') |
2937 | + currency_pool = self.pool.get('res.currency') |
2938 | + invoice_pool = self.pool.get('account.invoice') |
2939 | + company_pool = self.pool.get('res.company') |
2940 | + for vch in self.browse(cr, uid, ids): |
2941 | + if vch.move_id: |
2942 | + continue |
2943 | + |
2944 | + if 'force_name' in context and context['force_name']: |
2945 | + name = context['force_name'] |
2946 | + elif vch.journal_id.sequence_id: |
2947 | + name = self.pool.get('ir.sequence').get_id(cr, uid, vch.journal_id.sequence_id.id) |
2948 | + else: |
2949 | + raise osv.except_osv(_('Error !'), _('Please define a sequence on the journal !')) |
2950 | + |
2951 | + move = { |
2952 | + 'name' : name, |
2953 | + 'journal_id': vch.journal_id.id, |
2954 | + 'narration' : vch.narration, |
2955 | + 'date':vch.date, |
2956 | + 'ref':vch.reference, |
2957 | + 'period_id': vch.period_id and vch.period_id.id or False |
2958 | + } |
2959 | + move_id = move_pool.create(cr, uid, move) |
2960 | + |
2961 | + #create the first line manually |
2962 | + company_currency = vch.journal_id.company_id.currency_id.id |
2963 | + debit = 0.0 |
2964 | + credit = 0.0 |
2965 | + # TODO: is there any other alternative then the voucher type ?? |
2966 | + # -for sale, purchase we have but for the payment and receipt we do not have as based on the bank/cash journal we can not know its payment or receipt |
2967 | + if vch.type in ('purchase', 'payment'): |
2968 | + credit = currency_pool.compute(cr, uid, vch.currency_id.id, company_currency, vch.amount) |
2969 | + elif vch.type in ('sale', 'receipt'): |
2970 | + debit = currency_pool.compute(cr, uid, vch.currency_id.id, company_currency, vch.amount) |
2971 | + if debit < 0: |
2972 | + credit = -debit |
2973 | + debit = 0.0 |
2974 | + if credit < 0: |
2975 | + debit = -credit |
2976 | + credit = 0.0 |
2977 | + move_line = { |
2978 | + 'name':vch.name or '/', |
2979 | + 'debit':debit, |
2980 | + 'credit':credit, |
2981 | + 'account_id':vch.account_id.id, |
2982 | + 'move_id':move_id , |
2983 | + 'journal_id':vch.journal_id.id, |
2984 | + 'period_id':vch.period_id.id, |
2985 | + 'partner_id':vch.partner_id.id, |
2986 | + 'currency_id':vch.currency_id.id, |
2987 | + 'amount_currency':vch.amount, |
2988 | + 'date':vch.date, |
2989 | + 'date_maturity':vch.date_due |
2990 | + } |
2991 | + |
2992 | + if (debit == 0.0 or credit == 0.0 or debit+credit > 0) and (debit > 0.0 or credit > 0.0): |
2993 | + master_line = move_line_pool.create(cr, uid, move_line) |
2994 | + company = company_pool.browse(cr, uid, vch.company_id.id, context) |
2995 | + rec_list_ids = [] |
2996 | + line_total = debit - credit |
2997 | + if vch.type == 'sale': |
2998 | + line_total = line_total - currency_pool.compute(cr, uid, vch.currency_id.id, company_currency, vch.tax_amount) |
2999 | + elif vch.type == 'purchase': |
3000 | + line_total = line_total + currency_pool.compute(cr, uid, vch.currency_id.id, company_currency, vch.tax_amount) |
3001 | + |
3002 | + writeoff_ids = [] |
3003 | + for line in vch.line_ids: |
3004 | + if not line.amount: |
3005 | + skip_flag = True |
3006 | + if line.available_credits: |
3007 | + for av_credits in line.available_credits: |
3008 | + if av_credits.use_credit and av_credits.discount_amount: |
3009 | + skip_flag=False |
3010 | + if skip_flag: |
3011 | + continue |
3012 | + amount_cash_discount = 0.0#self.calc_cash_discount(line, line.amount) |
3013 | + amount_writeoff = 0.0#calc_writeoff(line, amount_cash_discount) |
3014 | + amount_interest = 0.0#calc_interest(line, amount_cash_discount + amount_writeoff) |
3015 | + amount_currency = currency_pool.compute(cr, uid, vch.currency_id.id, company_currency, line.amount) |
3016 | + amount = amount_currency |
3017 | + move_line = { |
3018 | + 'journal_id':vch.journal_id.id, |
3019 | + 'period_id':vch.period_id.id, |
3020 | + 'name':line.name and line.name or '/', |
3021 | + 'account_id':line.account_id.id, |
3022 | + 'move_id':move_id, |
3023 | + 'partner_id':vch.partner_id.id, |
3024 | + 'currency_id':vch.currency_id.id, |
3025 | + #Posting amount after currency conversion |
3026 | + 'amount_currency':amount, |
3027 | + 'analytic_account_id':line.account_analytic_id and line.account_analytic_id.id or False, |
3028 | + 'quantity':1, |
3029 | + 'credit':0.0, |
3030 | + 'debit':0.0, |
3031 | + 'date':vch.date |
3032 | + } |
3033 | + if line.invoice_id: |
3034 | + move_line['partner_id'] = line.invoice_id.partner_id.id |
3035 | + if amount < 0: |
3036 | + amount = -amount |
3037 | + if line.type == 'dr': |
3038 | + line.type = 'cr' |
3039 | + else: |
3040 | + line.type = 'dr' |
3041 | + |
3042 | + if (line.type=='dr'): |
3043 | + line_total += amount |
3044 | + move_line['debit'] = amount |
3045 | + else: |
3046 | + line_total -= (amount+line.credit_used) |
3047 | + move_line['credit'] = (amount+line.credit_used) |
3048 | + |
3049 | + if vch.tax_id and vch.type in ('sale', 'purchase'): |
3050 | + move_line.update({ |
3051 | + 'account_tax_id':vch.tax_id.id, |
3052 | + }) |
3053 | + |
3054 | + if line_total < 0.01 and line_total > -0.01: |
3055 | + line_total = 0.0 |
3056 | + |
3057 | + master_line = move_line_pool.create(cr, uid, move_line) |
3058 | + if line.move_line_id.id: |
3059 | + rec_ids = [master_line, line.move_line_id.id] |
3060 | + rec_list_ids.append(rec_ids) |
3061 | + |
3062 | + if line.invoice_id.id: |
3063 | + invoice = self.pool.get('account.invoice').browse(cr, uid, line.invoice_id.id) |
3064 | + types = {'out_invoice': -1, 'in_invoice': 1, 'out_refund': 1, 'in_refund': -1} |
3065 | + direction = types[invoice.type] |
3066 | + |
3067 | + ''' |
3068 | + Post Discount Lines for supplier |
3069 | + ''' |
3070 | + |
3071 | + if line.type == 'dr' and line._columns.has_key('available_discounts') and line.available_discounts: # and line.cash_discount > 0.0: |
3072 | + for available_discounts in line.available_discounts: |
3073 | + if available_discounts.use_discount: |
3074 | + l1 = { |
3075 | + 'journal_id':vch.journal_id.id, |
3076 | + 'period_id':vch.period_id.id, |
3077 | + 'debit': direction * available_discounts.discount_amount>0 and direction * available_discounts.discount_amount, |
3078 | + 'credit': direction * available_discounts.discount_amount<0 and - direction * available_discounts.discount_amount, |
3079 | + 'account_id': line.account_id.id, |
3080 | + 'partner_id': line.move_line_id.partner_id.id, #line.partner_id.id, |
3081 | + 'move_id':move_id, |
3082 | + 'ref':'Cash Discount', |
3083 | + 'name':line.name and line.name or '/', |
3084 | + 'date': vch.date, |
3085 | + 'currency_id':vch.currency_id.id, |
3086 | + 'amount_currency':available_discounts.discount_amount and - direction * available_discounts.discount_amount or 0.0, |
3087 | + 'company_id': line.company_id.id, |
3088 | + } |
3089 | + l2 = { |
3090 | + 'journal_id':vch.journal_id.id, |
3091 | + 'period_id':vch.period_id.id, |
3092 | + 'debit': direction * available_discounts.discount_amount<0 and - direction * available_discounts.discount_amount, |
3093 | + 'credit': direction * available_discounts.discount_amount>0 and direction * available_discounts.discount_amount, |
3094 | + 'account_id': available_discounts.gl_account.id, |
3095 | + 'partner_id': line.move_line_id.partner_id.id, |
3096 | + 'move_id':move_id, |
3097 | + 'ref':'Cash Discount', |
3098 | + 'name':line.name and line.name or '/', |
3099 | + 'date': vch.date, |
3100 | + 'currency_id':vch.currency_id.id, |
3101 | + 'amount_currency':available_discounts.discount_amount and - direction * available_discounts.discount_amount or 0.0, |
3102 | + 'company_id': line.company_id.id, |
3103 | + } |
3104 | + name = invoice.number |
3105 | + l1['name'] = name |
3106 | + l2['name'] = name |
3107 | + move_lines = [l1,l2] |
3108 | + for move_line in move_lines: |
3109 | + master_line = move_line_pool.create(cr, uid, move_line) |
3110 | + if line.move_line_id.id and move_line['account_id'] == line.move_line_id.account_id.id: |
3111 | + rec_ids = [master_line, line.move_line_id.id] |
3112 | + rec_list_ids.append(rec_ids) |
3113 | + |
3114 | + |
3115 | + |
3116 | + ''' |
3117 | + Post Discount Lines for customer |
3118 | + ''' |
3119 | + |
3120 | + |
3121 | + if line.type == 'cr' and line._columns.has_key('available_discounts') and line.available_discounts: # and line.cash_discount > 0.0: |
3122 | + for available_discounts in line.available_discounts: |
3123 | + if available_discounts.use_discount: |
3124 | + l1 = { |
3125 | + 'journal_id':vch.journal_id.id, |
3126 | + 'period_id':vch.period_id.id, |
3127 | + 'debit': direction * available_discounts.discount_amount>0 and direction * available_discounts.discount_amount, |
3128 | + 'credit': direction * available_discounts.discount_amount<0 and - direction * available_discounts.discount_amount, |
3129 | + 'account_id': line.account_id.id, |
3130 | + 'partner_id': line.move_line_id.partner_id.id, #line.partner_id.id, |
3131 | + 'move_id':move_id, |
3132 | + 'ref':'Cash Discount', |
3133 | + 'name':line.name and line.name or '/', |
3134 | + 'date': vch.date, |
3135 | + 'currency_id':vch.currency_id.id, |
3136 | + 'amount_currency':available_discounts.discount_amount and - direction * available_discounts.discount_amount or 0.0, |
3137 | + 'company_id': line.company_id.id, |
3138 | + } |
3139 | + l2 = { |
3140 | + 'journal_id':vch.journal_id.id, |
3141 | + 'period_id':vch.period_id.id, |
3142 | + 'debit': direction * available_discounts.discount_amount<0 and - direction * available_discounts.discount_amount, |
3143 | + 'credit': direction * available_discounts.discount_amount>0 and direction * available_discounts.discount_amount, |
3144 | + 'account_id': available_discounts.gl_account.id, |
3145 | + 'partner_id': line.move_line_id.partner_id.id, |
3146 | + 'move_id':move_id, |
3147 | + 'ref':'Cash Discount', |
3148 | + 'name':line.name and line.name or '/', |
3149 | + 'date': vch.date, |
3150 | + 'currency_id':vch.currency_id.id, |
3151 | + 'amount_currency':available_discounts.discount_amount and - direction * available_discounts.discount_amount or 0.0, |
3152 | + 'company_id': line.company_id.id, |
3153 | + } |
3154 | + name = invoice.number |
3155 | + l1['name'] = name |
3156 | + l2['name'] = name |
3157 | + move_lines = [l1,l2] |
3158 | + for move_line in move_lines: |
3159 | + master_line = move_line_pool.create(cr, uid, move_line) |
3160 | + if line.move_line_id.id and move_line['account_id'] == line.move_line_id.account_id.id: |
3161 | + rec_ids = [master_line, line.move_line_id.id] |
3162 | + rec_list_ids.append(rec_ids) |
3163 | + ''' |
3164 | + Post Writeoff |
3165 | + ''' |
3166 | + if line.type == 'cr' and line._columns.has_key('writeoff_ids') and line.writeoff_ids: |
3167 | + for writeoff in line.writeoff_ids: |
3168 | + l1 = { |
3169 | + 'journal_id':vch.journal_id.id, |
3170 | + 'period_id':vch.period_id.id, |
3171 | + 'debit': direction * writeoff.writeoff_amount>0 and direction * writeoff.writeoff_amount, |
3172 | + 'credit': direction * writeoff.writeoff_amount<0 and - direction * writeoff.writeoff_amount, |
3173 | + 'account_id': line.account_id.id, |
3174 | + 'partner_id': line.move_line_id.partner_id.id, #, |
3175 | + 'move_id':move_id, |
3176 | + 'ref':'Writeoff', |
3177 | + 'name':line.name and line.name or '/', |
3178 | + 'date': vch.date, |
3179 | + 'currency_id':vch.currency_id.id, |
3180 | + 'amount_currency':writeoff.writeoff_amount and - direction * writeoff.writeoff_amount or 0.0, |
3181 | + 'company_id': line.company_id.id, |
3182 | + } |
3183 | + l2 = { |
3184 | + 'journal_id':vch.journal_id.id, |
3185 | + 'period_id':vch.period_id.id, |
3186 | + 'debit': direction * writeoff.writeoff_amount<0 and - direction * writeoff.writeoff_amount, |
3187 | + 'credit': direction * writeoff.writeoff_amount>0 and direction * writeoff.writeoff_amount, |
3188 | + 'account_id': writeoff.gl_account.id, |
3189 | + 'partner_id': line.partner_id.id, |
3190 | + 'move_id':move_id, |
3191 | + 'ref':'Writeoff', |
3192 | + 'name':line.name and line.name or '/', |
3193 | + 'date': vch.date, |
3194 | + 'currency_id':vch.currency_id.id, |
3195 | + 'amount_currency':writeoff.writeoff_amount and - direction * writeoff.writeoff_amount or 0.0, |
3196 | + 'company_id': line.company_id.id, |
3197 | + } |
3198 | + name = invoice.number |
3199 | + l1['name'] = name |
3200 | + l2['name'] = name |
3201 | + move_lines = [l1,l2] |
3202 | + for move_line in move_lines: |
3203 | + master_line = move_line_pool.create(cr, uid, move_line) |
3204 | + if line.move_line_id.id and move_line['account_id'] == line.move_line_id.account_id.id: |
3205 | + rec_ids = [master_line, line.move_line_id.id] |
3206 | + rec_list_ids.append(rec_ids) |
3207 | + |
3208 | + if line.type == 'dr': |
3209 | + line.write({ 'pending_credits':0}) |
3210 | + |
3211 | + diff = line_total |
3212 | + if not self.pool.get('res.currency').is_zero(cr, uid, vch.currency_id, line_total): |
3213 | + move_line = { |
3214 | + 'name':name, |
3215 | + 'account_id':False, |
3216 | + 'move_id':move_id , |
3217 | + 'partner_id':vch.partner_id.id, |
3218 | + 'date':vch.date, |
3219 | + 'credit':diff>0 and diff or 0.0, |
3220 | + 'debit':diff<0 and -diff or 0.0, |
3221 | + } |
3222 | + account_id = False |
3223 | + if vch.type in ('sale', 'receipt'): |
3224 | + account_id = vch.partner_id.property_account_receivable.id |
3225 | + else: |
3226 | + account_id = vch.partner_id.property_account_payable.id |
3227 | + move_line['account_id'] = account_id |
3228 | + move_line_id = move_line_pool.create(cr, uid, move_line) |
3229 | +# if line.move_line_id.id: |
3230 | +# rec_ids = [move_line, line.move_line_id.id] |
3231 | +# rec_list_ids.append(rec_ids) |
3232 | + |
3233 | + self.write(cr, uid, [vch.id], { |
3234 | + 'move_id': move_id, |
3235 | + 'state':'posted' |
3236 | + }) |
3237 | + move_pool.post(cr, uid, [move_id], context={}) |
3238 | + |
3239 | + # let's see if we can incorporate this in the reconciliation |
3240 | + #diff = 0 |
3241 | + if diff > 0.0: |
3242 | + diff = line_total |
3243 | + rec_ids = [] |
3244 | + debit_ids = [] |
3245 | + applied_amount = 0.0 |
3246 | + move = move_pool.browse(cr, uid, move_id, context={}) |
3247 | + for line in move.line_id: |
3248 | + if line.account_id.id == vch.journal_id.default_credit_account_id.id: |
3249 | + applied_amount += line.debit |
3250 | + if line.id and line.credit > 0.0: |
3251 | + if line.id not in rec_ids: |
3252 | + rec_ids.append(line.id) |
3253 | + if line.id and line.debit > 0.0: |
3254 | + if line.id not in debit_ids: |
3255 | + debit_ids.append(line.id) |
3256 | + if applied_amount == diff: |
3257 | + for vchcr in vch.line_cr_ids: |
3258 | + if vchcr.amount and vchcr.move_line_id.id not in rec_ids: |
3259 | + rec_ids.append(vchcr.move_line_id.id) |
3260 | + for vchdr in vch.line_dr_ids: |
3261 | + if vchdr.amount and vchdr.move_line_id.id not in debit_ids: |
3262 | + debit_ids.append(vchdr.move_line_id.id) |
3263 | + rec_list_ids = [rec_ids, debit_ids] |
3264 | + for rec_ids in rec_list_ids: |
3265 | + if len(rec_ids) >= 2: |
3266 | + move_line_pool.reconcile_partial(cr, uid, rec_ids) |
3267 | + return True |
3268 | + |
3269 | +account_voucher() |
3270 | + |
3271 | +class account_voucher_line(osv.osv): |
3272 | + _inherit = 'account.voucher.line' |
3273 | + _order = "date_due" |
3274 | + |
3275 | + |
3276 | + def _update_credit_lines(self,cr, uid, ids, context): |
3277 | + ''' |
3278 | + Create or update the list of credit that can be used under each voucher line. |
3279 | + To be called from the calculate/re-calculate action |
3280 | + ''' |
3281 | + credits_used_pool = self.pool.get('account.voucher.line.credits_to_use') |
3282 | + for line in self.browse(cr , uid, ids, context): |
3283 | + credits_lines_used = [x.orginal_credit_line_id.id for x in line.available_credits] |
3284 | + for credit_line in line.voucher_id.line_dr_ids : |
3285 | + if credit_line.id not in credits_lines_used and line.invoice_id and line.invoice_id.payment_term: |
3286 | + # |
3287 | + credits_used_pool.create(cr, uid, { |
3288 | + 'voucher_line_id': line.id, |
3289 | + 'orginal_credit_line_id':credit_line.id, |
3290 | + 'use_credit': False, |
3291 | + 'inv_credit': credit_line.move_line_id.id, |
3292 | + 'discount_window_date': credit_line.date_original, |
3293 | + 'orginal_amount': credit_line.amount_original, |
3294 | + 'available_amount': credit_line.amount_unreconciled - credit_line.pending_credits, |
3295 | + 'discount_amount': 0.0, |
3296 | + 'gl_account' : credit_line.account_id.id,}) |
3297 | + else : |
3298 | + 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) |
3299 | + if to_update_credit_line_ids: |
3300 | + credits_used_pool.write(cr, uid,to_update_credit_line_ids,{'available_amount': credit_line.amount_unreconciled-credit_line.pending_credits}, context=context) |
3301 | + |
3302 | + |
3303 | + def write(self, cr, user, ids, vals, context=None): |
3304 | + ''' |
3305 | + Add invoice and description in payment modification line |
3306 | + ''' |
3307 | + if type(ids) == type([]): |
3308 | + move = self.browse(cr, user,ids[0]).move_line_id |
3309 | + else: |
3310 | + move = self.browse(cr, user,ids).move_line_id |
3311 | + if move: |
3312 | + vals['invoice_id'] = move.invoice and move.invoice.id |
3313 | + vals['name'] = move.invoice and move.invoice.number |
3314 | + |
3315 | + return super(account_voucher_line, self).write(cr, user, ids, vals, context) |
3316 | + |
3317 | + def create(self, cr, user, vals, context=None): |
3318 | + ''' |
3319 | + Add invoice and description in payment modification line |
3320 | + ''' |
3321 | + if vals.has_key('move_line_id') and vals['move_line_id']: |
3322 | + move = self.pool.get('account.move.line').browse(cr, user,vals['move_line_id']) |
3323 | + vals['invoice_id'] = move.invoice and move.invoice.id |
3324 | + vals['name'] = move.invoice and move.invoice.number |
3325 | + return super(account_voucher_line, self).create(cr, user, vals, context) |
3326 | + |
3327 | + def calc_amt(self, cr, uid, ids, context={}): |
3328 | + ''' |
3329 | + Function to calculate Pending Credits Used |
3330 | + can be removed : Not used anymore : verify first |
3331 | + ''' |
3332 | + res = {} |
3333 | + result = 0.0 |
3334 | + |
3335 | + for id in ids: |
3336 | + res[id] = result |
3337 | + return res |
3338 | + |
3339 | + def _credits_calc(self, cr, uid, ids, name, args, context): |
3340 | + ''' |
3341 | + Function to calculate Pending Credits Used |
3342 | + ''' |
3343 | + credits_used_pool = self.pool.get('account.voucher.line.credits_to_use') |
3344 | + res={} |
3345 | + for line in self.browse(cr, uid, ids): |
3346 | + credits_used_ids = credits_used_pool.search(cr, uid, [('orginal_credit_line_id','=',line.id)]) |
3347 | + res[line.id] = 0.0 |
3348 | + if line.voucher_id.state != 'draft': |
3349 | + continue |
3350 | + for credit_used in credits_used_pool.browse(cr, uid, credits_used_ids, context=context): |
3351 | + if credit_used.use_credit: |
3352 | + res[line.id] += credit_used.discount_amount |
3353 | + return res |
3354 | + def _compute_credit_used(self, cr, uid, ids, name, args, context=None): |
3355 | + ''' |
3356 | + Field function for credit_used |
3357 | + ''' |
3358 | + res = {} |
3359 | + for line in self.browse(cr, uid, ids): |
3360 | + res[line.id] = 0.0 |
3361 | + for credit_line in line.available_credits: |
3362 | + if credit_line.use_credit : |
3363 | + res[line.id] += credit_line.discount_amount |
3364 | + return res |
3365 | + |
3366 | + def _compute_balance(self, cr, uid, ids, name, args, context=None): |
3367 | + ''' |
3368 | + Field function [multi] to calculate amount_original, amount_unreconciled and amount_difference |
3369 | + ''' |
3370 | + currency_pool = self.pool.get('res.currency') |
3371 | + rs_data = {} |
3372 | + for line in self.browse(cr, uid, ids): |
3373 | + ctx = context.copy() |
3374 | + ctx.update({'date': line.voucher_id.date}) |
3375 | + res = {} |
3376 | + company_currency = line.voucher_id.journal_id.company_id.currency_id.id |
3377 | + voucher_currency = line.voucher_id.currency_id.id |
3378 | + move_line = line.move_line_id or False |
3379 | + if not move_line: |
3380 | + res['amount_original'] = 0.0 |
3381 | + res['amount_unreconciled'] = 0.0 |
3382 | + |
3383 | + elif move_line and move_line.credit > 0: |
3384 | + res['amount_original'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.credit, context=ctx) |
3385 | + else: |
3386 | + res['amount_original'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.debit, context=ctx) |
3387 | + |
3388 | + if move_line: |
3389 | + res['amount_unreconciled'] = currency_pool.compute(cr, uid, company_currency, voucher_currency, move_line.amount_unreconciled - line.pending_credits , context=ctx) |
3390 | + if line.amount > 0.0: |
3391 | + res['amount_difference'] = res['amount_unreconciled'] - line.amount - line.credit_used |
3392 | + else: |
3393 | + res['amount_difference'] = 0.0 |
3394 | + rs_data[line.id] = res |
3395 | + return rs_data |
3396 | + |
3397 | + def _get_due_date(self, cr, uid, ids, context=None): |
3398 | + ''' |
3399 | + Store function to identify the voucher lines that need recalculation of date_due in the case of any change on account move line |
3400 | + Fixme: make sure that it return a list of voucher line id only |
3401 | + ''' |
3402 | + result = {} |
3403 | + for line in self.pool.get('account.move.line').browse(cr, uid, ids, context=context): |
3404 | +# result[line.invoice_id.id] = True ##Changed by Jabir to fix error when clicking Post button from Customer Payment form. 2010/11/24 |
3405 | + result[line.invoice.id] = True |
3406 | + return result.keys() |
3407 | + |
3408 | + def _compute_discount_used(self, cr, uid, ids, name, args, context=None): |
3409 | + ''' |
3410 | + Field function to calculate discount_used |
3411 | + Hook function : to be redefined on account_cash_discount_us |
3412 | + ''' |
3413 | + res = {} |
3414 | + for id in ids: |
3415 | + res[id] = 0.0 |
3416 | + return res |
3417 | + def _calc_writeoff(self, cr, uid, ids, name, args, context): |
3418 | + ''' |
3419 | + Field function to calculate writeoff_amount |
3420 | + Hook function : to be redefined on account_voucher_writeoff_us |
3421 | + ''' |
3422 | + res={} |
3423 | + for id in ids: |
3424 | + res[id] = 0.0 |
3425 | + return res |
3426 | + |
3427 | + |
3428 | + def _order_compute_credit_used(self, cr, uid, ids, context=None): |
3429 | + """ |
3430 | + Store function - Field : credit_used, model : account.voucher.line.credits_to_use |
3431 | + """ |
3432 | + operation_ids = [] |
3433 | + for credits_to_use in self.pool.get('account.voucher.line.credits_to_use').browse(cr,uid,ids,context=context): |
3434 | + operation_ids.append(credits_to_use.voucher_line_id and credits_to_use.voucher_line_id.id) |
3435 | + return operation_ids |
3436 | + |
3437 | + def _get_voucher_line_ids(self, cr, uid, ids, context=None): |
3438 | + ''' |
3439 | + Store function - field : company_id, model :account.voucher |
3440 | + ''' |
3441 | + result = [] |
3442 | + for vch_lines in self.pool.get('account.voucher').read(cr, uid, ids, ['line_ids'], context=context): |
3443 | + result +=vch_lines['line_ids'] |
3444 | + return result |
3445 | + |
3446 | + _columns = { |
3447 | + 'invoice_id': fields.many2one('account.invoice', 'Invoice'), |
3448 | + 'account_id':fields.many2one('account.account','G/L Account', required=True), |
3449 | + 'amount':fields.float('Payment Amt', digits=(14,2), required=True), |
3450 | + 'date_due': fields.related('move_line_id','date_maturity', type='date', relation='account.move.line', string='Due Date', readonly=True , store={ |
3451 | + 'account.voucher.line': (lambda self, cr, uid, ids, c={}: ids, ['move_line_id'], 20), |
3452 | + 'account.move.line': (_get_due_date, ['date_maturity'], 20), |
3453 | + }), |
3454 | + 'amount_original': fields.function(_compute_balance, method=True, multi='dc', type='float', string='Original Amt', store=True, readonly=True), |
3455 | + 'amount_unreconciled': fields.function(_compute_balance, method=True, multi='dc', type='float', string='Amt Due', store=True, readonly=True), |
3456 | + 'company_id': fields.related('voucher_id','company_id',type='many2one', relation='res.company', string='Company', store={ |
3457 | + 'account.voucher': (_get_voucher_line_ids, ['company_id'], 20), |
3458 | + }), |
3459 | + 'credit_used': fields.function(_compute_credit_used, method=True, type='float', string='Credit Used', |
3460 | + store={'account.voucher.line.credits_to_use':(_order_compute_credit_used,['use_credit','discount_amount'], 10)}, readonly=True), |
3461 | + 'amount_difference': fields.function(_compute_balance, method=True, multi='dc', type='float', string='Unpaid Amt', digits=(16, 2) ), |
3462 | + 'writeoff': fields.boolean("Writeoff"), |
3463 | + 'pay': fields.boolean("Pay", required=True), |
3464 | + 'pending_credits':fields.function(_credits_calc, method=True, string='Pending Credits Used', type='float'), |
3465 | + 'available_credits':fields.one2many('account.voucher.line.credits_to_use', 'voucher_line_id', 'Available credits' ), |
3466 | + 'discount_used': fields.function(_compute_discount_used, method=True, type='float', string='Discount Used', store=False, readonly=True), |
3467 | + 'writeoff_amount':fields.function(_calc_writeoff, method=True, string='Write-off Amt', type='float', store=False,), |
3468 | + } |
3469 | + |
3470 | + def recalculate_values(self, cr, uid, ids, context={}): |
3471 | + ''' |
3472 | + Re-calculate button action |
3473 | + ''' |
3474 | + if type(ids) == type([]): |
3475 | + voucher_line = self.browse(cr,uid,ids[0]) |
3476 | + else: |
3477 | + voucher_line = self.browse(cr,uid,ids) |
3478 | + self.pool.get('account.voucher').calc_diff(cr, uid, [voucher_line.voucher_id.id]) |
3479 | + return True |
3480 | + def clear_values(self, cr, uid, ids, context={}): |
3481 | + ''' |
3482 | + Clear all selected discounts, credits and writeoffs and manually entered values |
3483 | + ''' |
3484 | + voucher_line = self.browse(cr,uid,ids[0]) |
3485 | + if voucher_line._columns.has_key('writeoff_ids'): |
3486 | + if voucher_line._columns.has_key('available_discounts'): |
3487 | + for lines in self.read(cr,uid,ids,['available_credits','writeoff_ids','available_discounts']): |
3488 | + lines['writeoff_ids'] and self.pool.get('account.voucher.line.writeoff').unlink(cr,uid,lines['writeoff_ids']) |
3489 | + lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'], |
3490 | + {'use_credit':False, 'discount_amount':0.0}) |
3491 | + lines['available_discounts'] and self.pool.get('account.voucher.line.discount_to_use').write(cr,uid,lines['available_discounts'], |
3492 | + {'use_discount':False, 'discount_amount':0.0}) |
3493 | + else: |
3494 | + for lines in self.read(cr,uid,ids,['available_credits','writeoff_ids']): |
3495 | + lines['writeoff_ids'] and self.pool.get('account.voucher.line.writeoff').unlink(cr,uid,lines['writeoff_ids']) |
3496 | + lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'], |
3497 | + {'use_credit':False, 'discount_amount':0.0}) |
3498 | + elif voucher_line._columns.has_key('available_discounts'): |
3499 | + for lines in self.read(cr,uid,ids,['available_credits','available_discounts']): |
3500 | + lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'], |
3501 | + {'use_credit':False, 'discount_amount':0.0}) |
3502 | + lines['available_discounts'] and self.pool.get('account.voucher.line.discount_to_use').write(cr,uid,lines['available_discounts'], |
3503 | + {'use_discount':False, 'discount_amount':0.0}) |
3504 | + else: |
3505 | + for lines in self.read(cr,uid,ids,['available_credits']): |
3506 | + lines['available_credits'] and self.pool.get('account.voucher.line.credits_to_use').write(cr,uid,lines['available_credits'], |
3507 | + {'use_credit':False, 'discount_amount':0.0}) |
3508 | + return True |
3509 | + |
3510 | + def onchange_pay(self, cr, uid, ids, line_amount, pay, amount_unreconciled,par_cr_ids, par_amount, credit_used, discount_used=0, writeoff_amount=0, context={}): |
3511 | + ''' |
3512 | + Function to automatically fill the values when the pay checkbox is selected |
3513 | + ''' |
3514 | + ret = {} |
3515 | + writeoff_amount = (not writeoff_amount and [0] or [writeoff_amount])[0] |
3516 | + discount_used = (not discount_used and [0] or [discount_used])[0] |
3517 | + credit_used = (not credit_used and [0] or [credit_used])[0] |
3518 | + if pay: |
3519 | + tot_amt = par_amount + line_amount |
3520 | + for credit in par_cr_ids: |
3521 | + if credit[2]['pay']: |
3522 | + tot_amt -= (credit[2]['amount']) |
3523 | + if tot_amt < 0: |
3524 | + ret['amount'] = 0.0 |
3525 | + else: |
3526 | + amount_unreconciled -= (discount_used+writeoff_amount+credit_used) |
3527 | + ret['amount'] = min(tot_amt,(amount_unreconciled<0) and 0 or amount_unreconciled) |
3528 | + else: |
3529 | + ret['amount'] = 0.0 |
3530 | + return {'value':ret} |
3531 | + |
3532 | + |
3533 | + |
3534 | +account_voucher_line() |
3535 | + |
3536 | +class account_bank_statement(osv.osv): |
3537 | + _inherit = 'account.bank.statement' |
3538 | + |
3539 | + def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, next_number, context=None): |
3540 | + ''' |
3541 | + TODO : Need careful testing of this function. |
3542 | + ''' |
3543 | +# st_line = self.pool.get('account.bank.statement.line').browse(cr, uid, st_line_id, context=context) |
3544 | +# if st_line.voucher_id: |
3545 | +# res = self.pool.get('account.voucher').proforma_voucher(cr, uid, [st_line.voucher_id.id], context={'force_name': next_number}) |
3546 | +# return self.pool.get('account.move.line').write(cr, uid, [x.id for x in st_line.voucher_id.move_ids], {'statement_id': st_line.statement_id.id}, context=context) |
3547 | +# return super(account_bank_statement, self).create_move_from_st_line(cr, uid, st_line, company_currency_id, next_number, context=context) |
3548 | + |
3549 | + voucher_obj = self.pool.get('account.voucher') |
3550 | + wf_service = netsvc.LocalService("workflow") |
3551 | + move_line_obj = self.pool.get('account.move.line') |
3552 | + bank_st_line_obj = self.pool.get('account.bank.statement.line') |
3553 | + st_line = bank_st_line_obj.browse(cr, uid, st_line_id, context=context) |
3554 | + if st_line.voucher_id: |
3555 | + voucher_obj.write(cr, uid, [st_line.voucher_id.id], {'number': next_number}, context=context) |
3556 | + if st_line.voucher_id.state == 'cancel': |
3557 | + voucher_obj.action_cancel_draft(cr, uid, [st_line.voucher_id.id], context=context) |
3558 | + wf_service.trg_validate(uid, 'account.voucher', st_line.voucher_id.id, 'proforma_voucher', cr) |
3559 | + |
3560 | + v = voucher_obj.browse(cr, uid, st_line.voucher_id.id, context=context) |
3561 | + bank_st_line_obj.write(cr, uid, [st_line_id], { |
3562 | + 'move_ids': [(4, v.move_id.id, False)] |
3563 | + }) |
3564 | + |
3565 | + return move_line_obj.write(cr, uid, [x.id for x in v.move_ids], {'statement_id': st_line.statement_id.id}, context=context) |
3566 | + return super(account_bank_statement, self).create_move_from_st_line(cr, uid, st_line.id, company_currency_id, next_number, context=context) |
3567 | + |
3568 | +account_bank_statement() |
3569 | + |
3570 | +class account_voucher_line_credits_to_use(osv.osv): |
3571 | + _name = "account.voucher.line.credits_to_use" |
3572 | + _rec_name = 'inv_credit' |
3573 | + |
3574 | + def _credit_balance(self, cr, uid, ids, name, args, context=None): |
3575 | + ''' |
3576 | + Function to calculate the value of variable Credit Balance |
3577 | + ''' |
3578 | + res = {} |
3579 | + for line in self.browse(cr, uid, ids, context=context): |
3580 | + if line.use_credit: |
3581 | + res[line.id] = line.available_amount - line.discount_amount |
3582 | + else: |
3583 | + res[line.id] = line.available_amount |
3584 | + return res |
3585 | + |
3586 | + _columns = { |
3587 | + 'voucher_line_id': fields.many2one('account.voucher.line', 'Account Voucher line', ondelete='cascade', readonly=True), |
3588 | + 'orginal_credit_line_id': fields.many2one('account.voucher.line', 'Account Voucher Credit Line', ondelete='cascade', readonly=True), |
3589 | + 'use_credit': fields.boolean('Use Credit',help='Used to indicate if credit should used against the invoice.', required=True), |
3590 | + 'inv_credit': fields.many2one('account.move.line', 'Invoice', help='Invoice of the credit', readonly=True), |
3591 | + 'discount_window_date': fields.date('Date',help='Date of the original credit', readonly=True), |
3592 | + 'orginal_amount': fields.float('Original Credit Amt', readonly=True), |
3593 | + 'available_amount': fields.float('Credit Amt Available', readonly=True), |
3594 | + 'discount_amount': fields.float('Amt to Use',help='Enter the amount of discount to be given.', required=True), |
3595 | + 'gl_account' : fields.many2one('account.account', 'G/L Account',help='Enter the General Ledger account number to record taking the cash discount.', required=True,readonly=True), |
3596 | + 'credit_bal': fields.function(_credit_balance, string='Credit Balance', method=True, type='float', store=False), |
3597 | + } |
3598 | + def onchage_use_credit(self, cr, uid, ids, use_credit, available_amount, amount_difference, context=None): |
3599 | + ''' |
3600 | + Function to automatically fill or remove the discount amount when use credit checkbox checked or unchecked |
3601 | + ''' |
3602 | + res = {} |
3603 | + if use_credit: |
3604 | + res['value'] = {'discount_amount': min(available_amount, amount_difference)} |
3605 | + else: |
3606 | + res['value'] = {'discount_amount': 0} |
3607 | + return res |
3608 | + def onchage_discount_amount(self, cr, uid, ids, available_amount, discount_amount, context=None): |
3609 | + ''' |
3610 | + Function to validate the discount amount |
3611 | + ''' |
3612 | + res = {} |
3613 | + if discount_amount < 0: |
3614 | + res['value'] = {'discount_amount': 0, 'use_credit':False } |
3615 | + res['warning'] = {'title': 'Credit not in the limit', 'message': 'Credit should not be a negative value.'} |
3616 | + return res |
3617 | + if discount_amount > available_amount: |
3618 | + res['value'] = {'discount_amount': available_amount, 'use_credit':True } |
3619 | + res['warning'] = {'title': 'Credit not in the limit', 'message': 'Please adjust the Credit Amt value to be less than or equal the Credit Available.'} |
3620 | + return res |
3621 | + if discount_amount == 0.0: |
3622 | + res['value'] = { 'use_credit':False } |
3623 | + else: |
3624 | + res['value'] = { 'use_credit':True } |
3625 | + return res |
3626 | +account_voucher_line_credits_to_use() |
3627 | + |
3628 | +''' |
3629 | + Hook for account_voucher_writeoff_us |
3630 | +''' |
3631 | +class res_company(osv.osv): |
3632 | + ''' |
3633 | + New field to keep the write-off account configuration on company |
3634 | + This Write-off account will be used on Account voucher. |
3635 | + ''' |
3636 | + _name = 'res.company' |
3637 | + _inherit = 'res.company' |
3638 | + _columns = { |
3639 | + 'def_supp_journal': fields.many2one('account.journal','Default Supplier Payment Method',readonly=False), |
3640 | + 'writeoff_account': fields.many2one('account.account', 'Writeoff Account', domain=[('type','!=','view'),('type','!=','consolidation')], |
3641 | + help="This is the designated write-off gl account that will be used when writing off remaining amounts in customer payment."), |
3642 | + } |
3643 | +res_company() |
3644 | |
3645 | === added file 'account_voucher_credits_us/voucher_payment_receipt_view.xml' |
3646 | --- account_voucher_credits_us/voucher_payment_receipt_view.xml 1970-01-01 00:00:00 +0000 |
3647 | +++ account_voucher_credits_us/voucher_payment_receipt_view.xml 2011-10-06 15:24:58 +0000 |
3648 | @@ -0,0 +1,220 @@ |
3649 | +<?xml version="1.0" encoding="UTF-8"?> |
3650 | +<openerp> |
3651 | + <data> |
3652 | + |
3653 | + |
3654 | + |
3655 | + <record model="ir.ui.view" id="view_vendor_receipt_form_1"> |
3656 | + <field name="name">account.voucher.receipt.form.1</field> |
3657 | + <field name="model">account.voucher</field> |
3658 | + <field name="type">form</field> |
3659 | + <field name="inherit_id" ref="account_voucher.view_vendor_receipt_form"/> |
3660 | + <field name="arch" type="xml"> |
3661 | + <xpath expr="/form/group/field[@name='amount']" position="attributes" > |
3662 | + <attribute name='on_change'></attribute> |
3663 | + </xpath> |
3664 | + <xpath expr="/form/group/field[@name='amount']" position="replace"> |
3665 | + <field name="amount" string="Paid Amount" /> |
3666 | + </xpath> |
3667 | + <xpath expr="/form/group[@col='10']/button[@name='cancel_voucher']" position="after"> |
3668 | + <button name="calc_diff" string="Calculate" type="object" states="draft" icon="gtk-execute" /> |
3669 | + </xpath> |
3670 | + <xpath expr="/form/notebook/page[@string='Payment Information']/group[@colspan='1']/group[@colspan='1']/field[@name='number']" position="after"> |
3671 | + <field name="auto_match" /> |
3672 | + </xpath> |
3673 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field[@name='line_dr_ids']/tree" position="replace"> |
3674 | + <tree string="Credits" editable="bottom"> |
3675 | + <field name="move_line_id"/> |
3676 | + <field name="date_original" readonly="1"/> |
3677 | + <field name="amount_original" readonly="1"/> |
3678 | + <field name="amount" sum="Total Amt Used" string="Amt Used" /> |
3679 | + <field name="pending_credits" sum="Total Pending Credit Used" readonly="1"/> |
3680 | + <field name="amount_unreconciled" string="Amt Available" readonly="1"/> |
3681 | + <field name="account_id" groups="base.group_extended" domain="[('type','=','receivable')]"/> |
3682 | + </tree> |
3683 | + <form string="Credits"> |
3684 | + <field name="move_line_id" /> |
3685 | + <field name="date_original" readonly="1"/> |
3686 | + <field name="amount_original" readonly="1"/> |
3687 | + <field name="amount" string="Amount Used" readonly="False"/> |
3688 | + <field name="pending_credits" readonly="1" sum="Total Credit Used"/> |
3689 | + <field name="amount_unreconciled" string="Amount Available" readonly="1"/> |
3690 | + <field name="account_id" groups="base.group_extended" domain="[('type','=','receivable')]"/> |
3691 | + </form> |
3692 | + </xpath> |
3693 | + |
3694 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field[@name='line_cr_ids']" position="replace"> |
3695 | + <field name="line_cr_ids" default_get="{'journal_id':journal_id, 'type':type, 'partner_id':partner_id}" colspan="4" nolabel="1" height="140" string="Payment Modification"> |
3696 | + <tree string="Invoices and Outstanding Transactions" editable="bottom"> |
3697 | + <field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}" |
3698 | + on_change="onchange_move_line_id(move_line_id)" |
3699 | + domain="[('account_id.type','in',('receivable','payable')), ('reconcile_id','=', False), ('partner_id','=',parent.partner_id)]" |
3700 | + /> |
3701 | + <field name="date_original" readonly="1"/> |
3702 | + <field name="date_due" readonly="1"/> |
3703 | + <field name="amount_original" readonly="1"/> |
3704 | + <field name="amount_unreconciled" sum="Open Balance" readonly="1"/> |
3705 | + <field name="pay" on_change="onchange_pay(amount, pay, amount_unreconciled, parent.line_cr_ids, parent.amount, credit_used, discount_used, writeoff_amount)"/> |
3706 | + <field name="amount" sum="Payment"/> |
3707 | + <field name="discount" /> |
3708 | + <field name="amount_difference"/> |
3709 | + <field name="credit_used"/> |
3710 | + <field name="account_id"/> |
3711 | + <field name="discount_used" invisible="1"/> |
3712 | + <field name="writeoff_amount" invisible="1"/> |
3713 | + </tree> |
3714 | + |
3715 | + |
3716 | + <form > |
3717 | + <group string="Invoice" colspan="4" col="4" > |
3718 | + <group colspan="2" cols="2"> |
3719 | + <field name="name" readonly="True"/> |
3720 | + <newline/> |
3721 | + <field name="invoice_id" readonly="True"/> |
3722 | + <newline/> |
3723 | + <field name="date_original" readonly="True"/> |
3724 | + </group> |
3725 | + |
3726 | + <group color="red" colspan="2" cols="2" > |
3727 | + <field name="amount_original"/> |
3728 | + <newline/> |
3729 | + <field name="amount_unreconciled"/> |
3730 | + <newline/> |
3731 | + <field name='amount' /> |
3732 | + <newline/> |
3733 | + <field name="credit_used"/> |
3734 | + <newline /> |
3735 | + <field name="amount_difference"/> |
3736 | + </group> |
3737 | + </group> |
3738 | + <notebook tabpos="up" colspan="4" > |
3739 | + <page string="Credit"> |
3740 | + <field name="available_credits" nolabel="1" colspan="4" string="Avilable Credits" view_mode="tree" > |
3741 | + </field> |
3742 | + </page> |
3743 | + <page string="Other Info" readonly="1"> |
3744 | + <field name='account_id'/> |
3745 | + <field name='partner_id' readonly="1"/> |
3746 | + <field name='untax_amount' readonly="1"/> |
3747 | + <field name='type' readonly="1"/> |
3748 | + <field name='account_analytic_id' readonly="1"/> |
3749 | + <field name='date_due' readonly="1"/> |
3750 | + <field name='company_id' readonly="1"/> |
3751 | + <field name='pay' on_change="onchange_pay(amount, pay, amount_unreconciled, parent.line_cr_ids, parent.amount, credit_used, discount_used, writeoff_amount)"/> |
3752 | + </page> |
3753 | + </notebook> |
3754 | + <group colspan="1" cols="1"> |
3755 | + <label/><label/> |
3756 | + <button name="clear_values" icon='gtk-clear' string="Clear" type="object" colspan="1"/> |
3757 | + <button name="recalculate_values" icon='gtk-refresh' string="Re-Calculate" type="object" colspan="1"/> |
3758 | + </group> |
3759 | + </form> |
3760 | + |
3761 | + </field> |
3762 | + </xpath> |
3763 | + |
3764 | + </field> |
3765 | + </record> |
3766 | + |
3767 | + |
3768 | + <record model="ir.ui.view" id="view_account_voucher_line_credits_to_use_tree"> |
3769 | + <field name="name">account.voucher.line.credits_to_use.tree</field> |
3770 | + <field name="model">account.voucher.line.credits_to_use</field> |
3771 | + <field name="type">tree</field> |
3772 | + <field name="arch" type="xml"> |
3773 | + <tree string="Available Credits" editable="top" > |
3774 | + <field name="use_credit" width="100" on_change="onchage_use_credit(use_credit, available_amount, parent.amount_difference)"/> |
3775 | + <field name="inv_credit"/> |
3776 | + <field name="discount_window_date"/> |
3777 | + <field name="orginal_amount"/> |
3778 | + <field name="available_amount"/> |
3779 | + <field name="discount_amount" on_change="onchage_discount_amount(available_amount, discount_amount)"/> |
3780 | + <field name="credit_bal"/> |
3781 | + <field name="gl_account"/> |
3782 | + </tree> |
3783 | + </field> |
3784 | + </record> |
3785 | + |
3786 | + <record model="ir.ui.view" id="view_vendor_receipt_form_2"> |
3787 | + <field name="name">account.voucher.receipt.form.2</field> |
3788 | + <field name="model">account.voucher</field> |
3789 | + <field name="type">form</field> |
3790 | + <field name="inherit_id" ref="account_voucher.view_vendor_receipt_form"/> |
3791 | + <field name="arch" type="xml"> |
3792 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field/tree/field[@name='move_line_id']" position="replace"> |
3793 | + <field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}" |
3794 | + domain="[('account_id.type','in',('receivable','payable')), ('reconcile_id','=', False), ('partner_id','=',parent.partner_id)]" |
3795 | + /> |
3796 | + </xpath> |
3797 | + </field> |
3798 | + </record> |
3799 | + <record model="ir.ui.view" id="view_vendor_receipt_form_3"> |
3800 | + <field name="name">account.voucher.receipt.form.3</field> |
3801 | + <field name="model">account.voucher</field> |
3802 | + <field name="type">form</field> |
3803 | + <field name="inherit_id" ref="account_voucher.view_vendor_receipt_form"/> |
3804 | + <field name="arch" type="xml"> |
3805 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field/tree/field[@name='account_id']" position="replace"> |
3806 | + <field name="account_id" groups="base.group_extended" domain="[('type','=','receivable')]"/> |
3807 | + </xpath> |
3808 | + </field> |
3809 | + </record> |
3810 | + <record model="ir.ui.view" id="view_vendor_receipt_form_4"> |
3811 | + <field name="name">account.voucher.receipt.form.4</field> |
3812 | + <field name="model">account.voucher</field> |
3813 | + <field name="type">form</field> |
3814 | + <field name="inherit_id" ref="account_voucher.view_vendor_receipt_form"/> |
3815 | + <field name="arch" type="xml"> |
3816 | + <xpath expr="/form/notebook/page[@string='Payment Information']/field/tree/field[@name='amount']" position="replace"> |
3817 | + <field name="amount" sum="Payment" /> |
3818 | + </xpath> |
3819 | + </field> |
3820 | + </record> |
3821 | + |
3822 | + <record id="action_proforma_voucher" model="ir.actions.act_window"> |
3823 | + <field name="name">Post Voucher</field> |
3824 | + <field name="type">ir.actions.act_window</field> |
3825 | + <field name="res_model">account.post.voucher</field> |
3826 | + <field name="view_type">form</field> |
3827 | + <field name="view_mode">form</field> |
3828 | + <field name="target">new</field> |
3829 | + </record> |
3830 | + <record model="ir.ui.view" id="view_vendor_receipt_form_5"> |
3831 | + <field name="name">account.voucher.receipt.form.5</field> |
3832 | + <field name="model">account.voucher</field> |
3833 | + <field name="type">form</field> |
3834 | + <field name="inherit_id" ref="account_voucher.view_vendor_receipt_form"/> |
3835 | + <field name="arch" type="xml"> |
3836 | + <xpath expr="/form/group[@col='10']/button[@name='proforma_voucher']" position="replace"> |
3837 | + <button name="%(action_proforma_voucher)d" string="Post" states="draft" type="action" attrs="{'invisible': ['|',('cc_info_hide','=',False),('state','<>','draft')]}" icon="terp-camera_test"/> |
3838 | + </xpath> |
3839 | + </field> |
3840 | + </record> |
3841 | + <!-- |
3842 | + Company |
3843 | + --> |
3844 | + <record id="view_company_form_jdc3" model="ir.ui.view"> |
3845 | + <field name="name">res.company.form.jdc3</field> |
3846 | + <field name="model">res.company</field> |
3847 | + <field name="type">form</field> |
3848 | + <field name="inherit_id" ref="base.view_company_form"/> |
3849 | + <field name="priority" eval="1"/> |
3850 | + <field name="arch" type="xml"> |
3851 | + <xpath expr="/form/notebook/page[@string='Configuration']" position="inside"> |
3852 | + <group> |
3853 | + <separator string="Supplier Payment" colspan="2"/><newline/> |
3854 | + <field name="def_supp_journal" domain="[('type','in',['bank','cash'])]"/> |
3855 | + </group> |
3856 | + </xpath> |
3857 | + |
3858 | + <xpath expr="/form/notebook" position="inside"> |
3859 | + <page string="Accounting"> |
3860 | + <field name="writeoff_account" colspan="2"/> |
3861 | + </page> |
3862 | + </xpath> |
3863 | + </field> |
3864 | + </record> |
3865 | + |
3866 | + |
3867 | + </data> |
3868 | +</openerp> |
3869 | |
3870 | === added directory 'account_voucher_credits_us/wizard' |
3871 | === added file 'account_voucher_credits_us/wizard/__init__.py' |
3872 | --- account_voucher_credits_us/wizard/__init__.py 1970-01-01 00:00:00 +0000 |
3873 | +++ account_voucher_credits_us/wizard/__init__.py 2011-10-06 15:24:58 +0000 |
3874 | @@ -0,0 +1,26 @@ |
3875 | +# -*- coding: utf-8 -*- |
3876 | +############################################################################## |
3877 | +# |
3878 | +# OpenERP, Open Source Management Solution |
3879 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
3880 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
3881 | +# |
3882 | +# This program is free software: you can redistribute it and/or modify |
3883 | +# it under the terms of the GNU General Public License as published by |
3884 | +# the Free Software Foundation, either version 3 of the License, or |
3885 | +# (at your option) any later version. |
3886 | +# |
3887 | +# This program is distributed in the hope that it will be useful, |
3888 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3889 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3890 | +# GNU General Public License for more details. |
3891 | +# |
3892 | +# You should have received a copy of the GNU General Public License |
3893 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
3894 | +# |
3895 | +############################################################################## |
3896 | + |
3897 | +import account_post_voucher |
3898 | + |
3899 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
3900 | + |
3901 | |
3902 | === added file 'account_voucher_credits_us/wizard/account_post_voucher.py' |
3903 | --- account_voucher_credits_us/wizard/account_post_voucher.py 1970-01-01 00:00:00 +0000 |
3904 | +++ account_voucher_credits_us/wizard/account_post_voucher.py 2011-10-06 15:24:58 +0000 |
3905 | @@ -0,0 +1,75 @@ |
3906 | +# -*- coding: utf-8 -*- |
3907 | +############################################################################## |
3908 | +# |
3909 | +# OpenERP, Open Source Management Solution |
3910 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
3911 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
3912 | +# |
3913 | +# This program is free software: you can redistribute it and/or modify |
3914 | +# it under the terms of the GNU General Public License as published by |
3915 | +# the Free Software Foundation, either version 3 of the License, or |
3916 | +# (at your option) any later version. |
3917 | +# |
3918 | +# This program is distributed in the hope that it will be useful, |
3919 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3920 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3921 | +# GNU General Public License for more details. |
3922 | +# |
3923 | +# You should have received a copy of the GNU General Public License |
3924 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
3925 | +# |
3926 | +############################################################################## |
3927 | + |
3928 | +from osv import fields, osv |
3929 | + |
3930 | +class account_post_voucher(osv.osv_memory): |
3931 | + _name = 'account.post.voucher' |
3932 | + _description = 'Account Pay Voucher' |
3933 | + |
3934 | + _columns = { |
3935 | + 'total_paid': fields.float('Total Received'), |
3936 | + 'total_allocated': fields.float('Total Allocated'), |
3937 | + 'ok_to_go': fields.float('OK to Go'), |
3938 | + } |
3939 | + |
3940 | + def _get_total_paid(self, cr, uid, context={}): |
3941 | + obj_voucher = self.pool.get('account.voucher') |
3942 | + return obj_voucher.browse(cr, uid, context['active_id'], context).amount |
3943 | + |
3944 | + def _get_total_allocated(self, cr, uid, context={}): |
3945 | + obj_voucher = self.pool.get('account.voucher') |
3946 | + voucher = obj_voucher.browse(cr, uid, context['active_id'], context) |
3947 | + total_allocated = 0.0 |
3948 | + for line in voucher.line_cr_ids: |
3949 | + total_allocated += line.amount |
3950 | + return total_allocated |
3951 | + |
3952 | + def _get_ok_to_go(self,cr, uid, context={}): |
3953 | + obj_voucher = self.pool.get('account.voucher') |
3954 | + voucher = obj_voucher.browse(cr, uid, context['active_id'], context) |
3955 | + total_allocated = 0.0 |
3956 | + for line in voucher.line_cr_ids: |
3957 | + total_allocated += line.amount |
3958 | + return total_allocated - voucher.amount |
3959 | + |
3960 | + _defaults = { |
3961 | + 'total_paid': _get_total_paid, |
3962 | + 'total_allocated': _get_total_allocated, |
3963 | + 'ok_to_go': _get_ok_to_go, |
3964 | + } |
3965 | + def onchange_ok_to_go(self,cr, uid, ids, ok_to_go, context={}): |
3966 | + if ok_to_go > 0.0: |
3967 | + return {'warning': {'title': 'Overallocated invoices', 'message': 'Reduce allocations to match Total Receipt'}} |
3968 | + else: |
3969 | + return {'value':{}} |
3970 | + def launch_wizard(self, cr, uid, ids, context=None): |
3971 | + """ |
3972 | + Don't allow post if total_allocated > total_paid. |
3973 | + """ |
3974 | + obj_voucher = self.pool.get('account.voucher') |
3975 | + obj_voucher.action_move_line_create(cr, uid, context['active_ids'], context) |
3976 | + return {} |
3977 | + |
3978 | +account_post_voucher() |
3979 | + |
3980 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
3981 | |
3982 | === added file 'account_voucher_credits_us/wizard/account_post_voucher.xml' |
3983 | --- account_voucher_credits_us/wizard/account_post_voucher.xml 1970-01-01 00:00:00 +0000 |
3984 | +++ account_voucher_credits_us/wizard/account_post_voucher.xml 2011-10-06 15:24:58 +0000 |
3985 | @@ -0,0 +1,40 @@ |
3986 | +<?xml version="1.0" encoding="utf-8"?> |
3987 | +<openerp> |
3988 | + <data> |
3989 | + |
3990 | + <record id="account_voucher_post_view" model="ir.ui.view"> |
3991 | + <field name="name">account.post.voucher.form</field> |
3992 | + <field name="model">account.post.voucher</field> |
3993 | + <field name="type">form</field> |
3994 | + <field name="arch" type="xml"> |
3995 | + <form string="Post Voucher"> |
3996 | + <group colspan="2" col="4"> |
3997 | + <field name="total_paid" readonly="True"/> |
3998 | + <field name="total_allocated" readonly="True"/> |
3999 | + <field name="ok_to_go" invisible="True" on_change="onchange_ok_to_go(ok_to_go)"/> |
4000 | + </group> |
4001 | + <group height="100" width="320"> |
4002 | + <separator string="Confirm Amounts?"/> |
4003 | + <newline/> |
4004 | + <group colspan="2" col="4"> |
4005 | + <button special="cancel" string="Cancel" icon="gtk-cancel"/> |
4006 | + <button name="launch_wizard" string="Yes" type="object" attrs="{'invisible':[('ok_to_go', '>', 0.0)]}" icon="gtk-ok" default_focus="1"/> |
4007 | + </group> |
4008 | + </group> |
4009 | + </form> |
4010 | + </field> |
4011 | + </record> |
4012 | + |
4013 | + <record id="action_proforma_voucher" model="ir.actions.act_window"> |
4014 | + <field name="name">Post Voucher</field> |
4015 | + <field name="type">ir.actions.act_window</field> |
4016 | + <field name="res_model">account.post.voucher</field> |
4017 | + <field name="view_type">form</field> |
4018 | + <field name="view_mode">form</field> |
4019 | + <field name="view_id" ref="account_voucher_post_view"/> |
4020 | + <field name="target">new</field> |
4021 | + </record> |
4022 | + |
4023 | + |
4024 | + </data> |
4025 | +</openerp> |
Having this feature is good but the implementation seems not good. It's not normal that the diff have 4000 lines of code, it should have around 200 max.