Merge lp:~camptocamp/banking-addons/bank-statement-reconcile_vre into lp:banking-addons/bank-statement-reconcile-61
- bank-statement-reconcile_vre
- Merge into bank-statement-reconcile-61
Status: | Superseded |
---|---|
Proposed branch: | lp:~camptocamp/banking-addons/bank-statement-reconcile_vre |
Merge into: | lp:banking-addons/bank-statement-reconcile-61 |
Diff against target: |
6036 lines (+2363/-1302) (has conflicts) 67 files modified
account_advanced_reconcile/__openerp__.py (+10/-14) account_advanced_reconcile/advanced_reconciliation.py (+5/-7) account_advanced_reconcile/base_advanced_reconciliation.py (+22/-24) account_advanced_reconcile/easy_reconcile.py (+5/-6) account_advanced_reconcile/easy_reconcile_view.xml (+1/-2) account_advanced_reconcile/i18n/fr.po (+15/-14) account_easy_reconcile/__openerp__.py (+16/-10) account_easy_reconcile/base_reconciliation.py (+24/-23) account_easy_reconcile/easy_reconcile.py (+78/-41) account_easy_reconcile/easy_reconcile.xml (+71/-51) account_easy_reconcile/easy_reconcile_history.py (+7/-0) account_easy_reconcile/easy_reconcile_history_view.xml (+24/-24) account_easy_reconcile/i18n/fr.po (+251/-47) account_easy_reconcile/security/ir_rule.xml (+25/-0) account_easy_reconcile/simple_reconciliation.py (+3/-5) account_statement_base_completion/__init__.py (+1/-1) account_statement_base_completion/__openerp__.py (+5/-2) account_statement_base_completion/data.xml (+8/-3) account_statement_base_completion/partner.py (+7/-7) account_statement_base_completion/statement.py (+348/-209) account_statement_base_completion/statement_view.xml (+7/-7) account_statement_base_import/__init__.py (+1/-1) account_statement_base_import/__openerp__.py (+8/-6) account_statement_base_import/parser/__init__.py (+1/-1) account_statement_base_import/parser/file_parser.py (+74/-36) account_statement_base_import/parser/generic_file_parser.py (+21/-21) account_statement_base_import/parser/parser.py (+26/-25) account_statement_base_import/statement.py (+176/-108) account_statement_base_import/statement_view.xml (+7/-5) account_statement_base_import/wizard/import_statement.py (+46/-42) account_statement_completion_voucher/__init__.py (+0/-1) account_statement_completion_voucher/__openerp__.py (+7/-5) account_statement_completion_voucher/statement_view.xml (+3/-3) account_statement_ext/__init__.py (+2/-1) account_statement_ext/__openerp__.py (+16/-10) account_statement_ext/account.py (+6/-8) account_statement_ext/i18n/fr.po (+2/-2) account_statement_ext/report/__init__.py (+2/-7) account_statement_ext/report/bank_statement_report.py (+19/-18) account_statement_ext/security/ir.model.access.csv (+1/-1) account_statement_ext/security/ir_rule.xml (+10/-0) account_statement_ext/statement.py (+407/-342) account_statement_ext/statement_view.xml (+78/-3) account_statement_ext/voucher.py (+49/-0) account_statement_ext_voucher/__init__.py (+0/-2) account_statement_ext_voucher/__openerp__.py (+13/-6) account_statement_ext_voucher/statement_voucher.py (+4/-3) account_statement_ext_voucher/statement_voucher_view.xml (+0/-17) account_statement_transactionid_completion/__openerp__.py (+5/-3) account_statement_transactionid_completion/statement.py (+40/-36) account_statement_transactionid_completion/statement_view.xml (+1/-1) account_statement_transactionid_import/__init__.py (+1/-1) account_statement_transactionid_import/__openerp__.py (+10/-8) account_statement_transactionid_import/parser/__init__.py (+1/-3) account_statement_transactionid_import/parser/transactionid_file_parser.py (+17/-30) account_statement_transactionid_import/statement.py (+16/-12) base_transaction_id/__openerp__.py (+19/-8) base_transaction_id/invoice.py (+8/-7) base_transaction_id/sale.py (+14/-10) base_transaction_id/stock.py (+16/-12) invoicing_voucher_killer/__init__.py (+20/-0) invoicing_voucher_killer/__openerp__.py (+39/-0) invoicing_voucher_killer/invoice_data.xml (+7/-0) invoicing_voucher_killer/invoice_view.xml (+48/-0) statement_voucher_killer/__init__.py (+21/-0) statement_voucher_killer/__openerp__.py (+40/-0) statement_voucher_killer/voucher.py (+128/-0) Text conflict in account_easy_reconcile/__openerp__.py Text conflict in account_easy_reconcile/easy_reconcile.py Text conflict in account_statement_ext/__openerp__.py Text conflict in account_statement_ext/statement.py Text conflict in account_statement_ext/statement_view.xml |
To merge this branch: | bzr merge lp:~camptocamp/banking-addons/bank-statement-reconcile_vre |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Banking Addons Core Editors | Pending | ||
Review via email: mp+168363@code.launchpad.net |
This proposal supersedes a proposal from 2013-06-10.
This proposal has been superseded by a proposal from 2013-06-10.
Commit message
Description of the change
This fix prevent account_
Unmerged revisions
- 93. By Vincent Renaville@camptocamp
-
[FIX] prevent crash if move ref is null
- 92. By Nicolas Bessi - Camptocamp
-
[MRG] [FIX] Restore default period in bank statement by taking context in account
- 91. By Nicolas Bessi - Camptocamp
-
[MRG] [IMP] Refine partner label lookup error message
[FIX] Restore error message in log
[FIX] Fix partner label lookup regexp - 90. By Nicolas Bessi - Camptocamp
-
[MRG] Major refactoring of statement import and completion:
Fix the way to look default account on partner:
- If master account is provided in profile it will be forced
- If the customer checkbox is checked on the found partner, type and account will be customer and receivable
- If the supplier checkbox is checked on the found partner, type and account will be supplier and payable
- If both checkbox are checked or none of them, it'll be based on the amount :
If amount is positif the type and account will be customer and receivable,
If amount is negativ, the type and account will be supplier and payableCompletion:
-Fix and refactor the the invoices lookup for completion
-Various fixes in completion rules
- Non matches lines are not mark as completed.Optimisation:
Refactoring of statement import:
We by pass ORM to increase performances.
TODO support of sparse fieldRefactoring of completion.
We have done some structural changes in order to avoid a lot of un needed call to ORM.
Bypass orm when writing to database.These merge is required in order to fix transaction id completion rules and import +
Handle the new semantic change in OpenERP partner model - 89. By Alexandre Fayolle - camptocamp
-
[FIX] permissions on account.
statement. profil: an accountant needs write access on the model to be able to import a bank statement otherwise, the message.post call fails
- 88. By Nicolas Bessi - Camptocamp
-
[MRG] Fixes performance trouble when using bank_statement_
label based completion rules by using memoizer pattern. Add lines in context to be able to acces them in completion rules. It is not
mandatory as we can do line.satement_id.line_ ids but it is more efficient. Some minor cleanup
- 87. By Nicolas Bessi - Camptocamp
-
[MRG] Improve statement import wizard by using mass writing of statement line in order to avoid store field loop computation.
- 86. By Nicolas Bessi - Camptocamp
-
[MRG] Improve statement import global usability by retuning usable error message while parsing files.
Allows empty value for float in parsed CSV.Added note about the additional dependency on python-xlrd in the description.
- 85. By Nicolas Bessi - Camptocamp
-
[MRG] Add a completion rule to allows supplier invoice completion baser on invoice number
- 84. By Nicolas Bessi - Camptocamp
-
[MRG] Adds two add-ons that prevent voucher to interfer with the statement ext related add-ons flow
Preview Diff
1 | === modified file 'account_advanced_reconcile/__openerp__.py' | |||
2 | --- account_advanced_reconcile/__openerp__.py 2012-11-28 13:22:22 +0000 | |||
3 | +++ account_advanced_reconcile/__openerp__.py 2013-06-10 07:05:32 +0000 | |||
4 | @@ -30,8 +30,6 @@ | |||
5 | 30 | 'description': """ | 30 | 'description': """ |
6 | 31 | Advanced reconciliation methods for the module account_easy_reconcile. | 31 | Advanced reconciliation methods for the module account_easy_reconcile. |
7 | 32 | 32 | ||
8 | 33 | account_easy_reconcile, which is a dependency, is available in the branch: lp:account-extra-addons | ||
9 | 34 | |||
10 | 35 | In addition to the features implemented in account_easy_reconcile, which are: | 33 | In addition to the features implemented in account_easy_reconcile, which are: |
11 | 36 | - reconciliation facilities for big volume of transactions | 34 | - reconciliation facilities for big volume of transactions |
12 | 37 | - setup different profiles of reconciliation by account | 35 | - setup different profiles of reconciliation by account |
13 | @@ -39,31 +37,31 @@ | |||
14 | 39 | - this module is also a base to create others reconciliation methods | 37 | - this module is also a base to create others reconciliation methods |
15 | 40 | which can plug in the profiles | 38 | which can plug in the profiles |
16 | 41 | - a profile a reconciliation can be run manually or by a cron | 39 | - a profile a reconciliation can be run manually or by a cron |
18 | 42 | - monitoring of reconcilation runs with a few logs | 40 | - monitoring of reconcilation runs with an history |
19 | 43 | 41 | ||
20 | 44 | It implements a basis to created advanced reconciliation methods in a few lines | 42 | It implements a basis to created advanced reconciliation methods in a few lines |
21 | 45 | of code. | 43 | of code. |
22 | 46 | 44 | ||
23 | 47 | Typically, such a method can be: | 45 | Typically, such a method can be: |
28 | 48 | - Reconcile entries if the partner and the ref are equal | 46 | - Reconcile Journal items if the partner and the ref are equal |
29 | 49 | - Reconcile entries if the partner is equal and the ref is the same than ref | 47 | - Reconcile Journal items if the partner is equal and the ref |
30 | 50 | or name | 48 | is the same than ref or name |
31 | 51 | - Reconcile entries if the partner is equal and the ref match with a pattern | 49 | - Reconcile Journal items if the partner is equal and the ref |
32 | 50 | match with a pattern | ||
33 | 52 | 51 | ||
34 | 53 | And they allows: | 52 | And they allows: |
35 | 54 | - Reconciliations with multiple credit / multiple debit lines | 53 | - Reconciliations with multiple credit / multiple debit lines |
36 | 55 | - Partial reconciliations | 54 | - Partial reconciliations |
37 | 56 | - Write-off amount as well | 55 | - Write-off amount as well |
38 | 57 | 56 | ||
42 | 58 | A method is already implemented in this module, it matches on entries: | 57 | A method is already implemented in this module, it matches on items: |
43 | 59 | * Partner | 58 | - Partner |
44 | 60 | * Ref on credit move lines should be case insensitive equals to the ref or | 59 | - Ref on credit move lines should be case insensitive equals to the ref or |
45 | 61 | the name of the debit move line | 60 | the name of the debit move line |
46 | 62 | 61 | ||
47 | 63 | The base class to find the reconciliations is built to be as efficient as | 62 | The base class to find the reconciliations is built to be as efficient as |
48 | 64 | possible. | 63 | possible. |
49 | 65 | 64 | ||
50 | 66 | |||
51 | 67 | So basically, if you have an invoice with 3 payments (one per month), the first | 65 | So basically, if you have an invoice with 3 payments (one per month), the first |
52 | 68 | month, it will partial reconcile the debit move line with the first payment, the second | 66 | month, it will partial reconcile the debit move line with the first payment, the second |
53 | 69 | month, it will partial reconcile the debit move line with 2 first payments, | 67 | month, it will partial reconcile the debit move line with 2 first payments, |
54 | @@ -75,9 +73,7 @@ | |||
55 | 75 | 73 | ||
56 | 76 | """, | 74 | """, |
57 | 77 | 'website': 'http://www.camptocamp.com', | 75 | 'website': 'http://www.camptocamp.com', |
61 | 78 | 'init_xml': [], | 76 | 'data': ['easy_reconcile_view.xml'], |
59 | 79 | 'update_xml': ['easy_reconcile_view.xml'], | ||
60 | 80 | 'demo_xml': [], | ||
62 | 81 | 'test': [], | 77 | 'test': [], |
63 | 82 | 'images': [], | 78 | 'images': [], |
64 | 83 | 'installable': True, | 79 | 'installable': True, |
65 | 84 | 80 | ||
66 | === modified file 'account_advanced_reconcile/advanced_reconciliation.py' | |||
67 | --- account_advanced_reconcile/advanced_reconciliation.py 2012-08-06 10:06:26 +0000 | |||
68 | +++ account_advanced_reconcile/advanced_reconciliation.py 2013-06-10 07:05:32 +0000 | |||
69 | @@ -19,14 +19,13 @@ | |||
70 | 19 | # | 19 | # |
71 | 20 | ############################################################################## | 20 | ############################################################################## |
72 | 21 | 21 | ||
77 | 22 | from openerp.osv.orm import TransientModel | 22 | from openerp.osv import orm |
78 | 23 | 23 | ||
79 | 24 | 24 | ||
80 | 25 | class easy_reconcile_advanced_ref(TransientModel): | 25 | class easy_reconcile_advanced_ref(orm.TransientModel): |
81 | 26 | 26 | ||
82 | 27 | _name = 'easy.reconcile.advanced.ref' | 27 | _name = 'easy.reconcile.advanced.ref' |
83 | 28 | _inherit = 'easy.reconcile.advanced' | 28 | _inherit = 'easy.reconcile.advanced' |
84 | 29 | _auto = True # False when inherited from AbstractModel | ||
85 | 30 | 29 | ||
86 | 31 | def _skip_line(self, cr, uid, rec, move_line, context=None): | 30 | def _skip_line(self, cr, uid, rec, move_line, context=None): |
87 | 32 | """ | 31 | """ |
88 | @@ -115,6 +114,5 @@ | |||
89 | 115 | :yield: matchers as tuple ('matcher key', value(s)) | 114 | :yield: matchers as tuple ('matcher key', value(s)) |
90 | 116 | """ | 115 | """ |
91 | 117 | yield ('partner_id', move_line['partner_id']) | 116 | yield ('partner_id', move_line['partner_id']) |
93 | 118 | yield ('ref', (move_line['ref'].lower().strip(), | 117 | yield ('ref', ((move_line['ref'] or '').lower().strip(), |
94 | 119 | move_line['name'].lower().strip())) | 118 | move_line['name'].lower().strip())) |
95 | 120 | |||
96 | 121 | 119 | ||
97 | === modified file 'account_advanced_reconcile/base_advanced_reconciliation.py' | |||
98 | --- account_advanced_reconcile/base_advanced_reconciliation.py 2012-08-06 10:06:26 +0000 | |||
99 | +++ account_advanced_reconcile/base_advanced_reconciliation.py 2013-06-10 07:05:32 +0000 | |||
100 | @@ -19,21 +19,17 @@ | |||
101 | 19 | # | 19 | # |
102 | 20 | ############################################################################## | 20 | ############################################################################## |
103 | 21 | 21 | ||
111 | 22 | from itertools import groupby, product | 22 | from itertools import product |
112 | 23 | from operator import itemgetter | 23 | from openerp.osv import orm |
113 | 24 | from openerp.osv.orm import Model, AbstractModel, TransientModel | 24 | |
114 | 25 | from openerp.osv import fields | 25 | |
115 | 26 | 26 | class easy_reconcile_advanced(orm.AbstractModel): | |
109 | 27 | |||
110 | 28 | class easy_reconcile_advanced(AbstractModel): | ||
116 | 29 | 27 | ||
117 | 30 | _name = 'easy.reconcile.advanced' | 28 | _name = 'easy.reconcile.advanced' |
118 | 31 | _inherit = 'easy.reconcile.base' | 29 | _inherit = 'easy.reconcile.base' |
119 | 32 | 30 | ||
120 | 33 | def _query_debit(self, cr, uid, rec, context=None): | 31 | def _query_debit(self, cr, uid, rec, context=None): |
124 | 34 | """Select all move (debit>0) as candidate. Optional choice on invoice | 32 | """Select all move (debit>0) as candidate. """ |
122 | 35 | will filter with an inner join on the related moves. | ||
123 | 36 | """ | ||
125 | 37 | select = self._select(rec) | 33 | select = self._select(rec) |
126 | 38 | sql_from = self._from(rec) | 34 | sql_from = self._from(rec) |
127 | 39 | where, params = self._where(rec) | 35 | where, params = self._where(rec) |
128 | @@ -47,9 +43,7 @@ | |||
129 | 47 | return cr.dictfetchall() | 43 | return cr.dictfetchall() |
130 | 48 | 44 | ||
131 | 49 | def _query_credit(self, cr, uid, rec, context=None): | 45 | def _query_credit(self, cr, uid, rec, context=None): |
135 | 50 | """Select all move (credit>0) as candidate. Optional choice on invoice | 46 | """Select all move (credit>0) as candidate. """ |
133 | 51 | will filter with an inner join on the related moves. | ||
134 | 52 | """ | ||
136 | 53 | select = self._select(rec) | 47 | select = self._select(rec) |
137 | 54 | sql_from = self._from(rec) | 48 | sql_from = self._from(rec) |
138 | 55 | where, params = self._where(rec) | 49 | where, params = self._where(rec) |
139 | @@ -176,9 +170,9 @@ | |||
140 | 176 | """ | 170 | """ |
141 | 177 | mkey, mvalue = matcher | 171 | mkey, mvalue = matcher |
142 | 178 | omkey, omvalue = opposite_matcher | 172 | omkey, omvalue = opposite_matcher |
146 | 179 | assert mkey == omkey, "A matcher %s is compared with a matcher %s, " \ | 173 | assert mkey == omkey, ("A matcher %s is compared with a matcher %s, " |
147 | 180 | " the _matchers and _opposite_matchers are probably wrong" % \ | 174 | " the _matchers and _opposite_matchers are probably wrong" % |
148 | 181 | (mkey, omkey) | 175 | (mkey, omkey)) |
149 | 182 | if not isinstance(mvalue, (list, tuple)): | 176 | if not isinstance(mvalue, (list, tuple)): |
150 | 183 | mvalue = mvalue, | 177 | mvalue = mvalue, |
151 | 184 | if not isinstance(omvalue, (list, tuple)): | 178 | if not isinstance(omvalue, (list, tuple)): |
152 | @@ -186,7 +180,13 @@ | |||
153 | 186 | return easy_reconcile_advanced._compare_matcher_values(mkey, mvalue, omvalue) | 180 | return easy_reconcile_advanced._compare_matcher_values(mkey, mvalue, omvalue) |
154 | 187 | 181 | ||
155 | 188 | def _compare_opposite(self, cr, uid, rec, move_line, opposite_move_line, | 182 | def _compare_opposite(self, cr, uid, rec, move_line, opposite_move_line, |
157 | 189 | matchers, context=None): | 183 | matchers, context=None): |
158 | 184 | """ Iterate over the matchers of the move lines vs opposite move lines | ||
159 | 185 | and if they all match, return True. | ||
160 | 186 | |||
161 | 187 | If all the matchers match for a move line and an opposite move line, | ||
162 | 188 | they are candidate for a reconciliation. | ||
163 | 189 | """ | ||
164 | 190 | opp_matchers = self._opposite_matchers(cr, uid, rec, opposite_move_line, | 190 | opp_matchers = self._opposite_matchers(cr, uid, rec, opposite_move_line, |
165 | 191 | context=context) | 191 | context=context) |
166 | 192 | for matcher in matchers: | 192 | for matcher in matchers: |
167 | @@ -216,14 +216,15 @@ | |||
168 | 216 | :return: list of matching lines | 216 | :return: list of matching lines |
169 | 217 | """ | 217 | """ |
170 | 218 | matchers = self._matchers(cr, uid, rec, move_line, context=context) | 218 | matchers = self._matchers(cr, uid, rec, move_line, context=context) |
173 | 219 | return [op for op in opposite_move_lines if \ | 219 | return [op for op in opposite_move_lines if |
174 | 220 | self._compare_opposite(cr, uid, rec, move_line, op, matchers, context=context)] | 220 | self._compare_opposite( |
175 | 221 | cr, uid, rec, move_line, op, matchers, context=context)] | ||
176 | 221 | 222 | ||
177 | 222 | def _action_rec(self, cr, uid, rec, context=None): | 223 | def _action_rec(self, cr, uid, rec, context=None): |
178 | 223 | credit_lines = self._query_credit(cr, uid, rec, context=context) | 224 | credit_lines = self._query_credit(cr, uid, rec, context=context) |
179 | 224 | debit_lines = self._query_debit(cr, uid, rec, context=context) | 225 | debit_lines = self._query_debit(cr, uid, rec, context=context) |
180 | 225 | return self._rec_auto_lines_advanced( | 226 | return self._rec_auto_lines_advanced( |
182 | 226 | cr, uid, rec, credit_lines, debit_lines, context=context) | 227 | cr, uid, rec, credit_lines, debit_lines, context=context) |
183 | 227 | 228 | ||
184 | 228 | def _skip_line(self, cr, uid, rec, move_line, context=None): | 229 | def _skip_line(self, cr, uid, rec, move_line, context=None): |
185 | 229 | """ | 230 | """ |
186 | @@ -234,9 +235,7 @@ | |||
187 | 234 | return False | 235 | return False |
188 | 235 | 236 | ||
189 | 236 | def _rec_auto_lines_advanced(self, cr, uid, rec, credit_lines, debit_lines, context=None): | 237 | def _rec_auto_lines_advanced(self, cr, uid, rec, credit_lines, debit_lines, context=None): |
193 | 237 | if context is None: | 238 | """ Advanced reconciliation main loop """ |
191 | 238 | context = {} | ||
192 | 239 | |||
194 | 240 | reconciled_ids = [] | 239 | reconciled_ids = [] |
195 | 241 | partial_reconciled_ids = [] | 240 | partial_reconciled_ids = [] |
196 | 242 | reconcile_groups = [] | 241 | reconcile_groups = [] |
197 | @@ -271,4 +270,3 @@ | |||
198 | 271 | partial_reconciled_ids += reconcile_group_ids | 270 | partial_reconciled_ids += reconcile_group_ids |
199 | 272 | 271 | ||
200 | 273 | return reconciled_ids, partial_reconciled_ids | 272 | return reconciled_ids, partial_reconciled_ids |
201 | 274 | |||
202 | 275 | 273 | ||
203 | === modified file 'account_advanced_reconcile/easy_reconcile.py' | |||
204 | --- account_advanced_reconcile/easy_reconcile.py 2012-06-20 14:10:01 +0000 | |||
205 | +++ account_advanced_reconcile/easy_reconcile.py 2013-06-10 07:05:32 +0000 | |||
206 | @@ -19,10 +19,10 @@ | |||
207 | 19 | # | 19 | # |
208 | 20 | ############################################################################## | 20 | ############################################################################## |
209 | 21 | 21 | ||
214 | 22 | from openerp.osv.orm import Model | 22 | from openerp.osv import orm |
215 | 23 | 23 | ||
216 | 24 | 24 | ||
217 | 25 | class account_easy_reconcile_method(Model): | 25 | class account_easy_reconcile_method(orm.Model): |
218 | 26 | 26 | ||
219 | 27 | _inherit = 'account.easy.reconcile.method' | 27 | _inherit = 'account.easy.reconcile.method' |
220 | 28 | 28 | ||
221 | @@ -31,7 +31,6 @@ | |||
222 | 31 | _get_all_rec_method(cr, uid, context=context) | 31 | _get_all_rec_method(cr, uid, context=context) |
223 | 32 | methods += [ | 32 | methods += [ |
224 | 33 | ('easy.reconcile.advanced.ref', | 33 | ('easy.reconcile.advanced.ref', |
226 | 34 | 'Advanced. Partner and Ref.'), | 34 | 'Advanced. Partner and Ref.'), |
227 | 35 | ] | 35 | ] |
228 | 36 | return methods | 36 | return methods |
229 | 37 | |||
230 | 38 | 37 | ||
231 | === modified file 'account_advanced_reconcile/easy_reconcile_view.xml' | |||
232 | --- account_advanced_reconcile/easy_reconcile_view.xml 2012-06-27 07:58:32 +0000 | |||
233 | +++ account_advanced_reconcile/easy_reconcile_view.xml 2013-06-10 07:05:32 +0000 | |||
234 | @@ -4,13 +4,12 @@ | |||
235 | 4 | <record id="view_easy_reconcile_form" model="ir.ui.view"> | 4 | <record id="view_easy_reconcile_form" model="ir.ui.view"> |
236 | 5 | <field name="name">account.easy.reconcile.form</field> | 5 | <field name="name">account.easy.reconcile.form</field> |
237 | 6 | <field name="model">account.easy.reconcile</field> | 6 | <field name="model">account.easy.reconcile</field> |
238 | 7 | <field name="type">form</field> | ||
239 | 8 | <field name="inherit_id" ref="account_easy_reconcile.account_easy_reconcile_form"/> | 7 | <field name="inherit_id" ref="account_easy_reconcile.account_easy_reconcile_form"/> |
240 | 9 | <field name="arch" type="xml"> | 8 | <field name="arch" type="xml"> |
241 | 10 | <page name="information" position="inside"> | 9 | <page name="information" position="inside"> |
242 | 11 | <group colspan="2" col="2"> | 10 | <group colspan="2" col="2"> |
243 | 12 | <separator colspan="4" string="Advanced. Partner and Ref"/> | 11 | <separator colspan="4" string="Advanced. Partner and Ref"/> |
245 | 13 | <label string="Match multiple debit vs multiple credit entries. Allow partial reconcilation. | 12 | <label string="Match multiple debit vs multiple credit entries. Allow partial reconciliation. |
246 | 14 | The lines should have the partner, the credit entry ref. is matched vs the debit entry ref. or name." colspan="4"/> | 13 | The lines should have the partner, the credit entry ref. is matched vs the debit entry ref. or name." colspan="4"/> |
247 | 15 | </group> | 14 | </group> |
248 | 16 | </page> | 15 | </page> |
249 | 17 | 16 | ||
250 | === modified file 'account_advanced_reconcile/i18n/fr.po' | |||
251 | --- account_advanced_reconcile/i18n/fr.po 2012-12-13 13:57:29 +0000 | |||
252 | +++ account_advanced_reconcile/i18n/fr.po 2013-06-10 07:05:32 +0000 | |||
253 | @@ -1,18 +1,19 @@ | |||
254 | 1 | # Translation of OpenERP Server. | 1 | # Translation of OpenERP Server. |
255 | 2 | # This file contains the translation of the following modules: | 2 | # This file contains the translation of the following modules: |
257 | 3 | # * account_advanced_reconcile | 3 | # * account_advanced_reconcile |
258 | 4 | # | 4 | # |
259 | 5 | msgid "" | 5 | msgid "" |
260 | 6 | msgstr "" | 6 | msgstr "" |
261 | 7 | "Project-Id-Version: OpenERP Server 6.1\n" | 7 | "Project-Id-Version: OpenERP Server 6.1\n" |
262 | 8 | "Report-Msgid-Bugs-To: \n" | 8 | "Report-Msgid-Bugs-To: \n" |
266 | 9 | "POT-Creation-Date: 2012-11-07 12:34+0000\n" | 9 | "POT-Creation-Date: 2013-01-04 08:25+0000\n" |
267 | 10 | "PO-Revision-Date: 2012-11-07 12:34+0000\n" | 10 | "PO-Revision-Date: 2013-01-04 09:27+0100\n" |
268 | 11 | "Last-Translator: <>\n" | 11 | "Last-Translator: Guewen Baconnier <guewen.baconnier@camptocamp.com>\n" |
269 | 12 | "Language-Team: \n" | 12 | "Language-Team: \n" |
270 | 13 | "Language: \n" | ||
271 | 13 | "MIME-Version: 1.0\n" | 14 | "MIME-Version: 1.0\n" |
272 | 14 | "Content-Type: text/plain; charset=UTF-8\n" | 15 | "Content-Type: text/plain; charset=UTF-8\n" |
274 | 15 | "Content-Transfer-Encoding: \n" | 16 | "Content-Transfer-Encoding: 8bit\n" |
275 | 16 | "Plural-Forms: \n" | 17 | "Plural-Forms: \n" |
276 | 17 | 18 | ||
277 | 18 | #. module: account_advanced_reconcile | 19 | #. module: account_advanced_reconcile |
278 | @@ -33,12 +34,6 @@ | |||
279 | 33 | msgstr "Méthode de lettrage pour le module account_easy_reconcile" | 34 | msgstr "Méthode de lettrage pour le module account_easy_reconcile" |
280 | 34 | 35 | ||
281 | 35 | #. module: account_advanced_reconcile | 36 | #. module: account_advanced_reconcile |
282 | 36 | #: field:easy.reconcile.advanced,date_base_on:0 | ||
283 | 37 | #: field:easy.reconcile.advanced.ref,date_base_on:0 | ||
284 | 38 | msgid "Date of reconcilation" | ||
285 | 39 | msgstr "Date de lettrage" | ||
286 | 40 | |||
287 | 41 | #. module: account_advanced_reconcile | ||
288 | 42 | #: field:easy.reconcile.advanced,journal_id:0 | 37 | #: field:easy.reconcile.advanced,journal_id:0 |
289 | 43 | #: field:easy.reconcile.advanced.ref,journal_id:0 | 38 | #: field:easy.reconcile.advanced.ref,journal_id:0 |
290 | 44 | msgid "Journal" | 39 | msgid "Journal" |
291 | @@ -51,6 +46,11 @@ | |||
292 | 51 | msgstr "Compte de produit" | 46 | msgstr "Compte de produit" |
293 | 52 | 47 | ||
294 | 53 | #. module: account_advanced_reconcile | 48 | #. module: account_advanced_reconcile |
295 | 49 | #: view:account.easy.reconcile:0 | ||
296 | 50 | msgid "Match multiple debit vs multiple credit entries. Allow partial reconciliation. The lines should have the partner, the credit entry ref. is matched vs the debit entry ref. or name." | ||
297 | 51 | msgstr "Le Lettrage peut s'effectuer sur plusieurs écritures de débit et crédit. Le Lettrage partiel est autorisé. Les écritures doivent avoir le même partenaire et la référence sur les écritures de crédit doit se retrouver dans la référence ou la description sur les écritures de débit." | ||
298 | 52 | |||
299 | 53 | #. module: account_advanced_reconcile | ||
300 | 54 | #: field:easy.reconcile.advanced,filter:0 | 54 | #: field:easy.reconcile.advanced,filter:0 |
301 | 55 | #: field:easy.reconcile.advanced.ref,filter:0 | 55 | #: field:easy.reconcile.advanced.ref,filter:0 |
302 | 56 | msgid "Filter" | 56 | msgid "Filter" |
303 | @@ -62,9 +62,10 @@ | |||
304 | 62 | msgstr "Avancé. Partenaire et Réf." | 62 | msgstr "Avancé. Partenaire et Réf." |
305 | 63 | 63 | ||
306 | 64 | #. module: account_advanced_reconcile | 64 | #. module: account_advanced_reconcile |
310 | 65 | #: view:account.easy.reconcile:0 | 65 | #: field:easy.reconcile.advanced,date_base_on:0 |
311 | 66 | msgid "Match multiple debit vs multiple credit entries. Allow partial reconcilation. The lines should have the partner, the credit entry ref. is matched vs the debit entry ref. or name." | 66 | #: field:easy.reconcile.advanced.ref,date_base_on:0 |
312 | 67 | msgstr "Le Lettrage peut s'effectuer sur plusieurs écritures de débit et crédit. Le Lettrage partiel est autorisé. Les écritures doivent avoir le même partenaire et la référence sur les écritures de crédit doit se retrouver dans la référence ou la description sur les écritures de débit." | 67 | msgid "Date of reconciliation" |
313 | 68 | msgstr "Date de lettrage" | ||
314 | 68 | 69 | ||
315 | 69 | #. module: account_advanced_reconcile | 70 | #. module: account_advanced_reconcile |
316 | 70 | #: model:ir.model,name:account_advanced_reconcile.model_easy_reconcile_advanced | 71 | #: model:ir.model,name:account_advanced_reconcile.model_easy_reconcile_advanced |
317 | 71 | 72 | ||
318 | === modified file 'account_easy_reconcile/__openerp__.py' | |||
319 | --- account_easy_reconcile/__openerp__.py 2013-03-12 12:11:33 +0000 | |||
320 | +++ account_easy_reconcile/__openerp__.py 2013-06-10 07:05:32 +0000 | |||
321 | @@ -20,12 +20,19 @@ | |||
322 | 20 | ############################################################################## | 20 | ############################################################################## |
323 | 21 | 21 | ||
324 | 22 | { | 22 | { |
325 | 23 | <<<<<<< TREE | ||
326 | 23 | "name" : "Easy Reconcile", | 24 | "name" : "Easy Reconcile", |
327 | 24 | "version" : "1.1", | 25 | "version" : "1.1", |
328 | 25 | "depends" : ["account", | 26 | "depends" : ["account", |
329 | 26 | "base_scheduler_creator" | 27 | "base_scheduler_creator" |
330 | 27 | ], | 28 | ], |
331 | 28 | "author" : "Akretion,Camptocamp", | 29 | "author" : "Akretion,Camptocamp", |
332 | 30 | ======= | ||
333 | 31 | "name": "Easy Reconcile", | ||
334 | 32 | "version": "1.3.0", | ||
335 | 33 | "depends": ["account"], | ||
336 | 34 | "author": "Akretion,Camptocamp", | ||
337 | 35 | >>>>>>> MERGE-SOURCE | ||
338 | 29 | "description": """ | 36 | "description": """ |
339 | 30 | Easy Reconcile | 37 | Easy Reconcile |
340 | 31 | ============== | 38 | ============== |
341 | @@ -44,13 +51,13 @@ | |||
342 | 44 | reconciliation methods which can plug in the profiles | 51 | reconciliation methods which can plug in the profiles |
343 | 45 | - a profile a reconciliation can be run manually or by a cron | 52 | - a profile a reconciliation can be run manually or by a cron |
344 | 46 | - monitoring of reconciliation runs with an history | 53 | - monitoring of reconciliation runs with an history |
346 | 47 | which keep track of the reconciled entries | 54 | which keep track of the reconciled Journal items |
347 | 48 | 55 | ||
348 | 49 | 2 simple reconciliation methods are integrated | 56 | 2 simple reconciliation methods are integrated |
349 | 50 | in this module, the simple reconciliations works | 57 | in this module, the simple reconciliations works |
350 | 51 | on 2 lines (1 debit / 1 credit) and do not allow | 58 | on 2 lines (1 debit / 1 credit) and do not allow |
351 | 52 | partial reconcilation, they also match on 1 key, | 59 | partial reconcilation, they also match on 1 key, |
353 | 53 | partner or entry name. | 60 | partner or Journal item name. |
354 | 54 | 61 | ||
355 | 55 | You may be interested to install also the | 62 | You may be interested to install also the |
356 | 56 | ``account_advanced_reconciliation`` module. | 63 | ``account_advanced_reconciliation`` module. |
357 | @@ -58,14 +65,13 @@ | |||
358 | 58 | allows multiple lines and partial. | 65 | allows multiple lines and partial. |
359 | 59 | 66 | ||
360 | 60 | """, | 67 | """, |
369 | 61 | "website" : "http://www.akretion.com/", | 68 | "website": "http://www.akretion.com/", |
370 | 62 | "category" : "Finance", | 69 | "category": "Finance", |
371 | 63 | "init_xml" : [], | 70 | "demo_xml": [], |
372 | 64 | "demo_xml" : [], | 71 | "data": ["easy_reconcile.xml", |
373 | 65 | "update_xml" : [ | 72 | "easy_reconcile_history_view.xml", |
374 | 66 | "easy_reconcile.xml", | 73 | "security/ir_rule.xml", |
375 | 67 | "easy_reconcile_history_view.xml", | 74 | "security/ir.model.access.csv"], |
368 | 68 | ], | ||
376 | 69 | 'license': 'AGPL-3', | 75 | 'license': 'AGPL-3', |
377 | 70 | "auto_install": False, | 76 | "auto_install": False, |
378 | 71 | "installable": True, | 77 | "installable": True, |
379 | 72 | 78 | ||
380 | === modified file 'account_easy_reconcile/base_reconciliation.py' | |||
381 | --- account_easy_reconcile/base_reconciliation.py 2012-11-01 16:12:50 +0000 | |||
382 | +++ account_easy_reconcile/base_reconciliation.py 2013-06-10 07:05:32 +0000 | |||
383 | @@ -1,7 +1,7 @@ | |||
384 | 1 | # -*- coding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- |
385 | 2 | ############################################################################## | 2 | ############################################################################## |
386 | 3 | # | 3 | # |
388 | 4 | # Copyright 2012 Camptocamp SA (Guewen Baconnier) | 4 | # Copyright 2012-2013 Camptocamp SA (Guewen Baconnier) |
389 | 5 | # Copyright (C) 2010 Sébastien Beau | 5 | # Copyright (C) 2010 Sébastien Beau |
390 | 6 | # | 6 | # |
391 | 7 | # This program is free software: you can redistribute it and/or modify | 7 | # This program is free software: you can redistribute it and/or modify |
392 | @@ -19,29 +19,29 @@ | |||
393 | 19 | # | 19 | # |
394 | 20 | ############################################################################## | 20 | ############################################################################## |
395 | 21 | 21 | ||
398 | 22 | from openerp.osv.orm import AbstractModel | 22 | from openerp.osv import fields, orm |
397 | 23 | from openerp.osv import fields | ||
399 | 24 | from operator import itemgetter, attrgetter | 23 | from operator import itemgetter, attrgetter |
400 | 25 | 24 | ||
401 | 26 | 25 | ||
403 | 27 | class easy_reconcile_base(AbstractModel): | 26 | class easy_reconcile_base(orm.AbstractModel): |
404 | 28 | """Abstract Model for reconciliation methods""" | 27 | """Abstract Model for reconciliation methods""" |
405 | 29 | 28 | ||
406 | 30 | _name = 'easy.reconcile.base' | 29 | _name = 'easy.reconcile.base' |
407 | 31 | 30 | ||
408 | 32 | _inherit = 'easy.reconcile.options' | 31 | _inherit = 'easy.reconcile.options' |
409 | 33 | _auto = True # restore property set to False by AbstractModel | ||
410 | 34 | 32 | ||
411 | 35 | _columns = { | 33 | _columns = { |
415 | 36 | 'account_id': fields.many2one('account.account', 'Account', required=True), | 34 | 'account_id': fields.many2one( |
416 | 37 | 'partner_ids': fields.many2many('res.partner', | 35 | 'account.account', 'Account', required=True), |
417 | 38 | string="Restrict on partners"), | 36 | 'partner_ids': fields.many2many( |
418 | 37 | 'res.partner', string="Restrict on partners"), | ||
419 | 39 | # other columns are inherited from easy.reconcile.options | 38 | # other columns are inherited from easy.reconcile.options |
420 | 40 | } | 39 | } |
421 | 41 | 40 | ||
422 | 42 | def automatic_reconcile(self, cr, uid, ids, context=None): | 41 | def automatic_reconcile(self, cr, uid, ids, context=None): |
425 | 43 | """ | 42 | """ Reconciliation method called from the view. |
426 | 44 | :return: list of reconciled ids, list of partially reconciled entries | 43 | |
427 | 44 | :return: list of reconciled ids, list of partially reconciled items | ||
428 | 45 | """ | 45 | """ |
429 | 46 | if isinstance(ids, (int, long)): | 46 | if isinstance(ids, (int, long)): |
430 | 47 | ids = [ids] | 47 | ids = [ids] |
431 | @@ -50,14 +50,15 @@ | |||
432 | 50 | return self._action_rec(cr, uid, rec, context=context) | 50 | return self._action_rec(cr, uid, rec, context=context) |
433 | 51 | 51 | ||
434 | 52 | def _action_rec(self, cr, uid, rec, context=None): | 52 | def _action_rec(self, cr, uid, rec, context=None): |
436 | 53 | """Must be inherited to implement the reconciliation | 53 | """ Must be inherited to implement the reconciliation |
437 | 54 | |||
438 | 54 | :return: list of reconciled ids | 55 | :return: list of reconciled ids |
439 | 55 | """ | 56 | """ |
440 | 56 | raise NotImplementedError | 57 | raise NotImplementedError |
441 | 57 | 58 | ||
442 | 58 | def _base_columns(self, rec): | 59 | def _base_columns(self, rec): |
445 | 59 | """Mandatory columns for move lines queries | 60 | """ Mandatory columns for move lines queries |
446 | 60 | An extra column aliased as `key` should be defined | 61 | An extra column aliased as ``key`` should be defined |
447 | 61 | in each query.""" | 62 | in each query.""" |
448 | 62 | aml_cols = ( | 63 | aml_cols = ( |
449 | 63 | 'id', | 64 | 'id', |
450 | @@ -104,7 +105,7 @@ | |||
451 | 104 | return where, params | 105 | return where, params |
452 | 105 | 106 | ||
453 | 106 | def _below_writeoff_limit(self, cr, uid, rec, lines, | 107 | def _below_writeoff_limit(self, cr, uid, rec, lines, |
455 | 107 | writeoff_limit, context=None): | 108 | writeoff_limit, context=None): |
456 | 108 | precision = self.pool.get('decimal.precision').precision_get( | 109 | precision = self.pool.get('decimal.precision').precision_get( |
457 | 109 | cr, uid, 'Account') | 110 | cr, uid, 'Account') |
458 | 110 | keys = ('debit', 'credit') | 111 | keys = ('debit', 'credit') |
459 | @@ -119,7 +120,8 @@ | |||
460 | 119 | writeoff_amount = round(debit - credit, precision) | 120 | writeoff_amount = round(debit - credit, precision) |
461 | 120 | return bool(writeoff_limit >= abs(writeoff_amount)), debit, credit | 121 | return bool(writeoff_limit >= abs(writeoff_amount)), debit, credit |
462 | 121 | 122 | ||
464 | 122 | def _get_rec_date(self, cr, uid, rec, lines, based_on='end_period_last_credit', context=None): | 123 | def _get_rec_date(self, cr, uid, rec, lines, |
465 | 124 | based_on='end_period_last_credit', context=None): | ||
466 | 123 | period_obj = self.pool.get('account.period') | 125 | period_obj = self.pool.get('account.period') |
467 | 124 | 126 | ||
468 | 125 | def last_period(mlines): | 127 | def last_period(mlines): |
469 | @@ -155,12 +157,14 @@ | |||
470 | 155 | """ Try to reconcile given lines | 157 | """ Try to reconcile given lines |
471 | 156 | 158 | ||
472 | 157 | :param list lines: list of dict of move lines, they must at least | 159 | :param list lines: list of dict of move lines, they must at least |
474 | 158 | contain values for : id, debit, credit | 160 | contain values for : id, debit, credit |
475 | 159 | :param boolean allow_partial: if True, partial reconciliation will be | 161 | :param boolean allow_partial: if True, partial reconciliation will be |
480 | 160 | created, otherwise only Full reconciliation will be created | 162 | created, otherwise only Full |
481 | 161 | :return: tuple of boolean values, first item is wether the the entries | 163 | reconciliation will be created |
482 | 162 | have been reconciled or not, the second is wether the reconciliation | 164 | :return: tuple of boolean values, first item is wether the items |
483 | 163 | is full (True) or partial (False) | 165 | have been reconciled or not, |
484 | 166 | the second is wether the reconciliation is full (True) | ||
485 | 167 | or partial (False) | ||
486 | 164 | """ | 168 | """ |
487 | 165 | if context is None: | 169 | if context is None: |
488 | 166 | context = {} | 170 | context = {} |
489 | @@ -168,8 +172,6 @@ | |||
490 | 168 | ml_obj = self.pool.get('account.move.line') | 172 | ml_obj = self.pool.get('account.move.line') |
491 | 169 | writeoff = rec.write_off | 173 | writeoff = rec.write_off |
492 | 170 | 174 | ||
493 | 171 | keys = ('debit', 'credit') | ||
494 | 172 | |||
495 | 173 | line_ids = [l['id'] for l in lines] | 175 | line_ids = [l['id'] for l in lines] |
496 | 174 | below_writeoff, sum_debit, sum_credit = self._below_writeoff_limit( | 176 | below_writeoff, sum_debit, sum_credit = self._below_writeoff_limit( |
497 | 175 | cr, uid, rec, lines, writeoff, context=context) | 177 | cr, uid, rec, lines, writeoff, context=context) |
498 | @@ -204,4 +206,3 @@ | |||
499 | 204 | return True, False | 206 | return True, False |
500 | 205 | 207 | ||
501 | 206 | return False, False | 208 | return False, False |
502 | 207 | |||
503 | 208 | 209 | ||
504 | === modified file 'account_easy_reconcile/easy_reconcile.py' | |||
505 | --- account_easy_reconcile/easy_reconcile.py 2013-01-03 15:27:55 +0000 | |||
506 | +++ account_easy_reconcile/easy_reconcile.py 2013-06-10 07:05:32 +0000 | |||
507 | @@ -1,7 +1,7 @@ | |||
508 | 1 | # -*- coding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- |
509 | 2 | ############################################################################## | 2 | ############################################################################## |
510 | 3 | # | 3 | # |
512 | 4 | # Copyright 2012 Camptocamp SA (Guewen Baconnier) | 4 | # Copyright 2012-2013 Camptocamp SA (Guewen Baconnier) |
513 | 5 | # Copyright (C) 2010 Sébastien Beau | 5 | # Copyright (C) 2010 Sébastien Beau |
514 | 6 | # | 6 | # |
515 | 7 | # This program is free software: you can redistribute it and/or modify | 7 | # This program is free software: you can redistribute it and/or modify |
516 | @@ -19,19 +19,18 @@ | |||
517 | 19 | # | 19 | # |
518 | 20 | ############################################################################## | 20 | ############################################################################## |
519 | 21 | 21 | ||
523 | 22 | import time | 22 | from openerp.osv import fields, osv, orm |
521 | 23 | from openerp.osv.orm import Model, AbstractModel | ||
522 | 24 | from openerp.osv import fields | ||
524 | 25 | from openerp.tools.translate import _ | 23 | from openerp.tools.translate import _ |
525 | 26 | from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT | 24 | from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT |
526 | 27 | 25 | ||
527 | 28 | 26 | ||
534 | 29 | class easy_reconcile_options(AbstractModel): | 27 | class easy_reconcile_options(orm.AbstractModel): |
535 | 30 | """Options of a reconciliation profile, columns | 28 | """Options of a reconciliation profile |
536 | 31 | shared by the configuration of methods and by the | 29 | |
537 | 32 | reconciliation wizards. This allows decoupling | 30 | Columns shared by the configuration of methods |
538 | 33 | of the methods with the wizards and allows to | 31 | and by the reconciliation wizards. |
539 | 34 | launch the wizards alone | 32 | This allows decoupling of the methods and the |
540 | 33 | wizards and allows to launch the wizards alone | ||
541 | 35 | """ | 34 | """ |
542 | 36 | 35 | ||
543 | 37 | _name = 'easy.reconcile.options' | 36 | _name = 'easy.reconcile.options' |
544 | @@ -46,12 +45,16 @@ | |||
545 | 46 | 45 | ||
546 | 47 | _columns = { | 46 | _columns = { |
547 | 48 | 'write_off': fields.float('Write off allowed'), | 47 | 'write_off': fields.float('Write off allowed'), |
552 | 49 | 'account_lost_id': fields.many2one('account.account', 'Account Lost'), | 48 | 'account_lost_id': fields.many2one( |
553 | 50 | 'account_profit_id': fields.many2one('account.account', 'Account Profit'), | 49 | 'account.account', 'Account Lost'), |
554 | 51 | 'journal_id': fields.many2one('account.journal', 'Journal'), | 50 | 'account_profit_id': fields.many2one( |
555 | 52 | 'date_base_on': fields.selection(_get_rec_base_date, | 51 | 'account.account', 'Account Profit'), |
556 | 52 | 'journal_id': fields.many2one( | ||
557 | 53 | 'account.journal', 'Journal'), | ||
558 | 54 | 'date_base_on': fields.selection( | ||
559 | 55 | _get_rec_base_date, | ||
560 | 53 | required=True, | 56 | required=True, |
562 | 54 | string='Date of reconcilation'), | 57 | string='Date of reconciliation'), |
563 | 55 | 'filter': fields.char('Filter', size=128), | 58 | 'filter': fields.char('Filter', size=128), |
564 | 56 | } | 59 | } |
565 | 57 | 60 | ||
566 | @@ -61,13 +64,12 @@ | |||
567 | 61 | } | 64 | } |
568 | 62 | 65 | ||
569 | 63 | 66 | ||
571 | 64 | class account_easy_reconcile_method(Model): | 67 | class account_easy_reconcile_method(orm.Model): |
572 | 65 | 68 | ||
573 | 66 | _name = 'account.easy.reconcile.method' | 69 | _name = 'account.easy.reconcile.method' |
574 | 67 | _description = 'reconcile method for account_easy_reconcile' | 70 | _description = 'reconcile method for account_easy_reconcile' |
575 | 68 | 71 | ||
576 | 69 | _inherit = 'easy.reconcile.options' | 72 | _inherit = 'easy.reconcile.options' |
577 | 70 | _auto = True # restore property set to False by AbstractModel | ||
578 | 71 | 73 | ||
579 | 72 | _order = 'sequence' | 74 | _order = 'sequence' |
580 | 73 | 75 | ||
581 | @@ -82,11 +84,24 @@ | |||
582 | 82 | return self._get_all_rec_method(cr, uid, context=None) | 84 | return self._get_all_rec_method(cr, uid, context=None) |
583 | 83 | 85 | ||
584 | 84 | _columns = { | 86 | _columns = { |
590 | 85 | 'name': fields.selection(_get_rec_method, 'Type', size=128, required=True), | 87 | 'name': fields.selection( |
591 | 86 | 'sequence': fields.integer('Sequence', required=True, | 88 | _get_rec_method, 'Type', required=True), |
592 | 87 | help="The sequence field is used to order the reconcile method"), | 89 | 'sequence': fields.integer( |
593 | 88 | 'task_id': fields.many2one('account.easy.reconcile', 'Task', | 90 | 'Sequence', |
594 | 89 | required=True, ondelete='cascade'), | 91 | required=True, |
595 | 92 | help="The sequence field is used to order " | ||
596 | 93 | "the reconcile method"), | ||
597 | 94 | 'task_id': fields.many2one( | ||
598 | 95 | 'account.easy.reconcile', | ||
599 | 96 | string='Task', | ||
600 | 97 | required=True, | ||
601 | 98 | ondelete='cascade'), | ||
602 | 99 | 'company_id': fields.related('task_id','company_id', | ||
603 | 100 | relation='res.company', | ||
604 | 101 | type='many2one', | ||
605 | 102 | string='Company', | ||
606 | 103 | store=True, | ||
607 | 104 | readonly=True), | ||
608 | 90 | } | 105 | } |
609 | 91 | 106 | ||
610 | 92 | _defaults = { | 107 | _defaults = { |
611 | @@ -94,8 +109,11 @@ | |||
612 | 94 | } | 109 | } |
613 | 95 | 110 | ||
614 | 96 | def init(self, cr): | 111 | def init(self, cr): |
617 | 97 | """ Migration stuff, name is not anymore methods names | 112 | """ Migration stuff |
618 | 98 | but models name""" | 113 | |
619 | 114 | Name is not anymore methods names but the name | ||
620 | 115 | of the model which does the reconciliation | ||
621 | 116 | """ | ||
622 | 99 | cr.execute(""" | 117 | cr.execute(""" |
623 | 100 | UPDATE account_easy_reconcile_method | 118 | UPDATE account_easy_reconcile_method |
624 | 101 | SET name = 'easy.reconcile.simple.partner' | 119 | SET name = 'easy.reconcile.simple.partner' |
625 | @@ -108,7 +126,7 @@ | |||
626 | 108 | """) | 126 | """) |
627 | 109 | 127 | ||
628 | 110 | 128 | ||
630 | 111 | class account_easy_reconcile(Model): | 129 | class account_easy_reconcile(orm.Model): |
631 | 112 | 130 | ||
632 | 113 | _name = 'account.easy.reconcile' | 131 | _name = 'account.easy.reconcile' |
633 | 114 | _description = 'account easy reconcile' | 132 | _description = 'account easy reconcile' |
634 | @@ -147,17 +165,22 @@ | |||
635 | 147 | return result | 165 | return result |
636 | 148 | 166 | ||
637 | 149 | _columns = { | 167 | _columns = { |
645 | 150 | 'name': fields.char('Name', size=64, required=True), | 168 | 'name': fields.char('Name', required=True), |
646 | 151 | 'account': fields.many2one('account.account', 'Account', required=True), | 169 | 'account': fields.many2one( |
647 | 152 | 'reconcile_method': fields.one2many('account.easy.reconcile.method', 'task_id', 'Method'), | 170 | 'account.account', 'Account', required=True), |
648 | 153 | 'unreconciled_count': fields.function(_get_total_unrec, | 171 | 'reconcile_method': fields.one2many( |
649 | 154 | type='integer', string='Unreconciled Entries'), | 172 | 'account.easy.reconcile.method', 'task_id', 'Method'), |
650 | 155 | 'reconciled_partial_count': fields.function(_get_partial_rec, | 173 | 'unreconciled_count': fields.function( |
651 | 156 | type='integer', string='Partially Reconciled Entries'), | 174 | _get_total_unrec, type='integer', string='Unreconciled Items'), |
652 | 175 | 'reconciled_partial_count': fields.function( | ||
653 | 176 | _get_partial_rec, | ||
654 | 177 | type='integer', | ||
655 | 178 | string='Partially Reconciled Items'), | ||
656 | 157 | 'history_ids': fields.one2many( | 179 | 'history_ids': fields.one2many( |
657 | 158 | 'easy.reconcile.history', | 180 | 'easy.reconcile.history', |
658 | 159 | 'easy_reconcile_id', | 181 | 'easy_reconcile_id', |
660 | 160 | string='History'), | 182 | string='History', |
661 | 183 | readonly=True), | ||
662 | 161 | 'last_history': | 184 | 'last_history': |
663 | 162 | fields.function( | 185 | fields.function( |
664 | 163 | _last_history, | 186 | _last_history, |
665 | @@ -165,16 +188,18 @@ | |||
666 | 165 | type='many2one', | 188 | type='many2one', |
667 | 166 | relation='easy.reconcile.history', | 189 | relation='easy.reconcile.history', |
668 | 167 | readonly=True), | 190 | readonly=True), |
669 | 191 | 'company_id': fields.many2one('res.company', 'Company'), | ||
670 | 168 | } | 192 | } |
671 | 169 | 193 | ||
672 | 170 | def _prepare_run_transient(self, cr, uid, rec_method, context=None): | 194 | def _prepare_run_transient(self, cr, uid, rec_method, context=None): |
673 | 171 | return {'account_id': rec_method.task_id.account.id, | 195 | return {'account_id': rec_method.task_id.account.id, |
674 | 172 | 'write_off': rec_method.write_off, | 196 | 'write_off': rec_method.write_off, |
680 | 173 | 'account_lost_id': rec_method.account_lost_id and \ | 197 | 'account_lost_id': (rec_method.account_lost_id and |
681 | 174 | rec_method.account_lost_id.id, | 198 | rec_method.account_lost_id.id), |
682 | 175 | 'account_profit_id': rec_method.account_profit_id and \ | 199 | 'account_profit_id': (rec_method.account_profit_id and |
683 | 176 | rec_method.account_profit_id.id, | 200 | rec_method.account_profit_id.id), |
684 | 177 | 'journal_id': rec_method.journal_id and rec_method.journal_id.id, | 201 | 'journal_id': (rec_method.journal_id and |
685 | 202 | rec_method.journal_id.id), | ||
686 | 178 | 'date_base_on': rec_method.date_base_on, | 203 | 'date_base_on': rec_method.date_base_on, |
687 | 179 | 'filter': rec_method.filter} | 204 | 'filter': rec_method.filter} |
688 | 180 | 205 | ||
689 | @@ -190,8 +215,6 @@ | |||
690 | 190 | res = cr.fetchall() | 215 | res = cr.fetchall() |
691 | 191 | return [row[0] for row in res] | 216 | return [row[0] for row in res] |
692 | 192 | 217 | ||
693 | 193 | if context is None: | ||
694 | 194 | context = {} | ||
695 | 195 | for rec in self.browse(cr, uid, ids, context=context): | 218 | for rec in self.browse(cr, uid, ids, context=context): |
696 | 196 | all_ml_rec_ids = [] | 219 | all_ml_rec_ids = [] |
697 | 197 | all_ml_partial_ids = [] | 220 | all_ml_partial_ids = [] |
698 | @@ -200,7 +223,8 @@ | |||
699 | 200 | rec_model = self.pool.get(method.name) | 223 | rec_model = self.pool.get(method.name) |
700 | 201 | auto_rec_id = rec_model.create( | 224 | auto_rec_id = rec_model.create( |
701 | 202 | cr, uid, | 225 | cr, uid, |
703 | 203 | self._prepare_run_transient(cr, uid, method, context=context), | 226 | self._prepare_run_transient( |
704 | 227 | cr, uid, method, context=context), | ||
705 | 204 | context=context) | 228 | context=context) |
706 | 205 | 229 | ||
707 | 206 | ml_rec_ids, ml_partial_ids = rec_model.automatic_reconcile( | 230 | ml_rec_ids, ml_partial_ids = rec_model.automatic_reconcile( |
708 | @@ -224,6 +248,7 @@ | |||
709 | 224 | context=context) | 248 | context=context) |
710 | 225 | return True | 249 | return True |
711 | 226 | 250 | ||
712 | 251 | <<<<<<< TREE | ||
713 | 227 | def _no_history(self, cr, uid, rec, context=None): | 252 | def _no_history(self, cr, uid, rec, context=None): |
714 | 228 | """ Raise an `osv.except_osv` error, supposed to | 253 | """ Raise an `osv.except_osv` error, supposed to |
715 | 229 | be called when there is no history on the reconciliation | 254 | be called when there is no history on the reconciliation |
716 | @@ -234,6 +259,18 @@ | |||
717 | 234 | _('There is no history of reconciled ' | 259 | _('There is no history of reconciled ' |
718 | 235 | 'entries on the task: %s.') % rec.name) | 260 | 'entries on the task: %s.') % rec.name) |
719 | 236 | 261 | ||
720 | 262 | ======= | ||
721 | 263 | def _no_history(self, cr, uid, rec, context=None): | ||
722 | 264 | """ Raise an `osv.except_osv` error, supposed to | ||
723 | 265 | be called when there is no history on the reconciliation | ||
724 | 266 | task. | ||
725 | 267 | """ | ||
726 | 268 | raise osv.except_osv( | ||
727 | 269 | _('Error'), | ||
728 | 270 | _('There is no history of reconciled ' | ||
729 | 271 | 'items on the task: %s.') % rec.name) | ||
730 | 272 | |||
731 | 273 | >>>>>>> MERGE-SOURCE | ||
732 | 237 | def last_history_reconcile(self, cr, uid, rec_id, context=None): | 274 | def last_history_reconcile(self, cr, uid, rec_id, context=None): |
733 | 238 | """ Get the last history record for this reconciliation profile | 275 | """ Get the last history record for this reconciliation profile |
734 | 239 | and return the action which opens move lines reconciled | 276 | and return the action which opens move lines reconciled |
735 | 240 | 277 | ||
736 | === modified file 'account_easy_reconcile/easy_reconcile.xml' | |||
737 | --- account_easy_reconcile/easy_reconcile.xml 2012-12-20 11:05:28 +0000 | |||
738 | +++ account_easy_reconcile/easy_reconcile.xml 2013-06-10 07:05:32 +0000 | |||
739 | @@ -1,4 +1,4 @@ | |||
741 | 1 | <?xml version="1.0" encoding="UTF-8"?> | 1 | <?xml version="1.0" encoding="UTF-8"?> |
742 | 2 | <openerp> | 2 | <openerp> |
743 | 3 | <data> | 3 | <data> |
744 | 4 | 4 | ||
745 | @@ -7,52 +7,64 @@ | |||
746 | 7 | <field name="name">account.easy.reconcile.form</field> | 7 | <field name="name">account.easy.reconcile.form</field> |
747 | 8 | <field name="priority">20</field> | 8 | <field name="priority">20</field> |
748 | 9 | <field name="model">account.easy.reconcile</field> | 9 | <field name="model">account.easy.reconcile</field> |
749 | 10 | <field name="type">form</field> | ||
750 | 11 | <field name="arch" type="xml"> | 10 | <field name="arch" type="xml"> |
787 | 12 | <form string="Automatic Easy Reconcile"> | 11 | <form string="Automatic Easy Reconcile" version="7.0"> |
788 | 13 | <separator colspan="4" string="Task Information" /> | 12 | <header> |
789 | 14 | <field name="name" select="1"/> | 13 | <button name="run_reconcile" class="oe_highlight" |
790 | 15 | <field name="account"/> | 14 | string="Start Auto Reconciliation" type="object"/> |
791 | 16 | <field name="unreconciled_count"/> | 15 | <button icon="STOCK_JUMP_TO" name="last_history_reconcile" |
792 | 17 | <field name="reconciled_partial_count"/> | 16 | class="oe_highlight" |
793 | 18 | <separator colspan="4" string="Reconcile Method" /> | 17 | string="Display items reconciled on the last run" |
794 | 19 | <notebook colspan="4"> | 18 | type="object"/> |
795 | 20 | <page name="methods" string="Configuration"> | 19 | <button icon="STOCK_JUMP_TO" name="last_history_partial" |
796 | 21 | <field name="reconcile_method" colspan = "4" nolabel="1"/> | 20 | class="oe_highlight" |
797 | 22 | <button icon="gtk-ok" name="run_reconcile" colspan="4" | 21 | string="Display items partially reconciled on the last run" |
798 | 23 | string="Start Auto Reconcilation" type="object"/> | 22 | type="object"/> |
799 | 24 | <button icon="STOCK_JUMP_TO" name="last_history_reconcile" colspan="2" | 23 | </header> |
800 | 25 | string="Display items reconciled on the last run" type="object"/> | 24 | <sheet> |
801 | 26 | <button icon="STOCK_JUMP_TO" name="last_history_partial" colspan="2" | 25 | <separator colspan="4" string="Profile Information" /> |
802 | 27 | string="Display items partially reconciled on the last run" | 26 | <group> |
803 | 28 | type="object"/> | 27 | <group> |
804 | 29 | </page> | 28 | <field name="name" select="1"/> |
805 | 30 | <page name="history" string="History"> | 29 | <field name="account"/> |
806 | 31 | <field name="history_ids" nolabel="1"> | 30 | <field name="company_id" groups="base.group_multi_company"/> |
807 | 32 | <tree string="Automatic Easy Reconcile History"> | 31 | </group> |
808 | 33 | <field name="date"/> | 32 | <group> |
809 | 34 | <!-- display the count of lines --> | 33 | <field name="unreconciled_count"/> |
810 | 35 | <field name="reconcile_line_ids"/> | 34 | <field name="reconciled_partial_count"/> |
811 | 36 | <button icon="STOCK_JUMP_TO" name="open_reconcile" | 35 | </group> |
812 | 37 | string="Go to reconciled items" type="object"/> | 36 | </group> |
813 | 38 | <!-- display the count of lines --> | 37 | <notebook colspan="4"> |
814 | 39 | <field name="partial_line_ids"/> | 38 | <page name="methods" string="Configuration"> |
815 | 40 | <button icon="STOCK_JUMP_TO" name="open_partial" | 39 | <field name="reconcile_method" colspan = "4" nolabel="1"/> |
816 | 41 | string="Go to partially reconciled items" type="object"/> | 40 | </page> |
817 | 42 | </tree> | 41 | <page name="history" string="History"> |
818 | 43 | </field> | 42 | <field name="history_ids" nolabel="1"> |
819 | 44 | </page> | 43 | <tree string="Automatic Easy Reconcile History"> |
820 | 45 | <page name="information" string="Information"> | 44 | <field name="date"/> |
821 | 46 | <separator colspan="4" string="Simple. Amount and Name"/> | 45 | <button icon="STOCK_JUMP_TO" name="open_reconcile" |
822 | 47 | <label string="Match one debit line vs one credit line. Do not allow partial reconcilation. | 46 | string="Go to reconciled items" type="object"/> |
823 | 47 | <button icon="STOCK_JUMP_TO" name="open_partial" | ||
824 | 48 | string="Go to partially reconciled items" type="object"/> | ||
825 | 49 | </tree> | ||
826 | 50 | </field> | ||
827 | 51 | </page> | ||
828 | 52 | <page name="information" string="Information"> | ||
829 | 53 | <separator colspan="4" string="Simple. Amount and Name"/> | ||
830 | 54 | <label string="Match one debit line vs one credit line. Do not allow partial reconciliation. | ||
831 | 48 | The lines should have the same amount (with the write-off) and the same name to be reconciled." colspan="4"/> | 55 | The lines should have the same amount (with the write-off) and the same name to be reconciled." colspan="4"/> |
832 | 49 | 56 | ||
835 | 50 | <separator colspan="4" string="Simple. Amount and Name"/> | 57 | <separator colspan="4" string="Simple. Amount and Partner"/> |
836 | 51 | <label string="Match one debit line vs one credit line. Do not allow partial reconcilation. | 58 | <label string="Match one debit line vs one credit line. Do not allow partial reconciliation. |
837 | 52 | The lines should have the same amount (with the write-off) and the same partner to be reconciled." colspan="4"/> | 59 | The lines should have the same amount (with the write-off) and the same partner to be reconciled." colspan="4"/> |
838 | 53 | 60 | ||
841 | 54 | </page> | 61 | <separator colspan="4" string="Simple. Amount and Reference"/> |
842 | 55 | </notebook> | 62 | <label string="Match one debit line vs one credit line. Do not allow partial reconciliation. |
843 | 63 | The lines should have the same amount (with the write-off) and the same reference to be reconciled." colspan="4"/> | ||
844 | 64 | |||
845 | 65 | </page> | ||
846 | 66 | </notebook> | ||
847 | 67 | </sheet> | ||
848 | 56 | </form> | 68 | </form> |
849 | 57 | </field> | 69 | </field> |
850 | 58 | </record> | 70 | </record> |
851 | @@ -61,11 +73,11 @@ | |||
852 | 61 | <field name="name">account.easy.reconcile.tree</field> | 73 | <field name="name">account.easy.reconcile.tree</field> |
853 | 62 | <field name="priority">20</field> | 74 | <field name="priority">20</field> |
854 | 63 | <field name="model">account.easy.reconcile</field> | 75 | <field name="model">account.easy.reconcile</field> |
855 | 64 | <field name="type">tree</field> | ||
856 | 65 | <field name="arch" type="xml"> | 76 | <field name="arch" type="xml"> |
857 | 66 | <tree string="Automatic Easy Reconcile"> | 77 | <tree string="Automatic Easy Reconcile"> |
858 | 67 | <field name="name"/> | 78 | <field name="name"/> |
859 | 68 | <field name="account"/> | 79 | <field name="account"/> |
860 | 80 | <field name="company_id" groups="base.group_multi_company"/> | ||
861 | 69 | <field name="unreconciled_count"/> | 81 | <field name="unreconciled_count"/> |
862 | 70 | <field name="reconciled_partial_count"/> | 82 | <field name="reconciled_partial_count"/> |
863 | 71 | <button icon="gtk-ok" name="run_reconcile" colspan="4" | 83 | <button icon="gtk-ok" name="run_reconcile" colspan="4" |
864 | @@ -85,16 +97,25 @@ | |||
865 | 85 | <field name="res_model">account.easy.reconcile</field> | 97 | <field name="res_model">account.easy.reconcile</field> |
866 | 86 | <field name="view_type">form</field> | 98 | <field name="view_type">form</field> |
867 | 87 | <field name="view_mode">tree,form</field> | 99 | <field name="view_mode">tree,form</field> |
868 | 100 | <field name="help" type="html"> | ||
869 | 101 | <p class="oe_view_nocontent_create"> | ||
870 | 102 | Click to add a reconciliation profile. | ||
871 | 103 | </p><p> | ||
872 | 104 | A reconciliation profile specifies, for one account, how | ||
873 | 105 | the entries should be reconciled. | ||
874 | 106 | You can select one or many reconciliation methods which will | ||
875 | 107 | be run sequentially to match the entries between them. | ||
876 | 108 | </p> | ||
877 | 109 | </field> | ||
878 | 88 | </record> | 110 | </record> |
879 | 89 | 111 | ||
880 | 90 | 112 | ||
882 | 91 | <!-- account.easy.reconcile.method view --> | 113 | <!-- account.easy.reconcile.method view --> |
883 | 92 | 114 | ||
884 | 93 | <record id="account_easy_reconcile_method_form" model="ir.ui.view"> | 115 | <record id="account_easy_reconcile_method_form" model="ir.ui.view"> |
885 | 94 | <field name="name">account.easy.reconcile.method.form</field> | 116 | <field name="name">account.easy.reconcile.method.form</field> |
886 | 95 | <field name="priority">20</field> | 117 | <field name="priority">20</field> |
887 | 96 | <field name="model">account.easy.reconcile.method</field> | 118 | <field name="model">account.easy.reconcile.method</field> |
888 | 97 | <field name="type">form</field> | ||
889 | 98 | <field name="arch" type="xml"> | 119 | <field name="arch" type="xml"> |
890 | 99 | <form string="Automatic Easy Reconcile Method"> | 120 | <form string="Automatic Easy Reconcile Method"> |
891 | 100 | <field name="sequence"/> | 121 | <field name="sequence"/> |
892 | @@ -104,7 +125,6 @@ | |||
893 | 104 | <field name="account_profit_id" attrs="{'required':[('write_off','>',0)]}"/> | 125 | <field name="account_profit_id" attrs="{'required':[('write_off','>',0)]}"/> |
894 | 105 | <field name="journal_id" attrs="{'required':[('write_off','>',0)]}"/> | 126 | <field name="journal_id" attrs="{'required':[('write_off','>',0)]}"/> |
895 | 106 | <field name="date_base_on"/> | 127 | <field name="date_base_on"/> |
896 | 107 | <field name="filter" groups="base.group_extended"/> | ||
897 | 108 | </form> | 128 | </form> |
898 | 109 | </field> | 129 | </field> |
899 | 110 | </record> | 130 | </record> |
900 | @@ -113,8 +133,7 @@ | |||
901 | 113 | <field name="name">account.easy.reconcile.method.tree</field> | 133 | <field name="name">account.easy.reconcile.method.tree</field> |
902 | 114 | <field name="priority">20</field> | 134 | <field name="priority">20</field> |
903 | 115 | <field name="model">account.easy.reconcile.method</field> | 135 | <field name="model">account.easy.reconcile.method</field> |
906 | 116 | <field name="type">tree</field> | 136 | <field name="arch" type="xml"> |
905 | 117 | <field name="arch" type="xml"> | ||
907 | 118 | <tree editable="top" string="Automatic Easy Reconcile Method"> | 137 | <tree editable="top" string="Automatic Easy Reconcile Method"> |
908 | 119 | <field name="sequence"/> | 138 | <field name="sequence"/> |
909 | 120 | <field name="name"/> | 139 | <field name="name"/> |
910 | @@ -123,14 +142,15 @@ | |||
911 | 123 | <field name="account_profit_id" attrs="{'required':[('write_off','>',0)]}"/> | 142 | <field name="account_profit_id" attrs="{'required':[('write_off','>',0)]}"/> |
912 | 124 | <field name="journal_id" attrs="{'required':[('write_off','>',0)]}"/> | 143 | <field name="journal_id" attrs="{'required':[('write_off','>',0)]}"/> |
913 | 125 | <field name="date_base_on"/> | 144 | <field name="date_base_on"/> |
914 | 126 | <field name="filter"/> | ||
915 | 127 | </tree> | 145 | </tree> |
916 | 128 | </field> | 146 | </field> |
917 | 129 | </record> | 147 | </record> |
918 | 130 | 148 | ||
920 | 131 | <!-- menu item --> | 149 | <!-- menu item --> |
921 | 132 | 150 | ||
923 | 133 | <menuitem action="action_account_easy_reconcile" id="menu_easy_reconcile" parent="account.periodical_processing_reconciliation"/> | 151 | <menuitem action="action_account_easy_reconcile" |
924 | 152 | id="menu_easy_reconcile" | ||
925 | 153 | parent="account.periodical_processing_reconciliation"/> | ||
926 | 134 | 154 | ||
927 | 135 | </data> | 155 | </data> |
928 | 136 | </openerp> | 156 | </openerp> |
929 | 137 | 157 | ||
930 | === modified file 'account_easy_reconcile/easy_reconcile_history.py' | |||
931 | --- account_easy_reconcile/easy_reconcile_history.py 2012-12-20 10:15:12 +0000 | |||
932 | +++ account_easy_reconcile/easy_reconcile_history.py 2013-06-10 07:05:32 +0000 | |||
933 | @@ -81,6 +81,13 @@ | |||
934 | 81 | relation='account.move.line', | 81 | relation='account.move.line', |
935 | 82 | readonly=True, | 82 | readonly=True, |
936 | 83 | multi='lines'), | 83 | multi='lines'), |
937 | 84 | 'company_id': fields.related('easy_reconcile_id','company_id', | ||
938 | 85 | relation='res.company', | ||
939 | 86 | type='many2one', | ||
940 | 87 | string='Company', | ||
941 | 88 | store=True, | ||
942 | 89 | readonly=True), | ||
943 | 90 | |||
944 | 84 | } | 91 | } |
945 | 85 | 92 | ||
946 | 86 | def _open_move_lines(self, cr, uid, history_id, rec_type='full', context=None): | 93 | def _open_move_lines(self, cr, uid, history_id, rec_type='full', context=None): |
947 | 87 | 94 | ||
948 | === modified file 'account_easy_reconcile/easy_reconcile_history_view.xml' | |||
949 | --- account_easy_reconcile/easy_reconcile_history_view.xml 2012-12-19 15:40:41 +0000 | |||
950 | +++ account_easy_reconcile/easy_reconcile_history_view.xml 2013-06-10 07:05:32 +0000 | |||
951 | @@ -5,7 +5,6 @@ | |||
952 | 5 | <record id="view_easy_reconcile_history_search" model="ir.ui.view"> | 5 | <record id="view_easy_reconcile_history_search" model="ir.ui.view"> |
953 | 6 | <field name="name">easy.reconcile.history.search</field> | 6 | <field name="name">easy.reconcile.history.search</field> |
954 | 7 | <field name="model">easy.reconcile.history</field> | 7 | <field name="model">easy.reconcile.history</field> |
955 | 8 | <field name="type">search</field> | ||
956 | 9 | <field name="arch" type="xml"> | 8 | <field name="arch" type="xml"> |
957 | 10 | <search string="Automatic Easy Reconcile History"> | 9 | <search string="Automatic Easy Reconcile History"> |
958 | 11 | <filter icon="terp-go-today" string="Today" | 10 | <filter icon="terp-go-today" string="Today" |
959 | @@ -34,44 +33,45 @@ | |||
960 | 34 | 33 | ||
961 | 35 | <record id="easy_reconcile_history_form" model="ir.ui.view"> | 34 | <record id="easy_reconcile_history_form" model="ir.ui.view"> |
962 | 36 | <field name="name">easy.reconcile.history.form</field> | 35 | <field name="name">easy.reconcile.history.form</field> |
963 | 37 | <field name="priority">16</field> | ||
964 | 38 | <field name="model">easy.reconcile.history</field> | 36 | <field name="model">easy.reconcile.history</field> |
965 | 39 | <field name="type">form</field> | ||
966 | 40 | <field name="arch" type="xml"> | 37 | <field name="arch" type="xml"> |
982 | 41 | <form string="Automatic Easy Reconcile History"> | 38 | <form string="Automatic Easy Reconcile History" version="7.0"> |
983 | 42 | <field name="easy_reconcile_id"/> | 39 | <header> |
984 | 43 | <field name="date"/> | 40 | <button name="open_reconcile" |
985 | 44 | <group colspan="2" col="2"> | 41 | string="Go to reconciled items" |
986 | 45 | <separator colspan="2" string="Reconcilations"/> | 42 | icon="STOCK_JUMP_TO" type="object"/> |
987 | 46 | <field name="reconcile_ids" nolabel="1"/> | 43 | <button name="open_partial" |
988 | 47 | </group> | 44 | string="Go to partially reconciled items" |
989 | 48 | <group colspan="2" col="2"> | 45 | icon="STOCK_JUMP_TO" type="object"/> |
990 | 49 | <separator colspan="2" string="Partial Reconcilations"/> | 46 | </header> |
991 | 50 | <field name="reconcile_partial_ids" nolabel="1"/> | 47 | <sheet> |
992 | 51 | </group> | 48 | <group> |
993 | 52 | <group col="2" colspan="4"> | 49 | <field name="easy_reconcile_id"/> |
994 | 53 | <button icon="STOCK_JUMP_TO" name="open_reconcile" string="Go to reconciled items" type="object"/> | 50 | <field name="date"/> |
995 | 54 | <button icon="STOCK_JUMP_TO" name="open_partial" string="Go to partially reconciled items" type="object"/> | 51 | <field name="company_id" groups="base.group_multi_company"/> |
996 | 55 | </group> | 52 | </group> |
997 | 53 | <group col="2"> | ||
998 | 54 | <separator colspan="2" string="Reconciliations"/> | ||
999 | 55 | <field name="reconcile_ids" nolabel="1"/> | ||
1000 | 56 | </group> | ||
1001 | 57 | <group col="2"> | ||
1002 | 58 | <separator colspan="2" string="Partial Reconciliations"/> | ||
1003 | 59 | <field name="reconcile_partial_ids" nolabel="1"/> | ||
1004 | 60 | </group> | ||
1005 | 61 | </sheet> | ||
1006 | 56 | </form> | 62 | </form> |
1007 | 57 | </field> | 63 | </field> |
1008 | 58 | </record> | 64 | </record> |
1009 | 59 | 65 | ||
1010 | 60 | <record id="easy_reconcile_history_tree" model="ir.ui.view"> | 66 | <record id="easy_reconcile_history_tree" model="ir.ui.view"> |
1011 | 61 | <field name="name">easy.reconcile.history.tree</field> | 67 | <field name="name">easy.reconcile.history.tree</field> |
1012 | 62 | <field name="priority">16</field> | ||
1013 | 63 | <field name="model">easy.reconcile.history</field> | 68 | <field name="model">easy.reconcile.history</field> |
1014 | 64 | <field name="type">tree</field> | ||
1015 | 65 | <field name="arch" type="xml"> | 69 | <field name="arch" type="xml"> |
1016 | 66 | <tree string="Automatic Easy Reconcile History"> | 70 | <tree string="Automatic Easy Reconcile History"> |
1017 | 67 | <field name="easy_reconcile_id"/> | 71 | <field name="easy_reconcile_id"/> |
1018 | 68 | <field name="date"/> | 72 | <field name="date"/> |
1019 | 69 | <!-- display the count of lines --> | ||
1020 | 70 | <field name="reconcile_line_ids"/> | ||
1021 | 71 | <button icon="STOCK_JUMP_TO" name="open_reconcile" | 73 | <button icon="STOCK_JUMP_TO" name="open_reconcile" |
1022 | 72 | string="Go to reconciled items" type="object"/> | 74 | string="Go to reconciled items" type="object"/> |
1023 | 73 | <!-- display the count of lines --> | ||
1024 | 74 | <field name="partial_line_ids"/> | ||
1025 | 75 | <button icon="STOCK_JUMP_TO" name="open_partial" | 75 | <button icon="STOCK_JUMP_TO" name="open_partial" |
1026 | 76 | string="Go to partially reconciled items" type="object"/> | 76 | string="Go to partially reconciled items" type="object"/> |
1027 | 77 | </tree> | 77 | </tree> |
1028 | 78 | 78 | ||
1029 | === modified file 'account_easy_reconcile/i18n/fr.po' | |||
1030 | --- account_easy_reconcile/i18n/fr.po 2013-03-12 12:11:33 +0000 | |||
1031 | +++ account_easy_reconcile/i18n/fr.po 2013-06-10 07:05:32 +0000 | |||
1032 | @@ -6,45 +6,73 @@ | |||
1033 | 6 | msgstr "" | 6 | msgstr "" |
1034 | 7 | "Project-Id-Version: OpenERP Server 6.1\n" | 7 | "Project-Id-Version: OpenERP Server 6.1\n" |
1035 | 8 | "Report-Msgid-Bugs-To: \n" | 8 | "Report-Msgid-Bugs-To: \n" |
1039 | 9 | "POT-Creation-Date: 2012-12-20 08:54+0000\n" | 9 | "POT-Creation-Date: 2013-01-04 08:39+0000\n" |
1040 | 10 | "PO-Revision-Date: 2012-11-07 12:59+0000\n" | 10 | "PO-Revision-Date: 2013-01-04 09:55+0100\n" |
1041 | 11 | "Last-Translator: <>\n" | 11 | "Last-Translator: Guewen Baconnier <guewen.baconnier@camptocamp.com>\n" |
1042 | 12 | "Language-Team: \n" | 12 | "Language-Team: \n" |
1043 | 13 | "Language: \n" | 13 | "Language: \n" |
1044 | 14 | "MIME-Version: 1.0\n" | 14 | "MIME-Version: 1.0\n" |
1045 | 15 | "Content-Type: text/plain; charset=UTF-8\n" | 15 | "Content-Type: text/plain; charset=UTF-8\n" |
1047 | 16 | "Content-Transfer-Encoding: \n" | 16 | "Content-Transfer-Encoding: 8bit\n" |
1048 | 17 | "Plural-Forms: \n" | 17 | "Plural-Forms: \n" |
1049 | 18 | 18 | ||
1050 | 19 | #. module: account_easy_reconcile | 19 | #. module: account_easy_reconcile |
1052 | 20 | #: code:addons/account_easy_reconcile/easy_reconcile_history.py:103 | 20 | #: code:addons/account_easy_reconcile/easy_reconcile_history.py:101 |
1053 | 21 | #: view:easy.reconcile.history:0 | ||
1054 | 22 | #: field:easy.reconcile.history,reconcile_ids:0 | ||
1055 | 23 | #, python-format | ||
1056 | 21 | msgid "Reconciliations" | 24 | msgid "Reconciliations" |
1057 | 22 | msgstr "Lettrages" | 25 | msgstr "Lettrages" |
1058 | 23 | 26 | ||
1059 | 24 | #. module: account_easy_reconcile | 27 | #. module: account_easy_reconcile |
1060 | 25 | #: view:account.easy.reconcile:0 | 28 | #: view:account.easy.reconcile:0 |
1061 | 29 | #: view:easy.reconcile.history:0 | ||
1062 | 30 | msgid "Automatic Easy Reconcile History" | ||
1063 | 31 | msgstr "Historique des lettrages automatisés" | ||
1064 | 32 | |||
1065 | 33 | #. module: account_easy_reconcile | ||
1066 | 34 | #: view:account.easy.reconcile:0 | ||
1067 | 26 | msgid "Information" | 35 | msgid "Information" |
1068 | 27 | msgstr "Information" | 36 | msgstr "Information" |
1069 | 28 | 37 | ||
1070 | 29 | #. module: account_easy_reconcile | 38 | #. module: account_easy_reconcile |
1077 | 30 | #: view:account.easy.reconcile:0 view:easy.reconcile.history:0 | 39 | #: view:account.easy.reconcile:0 |
1078 | 31 | msgid "Automatic Easy Reconcile History" | 40 | #: view:easy.reconcile.history:0 |
1073 | 32 | msgstr "Historique des lettrages automatisés" | ||
1074 | 33 | |||
1075 | 34 | #. module: account_easy_reconcile | ||
1076 | 35 | #: view:account.easy.reconcile:0 view:easy.reconcile.history:0 | ||
1079 | 36 | msgid "Go to partially reconciled items" | 41 | msgid "Go to partially reconciled items" |
1080 | 37 | msgstr "Voir les entrées partiellement lettrées" | 42 | msgstr "Voir les entrées partiellement lettrées" |
1081 | 38 | 43 | ||
1082 | 39 | #. module: account_easy_reconcile | 44 | #. module: account_easy_reconcile |
1083 | 45 | #: help:account.easy.reconcile.method,sequence:0 | ||
1084 | 46 | msgid "The sequence field is used to order the reconcile method" | ||
1085 | 47 | msgstr "La séquence détermine l'ordre des méthodes de lettrage" | ||
1086 | 48 | |||
1087 | 49 | #. module: account_easy_reconcile | ||
1088 | 40 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_history | 50 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_history |
1089 | 41 | msgid "easy.reconcile.history" | 51 | msgid "easy.reconcile.history" |
1090 | 42 | msgstr "easy.reconcile.history" | 52 | msgstr "easy.reconcile.history" |
1091 | 43 | 53 | ||
1092 | 44 | #. module: account_easy_reconcile | 54 | #. module: account_easy_reconcile |
1096 | 45 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_simple_name | 55 | #: model:ir.actions.act_window,help:account_easy_reconcile.action_account_easy_reconcile |
1097 | 46 | msgid "easy.reconcile.simple.name" | 56 | msgid "" |
1098 | 47 | msgstr "easy.reconcile.simple.name" | 57 | "<p class=\"oe_view_nocontent_create\">\n" |
1099 | 58 | " Click to add a reconciliation profile.\n" | ||
1100 | 59 | " </p><p>\n" | ||
1101 | 60 | " A reconciliation profile specifies, for one account, how\n" | ||
1102 | 61 | " the entries should be reconciled.\n" | ||
1103 | 62 | " You can select one or many reconciliation methods which will\n" | ||
1104 | 63 | " be run sequentially to match the entries between them.\n" | ||
1105 | 64 | " </p>\n" | ||
1106 | 65 | " " | ||
1107 | 66 | msgstr "" | ||
1108 | 67 | "<p class=\"oe_view_nocontent_create\">\n" | ||
1109 | 68 | " Cliquez pour ajouter un profil de lettrage.\n" | ||
1110 | 69 | " </p><p>\n" | ||
1111 | 70 | " Un profil de lettrage spécifie, pour un compte, comment\n" | ||
1112 | 71 | " les écritures doivent être lettrées.\n" | ||
1113 | 72 | " Vous pouvez sélectionner une ou plusieurs méthodes de lettrage\n" | ||
1114 | 73 | " qui seront lancées successivement pour identifier les écritures\n" | ||
1115 | 74 | " devant être lettrées. </p>\n" | ||
1116 | 75 | " " | ||
1117 | 48 | 76 | ||
1118 | 49 | #. module: account_easy_reconcile | 77 | #. module: account_easy_reconcile |
1119 | 50 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_options | 78 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_options |
1120 | @@ -57,14 +85,9 @@ | |||
1121 | 57 | msgstr "Grouper par..." | 85 | msgstr "Grouper par..." |
1122 | 58 | 86 | ||
1123 | 59 | #. module: account_easy_reconcile | 87 | #. module: account_easy_reconcile |
1132 | 60 | #: view:account.easy.reconcile:0 | 88 | #: field:account.easy.reconcile,unreconciled_count:0 |
1133 | 61 | msgid "Task Information" | 89 | msgid "Unreconciled Items" |
1134 | 62 | msgstr "Information sur la tâche" | 90 | msgstr "Écritures non lettrées" |
1127 | 63 | |||
1128 | 64 | #. module: account_easy_reconcile | ||
1129 | 65 | #: view:account.easy.reconcile:0 | ||
1130 | 66 | msgid "Reconcile Method" | ||
1131 | 67 | msgstr "Méthode de lettrage" | ||
1135 | 68 | 91 | ||
1136 | 69 | #. module: account_easy_reconcile | 92 | #. module: account_easy_reconcile |
1137 | 70 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_base | 93 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_base |
1138 | @@ -72,6 +95,16 @@ | |||
1139 | 72 | msgstr "easy.reconcile.base" | 95 | msgstr "easy.reconcile.base" |
1140 | 73 | 96 | ||
1141 | 74 | #. module: account_easy_reconcile | 97 | #. module: account_easy_reconcile |
1142 | 98 | #: field:easy.reconcile.history,reconcile_line_ids:0 | ||
1143 | 99 | msgid "Reconciled Items" | ||
1144 | 100 | msgstr "Écritures lettrées" | ||
1145 | 101 | |||
1146 | 102 | #. module: account_easy_reconcile | ||
1147 | 103 | #: field:account.easy.reconcile,reconcile_method:0 | ||
1148 | 104 | msgid "Method" | ||
1149 | 105 | msgstr "Méthode" | ||
1150 | 106 | |||
1151 | 107 | #. module: account_easy_reconcile | ||
1152 | 75 | #: view:easy.reconcile.history:0 | 108 | #: view:easy.reconcile.history:0 |
1153 | 76 | msgid "7 Days" | 109 | msgid "7 Days" |
1154 | 77 | msgstr "7 jours" | 110 | msgstr "7 jours" |
1155 | @@ -82,29 +115,51 @@ | |||
1156 | 82 | msgstr "Lettrage automatisé" | 115 | msgstr "Lettrage automatisé" |
1157 | 83 | 116 | ||
1158 | 84 | #. module: account_easy_reconcile | 117 | #. module: account_easy_reconcile |
1159 | 118 | #: field:easy.reconcile.history,date:0 | ||
1160 | 119 | msgid "Run date" | ||
1161 | 120 | msgstr "Date de lancement" | ||
1162 | 121 | |||
1163 | 122 | #. module: account_easy_reconcile | ||
1164 | 123 | #: view:account.easy.reconcile:0 | ||
1165 | 124 | msgid "Match one debit line vs one credit line. Do not allow partial reconciliation. The lines should have the same amount (with the write-off) and the same reference to be reconciled." | ||
1166 | 125 | msgstr "Lettre un débit avec un crédit ayant le même montant et la même référence. Le lettrage ne peut être partiel (écriture d'ajustement en cas d'écart)." | ||
1167 | 126 | |||
1168 | 127 | #. module: account_easy_reconcile | ||
1169 | 85 | #: model:ir.actions.act_window,name:account_easy_reconcile.act_easy_reconcile_to_history | 128 | #: model:ir.actions.act_window,name:account_easy_reconcile.act_easy_reconcile_to_history |
1170 | 86 | msgid "History Details" | 129 | msgid "History Details" |
1171 | 87 | msgstr "Détails de l'historique" | 130 | msgstr "Détails de l'historique" |
1172 | 88 | 131 | ||
1173 | 89 | #. module: account_easy_reconcile | 132 | #. module: account_easy_reconcile |
1174 | 90 | #: view:account.easy.reconcile:0 | 133 | #: view:account.easy.reconcile:0 |
1175 | 91 | msgid "" | ||
1176 | 92 | "Match one debit line vs one credit line. Do not allow partial reconcilation. " | ||
1177 | 93 | "The lines should have the same amount (with the write-off) and the same name " | ||
1178 | 94 | "to be reconciled." | ||
1179 | 95 | msgstr "" | ||
1180 | 96 | "Lettre un débit avec un crédit ayant le même montant et la même description. " | ||
1181 | 97 | "Le lettrage ne peut être partiel (écriture d'ajustement en cas d'écart)." | ||
1182 | 98 | |||
1183 | 99 | #. module: account_easy_reconcile | ||
1184 | 100 | #: view:account.easy.reconcile:0 | ||
1185 | 101 | msgid "Display items reconciled on the last run" | 134 | msgid "Display items reconciled on the last run" |
1186 | 102 | msgstr "Voir les entrées lettrées au dernier lettrage" | 135 | msgstr "Voir les entrées lettrées au dernier lettrage" |
1187 | 103 | 136 | ||
1188 | 104 | #. module: account_easy_reconcile | 137 | #. module: account_easy_reconcile |
1192 | 105 | #: model:ir.model,name:account_easy_reconcile.model_account_easy_reconcile_method | 138 | #: field:account.easy.reconcile.method,name:0 |
1193 | 106 | msgid "reconcile method for account_easy_reconcile" | 139 | msgid "Type" |
1194 | 107 | msgstr "Méthode de lettrage" | 140 | msgstr "Type" |
1195 | 141 | |||
1196 | 142 | #. module: account_easy_reconcile | ||
1197 | 143 | #: field:account.easy.reconcile.method,journal_id:0 | ||
1198 | 144 | #: field:easy.reconcile.base,journal_id:0 | ||
1199 | 145 | #: field:easy.reconcile.options,journal_id:0 | ||
1200 | 146 | #: field:easy.reconcile.simple,journal_id:0 | ||
1201 | 147 | #: field:easy.reconcile.simple.name,journal_id:0 | ||
1202 | 148 | #: field:easy.reconcile.simple.partner,journal_id:0 | ||
1203 | 149 | #: field:easy.reconcile.simple.reference,journal_id:0 | ||
1204 | 150 | msgid "Journal" | ||
1205 | 151 | msgstr "Journal" | ||
1206 | 152 | |||
1207 | 153 | #. module: account_easy_reconcile | ||
1208 | 154 | #: field:account.easy.reconcile.method,account_profit_id:0 | ||
1209 | 155 | #: field:easy.reconcile.base,account_profit_id:0 | ||
1210 | 156 | #: field:easy.reconcile.options,account_profit_id:0 | ||
1211 | 157 | #: field:easy.reconcile.simple,account_profit_id:0 | ||
1212 | 158 | #: field:easy.reconcile.simple.name,account_profit_id:0 | ||
1213 | 159 | #: field:easy.reconcile.simple.partner,account_profit_id:0 | ||
1214 | 160 | #: field:easy.reconcile.simple.reference,account_profit_id:0 | ||
1215 | 161 | msgid "Account Profit" | ||
1216 | 162 | msgstr "Compte de profits" | ||
1217 | 108 | 163 | ||
1218 | 109 | #. module: account_easy_reconcile | 164 | #. module: account_easy_reconcile |
1219 | 110 | #: view:easy.reconcile.history:0 | 165 | #: view:easy.reconcile.history:0 |
1220 | @@ -117,6 +172,15 @@ | |||
1221 | 117 | msgstr "Simple. Montant et description" | 172 | msgstr "Simple. Montant et description" |
1222 | 118 | 173 | ||
1223 | 119 | #. module: account_easy_reconcile | 174 | #. module: account_easy_reconcile |
1224 | 175 | #: field:easy.reconcile.base,partner_ids:0 | ||
1225 | 176 | #: field:easy.reconcile.simple,partner_ids:0 | ||
1226 | 177 | #: field:easy.reconcile.simple.name,partner_ids:0 | ||
1227 | 178 | #: field:easy.reconcile.simple.partner,partner_ids:0 | ||
1228 | 179 | #: field:easy.reconcile.simple.reference,partner_ids:0 | ||
1229 | 180 | msgid "Restrict on partners" | ||
1230 | 181 | msgstr "Filtrer sur des partenaires" | ||
1231 | 182 | |||
1232 | 183 | #. module: account_easy_reconcile | ||
1233 | 120 | #: model:ir.actions.act_window,name:account_easy_reconcile.action_account_easy_reconcile | 184 | #: model:ir.actions.act_window,name:account_easy_reconcile.action_account_easy_reconcile |
1234 | 121 | #: model:ir.ui.menu,name:account_easy_reconcile.menu_easy_reconcile | 185 | #: model:ir.ui.menu,name:account_easy_reconcile.menu_easy_reconcile |
1235 | 122 | msgid "Easy Automatic Reconcile" | 186 | msgid "Easy Automatic Reconcile" |
1236 | @@ -133,54 +197,162 @@ | |||
1237 | 133 | msgstr "Date" | 197 | msgstr "Date" |
1238 | 134 | 198 | ||
1239 | 135 | #. module: account_easy_reconcile | 199 | #. module: account_easy_reconcile |
1240 | 200 | #: field:account.easy.reconcile,last_history:0 | ||
1241 | 201 | msgid "Last History" | ||
1242 | 202 | msgstr "Dernier historique" | ||
1243 | 203 | |||
1244 | 204 | #. module: account_easy_reconcile | ||
1245 | 136 | #: view:account.easy.reconcile:0 | 205 | #: view:account.easy.reconcile:0 |
1246 | 137 | msgid "Configuration" | 206 | msgid "Configuration" |
1247 | 138 | msgstr "Configuration" | 207 | msgstr "Configuration" |
1248 | 139 | 208 | ||
1249 | 140 | #. module: account_easy_reconcile | 209 | #. module: account_easy_reconcile |
1250 | 210 | #: field:account.easy.reconcile,reconciled_partial_count:0 | ||
1251 | 211 | #: field:easy.reconcile.history,partial_line_ids:0 | ||
1252 | 212 | msgid "Partially Reconciled Items" | ||
1253 | 213 | msgstr "Écritures partiellement lettrées" | ||
1254 | 214 | |||
1255 | 215 | #. module: account_easy_reconcile | ||
1256 | 141 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_simple_partner | 216 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_simple_partner |
1257 | 142 | msgid "easy.reconcile.simple.partner" | 217 | msgid "easy.reconcile.simple.partner" |
1258 | 143 | msgstr "easy.reconcile.simple.partner" | 218 | msgstr "easy.reconcile.simple.partner" |
1259 | 144 | 219 | ||
1260 | 145 | #. module: account_easy_reconcile | 220 | #. module: account_easy_reconcile |
1261 | 221 | #: field:account.easy.reconcile.method,write_off:0 | ||
1262 | 222 | #: field:easy.reconcile.base,write_off:0 | ||
1263 | 223 | #: field:easy.reconcile.options,write_off:0 | ||
1264 | 224 | #: field:easy.reconcile.simple,write_off:0 | ||
1265 | 225 | #: field:easy.reconcile.simple.name,write_off:0 | ||
1266 | 226 | #: field:easy.reconcile.simple.partner,write_off:0 | ||
1267 | 227 | #: field:easy.reconcile.simple.reference,write_off:0 | ||
1268 | 228 | msgid "Write off allowed" | ||
1269 | 229 | msgstr "Écart autorisé" | ||
1270 | 230 | |||
1271 | 231 | #. module: account_easy_reconcile | ||
1272 | 146 | #: view:account.easy.reconcile:0 | 232 | #: view:account.easy.reconcile:0 |
1273 | 147 | msgid "Automatic Easy Reconcile" | 233 | msgid "Automatic Easy Reconcile" |
1274 | 148 | msgstr "Lettrage automatisé" | 234 | msgstr "Lettrage automatisé" |
1275 | 149 | 235 | ||
1276 | 150 | #. module: account_easy_reconcile | 236 | #. module: account_easy_reconcile |
1277 | 237 | #: field:account.easy.reconcile,account:0 | ||
1278 | 238 | #: field:easy.reconcile.base,account_id:0 | ||
1279 | 239 | #: field:easy.reconcile.simple,account_id:0 | ||
1280 | 240 | #: field:easy.reconcile.simple.name,account_id:0 | ||
1281 | 241 | #: field:easy.reconcile.simple.partner,account_id:0 | ||
1282 | 242 | #: field:easy.reconcile.simple.reference,account_id:0 | ||
1283 | 243 | msgid "Account" | ||
1284 | 244 | msgstr "Compte" | ||
1285 | 245 | |||
1286 | 246 | #. module: account_easy_reconcile | ||
1287 | 247 | #: field:account.easy.reconcile.method,task_id:0 | ||
1288 | 248 | msgid "Task" | ||
1289 | 249 | msgstr "Tâche" | ||
1290 | 250 | |||
1291 | 251 | #. module: account_easy_reconcile | ||
1292 | 252 | #: field:account.easy.reconcile,name:0 | ||
1293 | 253 | msgid "Name" | ||
1294 | 254 | msgstr "Nom" | ||
1295 | 255 | |||
1296 | 256 | #. module: account_easy_reconcile | ||
1297 | 257 | #: view:account.easy.reconcile:0 | ||
1298 | 258 | msgid "Simple. Amount and Partner" | ||
1299 | 259 | msgstr "Simple. Montant et partenaire" | ||
1300 | 260 | |||
1301 | 261 | #. module: account_easy_reconcile | ||
1302 | 151 | #: view:account.easy.reconcile:0 | 262 | #: view:account.easy.reconcile:0 |
1303 | 152 | msgid "Start Auto Reconcilation" | 263 | msgid "Start Auto Reconcilation" |
1304 | 153 | msgstr "Lancer le lettrage automatisé" | 264 | msgstr "Lancer le lettrage automatisé" |
1305 | 154 | 265 | ||
1306 | 155 | #. module: account_easy_reconcile | 266 | #. module: account_easy_reconcile |
1307 | 267 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_simple_name | ||
1308 | 268 | msgid "easy.reconcile.simple.name" | ||
1309 | 269 | msgstr "easy.reconcile.simple.name" | ||
1310 | 270 | |||
1311 | 271 | #. module: account_easy_reconcile | ||
1312 | 272 | #: field:account.easy.reconcile.method,filter:0 | ||
1313 | 273 | #: field:easy.reconcile.base,filter:0 | ||
1314 | 274 | #: field:easy.reconcile.options,filter:0 | ||
1315 | 275 | #: field:easy.reconcile.simple,filter:0 | ||
1316 | 276 | #: field:easy.reconcile.simple.name,filter:0 | ||
1317 | 277 | #: field:easy.reconcile.simple.partner,filter:0 | ||
1318 | 278 | #: field:easy.reconcile.simple.reference,filter:0 | ||
1319 | 279 | msgid "Filter" | ||
1320 | 280 | msgstr "Filtre" | ||
1321 | 281 | |||
1322 | 282 | #. module: account_easy_reconcile | ||
1323 | 283 | #: view:account.easy.reconcile:0 | ||
1324 | 284 | msgid "Match one debit line vs one credit line. Do not allow partial reconciliation. The lines should have the same amount (with the write-off) and the same partner to be reconciled." | ||
1325 | 285 | msgstr "Lettre un débit avec un crédit ayant le même montant et le même partenaire. Le lettrage ne peut être partiel (écriture d'ajustement en cas d'écart)." | ||
1326 | 286 | |||
1327 | 287 | #. module: account_easy_reconcile | ||
1328 | 288 | #: field:easy.reconcile.history,easy_reconcile_id:0 | ||
1329 | 289 | msgid "Reconcile Profile" | ||
1330 | 290 | msgstr "Profil de réconciliation" | ||
1331 | 291 | |||
1332 | 292 | #. module: account_easy_reconcile | ||
1333 | 293 | #: view:account.easy.reconcile:0 | ||
1334 | 294 | msgid "Start Auto Reconciliation" | ||
1335 | 295 | msgstr "Lancer le lettrage automatisé" | ||
1336 | 296 | |||
1337 | 297 | #. module: account_easy_reconcile | ||
1338 | 298 | #: code:addons/account_easy_reconcile/easy_reconcile.py:250 | ||
1339 | 299 | #, python-format | ||
1340 | 300 | msgid "Error" | ||
1341 | 301 | msgstr "Erreur" | ||
1342 | 302 | |||
1343 | 303 | #. module: account_easy_reconcile | ||
1344 | 304 | #: code:addons/account_easy_reconcile/easy_reconcile.py:251 | ||
1345 | 305 | #, python-format | ||
1346 | 306 | msgid "There is no history of reconciled items on the task: %s." | ||
1347 | 307 | msgstr "Il n'y a pas d'historique d'écritures lettrées sur la tâche: %s." | ||
1348 | 308 | |||
1349 | 309 | #. module: account_easy_reconcile | ||
1350 | 310 | #: view:account.easy.reconcile:0 | ||
1351 | 311 | msgid "Match one debit line vs one credit line. Do not allow partial reconciliation. The lines should have the same amount (with the write-off) and the same name to be reconciled." | ||
1352 | 312 | msgstr "Lettre un débit avec un crédit ayant le même montant et la même description. Le lettrage ne peut être partiel (écriture d'ajustement en cas d'écart)." | ||
1353 | 313 | |||
1354 | 314 | #. module: account_easy_reconcile | ||
1355 | 315 | #: field:account.easy.reconcile.method,account_lost_id:0 | ||
1356 | 316 | #: field:easy.reconcile.base,account_lost_id:0 | ||
1357 | 317 | #: field:easy.reconcile.options,account_lost_id:0 | ||
1358 | 318 | #: field:easy.reconcile.simple,account_lost_id:0 | ||
1359 | 319 | #: field:easy.reconcile.simple.name,account_lost_id:0 | ||
1360 | 320 | #: field:easy.reconcile.simple.partner,account_lost_id:0 | ||
1361 | 321 | #: field:easy.reconcile.simple.reference,account_lost_id:0 | ||
1362 | 322 | msgid "Account Lost" | ||
1363 | 323 | msgstr "Compte de pertes" | ||
1364 | 324 | |||
1365 | 325 | #. module: account_easy_reconcile | ||
1366 | 156 | #: view:easy.reconcile.history:0 | 326 | #: view:easy.reconcile.history:0 |
1367 | 157 | msgid "Reconciliation Profile" | 327 | msgid "Reconciliation Profile" |
1368 | 158 | msgstr "Profil de réconciliation" | 328 | msgstr "Profil de réconciliation" |
1369 | 159 | 329 | ||
1370 | 160 | #. module: account_easy_reconcile | 330 | #. module: account_easy_reconcile |
1371 | 161 | #: view:account.easy.reconcile:0 | 331 | #: view:account.easy.reconcile:0 |
1372 | 332 | #: field:account.easy.reconcile,history_ids:0 | ||
1373 | 162 | msgid "History" | 333 | msgid "History" |
1374 | 163 | msgstr "Historique" | 334 | msgstr "Historique" |
1375 | 164 | 335 | ||
1376 | 165 | #. module: account_easy_reconcile | 336 | #. module: account_easy_reconcile |
1378 | 166 | #: view:account.easy.reconcile:0 view:easy.reconcile.history:0 | 337 | #: view:account.easy.reconcile:0 |
1379 | 338 | #: view:easy.reconcile.history:0 | ||
1380 | 167 | msgid "Go to reconciled items" | 339 | msgid "Go to reconciled items" |
1381 | 168 | msgstr "Voir les entrées lettrées" | 340 | msgstr "Voir les entrées lettrées" |
1382 | 169 | 341 | ||
1383 | 170 | #. module: account_easy_reconcile | 342 | #. module: account_easy_reconcile |
1384 | 343 | #: view:account.easy.reconcile:0 | ||
1385 | 344 | msgid "Profile Information" | ||
1386 | 345 | msgstr "Information sur le profil" | ||
1387 | 346 | |||
1388 | 347 | #. module: account_easy_reconcile | ||
1389 | 171 | #: view:account.easy.reconcile.method:0 | 348 | #: view:account.easy.reconcile.method:0 |
1390 | 172 | msgid "Automatic Easy Reconcile Method" | 349 | msgid "Automatic Easy Reconcile Method" |
1391 | 173 | msgstr "Méthode de lettrage automatisé" | 350 | msgstr "Méthode de lettrage automatisé" |
1392 | 174 | 351 | ||
1393 | 175 | #. module: account_easy_reconcile | 352 | #. module: account_easy_reconcile |
1394 | 176 | #: view:account.easy.reconcile:0 | 353 | #: view:account.easy.reconcile:0 |
1402 | 177 | msgid "" | 354 | msgid "Simple. Amount and Reference" |
1403 | 178 | "Match one debit line vs one credit line. Do not allow partial reconcilation. " | 355 | msgstr "Simple. Montant et référence" |
1397 | 179 | "The lines should have the same amount (with the write-off) and the same " | ||
1398 | 180 | "partner to be reconciled." | ||
1399 | 181 | msgstr "" | ||
1400 | 182 | "Lettre un débit avec un crédit ayant le même montant et le même partenaire. " | ||
1401 | 183 | "Le lettrage ne peut être partiel (écriture d'ajustement en cas d'écart)." | ||
1404 | 184 | 356 | ||
1405 | 185 | #. module: account_easy_reconcile | 357 | #. module: account_easy_reconcile |
1406 | 186 | #: view:account.easy.reconcile:0 | 358 | #: view:account.easy.reconcile:0 |
1407 | @@ -188,9 +360,9 @@ | |||
1408 | 188 | msgstr "Afficher les entrées partiellement lettrées au dernier lettrage" | 360 | msgstr "Afficher les entrées partiellement lettrées au dernier lettrage" |
1409 | 189 | 361 | ||
1410 | 190 | #. module: account_easy_reconcile | 362 | #. module: account_easy_reconcile |
1414 | 191 | #: view:easy.reconcile.history:0 | 363 | #: field:account.easy.reconcile.method,sequence:0 |
1415 | 192 | msgid "Partial Reconcilations" | 364 | msgid "Sequence" |
1416 | 193 | msgstr "Lettrages partiels" | 365 | msgstr "Séquence" |
1417 | 194 | 366 | ||
1418 | 195 | #. module: account_easy_reconcile | 367 | #. module: account_easy_reconcile |
1419 | 196 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_simple | 368 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_simple |
1420 | @@ -203,11 +375,30 @@ | |||
1421 | 203 | msgstr "Lettrages des 7 derniers jours" | 375 | msgstr "Lettrages des 7 derniers jours" |
1422 | 204 | 376 | ||
1423 | 205 | #. module: account_easy_reconcile | 377 | #. module: account_easy_reconcile |
1425 | 206 | #: code:addons/account_easy_reconcile/easy_reconcile_history.py:106 | 378 | #: field:account.easy.reconcile.method,date_base_on:0 |
1426 | 379 | #: field:easy.reconcile.base,date_base_on:0 | ||
1427 | 380 | #: field:easy.reconcile.options,date_base_on:0 | ||
1428 | 381 | #: field:easy.reconcile.simple,date_base_on:0 | ||
1429 | 382 | #: field:easy.reconcile.simple.name,date_base_on:0 | ||
1430 | 383 | #: field:easy.reconcile.simple.partner,date_base_on:0 | ||
1431 | 384 | #: field:easy.reconcile.simple.reference,date_base_on:0 | ||
1432 | 385 | msgid "Date of reconciliation" | ||
1433 | 386 | msgstr "Date de lettrage" | ||
1434 | 387 | |||
1435 | 388 | #. module: account_easy_reconcile | ||
1436 | 389 | #: code:addons/account_easy_reconcile/easy_reconcile_history.py:104 | ||
1437 | 390 | #: view:easy.reconcile.history:0 | ||
1438 | 391 | #: field:easy.reconcile.history,reconcile_partial_ids:0 | ||
1439 | 392 | #, python-format | ||
1440 | 207 | msgid "Partial Reconciliations" | 393 | msgid "Partial Reconciliations" |
1441 | 208 | msgstr "Lettrages partiels" | 394 | msgstr "Lettrages partiels" |
1442 | 209 | 395 | ||
1443 | 210 | #. module: account_easy_reconcile | 396 | #. module: account_easy_reconcile |
1444 | 397 | #: model:ir.model,name:account_easy_reconcile.model_account_easy_reconcile_method | ||
1445 | 398 | msgid "reconcile method for account_easy_reconcile" | ||
1446 | 399 | msgstr "Méthode de lettrage" | ||
1447 | 400 | |||
1448 | 401 | #. module: account_easy_reconcile | ||
1449 | 211 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_simple_reference | 402 | #: model:ir.model,name:account_easy_reconcile.model_easy_reconcile_simple_reference |
1450 | 212 | msgid "easy.reconcile.simple.reference" | 403 | msgid "easy.reconcile.simple.reference" |
1451 | 213 | msgstr "easy.reconcile.simple.reference" | 404 | msgstr "easy.reconcile.simple.reference" |
1452 | @@ -217,5 +408,18 @@ | |||
1453 | 217 | msgid "account easy reconcile" | 408 | msgid "account easy reconcile" |
1454 | 218 | msgstr "Lettrage automatisé" | 409 | msgstr "Lettrage automatisé" |
1455 | 219 | 410 | ||
1456 | 411 | #~ msgid "Unreconciled Entries" | ||
1457 | 412 | #~ msgstr "Écritures non lettrées" | ||
1458 | 413 | |||
1459 | 414 | #, fuzzy | ||
1460 | 415 | #~ msgid "Partially Reconciled Entries" | ||
1461 | 416 | #~ msgstr "Lettrages partiels" | ||
1462 | 417 | |||
1463 | 418 | #~ msgid "Task Information" | ||
1464 | 419 | #~ msgstr "Information sur la tâche" | ||
1465 | 420 | |||
1466 | 421 | #~ msgid "Reconcile Method" | ||
1467 | 422 | #~ msgstr "Méthode de lettrage" | ||
1468 | 423 | |||
1469 | 220 | #~ msgid "Log" | 424 | #~ msgid "Log" |
1470 | 221 | #~ msgstr "Historique" | 425 | #~ msgstr "Historique" |
1471 | 222 | 426 | ||
1472 | === added file 'account_easy_reconcile/security/ir_rule.xml' | |||
1473 | --- account_easy_reconcile/security/ir_rule.xml 1970-01-01 00:00:00 +0000 | |||
1474 | +++ account_easy_reconcile/security/ir_rule.xml 2013-06-10 07:05:32 +0000 | |||
1475 | @@ -0,0 +1,25 @@ | |||
1476 | 1 | <?xml version="1.0" encoding="utf-8"?> | ||
1477 | 2 | <openerp> | ||
1478 | 3 | <data noupdate="1"> | ||
1479 | 4 | <record id="easy_reconcile_rule" model="ir.rule"> | ||
1480 | 5 | <field name="name">Easy reconcile multi-company</field> | ||
1481 | 6 | <field name="model_id" ref="model_account_easy_reconcile"/> | ||
1482 | 7 | <field name="global" eval="True"/> | ||
1483 | 8 | <field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> | ||
1484 | 9 | </record> | ||
1485 | 10 | |||
1486 | 11 | <record id="easy_reconcile_history_rule" model="ir.rule"> | ||
1487 | 12 | <field name="name">Easy reconcile history multi-company</field> | ||
1488 | 13 | <field name="model_id" ref="model_easy_reconcile_history"/> | ||
1489 | 14 | <field name="global" eval="True"/> | ||
1490 | 15 | <field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> | ||
1491 | 16 | </record> | ||
1492 | 17 | |||
1493 | 18 | <record id="easy_reconcile_method_rule" model="ir.rule"> | ||
1494 | 19 | <field name="name">Easy reconcile method multi-company</field> | ||
1495 | 20 | <field name="model_id" ref="model_account_easy_reconcile_method"/> | ||
1496 | 21 | <field name="global" eval="True"/> | ||
1497 | 22 | <field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> | ||
1498 | 23 | </record> | ||
1499 | 24 | </data> | ||
1500 | 25 | </openerp> | ||
1501 | 0 | 26 | ||
1502 | === modified file 'account_easy_reconcile/simple_reconciliation.py' | |||
1503 | --- account_easy_reconcile/simple_reconciliation.py 2012-11-01 16:14:03 +0000 | |||
1504 | +++ account_easy_reconcile/simple_reconciliation.py 2013-06-10 07:05:32 +0000 | |||
1505 | @@ -1,7 +1,7 @@ | |||
1506 | 1 | # -*- coding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- |
1507 | 2 | ############################################################################## | 2 | ############################################################################## |
1508 | 3 | # | 3 | # |
1510 | 4 | # Copyright 2012 Camptocamp SA (Guewen Baconnier) | 4 | # Copyright 2012-2013 Camptocamp SA (Guewen Baconnier) |
1511 | 5 | # Copyright (C) 2010 Sébastien Beau | 5 | # Copyright (C) 2010 Sébastien Beau |
1512 | 6 | # | 6 | # |
1513 | 7 | # This program is free software: you can redistribute it and/or modify | 7 | # This program is free software: you can redistribute it and/or modify |
1514 | @@ -41,7 +41,7 @@ | |||
1515 | 41 | count = 0 | 41 | count = 0 |
1516 | 42 | res = [] | 42 | res = [] |
1517 | 43 | while (count < len(lines)): | 43 | while (count < len(lines)): |
1519 | 44 | for i in range(count+1, len(lines)): | 44 | for i in xrange(count+1, len(lines)): |
1520 | 45 | writeoff_account_id = False | 45 | writeoff_account_id = False |
1521 | 46 | if lines[count][self._key_field] != lines[i][self._key_field]: | 46 | if lines[count][self._key_field] != lines[i][self._key_field]: |
1522 | 47 | break | 47 | break |
1523 | @@ -94,7 +94,6 @@ | |||
1524 | 94 | 94 | ||
1525 | 95 | _name = 'easy.reconcile.simple.name' | 95 | _name = 'easy.reconcile.simple.name' |
1526 | 96 | _inherit = 'easy.reconcile.simple' | 96 | _inherit = 'easy.reconcile.simple' |
1527 | 97 | _auto = True # False when inherited from AbstractModel | ||
1528 | 98 | 97 | ||
1529 | 99 | # has to be subclassed | 98 | # has to be subclassed |
1530 | 100 | # field name used as key for matching the move lines | 99 | # field name used as key for matching the move lines |
1531 | @@ -105,17 +104,16 @@ | |||
1532 | 105 | 104 | ||
1533 | 106 | _name = 'easy.reconcile.simple.partner' | 105 | _name = 'easy.reconcile.simple.partner' |
1534 | 107 | _inherit = 'easy.reconcile.simple' | 106 | _inherit = 'easy.reconcile.simple' |
1535 | 108 | _auto = True # False when inherited from AbstractModel | ||
1536 | 109 | 107 | ||
1537 | 110 | # has to be subclassed | 108 | # has to be subclassed |
1538 | 111 | # field name used as key for matching the move lines | 109 | # field name used as key for matching the move lines |
1539 | 112 | _key_field = 'partner_id' | 110 | _key_field = 'partner_id' |
1540 | 113 | 111 | ||
1541 | 112 | |||
1542 | 114 | class easy_reconcile_simple_reference(TransientModel): | 113 | class easy_reconcile_simple_reference(TransientModel): |
1543 | 115 | 114 | ||
1544 | 116 | _name = 'easy.reconcile.simple.reference' | 115 | _name = 'easy.reconcile.simple.reference' |
1545 | 117 | _inherit = 'easy.reconcile.simple' | 116 | _inherit = 'easy.reconcile.simple' |
1546 | 118 | _auto = True # False when inherited from AbstractModel | ||
1547 | 119 | 117 | ||
1548 | 120 | # has to be subclassed | 118 | # has to be subclassed |
1549 | 121 | # field name used as key for matching the move lines | 119 | # field name used as key for matching the move lines |
1550 | 122 | 120 | ||
1551 | === modified file 'account_statement_base_completion/__init__.py' | |||
1552 | --- account_statement_base_completion/__init__.py 2012-06-22 15:45:50 +0000 | |||
1553 | +++ account_statement_base_completion/__init__.py 2013-06-10 07:05:32 +0000 | |||
1554 | @@ -20,4 +20,4 @@ | |||
1555 | 20 | ############################################################################## | 20 | ############################################################################## |
1556 | 21 | 21 | ||
1557 | 22 | import statement | 22 | import statement |
1558 | 23 | import partner | ||
1559 | 24 | \ No newline at end of file | 23 | \ No newline at end of file |
1560 | 24 | import partner | ||
1561 | 25 | 25 | ||
1562 | === modified file 'account_statement_base_completion/__openerp__.py' | |||
1563 | --- account_statement_base_completion/__openerp__.py 2012-07-31 14:29:55 +0000 | |||
1564 | +++ account_statement_base_completion/__openerp__.py 2013-06-10 07:05:32 +0000 | |||
1565 | @@ -24,7 +24,7 @@ | |||
1566 | 24 | 'author': 'Camptocamp', | 24 | 'author': 'Camptocamp', |
1567 | 25 | 'maintainer': 'Camptocamp', | 25 | 'maintainer': 'Camptocamp', |
1568 | 26 | 'category': 'Finance', | 26 | 'category': 'Finance', |
1570 | 27 | 'complexity': 'normal', #easy, normal, expert | 27 | 'complexity': 'normal', |
1571 | 28 | 'depends': ['account_statement_ext'], | 28 | 'depends': ['account_statement_ext'], |
1572 | 29 | 'description': """ | 29 | 'description': """ |
1573 | 30 | The goal of this module is to improve the basic bank statement, help dealing with huge volume of | 30 | The goal of this module is to improve the basic bank statement, help dealing with huge volume of |
1574 | @@ -52,6 +52,10 @@ | |||
1575 | 52 | 52 | ||
1576 | 53 | You can use it with our account_advanced_reconcile module to automatize the reconciliation process. | 53 | You can use it with our account_advanced_reconcile module to automatize the reconciliation process. |
1577 | 54 | 54 | ||
1578 | 55 | |||
1579 | 56 | TODO: The rules that look for invoices to find out the partner should take back the payable / receivable | ||
1580 | 57 | account from there directly instead of retrieving it from partner properties ! | ||
1581 | 58 | |||
1582 | 55 | """, | 59 | """, |
1583 | 56 | 'website': 'http://www.camptocamp.com', | 60 | 'website': 'http://www.camptocamp.com', |
1584 | 57 | 'init_xml': [], | 61 | 'init_xml': [], |
1585 | @@ -67,5 +71,4 @@ | |||
1586 | 67 | 'images': [], | 71 | 'images': [], |
1587 | 68 | 'auto_install': False, | 72 | 'auto_install': False, |
1588 | 69 | 'license': 'AGPL-3', | 73 | 'license': 'AGPL-3', |
1589 | 70 | 'active': False, | ||
1590 | 71 | } | 74 | } |
1591 | 72 | 75 | ||
1592 | === modified file 'account_statement_base_completion/data.xml' | |||
1593 | --- account_statement_base_completion/data.xml 2012-06-26 09:21:35 +0000 | |||
1594 | +++ account_statement_base_completion/data.xml 2013-06-10 07:05:32 +0000 | |||
1595 | @@ -7,7 +7,7 @@ | |||
1596 | 7 | <field name="sequence">60</field> | 7 | <field name="sequence">60</field> |
1597 | 8 | <field name="function_to_call">get_from_label_and_partner_field</field> | 8 | <field name="function_to_call">get_from_label_and_partner_field</field> |
1598 | 9 | </record> | 9 | </record> |
1600 | 10 | 10 | ||
1601 | 11 | <record id="bank_statement_completion_rule_3" model="account.statement.completion.rule"> | 11 | <record id="bank_statement_completion_rule_3" model="account.statement.completion.rule"> |
1602 | 12 | <field name="name">Match from line label (based on partner name)</field> | 12 | <field name="name">Match from line label (based on partner name)</field> |
1603 | 13 | <field name="sequence">70</field> | 13 | <field name="sequence">70</field> |
1604 | @@ -26,7 +26,12 @@ | |||
1605 | 26 | <field name="function_to_call">get_from_ref_and_invoice</field> | 26 | <field name="function_to_call">get_from_ref_and_invoice</field> |
1606 | 27 | </record> | 27 | </record> |
1607 | 28 | 28 | ||
1610 | 29 | 29 | <record id="bank_statement_completion_rule_5" model="account.statement.completion.rule"> | |
1611 | 30 | 30 | <field name="name">Match from line reference (based on Invoice Supplier number)</field> | |
1612 | 31 | <field name="sequence">45</field> | ||
1613 | 32 | <field name="function_to_call">get_from_ref_and_supplier_invoice</field> | ||
1614 | 33 | </record> | ||
1615 | 34 | |||
1616 | 35 | |||
1617 | 31 | </data> | 36 | </data> |
1618 | 32 | </openerp> | 37 | </openerp> |
1619 | 33 | 38 | ||
1620 | === modified file 'account_statement_base_completion/partner.py' | |||
1621 | --- account_statement_base_completion/partner.py 2012-06-20 14:10:01 +0000 | |||
1622 | +++ account_statement_base_completion/partner.py 2013-06-10 07:05:32 +0000 | |||
1623 | @@ -1,4 +1,4 @@ | |||
1625 | 1 | # -*- encoding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- |
1626 | 2 | ################################################################################# | 2 | ################################################################################# |
1627 | 3 | # # | 3 | # # |
1628 | 4 | # Copyright (C) 2011 Akretion & Camptocamp | 4 | # Copyright (C) 2011 Akretion & Camptocamp |
1629 | @@ -19,9 +19,11 @@ | |||
1630 | 19 | # # | 19 | # # |
1631 | 20 | ################################################################################# | 20 | ################################################################################# |
1632 | 21 | 21 | ||
1636 | 22 | from osv import fields, osv | 22 | from openerp.osv.orm import Model |
1637 | 23 | 23 | from openerp.osv import fields, osv | |
1638 | 24 | class res_partner(osv.osv): | 24 | |
1639 | 25 | |||
1640 | 26 | class res_partner(Model): | ||
1641 | 25 | """ | 27 | """ |
1642 | 26 | Add a bank label on the partner so that we can use it to match | 28 | Add a bank label on the partner so that we can use it to match |
1643 | 27 | this partner when we found this in a statement line. | 29 | this partner when we found this in a statement line. |
1644 | @@ -29,10 +31,8 @@ | |||
1645 | 29 | _inherit = 'res.partner' | 31 | _inherit = 'res.partner' |
1646 | 30 | 32 | ||
1647 | 31 | _columns = { | 33 | _columns = { |
1649 | 32 | 'bank_statement_label':fields.char('Bank Statement Label', size=100, | 34 | 'bank_statement_label': fields.char('Bank Statement Label', size=100, |
1650 | 33 | help="Enter the various label found on your bank statement separated by a ; If \ | 35 | help="Enter the various label found on your bank statement separated by a ; If \ |
1651 | 34 | one of this label is include in the bank statement line, the partner will be automatically \ | 36 | one of this label is include in the bank statement line, the partner will be automatically \ |
1652 | 35 | filled (as long as you use this method/rules in your statement profile)."), | 37 | filled (as long as you use this method/rules in your statement profile)."), |
1653 | 36 | } | 38 | } |
1654 | 37 | |||
1655 | 38 | res_partner() | ||
1656 | 39 | 39 | ||
1657 | === modified file 'account_statement_base_completion/statement.py' | |||
1658 | --- account_statement_base_completion/statement.py 2012-12-13 13:57:29 +0000 | |||
1659 | +++ account_statement_base_completion/statement.py 2013-06-10 07:05:32 +0000 | |||
1660 | @@ -18,14 +18,22 @@ | |||
1661 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
1662 | 19 | # | 19 | # |
1663 | 20 | ############################################################################## | 20 | ############################################################################## |
1664 | 21 | # TODO replace customer supplier by package constant | ||
1665 | 22 | import traceback | ||
1666 | 23 | import sys | ||
1667 | 24 | import logging | ||
1668 | 25 | |||
1669 | 26 | from collections import defaultdict | ||
1670 | 27 | import re | ||
1671 | 21 | from tools.translate import _ | 28 | from tools.translate import _ |
1677 | 22 | import netsvc | 29 | from openerp.osv import osv, orm, fields |
1678 | 23 | logger = netsvc.Logger() | 30 | from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT |
1679 | 24 | from openerp.osv.orm import Model, fields | 31 | from operator import attrgetter |
1675 | 25 | from openerp.osv import fields, osv | ||
1676 | 26 | from operator import itemgetter, attrgetter | ||
1680 | 27 | import datetime | 32 | import datetime |
1681 | 28 | 33 | ||
1682 | 34 | _logger = logging.getLogger(__name__) | ||
1683 | 35 | |||
1684 | 36 | |||
1685 | 29 | class ErrorTooManyPartner(Exception): | 37 | class ErrorTooManyPartner(Exception): |
1686 | 30 | """ | 38 | """ |
1687 | 31 | New Exception definition that is raised when more than one partner is matched by | 39 | New Exception definition that is raised when more than one partner is matched by |
1688 | @@ -33,233 +41,338 @@ | |||
1689 | 33 | """ | 41 | """ |
1690 | 34 | def __init__(self, value): | 42 | def __init__(self, value): |
1691 | 35 | self.value = value | 43 | self.value = value |
1692 | 44 | |||
1693 | 36 | def __str__(self): | 45 | def __str__(self): |
1694 | 37 | return repr(self.value) | 46 | return repr(self.value) |
1695 | 38 | 47 | ||
1698 | 39 | 48 | def __repr__(self): | |
1699 | 40 | class AccountStatementProfil(Model): | 49 | return repr(self.value) |
1700 | 50 | |||
1701 | 51 | |||
1702 | 52 | class AccountStatementProfil(orm.Model): | ||
1703 | 41 | """ | 53 | """ |
1704 | 42 | Extend the class to add rules per profile that will match at least the partner, | 54 | Extend the class to add rules per profile that will match at least the partner, |
1705 | 43 | but it could also be used to match other values as well. | 55 | but it could also be used to match other values as well. |
1706 | 44 | """ | 56 | """ |
1708 | 45 | 57 | ||
1709 | 46 | _inherit = "account.statement.profile" | 58 | _inherit = "account.statement.profile" |
1713 | 47 | 59 | ||
1714 | 48 | _columns={ | 60 | _columns = { |
1715 | 49 | # @Akretion : For now, we don't implement this features, but this would probably be there: | 61 | # @Akretion: For now, we don't implement this features, but this would probably be there: |
1716 | 50 | # 'auto_completion': fields.text('Auto Completion'), | 62 | # 'auto_completion': fields.text('Auto Completion'), |
1717 | 51 | # 'transferts_account_id':fields.many2one('account.account', 'Transferts Account'), | 63 | # 'transferts_account_id':fields.many2one('account.account', 'Transferts Account'), |
1722 | 52 | # => You can implement it in a module easily, we design it with your needs in mind | 64 | # => You can implement it in a module easily, we design it with your needs in mind |
1723 | 53 | # as well ! | 65 | # as well! |
1724 | 54 | 66 | ||
1725 | 55 | 'rule_ids':fields.many2many('account.statement.completion.rule', | 67 | 'rule_ids': fields.many2many( |
1726 | 68 | 'account.statement.completion.rule', | ||
1727 | 56 | string='Related statement profiles', | 69 | string='Related statement profiles', |
1730 | 57 | rel='as_rul_st_prof_rel', | 70 | rel='as_rul_st_prof_rel'), |
1729 | 58 | ), | ||
1731 | 59 | } | 71 | } |
1734 | 60 | 72 | ||
1735 | 61 | def find_values_from_rules(self, cr, uid, id, line_id, context=None): | 73 | def _get_callable(self, cr, uid, profile, context=None): |
1736 | 74 | if isinstance(profile, (int, long)): | ||
1737 | 75 | prof = self.browse(cr, uid, profile, context=context) | ||
1738 | 76 | else: | ||
1739 | 77 | prof = profile | ||
1740 | 78 | # We need to respect the sequence order | ||
1741 | 79 | sorted_array = sorted(prof.rule_ids, key=attrgetter('sequence')) | ||
1742 | 80 | return tuple((x.function_to_call for x in sorted_array)) | ||
1743 | 81 | |||
1744 | 82 | def _find_values_from_rules(self, cr, uid, calls, line, context=None): | ||
1745 | 62 | """ | 83 | """ |
1747 | 63 | This method will execute all related rules, in their sequence order, | 84 | This method will execute all related rules, in their sequence order, |
1748 | 64 | to retrieve all the values returned by the first rules that will match. | 85 | to retrieve all the values returned by the first rules that will match. |
1751 | 65 | 86 | :param calls: list of lookup function name available in rules | |
1752 | 66 | :param int/long line_id: id of the concerned account.bank.statement.line | 87 | :param dict line: read of the concerned account.bank.statement.line |
1753 | 67 | :return: | 88 | :return: |
1754 | 68 | A dict of value that can be passed directly to the write method of | 89 | A dict of value that can be passed directly to the write method of |
1755 | 69 | the statement line or {} | 90 | the statement line or {} |
1756 | 70 | {'partner_id': value, | 91 | {'partner_id': value, |
1759 | 71 | 'account_id' : value, | 92 | 'account_id: value, |
1760 | 72 | 93 | ||
1761 | 73 | ...} | 94 | ...} |
1762 | 74 | """ | 95 | """ |
1766 | 75 | if not context: | 96 | if context is None: |
1767 | 76 | context={} | 97 | context = {} |
1768 | 77 | res = {} | 98 | if not calls: |
1769 | 99 | calls = self._get_callable(cr, uid, line['profile_id'], context=context) | ||
1770 | 78 | rule_obj = self.pool.get('account.statement.completion.rule') | 100 | rule_obj = self.pool.get('account.statement.completion.rule') |
1777 | 79 | profile = self.browse(cr, uid, id, context=context) | 101 | |
1778 | 80 | # We need to respect the sequence order | 102 | for call in calls: |
1779 | 81 | sorted_array = sorted(profile.rule_ids, key=attrgetter('sequence')) | 103 | method_to_call = getattr(rule_obj, call) |
1780 | 82 | for rule in sorted_array: | 104 | result = method_to_call(cr, uid, line, context) |
1775 | 83 | method_to_call = getattr(rule_obj, rule.function_to_call) | ||
1776 | 84 | result = method_to_call(cr,uid,line_id,context) | ||
1781 | 85 | if result: | 105 | if result: |
1782 | 106 | result['already_completed'] = True | ||
1783 | 86 | return result | 107 | return result |
1788 | 87 | return res | 108 | return None |
1789 | 88 | 109 | ||
1790 | 89 | 110 | ||
1791 | 90 | class AccountStatementCompletionRule(Model): | 111 | class AccountStatementCompletionRule(orm.Model): |
1792 | 91 | """ | 112 | """ |
1793 | 92 | This will represent all the completion method that we can have to | 113 | This will represent all the completion method that we can have to |
1794 | 93 | fullfill the bank statement lines. You'll be able to extend them in you own module | 114 | fullfill the bank statement lines. You'll be able to extend them in you own module |
1795 | 94 | and choose those to apply for every statement profile. | 115 | and choose those to apply for every statement profile. |
1796 | 95 | The goal of a rule is to fullfill at least the partner of the line, but | 116 | The goal of a rule is to fullfill at least the partner of the line, but |
1798 | 96 | if possible also the reference because we'll use it in the reconciliation | 117 | if possible also the reference because we'll use it in the reconciliation |
1799 | 97 | process. The reference should contain the invoice number or the SO number | 118 | process. The reference should contain the invoice number or the SO number |
1800 | 98 | or any reference that will be matched by the invoice accounting move. | 119 | or any reference that will be matched by the invoice accounting move. |
1801 | 99 | """ | 120 | """ |
1803 | 100 | 121 | ||
1804 | 101 | _name = "account.statement.completion.rule" | 122 | _name = "account.statement.completion.rule" |
1805 | 102 | _order = "sequence asc" | 123 | _order = "sequence asc" |
1807 | 103 | 124 | ||
1808 | 104 | def _get_functions(self, cr, uid, context=None): | 125 | def _get_functions(self, cr, uid, context=None): |
1809 | 105 | """ | 126 | """ |
1810 | 106 | List of available methods for rules. Override this to add you own. | 127 | List of available methods for rules. Override this to add you own. |
1811 | 107 | """ | 128 | """ |
1812 | 108 | return [ | 129 | return [ |
1814 | 109 | ('get_from_ref_and_invoice', 'From line reference (based on invoice number)'), | 130 | ('get_from_ref_and_invoice', 'From line reference (based on customer invoice number)'), |
1815 | 131 | ('get_from_ref_and_supplier_invoice', 'From line reference (based on supplier invoice number)'), | ||
1816 | 110 | ('get_from_ref_and_so', 'From line reference (based on SO number)'), | 132 | ('get_from_ref_and_so', 'From line reference (based on SO number)'), |
1817 | 111 | ('get_from_label_and_partner_field', 'From line label (based on partner field)'), | 133 | ('get_from_label_and_partner_field', 'From line label (based on partner field)'), |
1822 | 112 | ('get_from_label_and_partner_name', 'From line label (based on partner name)'), | 134 | ('get_from_label_and_partner_name', 'From line label (based on partner name)')] |
1823 | 113 | ] | 135 | |
1824 | 114 | 136 | _columns = { | |
1821 | 115 | _columns={ | ||
1825 | 116 | 'sequence': fields.integer('Sequence', help="Lower means parsed first."), | 137 | 'sequence': fields.integer('Sequence', help="Lower means parsed first."), |
1826 | 117 | 'name': fields.char('Name', size=128), | 138 | 'name': fields.char('Name', size=128), |
1829 | 118 | 'profile_ids': fields.many2many('account.statement.profile', | 139 | 'profile_ids': fields.many2many( |
1830 | 119 | rel='as_rul_st_prof_rel', | 140 | 'account.statement.profile', |
1831 | 141 | rel='as_rul_st_prof_rel', | ||
1832 | 120 | string='Related statement profiles'), | 142 | string='Related statement profiles'), |
1833 | 121 | 'function_to_call': fields.selection(_get_functions, 'Method'), | 143 | 'function_to_call': fields.selection(_get_functions, 'Method'), |
1834 | 122 | } | 144 | } |
1853 | 123 | 145 | ||
1854 | 124 | def get_from_ref_and_invoice(self, cursor, uid, line_id, context=None): | 146 | def _find_invoice(self, cr, uid, st_line, inv_type, context=None): |
1855 | 125 | """ | 147 | """Find invoice related to statement line""" |
1856 | 126 | Match the partner based on the invoice number and the reference of the statement | 148 | inv_obj = self.pool.get('account.invoice') |
1857 | 127 | line. Then, call the generic get_values_for_line method to complete other values. | 149 | if inv_type == 'supplier': |
1858 | 128 | If more than one partner matched, raise the ErrorTooManyPartner error. | 150 | type_domain = ('in_invoice', 'in_refund') |
1859 | 129 | 151 | number_field = 'supplier_invoice_number' | |
1860 | 130 | :param int/long line_id: id of the concerned account.bank.statement.line | 152 | elif inv_type == 'customer': |
1861 | 131 | :return: | 153 | type_domain = ('out_invoice', 'out_refund') |
1862 | 132 | A dict of value that can be passed directly to the write method of | 154 | number_field = 'number' |
1863 | 133 | the statement line or {} | 155 | else: |
1864 | 134 | {'partner_id': value, | 156 | raise osv.except_osv(_('System error'), |
1865 | 135 | 'account_id' : value, | 157 | _('Invalid invoice type for completion: %') % inv_type) |
1866 | 136 | 158 | ||
1867 | 137 | ...} | 159 | inv_id = inv_obj.search(cr, uid, |
1868 | 138 | """ | 160 | [(number_field, '=', st_line['ref'].strip()), |
1869 | 139 | st_obj = self.pool.get('account.bank.statement.line') | 161 | ('type', 'in', type_domain)], |
1870 | 140 | st_line = st_obj.browse(cursor,uid,line_id) | 162 | context=context) |
1871 | 163 | if inv_id: | ||
1872 | 164 | if len(inv_id) == 1: | ||
1873 | 165 | inv = inv_obj.browse(cr, uid, inv_id[0], context=context) | ||
1874 | 166 | else: | ||
1875 | 167 | raise ErrorTooManyPartner(_('Line named "%s" (Ref:%s) was matched by more ' | ||
1876 | 168 | 'than one partner while looking on %s invoices') % | ||
1877 | 169 | (st_line['name'], st_line['ref'], inv_type)) | ||
1878 | 170 | return inv | ||
1879 | 171 | return False | ||
1880 | 172 | |||
1881 | 173 | def _from_invoice(self, cr, uid, line, inv_type, context): | ||
1882 | 174 | """Populate statement line values""" | ||
1883 | 175 | if not inv_type in ('supplier', 'customer'): | ||
1884 | 176 | raise osv.except_osv(_('System error'), | ||
1885 | 177 | _('Invalid invoice type for completion: %') % inv_type) | ||
1886 | 141 | res = {} | 178 | res = {} |
1899 | 142 | if st_line: | 179 | inv = self._find_invoice(cr, uid, line, inv_type, context=context) |
1900 | 143 | inv_obj = self.pool.get('account.invoice') | 180 | if inv: |
1901 | 144 | inv_id = inv_obj.search(cursor, uid, [('number', '=', st_line.ref)]) | 181 | res = {'partner_id': inv.partner_id.id, |
1902 | 145 | if inv_id: | 182 | 'account_id': inv.account_id.id, |
1903 | 146 | if inv_id and len(inv_id) == 1: | 183 | 'type': inv_type} |
1904 | 147 | inv = inv_obj.browse(cursor, uid, inv_id[0]) | 184 | override_acc = line['master_account_id'] |
1905 | 148 | res['partner_id'] = inv.partner_id.id | 185 | if override_acc: |
1906 | 149 | elif inv_id and len(inv_id) > 1: | 186 | res['account_id'] = override_acc |
1895 | 150 | raise ErrorTooManyPartner(_('Line named "%s" (Ref:%s) was matched by more than one partner.')%(st_line.name,st_line.ref)) | ||
1896 | 151 | st_vals = st_obj.get_values_for_line(cursor, uid, profile_id = st_line.statement_id.profile_id.id, | ||
1897 | 152 | partner_id = res.get('partner_id',False), line_type = st_line.type, amount = st_line.amount, context = context) | ||
1898 | 153 | res.update(st_vals) | ||
1907 | 154 | return res | 187 | return res |
1908 | 155 | 188 | ||
1922 | 156 | def get_from_ref_and_so(self, cursor, uid, line_id, context=None): | 189 | # Should be private but data are initialised with no update XML |
1923 | 157 | """ | 190 | def get_from_ref_and_supplier_invoice(self, cr, uid, line, context=None): |
1924 | 158 | Match the partner based on the SO number and the reference of the statement | 191 | """ |
1925 | 159 | line. Then, call the generic get_values_for_line method to complete other values. | 192 | Match the partner based on the invoice supplier invoice number and the reference of the statement |
1926 | 160 | If more than one partner matched, raise the ErrorTooManyPartner error. | 193 | line. Then, call the generic get_values_for_line method to complete other values. |
1927 | 161 | 194 | If more than one partner matched, raise the ErrorTooManyPartner error. | |
1928 | 162 | :param int/long line_id: id of the concerned account.bank.statement.line | 195 | |
1929 | 163 | :return: | 196 | :param dict line: read of the concerned account.bank.statement.line |
1930 | 164 | A dict of value that can be passed directly to the write method of | 197 | :return: |
1931 | 165 | the statement line or {} | 198 | A dict of value that can be passed directly to the write method of |
1932 | 166 | {'partner_id': value, | 199 | the statement line or {} |
1933 | 167 | 'account_id' : value, | 200 | {'partner_id': value, |
1934 | 168 | 201 | 'account_id': value, | |
1935 | 202 | |||
1936 | 203 | ...} | ||
1937 | 204 | """ | ||
1938 | 205 | return self._from_invoice(cr, uid, line, 'supplier', context=context) | ||
1939 | 206 | |||
1940 | 207 | # Should be private but data are initialised with no update XML | ||
1941 | 208 | def get_from_ref_and_invoice(self, cr, uid, line, context=None): | ||
1942 | 209 | """ | ||
1943 | 210 | Match the partner based on the invoice number and the reference of the statement | ||
1944 | 211 | line. Then, call the generic get_values_for_line method to complete other values. | ||
1945 | 212 | If more than one partner matched, raise the ErrorTooManyPartner error. | ||
1946 | 213 | |||
1947 | 214 | :param dict line: read of the concerned account.bank.statement.line | ||
1948 | 215 | :return: | ||
1949 | 216 | A dict of value that can be passed directly to the write method of | ||
1950 | 217 | the statement line or {} | ||
1951 | 218 | {'partner_id': value, | ||
1952 | 219 | 'account_id': value, | ||
1953 | 220 | ...} | ||
1954 | 221 | """ | ||
1955 | 222 | return self._from_invoice(cr, uid, line, 'customer', context=context) | ||
1956 | 223 | |||
1957 | 224 | # Should be private but data are initialised with no update XML | ||
1958 | 225 | def get_from_ref_and_so(self, cr, uid, st_line, context=None): | ||
1959 | 226 | """ | ||
1960 | 227 | Match the partner based on the SO number and the reference of the statement | ||
1961 | 228 | line. Then, call the generic get_values_for_line method to complete other values. | ||
1962 | 229 | If more than one partner matched, raise the ErrorTooManyPartner error. | ||
1963 | 230 | |||
1964 | 231 | :param int/long st_line: read of the concerned account.bank.statement.line | ||
1965 | 232 | :return: | ||
1966 | 233 | A dict of value that can be passed directly to the write method of | ||
1967 | 234 | the statement line or {} | ||
1968 | 235 | {'partner_id': value, | ||
1969 | 236 | 'account_id': value, | ||
1970 | 237 | |||
1971 | 169 | ...} | 238 | ...} |
1972 | 170 | """ | 239 | """ |
1973 | 171 | st_obj = self.pool.get('account.bank.statement.line') | 240 | st_obj = self.pool.get('account.bank.statement.line') |
1974 | 172 | st_line = st_obj.browse(cursor,uid,line_id) | ||
1975 | 173 | res = {} | 241 | res = {} |
1976 | 174 | if st_line: | 242 | if st_line: |
1977 | 175 | so_obj = self.pool.get('sale.order') | 243 | so_obj = self.pool.get('sale.order') |
1979 | 176 | so_id = so_obj.search(cursor, uid, [('name', '=', st_line.ref)]) | 244 | so_id = so_obj.search(cr, |
1980 | 245 | uid, | ||
1981 | 246 | [('name', '=', st_line['ref'])], | ||
1982 | 247 | context=context) | ||
1983 | 177 | if so_id: | 248 | if so_id: |
1984 | 178 | if so_id and len(so_id) == 1: | 249 | if so_id and len(so_id) == 1: |
1986 | 179 | so = so_obj.browse(cursor, uid, so_id[0]) | 250 | so = so_obj.browse(cr, uid, so_id[0], context=context) |
1987 | 180 | res['partner_id'] = so.partner_id.id | 251 | res['partner_id'] = so.partner_id.id |
1988 | 181 | elif so_id and len(so_id) > 1: | 252 | elif so_id and len(so_id) > 1: |
1992 | 182 | raise ErrorTooManyPartner(_('Line named "%s" (Ref:%s) was matched by more than one partner.')%(st_line.name,st_line.ref)) | 253 | raise ErrorTooManyPartner(_('Line named "%s" (Ref:%s) was matched by more ' |
1993 | 183 | st_vals = st_obj.get_values_for_line(cursor, uid, profile_id = st_line.statement_id.profile_id.id, | 254 | 'than one partner while looking on SO by ref.') % |
1994 | 184 | partner_id = res.get('partner_id',False), line_type = st_line.type, amount = st_line.amount, context = context) | 255 | (st_line['name'], st_line['ref'])) |
1995 | 256 | st_vals = st_obj.get_values_for_line(cr, | ||
1996 | 257 | uid, | ||
1997 | 258 | profile_id=st_line['profile_id'], | ||
1998 | 259 | master_account_id=st_line['master_account_id'], | ||
1999 | 260 | partner_id=res.get('partner_id', False), | ||
2000 | 261 | line_type='customer', | ||
2001 | 262 | amount=st_line['amount'] if st_line['amount'] else 0.0, | ||
2002 | 263 | context=context) | ||
2003 | 185 | res.update(st_vals) | 264 | res.update(st_vals) |
2004 | 186 | return res | 265 | return res |
2005 | 187 | |||
2006 | 188 | 266 | ||
2008 | 189 | def get_from_label_and_partner_field(self, cursor, uid, line_id, context=None): | 267 | # Should be private but data are initialised with no update XML |
2009 | 268 | def get_from_label_and_partner_field(self, cr, uid, st_line, context=None): | ||
2010 | 190 | """ | 269 | """ |
2011 | 191 | Match the partner based on the label field of the statement line | 270 | Match the partner based on the label field of the statement line |
2012 | 192 | and the text defined in the 'bank_statement_label' field of the partner. | 271 | and the text defined in the 'bank_statement_label' field of the partner. |
2014 | 193 | Remember that we can have values separated with ; Then, call the generic | 272 | Remember that we can have values separated with ; Then, call the generic |
2015 | 194 | get_values_for_line method to complete other values. | 273 | get_values_for_line method to complete other values. |
2016 | 195 | If more than one partner matched, raise the ErrorTooManyPartner error. | 274 | If more than one partner matched, raise the ErrorTooManyPartner error. |
2017 | 196 | 275 | ||
2019 | 197 | :param int/long line_id: id of the concerned account.bank.statement.line | 276 | :param dict st_line: read of the concerned account.bank.statement.line |
2020 | 198 | :return: | 277 | :return: |
2021 | 199 | A dict of value that can be passed directly to the write method of | 278 | A dict of value that can be passed directly to the write method of |
2022 | 200 | the statement line or {} | 279 | the statement line or {} |
2023 | 201 | {'partner_id': value, | 280 | {'partner_id': value, |
2026 | 202 | 'account_id' : value, | 281 | 'account_id': value, |
2027 | 203 | 282 | ||
2028 | 204 | ...} | 283 | ...} |
2029 | 205 | """ | 284 | """ |
2030 | 206 | partner_obj = self.pool.get('res.partner') | 285 | partner_obj = self.pool.get('res.partner') |
2031 | 207 | st_obj = self.pool.get('account.bank.statement.line') | 286 | st_obj = self.pool.get('account.bank.statement.line') |
2032 | 208 | st_line = st_obj.browse(cursor,uid,line_id) | ||
2033 | 209 | res = {} | 287 | res = {} |
2048 | 210 | compt = 0 | 288 | # As we have to iterate on each partner for each line, |
2049 | 211 | if st_line: | 289 | #Â we memoize the pair to avoid |
2050 | 212 | ids = partner_obj.search(cursor, uid, [['bank_statement_label', '!=', False]], context=context) | 290 | # to redo computation for each line. |
2051 | 213 | for partner in partner_obj.browse(cursor, uid, ids, context=context): | 291 | # Following code can be done by a single SQL query |
2052 | 214 | for partner_label in partner.bank_statement_label.split(';'): | 292 | # but this option is not really maintanable |
2053 | 215 | if partner_label in st_line.label: | 293 | if not context.get('label_memoizer'): |
2054 | 216 | compt += 1 | 294 | context['label_memoizer'] = defaultdict(list) |
2055 | 217 | res['partner_id'] = partner.id | 295 | partner_ids = partner_obj.search(cr, |
2056 | 218 | if compt > 1: | 296 | uid, |
2057 | 219 | raise ErrorTooManyPartner(_('Line named "%s" (Ref:%s) was matched by more than one partner.')%(st_line.name,st_line.ref)) | 297 | [('bank_statement_label', '!=', False)]) |
2058 | 220 | if res: | 298 | line_ids = context.get('line_ids', []) |
2059 | 221 | st_vals = st_obj.get_values_for_line(cursor, uid, profile_id = st_line.statement_id.profile_id.id, | 299 | for partner in partner_obj.browse(cr, uid, partner_ids, context=context): |
2060 | 222 | partner_id = res.get('partner_id',False), line_type = st_line.type, amount = st_line.amount, context = context) | 300 | vals = '|'.join(re.escape(x.strip()) for x in partner.bank_statement_label.split(';')) |
2061 | 223 | res.update(st_vals) | 301 | or_regex = ".*%s.*" % vals |
2062 | 302 | sql = ("SELECT id from account_bank_statement_line" | ||
2063 | 303 | " WHERE id in %s" | ||
2064 | 304 | " AND name ~* %s") | ||
2065 | 305 | cr.execute(sql, (line_ids, or_regex)) | ||
2066 | 306 | pairs = cr.fetchall() | ||
2067 | 307 | for pair in pairs: | ||
2068 | 308 | context['label_memoizer'][pair[0]].append(partner) | ||
2069 | 309 | |||
2070 | 310 | if st_line['id'] in context['label_memoizer']: | ||
2071 | 311 | found_partner = context['label_memoizer'][st_line['id']] | ||
2072 | 312 | if len(found_partner) > 1: | ||
2073 | 313 | msg = (_('Line named "%s" (Ref:%s) was matched by ' | ||
2074 | 314 | 'more than one partner while looking on partner label: %s') % | ||
2075 | 315 | (st_line['name'], st_line['ref'], ','.join([x.name for x in found_partner]))) | ||
2076 | 316 | raise ErrorTooManyPartner(msg) | ||
2077 | 317 | res['partner_id'] = found_partner[0].id | ||
2078 | 318 | st_vals = st_obj.get_values_for_line(cr, | ||
2079 | 319 | uid, | ||
2080 | 320 | profile_id=st_line['profile_id'], | ||
2081 | 321 | master_account_id=st_line['master_account_id'], | ||
2082 | 322 | partner_id=found_partner[0].id, | ||
2083 | 323 | line_type=False, | ||
2084 | 324 | amount=st_line['amount'] if st_line['amount'] else 0.0, | ||
2085 | 325 | context=context) | ||
2086 | 326 | res.update(st_vals) | ||
2087 | 224 | return res | 327 | return res |
2088 | 225 | 328 | ||
2090 | 226 | def get_from_label_and_partner_name(self, cursor, uid, line_id, context=None): | 329 | def get_from_label_and_partner_name(self, cr, uid, st_line, context=None): |
2091 | 227 | """ | 330 | """ |
2092 | 228 | Match the partner based on the label field of the statement line | 331 | Match the partner based on the label field of the statement line |
2093 | 229 | and the name of the partner. | 332 | and the name of the partner. |
2094 | 230 | Then, call the generic get_values_for_line method to complete other values. | 333 | Then, call the generic get_values_for_line method to complete other values. |
2095 | 231 | If more than one partner matched, raise the ErrorTooManyPartner error. | 334 | If more than one partner matched, raise the ErrorTooManyPartner error. |
2096 | 232 | 335 | ||
2098 | 233 | :param int/long line_id: id of the concerned account.bank.statement.line | 336 | :param dict st_line: read of the concerned account.bank.statement.line |
2099 | 234 | :return: | 337 | :return: |
2100 | 235 | A dict of value that can be passed directly to the write method of | 338 | A dict of value that can be passed directly to the write method of |
2101 | 236 | the statement line or {} | 339 | the statement line or {} |
2102 | 237 | {'partner_id': value, | 340 | {'partner_id': value, |
2105 | 238 | 'account_id' : value, | 341 | 'account_id': value, |
2106 | 239 | 342 | ||
2107 | 240 | ...} | 343 | ...} |
2108 | 241 | """ | 344 | """ |
2109 | 242 | # This Method has not been tested yet ! | ||
2110 | 243 | res = {} | 345 | res = {} |
2111 | 346 | # We memoize allowed partner | ||
2112 | 347 | if not context.get('partner_memoizer'): | ||
2113 | 348 | context['partner_memoizer'] = tuple(self.pool['res.partner'].search(cr, uid, [])) | ||
2114 | 349 | if not context['partner_memoizer']: | ||
2115 | 350 | return res | ||
2116 | 244 | st_obj = self.pool.get('account.bank.statement.line') | 351 | st_obj = self.pool.get('account.bank.statement.line') |
2131 | 245 | st_line = st_obj.browse(cursor,uid,line_id) | 352 | sql = "SELECT id FROM res_partner WHERE name ~* %s and id in %s" |
2132 | 246 | if st_line: | 353 | pattern = ".*%s.*" % re.escape(st_line['name']) |
2133 | 247 | sql = "SELECT id FROM res_partner WHERE name ~* %s" | 354 | cr.execute(sql, (pattern, context['partner_memoizer'])) |
2134 | 248 | pattern = ".*%s.*" % st_line.label | 355 | result = cr.fetchall() |
2135 | 249 | cursor.execute(sql, (pattern,)) | 356 | if not result: |
2136 | 250 | result = cursor.fetchall() | 357 | return res |
2137 | 251 | if len(result) > 1: | 358 | if len(result) > 1: |
2138 | 252 | raise ErrorTooManyPartner(_('Line named "%s" (Ref:%s) was matched by more than one partner.')%(st_line.name,st_line.ref)) | 359 | raise ErrorTooManyPartner(_('Line named "%s" (Ref:%s) was matched by more ' |
2139 | 253 | for id in result[0]: | 360 | 'than one partner while looking on partner by name') % |
2140 | 254 | res['partner_id'] = id | 361 | (st_line['name'], st_line['ref'])) |
2141 | 255 | if res: | 362 | res['partner_id'] = result[0][0] |
2142 | 256 | st_vals = st_obj.get_values_for_line(cursor, uid, profile_id = st_line.statement_id.profile_id.id, | 363 | st_vals = st_obj.get_values_for_line(cr, |
2143 | 257 | partner_id = res.get('partner_id',False), line_type = st_line.type, amount = st_line.amount, context = context) | 364 | uid, |
2144 | 258 | res.update(st_vals) | 365 | profile_id=st_line['porfile_id'], |
2145 | 366 | master_account_id=st_line['master_account_id'], | ||
2146 | 367 | partner_id=res['partner_id'], | ||
2147 | 368 | line_type=False, | ||
2148 | 369 | amount=st_line['amount'] if st_line['amount'] else 0.0, | ||
2149 | 370 | context=context) | ||
2150 | 371 | res.update(st_vals) | ||
2151 | 259 | return res | 372 | return res |
2155 | 260 | 373 | ||
2156 | 261 | 374 | ||
2157 | 262 | class AccountStatementLine(Model): | 375 | class AccountStatementLine(orm.Model): |
2158 | 263 | """ | 376 | """ |
2159 | 264 | Add sparse field on the statement line to allow to store all the | 377 | Add sparse field on the statement line to allow to store all the |
2160 | 265 | bank infos that are given by a bank/office. You can then add you own in your | 378 | bank infos that are given by a bank/office. You can then add you own in your |
2161 | @@ -270,23 +383,29 @@ | |||
2162 | 270 | """ | 383 | """ |
2163 | 271 | _inherit = "account.bank.statement.line" | 384 | _inherit = "account.bank.statement.line" |
2164 | 272 | 385 | ||
2175 | 273 | _columns={ | 386 | _columns = { |
2176 | 274 | 'additionnal_bank_fields' : fields.serialized('Additionnal infos from bank', | 387 | 'additionnal_bank_fields': fields.serialized( |
2177 | 275 | help="Used by completion and import system. Adds every field that is present in your bank/office \ | 388 | 'Additionnal infos from bank', |
2178 | 276 | statement file"), | 389 | help="Used by completion and import system. Adds every field that " |
2179 | 277 | 'label': fields.sparse(type='char', string='Label', | 390 | "is present in your bank/office statement file"), |
2180 | 278 | serialization_field='additionnal_bank_fields', | 391 | 'label': fields.sparse( |
2181 | 279 | help="Generiy field to store a label given from the bank/office on which we can \ | 392 | type='char', |
2182 | 280 | base the default/standard providen rule."), | 393 | string='Label', |
2183 | 281 | 'already_completed': fields.boolean("Auto-Completed", | 394 | serialization_field='additionnal_bank_fields', |
2184 | 282 | help="When this checkbox is ticked, the auto-completion process/button will ignore this line."), | 395 | help="Generic field to store a label given from the " |
2185 | 396 | "bank/office on which we can base the default/standard " | ||
2186 | 397 | "providen rule."), | ||
2187 | 398 | 'already_completed': fields.boolean( | ||
2188 | 399 | "Auto-Completed", | ||
2189 | 400 | help="When this checkbox is ticked, the auto-completion " | ||
2190 | 401 | "process/button will ignore this line."), | ||
2191 | 283 | } | 402 | } |
2192 | 403 | |||
2193 | 284 | _defaults = { | 404 | _defaults = { |
2194 | 285 | 'already_completed': False, | 405 | 'already_completed': False, |
2195 | 286 | } | 406 | } |
2199 | 287 | 407 | ||
2200 | 288 | 408 | def _get_line_values_from_rules(self, cr, uid, line, rules, context=None): | |
2198 | 289 | def get_line_values_from_rules(self, cr, uid, ids, context=None): | ||
2201 | 290 | """ | 409 | """ |
2202 | 291 | We'll try to find out the values related to the line based on rules setted on | 410 | We'll try to find out the values related to the line based on rules setted on |
2203 | 292 | the profile.. We will ignore line for which already_completed is ticked. | 411 | the profile.. We will ignore line for which already_completed is ticked. |
2204 | @@ -294,31 +413,20 @@ | |||
2205 | 294 | :return: | 413 | :return: |
2206 | 295 | A dict of dict value that can be passed directly to the write method of | 414 | A dict of dict value that can be passed directly to the write method of |
2207 | 296 | the statement line or {}. The first dict has statement line ID as a key: | 415 | the statement line or {}. The first dict has statement line ID as a key: |
2209 | 297 | {117009: {'partner_id': 100997, 'account_id': 489L}} | 416 | {117009: {'partner_id': 100997, 'account_id': 489L}} |
2210 | 298 | """ | 417 | """ |
2211 | 299 | profile_obj = self.pool.get('account.statement.profile') | 418 | profile_obj = self.pool.get('account.statement.profile') |
2234 | 300 | st_obj = self.pool.get('account.bank.statement.line') | 419 | if line.get('already_completed'): |
2235 | 301 | res={} | 420 | return {} |
2236 | 302 | errors_stack = [] | 421 | # Ask the rule |
2237 | 303 | for line in self.browse(cr,uid, ids, context): | 422 | vals = profile_obj._find_values_from_rules(cr, uid, rules, line, context) |
2238 | 304 | if not line.already_completed: | 423 | if vals: |
2239 | 305 | try: | 424 | vals['id'] = line['id'] |
2240 | 306 | # Take the default values | 425 | return vals |
2241 | 307 | res[line.id] = st_obj.get_values_for_line(cr, uid, profile_id = line.statement_id.profile_id.id, | 426 | return {} |
2242 | 308 | line_type = line.type, amount = line.amount, context = context) | 427 | |
2243 | 309 | # Ask the rule | 428 | |
2244 | 310 | vals = profile_obj.find_values_from_rules(cr, uid, line.statement_id.profile_id.id, line.id, context) | 429 | class AccountBankSatement(orm.Model): |
2223 | 311 | # Merge the result | ||
2224 | 312 | res[line.id].update(vals) | ||
2225 | 313 | except ErrorTooManyPartner, exc: | ||
2226 | 314 | msg = "Line ID %s had following error: %s" % (line.id, exc.value) | ||
2227 | 315 | errors_stack.append(msg) | ||
2228 | 316 | if errors_stack: | ||
2229 | 317 | msg = u"\n".join(errors_stack) | ||
2230 | 318 | raise ErrorTooManyPartner(msg) | ||
2231 | 319 | return res | ||
2232 | 320 | |||
2233 | 321 | class AccountBankSatement(Model): | ||
2245 | 322 | """ | 430 | """ |
2246 | 323 | We add a basic button and stuff to support the auto-completion | 431 | We add a basic button and stuff to support the auto-completion |
2247 | 324 | of the bank statement once line have been imported or manually fullfill. | 432 | of the bank statement once line have been imported or manually fullfill. |
2248 | @@ -328,61 +436,92 @@ | |||
2249 | 328 | _columns = { | 436 | _columns = { |
2250 | 329 | 'completion_logs': fields.text('Completion Log', readonly=True), | 437 | 'completion_logs': fields.text('Completion Log', readonly=True), |
2251 | 330 | } | 438 | } |
2253 | 331 | 439 | ||
2254 | 332 | def write_completion_log(self, cr, uid, stat_id, error_msg, number_imported, context=None): | 440 | def write_completion_log(self, cr, uid, stat_id, error_msg, number_imported, context=None): |
2255 | 333 | """ | 441 | """ |
2256 | 334 | Write the log in the completion_logs field of the bank statement to let the user | 442 | Write the log in the completion_logs field of the bank statement to let the user |
2257 | 335 | know what have been done. This is an append mode, so we don't overwrite what | 443 | know what have been done. This is an append mode, so we don't overwrite what |
2258 | 336 | already recoded. | 444 | already recoded. |
2260 | 337 | 445 | ||
2261 | 338 | :param int/long stat_id: ID of the account.bank.statement | 446 | :param int/long stat_id: ID of the account.bank.statement |
2262 | 339 | :param char error_msg: Message to add | 447 | :param char error_msg: Message to add |
2263 | 340 | :number_imported int/long: Number of lines that have been completed | 448 | :number_imported int/long: Number of lines that have been completed |
2266 | 341 | :return : True | 449 | :return True |
2265 | 342 | |||
2267 | 343 | """ | 450 | """ |
2282 | 344 | error_log = "" | 451 | user_name = self.pool.get('res.users').read(cr, uid, uid, |
2283 | 345 | user_name = self.pool.get('res.users').read(cr, uid, uid, ['name'])['name'] | 452 | ['name'], context=context)['name'] |
2284 | 346 | log = self.read(cr, uid, stat_id, ['completion_logs'], context=context)['completion_logs'] | 453 | |
2285 | 347 | log_line = log and log.split("\n") or [] | 454 | log = self.read(cr, uid, stat_id, ['completion_logs'], |
2286 | 348 | completion_date = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') | 455 | context=context)['completion_logs'] |
2287 | 349 | if error_msg: | 456 | log = log if log else "" |
2288 | 350 | error_log = error_msg | 457 | |
2289 | 351 | log_line[0:0] = [completion_date + ' : ' | 458 | completion_date = datetime.datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT) |
2290 | 352 | + _("Bank Statement ID %s has %s lines completed by %s") %(stat_id, number_imported, user_name) | 459 | message = (_("%s Bank Statement ID %s has %s lines completed by %s \n%s\n%s\n") % |
2291 | 353 | + "\n" + error_log + "-------------" + "\n"] | 460 | (completion_date, stat_id, number_imported, user_name, error_msg, log)) |
2292 | 354 | log = "\n".join(log_line) | 461 | self.write(cr, uid, [stat_id], {'completion_logs': message}, context=context) |
2293 | 355 | self.write(cr, uid, [stat_id], {'completion_logs' : log}, context=context) | 462 | |
2294 | 356 | logger.notifyChannel('Bank Statement Completion', netsvc.LOG_INFO, | 463 | body = (_('Statement ID %s auto-completed for %s lines completed') % |
2295 | 357 | "Bank Statement ID %s has %s lines completed"%(stat_id, number_imported)) | 464 | (stat_id, number_imported)), |
2296 | 465 | self.message_post(cr, uid, | ||
2297 | 466 | [stat_id], | ||
2298 | 467 | body=body, | ||
2299 | 468 | context=context) | ||
2300 | 358 | return True | 469 | return True |
2302 | 359 | 470 | ||
2303 | 360 | def button_auto_completion(self, cr, uid, ids, context=None): | 471 | def button_auto_completion(self, cr, uid, ids, context=None): |
2304 | 361 | """ | 472 | """ |
2305 | 362 | Complete line with values given by rules and tic the already_completed | 473 | Complete line with values given by rules and tic the already_completed |
2307 | 363 | checkbox so we won't compute them again unless the user untick them ! | 474 | checkbox so we won't compute them again unless the user untick them! |
2308 | 364 | """ | 475 | """ |
2313 | 365 | if not context: | 476 | if context is None: |
2314 | 366 | context={} | 477 | context = {} |
2315 | 367 | stat_line_obj = self.pool.get('account.bank.statement.line') | 478 | stat_line_obj = self.pool['account.bank.statement.line'] |
2316 | 368 | msg = "" | 479 | profile_obj = self.pool.get('account.statement.profile') |
2317 | 369 | compl_lines = 0 | 480 | compl_lines = 0 |
2318 | 481 | stat_line_obj.check_access_rule(cr, uid, [], 'create') | ||
2319 | 482 | stat_line_obj.check_access_rights(cr, uid, 'create', raise_exception=True) | ||
2320 | 370 | for stat in self.browse(cr, uid, ids, context=context): | 483 | for stat in self.browse(cr, uid, ids, context=context): |
2321 | 484 | msg_lines = [] | ||
2322 | 371 | ctx = context.copy() | 485 | ctx = context.copy() |
2325 | 372 | for line in stat.line_ids: | 486 | ctx['line_ids'] = tuple((x.id for x in stat.line_ids)) |
2326 | 373 | res = {} | 487 | b_profile = stat.profile_id |
2327 | 488 | rules = profile_obj._get_callable(cr, uid, b_profile, context=context) | ||
2328 | 489 | profile_id = b_profile.id # Only for perfo even it gains almost nothing | ||
2329 | 490 | master_account_id = b_profile.receivable_account_id | ||
2330 | 491 | master_account_id = master_account_id.id if master_account_id else False | ||
2331 | 492 | res = False | ||
2332 | 493 | for line in stat_line_obj.read(cr, uid, ctx['line_ids']): | ||
2333 | 374 | try: | 494 | try: |
2335 | 375 | res = stat_line_obj.get_line_values_from_rules(cr, uid, [line.id], context=ctx) | 495 | # performance trick |
2336 | 496 | line['master_account_id'] = master_account_id | ||
2337 | 497 | line['profile_id'] = profile_id | ||
2338 | 498 | res = stat_line_obj._get_line_values_from_rules(cr, uid, line, | ||
2339 | 499 | rules, context=ctx) | ||
2340 | 376 | if res: | 500 | if res: |
2341 | 377 | compl_lines += 1 | 501 | compl_lines += 1 |
2342 | 378 | except ErrorTooManyPartner, exc: | 502 | except ErrorTooManyPartner, exc: |
2344 | 379 | msg += exc.value + "\n" | 503 | msg_lines.append(repr(exc)) |
2345 | 380 | except Exception, exc: | 504 | except Exception, exc: |
2348 | 381 | msg += exc.value + "\n" | 505 | msg_lines.append(repr(exc)) |
2349 | 382 | # vals = res and res.keys() or False | 506 | error_type, error_value, trbk = sys.exc_info() |
2350 | 507 | st = "Error: %s\nDescription: %s\nTraceback:" % (error_type.__name__, error_value) | ||
2351 | 508 | st += ''.join(traceback.format_tb(trbk, 30)) | ||
2352 | 509 | _logger.error(st) | ||
2353 | 383 | if res: | 510 | if res: |
2358 | 384 | vals = res[line.id] | 511 | #stat_line_obj.write(cr, uid, [line.id], vals, context=ctx) |
2359 | 385 | vals['already_completed'] = True | 512 | try: |
2360 | 386 | stat_line_obj.write(cr, uid, line.id, vals, context=ctx) | 513 | stat_line_obj._update_line(cr, uid, res, context=context) |
2361 | 387 | self.write_completion_log(cr, uid, stat.id, msg, compl_lines, context=context) | 514 | except Exception as exc: |
2362 | 515 | msg_lines.append(repr(exc)) | ||
2363 | 516 | error_type, error_value, trbk = sys.exc_info() | ||
2364 | 517 | st = "Error: %s\nDescription: %s\nTraceback:" % (error_type.__name__, error_value) | ||
2365 | 518 | st += ''.join(traceback.format_tb(trbk, 30)) | ||
2366 | 519 | _logger.error(st) | ||
2367 | 520 | # we can commit as it is not needed to be atomic | ||
2368 | 521 | # commiting here adds a nice perfo boost | ||
2369 | 522 | if not compl_lines % 500: | ||
2370 | 523 | cr.commit() | ||
2371 | 524 | msg = u'\n'.join(msg_lines) | ||
2372 | 525 | self.write_completion_log(cr, uid, stat.id, | ||
2373 | 526 | msg, compl_lines, context=context) | ||
2374 | 388 | return True | 527 | return True |
2375 | 389 | 528 | ||
2376 | === modified file 'account_statement_base_completion/statement_view.xml' | |||
2377 | --- account_statement_base_completion/statement_view.xml 2012-08-02 12:46:12 +0000 | |||
2378 | +++ account_statement_base_completion/statement_view.xml 2013-06-10 07:05:32 +0000 | |||
2379 | @@ -10,21 +10,21 @@ | |||
2380 | 10 | <field name="type">form</field> | 10 | <field name="type">form</field> |
2381 | 11 | <field name="arch" type="xml"> | 11 | <field name="arch" type="xml"> |
2382 | 12 | <data> | 12 | <data> |
2384 | 13 | <xpath expr="/form/notebook/page/field[@name='line_ids']/form/field[@name='sequence']" position="after"> | 13 | <xpath expr="/form/sheet/notebook/page/field[@name='line_ids']/form/group/field[@name='sequence']" position="after"> |
2385 | 14 | <separator colspan="4" string="Importation related infos"/> | 14 | <separator colspan="4" string="Importation related infos"/> |
2386 | 15 | <field name="label" /> | 15 | <field name="label" /> |
2387 | 16 | <field name="already_completed" /> | 16 | <field name="already_completed" /> |
2388 | 17 | </xpath> | 17 | </xpath> |
2389 | 18 | 18 | ||
2393 | 19 | <xpath expr="/form/group[2]" position="attributes"> | 19 | <!-- <xpath expr="/form/group[2]" position="attributes"> |
2394 | 20 | <attribute name="col">10</attribute> | 20 | <attribute name="col">10</attribute> |
2395 | 21 | </xpath> | 21 | </xpath> --> |
2396 | 22 | 22 | ||
2398 | 23 | <xpath expr="/form/group/field[@name='balance_end']" position="after"> | 23 | <xpath expr="/form/sheet/div[@name='import_buttons']" position="after"> |
2399 | 24 | <button name="button_auto_completion" string="Auto Completion" states='draft,open' type="object" colspan="1"/> | 24 | <button name="button_auto_completion" string="Auto Completion" states='draft,open' type="object" colspan="1"/> |
2400 | 25 | </xpath> | 25 | </xpath> |
2401 | 26 | 26 | ||
2403 | 27 | <xpath expr="/form/notebook/page[@string='Journal Entries']" position="after"> | 27 | <xpath expr="/form/sheet/notebook/page[@string='Transactions']" position="after"> |
2404 | 28 | <page string="Completion Logs" attrs="{'invisible':[('completion_logs','=',False)]}"> | 28 | <page string="Completion Logs" attrs="{'invisible':[('completion_logs','=',False)]}"> |
2405 | 29 | <field name="completion_logs" colspan="4" nolabel="1" attrs="{'invisible':[('completion_logs','=',False)]}"/> | 29 | <field name="completion_logs" colspan="4" nolabel="1" attrs="{'invisible':[('completion_logs','=',False)]}"/> |
2406 | 30 | </page> | 30 | </page> |
2407 | @@ -40,7 +40,7 @@ | |||
2408 | 40 | <field name="type">form</field> | 40 | <field name="type">form</field> |
2409 | 41 | <field name="arch" type="xml"> | 41 | <field name="arch" type="xml"> |
2410 | 42 | <data> | 42 | <data> |
2412 | 43 | <xpath expr="/form/notebook/page/field[@name='line_ids']/tree/field[@name='amount']" position="after"> | 43 | <xpath expr="/form/sheet/notebook/page/field[@name='line_ids']/tree/field[@name='amount']" position="after"> |
2413 | 44 | <field name="already_completed" /> | 44 | <field name="already_completed" /> |
2414 | 45 | </xpath> | 45 | </xpath> |
2415 | 46 | </data> | 46 | </data> |
2416 | 47 | 47 | ||
2417 | === modified file 'account_statement_base_import/__init__.py' | |||
2418 | --- account_statement_base_import/__init__.py 2012-06-20 14:10:01 +0000 | |||
2419 | +++ account_statement_base_import/__init__.py 2013-06-10 07:05:32 +0000 | |||
2420 | @@ -20,4 +20,4 @@ | |||
2421 | 20 | ############################################################################## | 20 | ############################################################################## |
2422 | 21 | import parser | 21 | import parser |
2423 | 22 | import wizard | 22 | import wizard |
2424 | 23 | import statement | ||
2425 | 24 | \ No newline at end of file | 23 | \ No newline at end of file |
2426 | 24 | import statement | ||
2427 | 25 | 25 | ||
2428 | === modified file 'account_statement_base_import/__openerp__.py' | |||
2429 | --- account_statement_base_import/__openerp__.py 2012-08-02 12:46:12 +0000 | |||
2430 | +++ account_statement_base_import/__openerp__.py 2013-06-10 07:05:32 +0000 | |||
2431 | @@ -24,8 +24,11 @@ | |||
2432 | 24 | 'author': 'Camptocamp', | 24 | 'author': 'Camptocamp', |
2433 | 25 | 'maintainer': 'Camptocamp', | 25 | 'maintainer': 'Camptocamp', |
2434 | 26 | 'category': 'Finance', | 26 | 'category': 'Finance', |
2437 | 27 | 'complexity': 'normal', #easy, normal, expert | 27 | 'complexity': 'normal', |
2438 | 28 | 'depends': ['account_statement_ext','account_statement_base_completion'], | 28 | 'depends': [ |
2439 | 29 | 'account_statement_ext', | ||
2440 | 30 | 'account_statement_base_completion' | ||
2441 | 31 | ], | ||
2442 | 29 | 'description': """ | 32 | 'description': """ |
2443 | 30 | This module brings basic methods and fields on bank statement to deal with | 33 | This module brings basic methods and fields on bank statement to deal with |
2444 | 31 | the importation of different bank and offices. A generic abstract method is defined and an | 34 | the importation of different bank and offices. A generic abstract method is defined and an |
2445 | @@ -35,6 +38,8 @@ | |||
2446 | 35 | a standard .csv or .xls file (you'll find it in the 'data' folder). It respects the profile | 38 | a standard .csv or .xls file (you'll find it in the 'data' folder). It respects the profile |
2447 | 36 | (provided by the accouhnt_statement_ext module) to pass the entries. That means, | 39 | (provided by the accouhnt_statement_ext module) to pass the entries. That means, |
2448 | 37 | you'll have to choose a file format for each profile. | 40 | you'll have to choose a file format for each profile. |
2449 | 41 | In order to achieve this it uses the `xlrd` Python module which you will need to install | ||
2450 | 42 | separately in your environment. | ||
2451 | 38 | 43 | ||
2452 | 39 | This module can handle a commission taken by the payment office and has the following format: | 44 | This module can handle a commission taken by the payment office and has the following format: |
2453 | 40 | 45 | ||
2454 | @@ -53,16 +58,13 @@ | |||
2455 | 53 | 58 | ||
2456 | 54 | """, | 59 | """, |
2457 | 55 | 'website': 'http://www.camptocamp.com', | 60 | 'website': 'http://www.camptocamp.com', |
2460 | 56 | 'init_xml': [], | 61 | 'data': [ |
2459 | 57 | 'update_xml': [ | ||
2461 | 58 | "wizard/import_statement_view.xml", | 62 | "wizard/import_statement_view.xml", |
2462 | 59 | "statement_view.xml", | 63 | "statement_view.xml", |
2463 | 60 | ], | 64 | ], |
2464 | 61 | 'demo_xml': [], | ||
2465 | 62 | 'test': [], | 65 | 'test': [], |
2466 | 63 | 'installable': True, | 66 | 'installable': True, |
2467 | 64 | 'images': [], | 67 | 'images': [], |
2468 | 65 | 'auto_install': False, | 68 | 'auto_install': False, |
2469 | 66 | 'license': 'AGPL-3', | 69 | 'license': 'AGPL-3', |
2470 | 67 | 'active': False, | ||
2471 | 68 | } | 70 | } |
2472 | 69 | 71 | ||
2473 | === modified file 'account_statement_base_import/parser/__init__.py' | |||
2474 | --- account_statement_base_import/parser/__init__.py 2012-06-20 14:10:01 +0000 | |||
2475 | +++ account_statement_base_import/parser/__init__.py 2013-06-10 07:05:32 +0000 | |||
2476 | @@ -22,4 +22,4 @@ | |||
2477 | 22 | from parser import new_bank_statement_parser | 22 | from parser import new_bank_statement_parser |
2478 | 23 | from parser import BankStatementImportParser | 23 | from parser import BankStatementImportParser |
2479 | 24 | import file_parser | 24 | import file_parser |
2480 | 25 | import generic_file_parser | ||
2481 | 26 | \ No newline at end of file | 25 | \ No newline at end of file |
2482 | 26 | import generic_file_parser | ||
2483 | 27 | 27 | ||
2484 | === modified file 'account_statement_base_import/parser/file_parser.py' | |||
2485 | --- account_statement_base_import/parser/file_parser.py 2012-11-26 10:23:58 +0000 | |||
2486 | +++ account_statement_base_import/parser/file_parser.py 2013-06-10 07:05:32 +0000 | |||
2487 | @@ -17,8 +17,8 @@ | |||
2488 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2489 | 18 | # | 18 | # |
2490 | 19 | ############################################################################## | 19 | ############################################################################## |
2491 | 20 | |||
2492 | 21 | from openerp.tools.translate import _ | 20 | from openerp.tools.translate import _ |
2493 | 21 | from openerp.osv.osv import except_osv | ||
2494 | 22 | import tempfile | 22 | import tempfile |
2495 | 23 | import datetime | 23 | import datetime |
2496 | 24 | from parser import BankStatementImportParser | 24 | from parser import BankStatementImportParser |
2497 | @@ -28,17 +28,19 @@ | |||
2498 | 28 | except: | 28 | except: |
2499 | 29 | raise Exception(_('Please install python lib xlrd')) | 29 | raise Exception(_('Please install python lib xlrd')) |
2500 | 30 | 30 | ||
2501 | 31 | |||
2502 | 31 | class FileParser(BankStatementImportParser): | 32 | class FileParser(BankStatementImportParser): |
2503 | 32 | """ | 33 | """ |
2504 | 33 | Generic abstract class for defining parser for .csv or .xls file format. | 34 | Generic abstract class for defining parser for .csv or .xls file format. |
2505 | 34 | """ | 35 | """ |
2508 | 35 | 36 | ||
2509 | 36 | def __init__(self, parse_name, keys_to_validate=[], ftype='csv', convertion_dict=None, header=None, *args, **kwargs): | 37 | def __init__(self, parse_name, keys_to_validate=None, ftype='csv', conversion_dict=None, |
2510 | 38 | header=None, *args, **kwargs): | ||
2511 | 37 | """ | 39 | """ |
2512 | 38 | :param char: parse_name : The name of the parser | 40 | :param char: parse_name : The name of the parser |
2513 | 39 | :param list: keys_to_validate : contain the key that need to be present in the file | 41 | :param list: keys_to_validate : contain the key that need to be present in the file |
2514 | 40 | :param char ftype: extension of the file (could be csv or xls) | 42 | :param char ftype: extension of the file (could be csv or xls) |
2516 | 41 | :param: convertion_dict : keys and type to convert of every column in the file like | 43 | :param: conversion_dict : keys and type to convert of every column in the file like |
2517 | 42 | { | 44 | { |
2518 | 43 | 'ref': unicode, | 45 | 'ref': unicode, |
2519 | 44 | 'label': unicode, | 46 | 'label': unicode, |
2520 | @@ -48,18 +50,19 @@ | |||
2521 | 48 | } | 50 | } |
2522 | 49 | :param list: header : specify header fields if the csv file has no header | 51 | :param list: header : specify header fields if the csv file has no header |
2523 | 50 | """ | 52 | """ |
2525 | 51 | 53 | ||
2526 | 52 | super(FileParser, self).__init__(parse_name, *args, **kwargs) | 54 | super(FileParser, self).__init__(parse_name, *args, **kwargs) |
2527 | 53 | if ftype in ('csv', 'xls'): | 55 | if ftype in ('csv', 'xls'): |
2528 | 54 | self.ftype = ftype | 56 | self.ftype = ftype |
2529 | 55 | else: | 57 | else: |
2533 | 56 | raise Exception(_('Invalide file type %s. please use csv or xls') % (ftype)) | 58 | raise except_osv(_('User Error'), |
2534 | 57 | self.keys_to_validate = keys_to_validate | 59 | _('Invalid file type %s. Please use csv or xls') % ftype) |
2535 | 58 | self.convertion_dict = convertion_dict | 60 | self.keys_to_validate = keys_to_validate if keys_to_validate is not None else [] |
2536 | 61 | self.conversion_dict = conversion_dict | ||
2537 | 59 | self.fieldnames = header | 62 | self.fieldnames = header |
2541 | 60 | self._datemode = 0 # used only for xls documents, | 63 | self._datemode = 0 # used only for xls documents, |
2542 | 61 | # 0 means Windows mode (1900 based dates). | 64 | # 0 means Windows mode (1900 based dates). |
2543 | 62 | # Set in _parse_xls, from the contents of the file | 65 | # Set in _parse_xls, from the contents of the file |
2544 | 63 | 66 | ||
2545 | 64 | def _custom_format(self, *args, **kwargs): | 67 | def _custom_format(self, *args, **kwargs): |
2546 | 65 | """ | 68 | """ |
2547 | @@ -78,7 +81,7 @@ | |||
2548 | 78 | Launch the parsing through .csv or .xls depending on the | 81 | Launch the parsing through .csv or .xls depending on the |
2549 | 79 | given ftype | 82 | given ftype |
2550 | 80 | """ | 83 | """ |
2552 | 81 | 84 | ||
2553 | 82 | res = None | 85 | res = None |
2554 | 83 | if self.ftype == 'csv': | 86 | if self.ftype == 'csv': |
2555 | 84 | res = self._parse_csv() | 87 | res = self._parse_csv() |
2556 | @@ -98,7 +101,8 @@ | |||
2557 | 98 | parsed_cols = self.result_row_list[0].keys() | 101 | parsed_cols = self.result_row_list[0].keys() |
2558 | 99 | for col in self.keys_to_validate: | 102 | for col in self.keys_to_validate: |
2559 | 100 | if col not in parsed_cols: | 103 | if col not in parsed_cols: |
2561 | 101 | raise Exception(_('Column %s not present in file') % (col)) | 104 | raise except_osv(_('Invalid data'), |
2562 | 105 | _('Column %s not present in file') % col) | ||
2563 | 102 | return True | 106 | return True |
2564 | 103 | 107 | ||
2565 | 104 | def _post(self, *args, **kwargs): | 108 | def _post(self, *args, **kwargs): |
2566 | @@ -108,7 +112,6 @@ | |||
2567 | 108 | self.result_row_list = self._cast_rows(*args, **kwargs) | 112 | self.result_row_list = self._cast_rows(*args, **kwargs) |
2568 | 109 | return True | 113 | return True |
2569 | 110 | 114 | ||
2570 | 111 | |||
2571 | 112 | def _parse_csv(self): | 115 | def _parse_csv(self): |
2572 | 113 | """ | 116 | """ |
2573 | 114 | :return: list of dict from csv file (line/rows) | 117 | :return: list of dict from csv file (line/rows) |
2574 | @@ -116,7 +119,7 @@ | |||
2575 | 116 | csv_file = tempfile.NamedTemporaryFile() | 119 | csv_file = tempfile.NamedTemporaryFile() |
2576 | 117 | csv_file.write(self.filebuffer) | 120 | csv_file.write(self.filebuffer) |
2577 | 118 | csv_file.flush() | 121 | csv_file.flush() |
2579 | 119 | with open(csv_file.name, 'rU') as fobj: | 122 | with open(csv_file.name, 'rU') as fobj: |
2580 | 120 | reader = UnicodeDictReader(fobj, fieldnames=self.fieldnames) | 123 | reader = UnicodeDictReader(fobj, fieldnames=self.fieldnames) |
2581 | 121 | return list(reader) | 124 | return list(reader) |
2582 | 122 | 125 | ||
2583 | @@ -128,17 +131,13 @@ | |||
2584 | 128 | wb_file.write(self.filebuffer) | 131 | wb_file.write(self.filebuffer) |
2585 | 129 | # We ensure that cursor is at beginig of file | 132 | # We ensure that cursor is at beginig of file |
2586 | 130 | wb_file.seek(0) | 133 | wb_file.seek(0) |
2598 | 131 | wb = xlrd.open_workbook(wb_file.name) | 134 | with xlrd.open_workbook(wb_file.name) as wb: |
2599 | 132 | self._datemode = wb.datemode | 135 | self._datemode = wb.datemode |
2600 | 133 | sheet = wb.sheet_by_index(0) | 136 | sheet = wb.sheet_by_index(0) |
2601 | 134 | header = sheet.row_values(0) | 137 | header = sheet.row_values(0) |
2602 | 135 | res = [] | 138 | res = [] |
2603 | 136 | for rownum in range(1, sheet.nrows): | 139 | for rownum in range(1, sheet.nrows): |
2604 | 137 | res.append(dict(zip(header, sheet.row_values(rownum)))) | 140 | res.append(dict(zip(header, sheet.row_values(rownum)))) |
2594 | 138 | try: | ||
2595 | 139 | wb_file.close() | ||
2596 | 140 | except Exception, e: | ||
2597 | 141 | pass #file is allready closed | ||
2605 | 142 | return res | 141 | return res |
2606 | 143 | 142 | ||
2607 | 144 | def _from_csv(self, result_set, conversion_rules): | 143 | def _from_csv(self, result_set, conversion_rules): |
2608 | @@ -149,11 +148,30 @@ | |||
2609 | 149 | for line in result_set: | 148 | for line in result_set: |
2610 | 150 | for rule in conversion_rules: | 149 | for rule in conversion_rules: |
2611 | 151 | if conversion_rules[rule] == datetime.datetime: | 150 | if conversion_rules[rule] == datetime.datetime: |
2615 | 152 | date_string = line[rule].split(' ')[0] | 151 | try: |
2616 | 153 | line[rule] = datetime.datetime.strptime(date_string, | 152 | date_string = line[rule].split(' ')[0] |
2617 | 154 | '%Y-%m-%d') | 153 | line[rule] = datetime.datetime.strptime(date_string, |
2618 | 154 | '%Y-%m-%d') | ||
2619 | 155 | except ValueError as err: | ||
2620 | 156 | raise except_osv(_("Date format is not valid."), | ||
2621 | 157 | _(" It should be YYYY-MM-DD for column: %s" | ||
2622 | 158 | " value: %s \n \n" | ||
2623 | 159 | " \n Please check the line with ref: %s" | ||
2624 | 160 | " \n \n Detail: %s") % (rule, | ||
2625 | 161 | line.get(rule, _('Missing')), | ||
2626 | 162 | line.get('ref', line), | ||
2627 | 163 | repr(err))) | ||
2628 | 155 | else: | 164 | else: |
2630 | 156 | line[rule] = conversion_rules[rule](line[rule]) | 165 | try: |
2631 | 166 | line[rule] = conversion_rules[rule](line[rule]) | ||
2632 | 167 | except Exception as err: | ||
2633 | 168 | raise except_osv(_('Invalid data'), | ||
2634 | 169 | _("Value %s of column %s is not valid." | ||
2635 | 170 | "\n Please check the line with ref %s:" | ||
2636 | 171 | "\n \n Detail: %s") % (line.get(rule, _('Missing')), | ||
2637 | 172 | rule, | ||
2638 | 173 | line.get('ref', line), | ||
2639 | 174 | repr(err))) | ||
2640 | 157 | return result_set | 175 | return result_set |
2641 | 158 | 176 | ||
2642 | 159 | def _from_xls(self, result_set, conversion_rules): | 177 | def _from_xls(self, result_set, conversion_rules): |
2643 | @@ -164,17 +182,37 @@ | |||
2644 | 164 | for line in result_set: | 182 | for line in result_set: |
2645 | 165 | for rule in conversion_rules: | 183 | for rule in conversion_rules: |
2646 | 166 | if conversion_rules[rule] == datetime.datetime: | 184 | if conversion_rules[rule] == datetime.datetime: |
2649 | 167 | t_tuple = xlrd.xldate_as_tuple(line[rule], self._datemode) | 185 | try: |
2650 | 168 | line[rule] = datetime.datetime(*t_tuple) | 186 | t_tuple = xlrd.xldate_as_tuple(line[rule], self._datemode) |
2651 | 187 | line[rule] = datetime.datetime(*t_tuple) | ||
2652 | 188 | except Exception as err: | ||
2653 | 189 | raise except_osv(_("Date format is not valid"), | ||
2654 | 190 | _("Please modify the cell formatting to date format" | ||
2655 | 191 | " for column: %s" | ||
2656 | 192 | " value: %s" | ||
2657 | 193 | "\n Please check the line with ref: %s" | ||
2658 | 194 | "\n \n Detail: %s") % (rule, | ||
2659 | 195 | line.get(rule, _('Missing')), | ||
2660 | 196 | line.get('ref', line), | ||
2661 | 197 | repr(err))) | ||
2662 | 169 | else: | 198 | else: |
2664 | 170 | line[rule] = conversion_rules[rule](line[rule]) | 199 | try: |
2665 | 200 | line[rule] = conversion_rules[rule](line[rule]) | ||
2666 | 201 | except Exception as err: | ||
2667 | 202 | raise except_osv(_('Invalid data'), | ||
2668 | 203 | _("Value %s of column %s is not valid." | ||
2669 | 204 | "\n Please check the line with ref %s:" | ||
2670 | 205 | "\n \n Detail: %s") % (line.get(rule, _('Missing')), | ||
2671 | 206 | rule, | ||
2672 | 207 | line.get('ref', line), | ||
2673 | 208 | repr(err))) | ||
2674 | 171 | return result_set | 209 | return result_set |
2675 | 172 | 210 | ||
2676 | 173 | def _cast_rows(self, *args, **kwargs): | 211 | def _cast_rows(self, *args, **kwargs): |
2677 | 174 | """ | 212 | """ |
2679 | 175 | Convert the self.result_row_list using the self.convertion_dict providen. | 213 | Convert the self.result_row_list using the self.conversion_dict providen. |
2680 | 176 | We call here _from_xls or _from_csv depending on the self.ftype variable. | 214 | We call here _from_xls or _from_csv depending on the self.ftype variable. |
2681 | 177 | """ | 215 | """ |
2684 | 178 | func = getattr(self, '_from_%s'%(self.ftype)) | 216 | func = getattr(self, '_from_%s' % self.ftype) |
2685 | 179 | res = func(self.result_row_list, self.convertion_dict) | 217 | res = func(self.result_row_list, self.conversion_dict) |
2686 | 180 | return res | 218 | return res |
2687 | 181 | 219 | ||
2688 | === modified file 'account_statement_base_import/parser/generic_file_parser.py' | |||
2689 | --- account_statement_base_import/parser/generic_file_parser.py 2012-06-20 14:10:01 +0000 | |||
2690 | +++ account_statement_base_import/parser/generic_file_parser.py 2013-06-10 07:05:32 +0000 | |||
2691 | @@ -23,31 +23,37 @@ | |||
2692 | 23 | import csv | 23 | import csv |
2693 | 24 | import tempfile | 24 | import tempfile |
2694 | 25 | import datetime | 25 | import datetime |
2695 | 26 | # from . import file_parser | ||
2696 | 27 | from file_parser import FileParser | 26 | from file_parser import FileParser |
2697 | 28 | try: | 27 | try: |
2698 | 29 | import xlrd | 28 | import xlrd |
2699 | 30 | except: | 29 | except: |
2700 | 31 | raise Exception(_('Please install python lib xlrd')) | 30 | raise Exception(_('Please install python lib xlrd')) |
2701 | 32 | 31 | ||
2702 | 32 | |||
2703 | 33 | def float_or_zero(val): | ||
2704 | 34 | """ Conversion function used to manage | ||
2705 | 35 | empty string into float usecase""" | ||
2706 | 36 | return float(val) if val else 0.0 | ||
2707 | 37 | |||
2708 | 38 | |||
2709 | 33 | class GenericFileParser(FileParser): | 39 | class GenericFileParser(FileParser): |
2710 | 34 | """ | 40 | """ |
2711 | 35 | Standard parser that use a define format in csv or xls to import into a | 41 | Standard parser that use a define format in csv or xls to import into a |
2713 | 36 | bank statement. This is mostely an example of how to proceed to create a new | 42 | bank statement. This is mostely an example of how to proceed to create a new |
2714 | 37 | parser, but will also be useful as it allow to import a basic flat file. | 43 | parser, but will also be useful as it allow to import a basic flat file. |
2715 | 38 | """ | 44 | """ |
2717 | 39 | 45 | ||
2718 | 40 | def __init__(self, parse_name, ftype='csv'): | 46 | def __init__(self, parse_name, ftype='csv'): |
2720 | 41 | convertion_dict = { | 47 | conversion_dict = { |
2721 | 42 | 'ref': unicode, | 48 | 'ref': unicode, |
2722 | 43 | 'label': unicode, | 49 | 'label': unicode, |
2723 | 44 | 'date': datetime.datetime, | 50 | 'date': datetime.datetime, |
2726 | 45 | 'amount': float, | 51 | 'amount': float_or_zero, |
2727 | 46 | 'commission_amount': float | 52 | 'commission_amount': float_or_zero |
2728 | 47 | } | 53 | } |
2729 | 48 | # Order of cols does not matter but first row of the file has to be header | 54 | # Order of cols does not matter but first row of the file has to be header |
2730 | 49 | keys_to_validate = ['ref', 'label', 'date', 'amount', 'commission_amount'] | 55 | keys_to_validate = ['ref', 'label', 'date', 'amount', 'commission_amount'] |
2732 | 50 | super(GenericFileParser,self).__init__(parse_name, keys_to_validate=keys_to_validate, ftype=ftype, convertion_dict=convertion_dict) | 56 | super(GenericFileParser, self).__init__(parse_name, keys_to_validate=keys_to_validate, ftype=ftype, conversion_dict=conversion_dict) |
2733 | 51 | 57 | ||
2734 | 52 | @classmethod | 58 | @classmethod |
2735 | 53 | def parser_for(cls, parser_name): | 59 | def parser_for(cls, parser_name): |
2736 | @@ -60,7 +66,7 @@ | |||
2737 | 60 | def get_st_line_vals(self, line, *args, **kwargs): | 66 | def get_st_line_vals(self, line, *args, **kwargs): |
2738 | 61 | """ | 67 | """ |
2739 | 62 | This method must return a dict of vals that can be passed to create | 68 | This method must return a dict of vals that can be passed to create |
2741 | 63 | method of statement line in order to record it. It is the responsibility | 69 | method of statement line in order to record it. It is the responsibility |
2742 | 64 | of every parser to give this dict of vals, so each one can implement his | 70 | of every parser to give this dict of vals, so each one can implement his |
2743 | 65 | own way of recording the lines. | 71 | own way of recording the lines. |
2744 | 66 | :param: line: a dict of vals that represent a line of result_row_list | 72 | :param: line: a dict of vals that represent a line of result_row_list |
2745 | @@ -77,14 +83,12 @@ | |||
2746 | 77 | In this generic parser, the commission is given for every line, so we store it | 83 | In this generic parser, the commission is given for every line, so we store it |
2747 | 78 | for each one. | 84 | for each one. |
2748 | 79 | """ | 85 | """ |
2757 | 80 | return { | 86 | return {'name': line.get('label', line.get('ref', '/')), |
2758 | 81 | 'name': line.get('label', line.get('ref','/')), | 87 | 'date': line.get('date', datetime.datetime.now().date()), |
2759 | 82 | 'date': line.get('date', datetime.datetime.now().date()), | 88 | 'amount': line.get('amount', 0.0), |
2760 | 83 | 'amount': line.get('amount', 0.0), | 89 | 'ref': line.get('ref', '/'), |
2761 | 84 | 'ref': line.get('ref','/'), | 90 | 'label': line.get('label', ''), |
2762 | 85 | 'label': line.get('label',''), | 91 | 'commission_amount': line.get('commission_amount', 0.0)} |
2755 | 86 | 'commission_amount': line.get('commission_amount', 0.0), | ||
2756 | 87 | } | ||
2763 | 88 | 92 | ||
2764 | 89 | def _post(self, *args, **kwargs): | 93 | def _post(self, *args, **kwargs): |
2765 | 90 | """ | 94 | """ |
2766 | @@ -93,10 +97,6 @@ | |||
2767 | 93 | res = super(GenericFileParser, self)._post(*args, **kwargs) | 97 | res = super(GenericFileParser, self)._post(*args, **kwargs) |
2768 | 94 | val = 0.0 | 98 | val = 0.0 |
2769 | 95 | for row in self.result_row_list: | 99 | for row in self.result_row_list: |
2771 | 96 | val += row.get('commission_amount',0.0) | 100 | val += row.get('commission_amount', 0.0) |
2772 | 97 | self.commission_global_amount = val | 101 | self.commission_global_amount = val |
2773 | 98 | return res | 102 | return res |
2774 | 99 | |||
2775 | 100 | |||
2776 | 101 | |||
2777 | 102 | |||
2778 | 103 | 103 | ||
2779 | === modified file 'account_statement_base_import/parser/parser.py' | |||
2780 | --- account_statement_base_import/parser/parser.py 2012-11-23 16:27:24 +0000 | |||
2781 | +++ account_statement_base_import/parser/parser.py 2013-06-10 07:05:32 +0000 | |||
2782 | @@ -21,6 +21,7 @@ | |||
2783 | 21 | import base64 | 21 | import base64 |
2784 | 22 | import csv | 22 | import csv |
2785 | 23 | 23 | ||
2786 | 24 | |||
2787 | 24 | def UnicodeDictReader(utf8_data, **kwargs): | 25 | def UnicodeDictReader(utf8_data, **kwargs): |
2788 | 25 | sniffer = csv.Sniffer() | 26 | sniffer = csv.Sniffer() |
2789 | 26 | pos = utf8_data.tell() | 27 | pos = utf8_data.tell() |
2790 | @@ -31,6 +32,7 @@ | |||
2791 | 31 | for row in csv_reader: | 32 | for row in csv_reader: |
2792 | 32 | yield dict([(key, unicode(value, 'utf-8')) for key, value in row.iteritems()]) | 33 | yield dict([(key, unicode(value, 'utf-8')) for key, value in row.iteritems()]) |
2793 | 33 | 34 | ||
2794 | 35 | |||
2795 | 34 | class BankStatementImportParser(object): | 36 | class BankStatementImportParser(object): |
2796 | 35 | """ | 37 | """ |
2797 | 36 | Generic abstract class for defining parser for different files and | 38 | Generic abstract class for defining parser for different files and |
2798 | @@ -38,7 +40,7 @@ | |||
2799 | 38 | own. If your file is a .csv or .xls format, you should consider inheirt | 40 | own. If your file is a .csv or .xls format, you should consider inheirt |
2800 | 39 | from the FileParser instead. | 41 | from the FileParser instead. |
2801 | 40 | """ | 42 | """ |
2803 | 41 | 43 | ||
2804 | 42 | def __init__(self, parser_name, *args, **kwargs): | 44 | def __init__(self, parser_name, *args, **kwargs): |
2805 | 43 | # The name of the parser as it will be called | 45 | # The name of the parser as it will be called |
2806 | 44 | self.parser_name = parser_name | 46 | self.parser_name = parser_name |
2807 | @@ -50,7 +52,7 @@ | |||
2808 | 50 | # Concatenate here the global commission taken by the bank/office | 52 | # Concatenate here the global commission taken by the bank/office |
2809 | 51 | # for this statement. | 53 | # for this statement. |
2810 | 52 | self.commission_global_amount = None | 54 | self.commission_global_amount = None |
2812 | 53 | 55 | ||
2813 | 54 | @classmethod | 56 | @classmethod |
2814 | 55 | def parser_for(cls, parser_name): | 57 | def parser_for(cls, parser_name): |
2815 | 56 | """ | 58 | """ |
2816 | @@ -58,17 +60,17 @@ | |||
2817 | 58 | return the good class from his name. | 60 | return the good class from his name. |
2818 | 59 | """ | 61 | """ |
2819 | 60 | return False | 62 | return False |
2821 | 61 | 63 | ||
2822 | 62 | def _decode_64b_stream(self): | 64 | def _decode_64b_stream(self): |
2823 | 63 | """ | 65 | """ |
2824 | 64 | Decode self.filebuffer in base 64 and override it | 66 | Decode self.filebuffer in base 64 and override it |
2825 | 65 | """ | 67 | """ |
2826 | 66 | self.filebuffer = base64.b64decode(self.filebuffer) | 68 | self.filebuffer = base64.b64decode(self.filebuffer) |
2827 | 67 | return True | 69 | return True |
2829 | 68 | 70 | ||
2830 | 69 | def _format(self, decode_base_64=True, **kwargs): | 71 | def _format(self, decode_base_64=True, **kwargs): |
2831 | 70 | """ | 72 | """ |
2833 | 71 | Decode into base 64 if asked and Format the given filebuffer by calling | 73 | Decode into base 64 if asked and Format the given filebuffer by calling |
2834 | 72 | _custom_format method. | 74 | _custom_format method. |
2835 | 73 | """ | 75 | """ |
2836 | 74 | if decode_base_64: | 76 | if decode_base_64: |
2837 | @@ -83,43 +85,40 @@ | |||
2838 | 83 | """ | 85 | """ |
2839 | 84 | return NotImplementedError | 86 | return NotImplementedError |
2840 | 85 | 87 | ||
2841 | 86 | |||
2842 | 87 | def _pre(self, *args, **kwargs): | 88 | def _pre(self, *args, **kwargs): |
2843 | 88 | """ | 89 | """ |
2845 | 89 | Implement a method in your parser to make a pre-treatment on datas before parsing | 90 | Implement a method in your parser to make a pre-treatment on datas before parsing |
2846 | 90 | them, like concatenate stuff, and so... Work on self.filebuffer | 91 | them, like concatenate stuff, and so... Work on self.filebuffer |
2847 | 91 | """ | 92 | """ |
2848 | 92 | return NotImplementedError | 93 | return NotImplementedError |
2849 | 93 | 94 | ||
2850 | 94 | def _parse(self, *args, **kwargs): | 95 | def _parse(self, *args, **kwargs): |
2851 | 95 | """ | 96 | """ |
2853 | 96 | Implement a method in your parser to save the result of parsing self.filebuffer | 97 | Implement a method in your parser to save the result of parsing self.filebuffer |
2854 | 97 | in self.result_row_list instance property. | 98 | in self.result_row_list instance property. |
2855 | 98 | """ | 99 | """ |
2856 | 99 | return NotImplementedError | 100 | return NotImplementedError |
2858 | 100 | 101 | ||
2859 | 101 | def _validate(self, *args, **kwargs): | 102 | def _validate(self, *args, **kwargs): |
2860 | 102 | """ | 103 | """ |
2861 | 103 | Implement a method in your parser to validate the self.result_row_list instance | 104 | Implement a method in your parser to validate the self.result_row_list instance |
2862 | 104 | property and raise an error if not valid. | 105 | property and raise an error if not valid. |
2863 | 105 | """ | 106 | """ |
2864 | 106 | return NotImplementedError | 107 | return NotImplementedError |
2866 | 107 | 108 | ||
2867 | 108 | def _post(self, *args, **kwargs): | 109 | def _post(self, *args, **kwargs): |
2868 | 109 | """ | 110 | """ |
2869 | 110 | Implement a method in your parser to make some last changes on the result of parsing | 111 | Implement a method in your parser to make some last changes on the result of parsing |
2871 | 111 | the datas, like converting dates, computing commission, ... | 112 | the datas, like converting dates, computing commission, ... |
2872 | 112 | Work on self.result_row_list and put the commission global amount if any | 113 | Work on self.result_row_list and put the commission global amount if any |
2873 | 113 | in the self.commission_global_amount one. | 114 | in the self.commission_global_amount one. |
2874 | 114 | """ | 115 | """ |
2875 | 115 | return NotImplementedError | 116 | return NotImplementedError |
2876 | 116 | |||
2877 | 117 | 117 | ||
2878 | 118 | |||
2879 | 119 | def get_st_line_vals(self, line, *args, **kwargs): | 118 | def get_st_line_vals(self, line, *args, **kwargs): |
2880 | 120 | """ | 119 | """ |
2883 | 121 | Implement a method in your parser that must return a dict of vals that can be | 120 | Implement a method in your parser that must return a dict of vals that can be |
2884 | 122 | passed to create method of statement line in order to record it. It is the responsibility | 121 | passed to create method of statement line in order to record it. It is the responsibility |
2885 | 123 | of every parser to give this dict of vals, so each one can implement his | 122 | of every parser to give this dict of vals, so each one can implement his |
2886 | 124 | own way of recording the lines. | 123 | own way of recording the lines. |
2887 | 125 | :param: line: a dict of vals that represent a line of result_row_list | 124 | :param: line: a dict of vals that represent a line of result_row_list |
2888 | @@ -133,17 +132,17 @@ | |||
2889 | 133 | } | 132 | } |
2890 | 134 | """ | 133 | """ |
2891 | 135 | return NotImplementedError | 134 | return NotImplementedError |
2893 | 136 | 135 | ||
2894 | 137 | def get_st_line_commision(self, *args, **kwargs): | 136 | def get_st_line_commision(self, *args, **kwargs): |
2895 | 138 | """ | 137 | """ |
2896 | 139 | This is called by the importation method to create the commission line in | 138 | This is called by the importation method to create the commission line in |
2897 | 140 | the bank statement. We will always create one line for the commission in the | 139 | the bank statement. We will always create one line for the commission in the |
2899 | 141 | bank statement, but it could be computated from a value of each line, or given | 140 | bank statement, but it could be computated from a value of each line, or given |
2900 | 142 | in a single line for the whole file. | 141 | in a single line for the whole file. |
2901 | 143 | return: float of the whole commission (self.commission_global_amount) | 142 | return: float of the whole commission (self.commission_global_amount) |
2902 | 144 | """ | 143 | """ |
2903 | 145 | return self.commission_global_amount | 144 | return self.commission_global_amount |
2905 | 146 | 145 | ||
2906 | 147 | def parse(self, filebuffer, *args, **kwargs): | 146 | def parse(self, filebuffer, *args, **kwargs): |
2907 | 148 | """ | 147 | """ |
2908 | 149 | This will be the method that will be called by wizard, button and so | 148 | This will be the method that will be called by wizard, button and so |
2909 | @@ -151,7 +150,7 @@ | |||
2910 | 151 | that need to be define for each parser. | 150 | that need to be define for each parser. |
2911 | 152 | Return: | 151 | Return: |
2912 | 153 | [] of rows as {'key':value} | 152 | [] of rows as {'key':value} |
2914 | 154 | 153 | ||
2915 | 155 | Note: The row_list must contain only value that are present in the account. | 154 | Note: The row_list must contain only value that are present in the account. |
2916 | 156 | bank.statement.line object !!! | 155 | bank.statement.line object !!! |
2917 | 157 | """ | 156 | """ |
2918 | @@ -165,7 +164,8 @@ | |||
2919 | 165 | self._validate(*args, **kwargs) | 164 | self._validate(*args, **kwargs) |
2920 | 166 | self._post(*args, **kwargs) | 165 | self._post(*args, **kwargs) |
2921 | 167 | return self.result_row_list | 166 | return self.result_row_list |
2923 | 168 | 167 | ||
2924 | 168 | |||
2925 | 169 | def itersubclasses(cls, _seen=None): | 169 | def itersubclasses(cls, _seen=None): |
2926 | 170 | """ | 170 | """ |
2927 | 171 | itersubclasses(cls) | 171 | itersubclasses(cls) |
2928 | @@ -179,7 +179,7 @@ | |||
2929 | 179 | >>> class C(A): pass | 179 | >>> class C(A): pass |
2930 | 180 | >>> class D(B,C): pass | 180 | >>> class D(B,C): pass |
2931 | 181 | >>> class E(D): pass | 181 | >>> class E(D): pass |
2933 | 182 | >>> | 182 | >>> |
2934 | 183 | >>> for cls in itersubclasses(A): | 183 | >>> for cls in itersubclasses(A): |
2935 | 184 | ... print(cls.__name__) | 184 | ... print(cls.__name__) |
2936 | 185 | B | 185 | B |
2937 | @@ -193,10 +193,11 @@ | |||
2938 | 193 | if not isinstance(cls, type): | 193 | if not isinstance(cls, type): |
2939 | 194 | raise TypeError('itersubclasses must be called with ' | 194 | raise TypeError('itersubclasses must be called with ' |
2940 | 195 | 'new-style classes, not %.100r' % cls) | 195 | 'new-style classes, not %.100r' % cls) |
2942 | 196 | if _seen is None: _seen = set() | 196 | if _seen is None: |
2943 | 197 | _seen = set() | ||
2944 | 197 | try: | 198 | try: |
2945 | 198 | subs = cls.__subclasses__() | 199 | subs = cls.__subclasses__() |
2947 | 199 | except TypeError: # fails only when cls is type | 200 | except TypeError: # fails only when cls is type |
2948 | 200 | subs = cls.__subclasses__(cls) | 201 | subs = cls.__subclasses__(cls) |
2949 | 201 | for sub in subs: | 202 | for sub in subs: |
2950 | 202 | if sub not in _seen: | 203 | if sub not in _seen: |
2951 | @@ -204,7 +205,8 @@ | |||
2952 | 204 | yield sub | 205 | yield sub |
2953 | 205 | for sub in itersubclasses(sub, _seen): | 206 | for sub in itersubclasses(sub, _seen): |
2954 | 206 | yield sub | 207 | yield sub |
2956 | 207 | 208 | ||
2957 | 209 | |||
2958 | 208 | def new_bank_statement_parser(parser_name, *args, **kwargs): | 210 | def new_bank_statement_parser(parser_name, *args, **kwargs): |
2959 | 209 | """ | 211 | """ |
2960 | 210 | Return an instance of the good parser class base on the providen name | 212 | Return an instance of the good parser class base on the providen name |
2961 | @@ -215,4 +217,3 @@ | |||
2962 | 215 | if cls.parser_for(parser_name): | 217 | if cls.parser_for(parser_name): |
2963 | 216 | return cls(parser_name, *args, **kwargs) | 218 | return cls(parser_name, *args, **kwargs) |
2964 | 217 | raise ValueError | 219 | raise ValueError |
2965 | 218 | |||
2966 | 219 | 220 | ||
2967 | === modified file 'account_statement_base_import/statement.py' | |||
2968 | --- account_statement_base_import/statement.py 2012-09-25 08:05:34 +0000 | |||
2969 | +++ account_statement_base_import/statement.py 2013-06-10 07:05:32 +0000 | |||
2970 | @@ -18,65 +18,62 @@ | |||
2971 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2972 | 19 | # | 19 | # |
2973 | 20 | ############################################################################## | 20 | ############################################################################## |
2976 | 21 | 21 | import sys | |
2977 | 22 | from tools.translate import _ | 22 | import traceback |
2978 | 23 | |||
2979 | 24 | import psycopg2 | ||
2980 | 25 | |||
2981 | 26 | from openerp.tools.translate import _ | ||
2982 | 23 | import datetime | 27 | import datetime |
2986 | 24 | import netsvc | 28 | from openerp.osv.orm import Model |
2984 | 25 | logger = netsvc.Logger() | ||
2985 | 26 | from openerp.osv.orm import Model, fields | ||
2987 | 27 | from openerp.osv import fields, osv | 29 | from openerp.osv import fields, osv |
2988 | 28 | # from account_statement_base_import.parser.file_parser import FileParser | ||
2989 | 29 | from parser import new_bank_statement_parser | 30 | from parser import new_bank_statement_parser |
2992 | 30 | import sys | 31 | |
2991 | 31 | import traceback | ||
2993 | 32 | 32 | ||
2994 | 33 | class AccountStatementProfil(Model): | 33 | class AccountStatementProfil(Model): |
2995 | 34 | _inherit = "account.statement.profile" | 34 | _inherit = "account.statement.profile" |
2998 | 35 | 35 | ||
2997 | 36 | |||
2999 | 37 | def get_import_type_selection(self, cr, uid, context=None): | 36 | def get_import_type_selection(self, cr, uid, context=None): |
3000 | 38 | """ | 37 | """ |
3001 | 39 | Has to be inherited to add parser | 38 | Has to be inherited to add parser |
3002 | 40 | """ | 39 | """ |
3003 | 41 | return [('generic_csvxls_so', 'Generic .csv/.xls based on SO Name')] | 40 | return [('generic_csvxls_so', 'Generic .csv/.xls based on SO Name')] |
3006 | 42 | 41 | ||
3005 | 43 | |||
3007 | 44 | _columns = { | 42 | _columns = { |
3011 | 45 | 'launch_import_completion': fields.boolean("Launch completion after import", | 43 | 'launch_import_completion': fields.boolean( |
3012 | 46 | help="Tic that box to automatically launch the completion on each imported\ | 44 | "Launch completion after import", |
3013 | 47 | file using this profile."), | 45 | help="Tic that box to automatically launch the completion " |
3014 | 46 | "on each imported file using this profile."), | ||
3015 | 48 | 'last_import_date': fields.datetime("Last Import Date"), | 47 | 'last_import_date': fields.datetime("Last Import Date"), |
3020 | 49 | 'rec_log': fields.text('log', readonly=True), | 48 | # we remove deprecated as it floods logs in standard/warning level sob... |
3021 | 50 | 'import_type': fields.selection(get_import_type_selection, 'Type of import', required=True, | 49 | 'rec_log': fields.text('log', readonly=True), # Deprecated |
3022 | 51 | help = "Choose here the method by which you want to import bank statement for this profile."), | 50 | 'import_type': fields.selection( |
3023 | 52 | 51 | get_import_type_selection, | |
3024 | 52 | 'Type of import', | ||
3025 | 53 | required=True, | ||
3026 | 54 | help="Choose here the method by which you want to import bank" | ||
3027 | 55 | "statement for this profile."), | ||
3028 | 56 | |||
3029 | 53 | } | 57 | } |
3031 | 54 | 58 | ||
3032 | 55 | def write_logs_after_import(self, cr, uid, ids, statement_id, num_lines, context): | 59 | def write_logs_after_import(self, cr, uid, ids, statement_id, num_lines, context): |
3033 | 56 | """ | 60 | """ |
3037 | 57 | Write the log in the logger + in the log field of the profile to report the user about | 61 | Write the log in the logger |
3038 | 58 | what has been done. | 62 | |
3036 | 59 | |||
3039 | 60 | :param int/long statement_id: ID of the concerned account.bank.statement | 63 | :param int/long statement_id: ID of the concerned account.bank.statement |
3040 | 61 | :param int/long num_lines: Number of line that have been parsed | 64 | :param int/long num_lines: Number of line that have been parsed |
3041 | 62 | :return: True | 65 | :return: True |
3042 | 63 | """ | 66 | """ |
3055 | 64 | if type(ids) is int: | 67 | self.message_post(cr, |
3056 | 65 | ids = [ids] | 68 | uid, |
3057 | 66 | for id in ids: | 69 | ids, |
3058 | 67 | log = self.read(cr, uid, id, ['rec_log'], context=context)['rec_log'] | 70 | body=_('Statement ID %s have been imported with %s lines.') % |
3059 | 68 | log_line = log and log.split("\n") or [] | 71 | (statement_id, num_lines), |
3060 | 69 | import_date = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') | 72 | context=context) |
3049 | 70 | log_line[0:0] = [import_date + ' : ' | ||
3050 | 71 | + _("Bank Statement ID %s have been imported with %s lines ") %(statement_id, num_lines)] | ||
3051 | 72 | log = "\n".join(log_line) | ||
3052 | 73 | self.write(cr, uid, id, {'rec_log' : log, 'last_import_date':import_date}, context=context) | ||
3053 | 74 | logger.notifyChannel('Bank Statement Import', netsvc.LOG_INFO, | ||
3054 | 75 | "Bank Statement ID %s have been imported with %s lines "%(statement_id, num_lines)) | ||
3061 | 76 | return True | 73 | return True |
3065 | 77 | 74 | ||
3066 | 78 | def prepare_global_commission_line_vals(self, cr, uid, parser, | 75 | def prepare_global_commission_line_vals( |
3067 | 79 | result_row_list, profile, statement_id, context): | 76 | self, cr, uid, parser, result_row_list, profile, statement_id, context): |
3068 | 80 | """ | 77 | """ |
3069 | 81 | Prepare the global commission line if there is one. The global | 78 | Prepare the global commission line if there is one. The global |
3070 | 82 | commission is computed by by calling the get_st_line_commision | 79 | commission is computed by by calling the get_st_line_commision |
3071 | @@ -86,7 +83,7 @@ | |||
3072 | 86 | :param: browse_record of the current parser | 83 | :param: browse_record of the current parser |
3073 | 87 | :param: result_row_list: [{'key':value}] | 84 | :param: result_row_list: [{'key':value}] |
3074 | 88 | :param: profile: browserecord of account.statement.profile | 85 | :param: profile: browserecord of account.statement.profile |
3076 | 89 | :param: statement_id : int/long of the current importing statement ID | 86 | :param: statement_id: int/long of the current importing statement ID |
3077 | 90 | :param: context: global context | 87 | :param: context: global context |
3078 | 91 | return: dict of vals that will be passed to create method of statement line. | 88 | return: dict of vals that will be passed to create method of statement line. |
3079 | 92 | """ | 89 | """ |
3080 | @@ -95,9 +92,8 @@ | |||
3081 | 95 | partner_id = profile.partner_id and profile.partner_id.id or False | 92 | partner_id = profile.partner_id and profile.partner_id.id or False |
3082 | 96 | commission_account_id = profile.commission_account_id and profile.commission_account_id.id or False | 93 | commission_account_id = profile.commission_account_id and profile.commission_account_id.id or False |
3083 | 97 | commission_analytic_id = profile.commission_analytic_id and profile.commission_analytic_id.id or False | 94 | commission_analytic_id = profile.commission_analytic_id and profile.commission_analytic_id.id or False |
3084 | 98 | statement_line_obj = self.pool.get('account.bank.statement.line') | ||
3085 | 99 | comm_values = { | 95 | comm_values = { |
3087 | 100 | 'name': 'IN '+ _('Commission line'), | 96 | 'name': 'IN ' + _('Commission line'), |
3088 | 101 | 'date': datetime.datetime.now().date(), | 97 | 'date': datetime.datetime.now().date(), |
3089 | 102 | 'amount': parser.get_st_line_commision(), | 98 | 'amount': parser.get_st_line_commision(), |
3090 | 103 | 'partner_id': partner_id, | 99 | 'partner_id': partner_id, |
3091 | @@ -106,118 +102,150 @@ | |||
3092 | 106 | 'account_id': commission_account_id, | 102 | 'account_id': commission_account_id, |
3093 | 107 | 'ref': 'commission', | 103 | 'ref': 'commission', |
3094 | 108 | 'analytic_account_id': commission_analytic_id, | 104 | 'analytic_account_id': commission_analytic_id, |
3096 | 109 | # !! We set the already_completed so auto-completion will not update those values ! | 105 | # !! We set the already_completed so auto-completion will not update those values! |
3097 | 110 | 'already_completed': True, | 106 | 'already_completed': True, |
3098 | 111 | } | 107 | } |
3099 | 112 | return comm_values | 108 | return comm_values |
3103 | 113 | 109 | ||
3104 | 114 | def prepare_statetement_lines_vals(self, cursor, uid, parser_vals, | 110 | def prepare_statetement_lines_vals( |
3105 | 115 | account_payable, account_receivable, statement_id, context): | 111 | self, cr, uid, parser_vals, account_payable, account_receivable, |
3106 | 112 | statement_id, context): | ||
3107 | 116 | """ | 113 | """ |
3108 | 117 | Hook to build the values of a line from the parser returned values. At | 114 | Hook to build the values of a line from the parser returned values. At |
3109 | 118 | least it fullfill the statement_id and account_id. Overide it to add your | 115 | least it fullfill the statement_id and account_id. Overide it to add your |
3113 | 119 | own completion if needed. | 116 | own completion if needed. |
3114 | 120 | 117 | ||
3115 | 121 | :param dict of vals from parser for account.bank.statement.line (called by | 118 | :param dict of vals from parser for account.bank.statement.line (called by |
3116 | 122 | parser.get_st_line_vals) | 119 | parser.get_st_line_vals) |
3117 | 123 | :param int/long account_payable: ID of the receivable account to use | 120 | :param int/long account_payable: ID of the receivable account to use |
3118 | 124 | :param int/long account_receivable: ID of the payable account to use | 121 | :param int/long account_receivable: ID of the payable account to use |
3119 | 125 | :param int/long statement_id: ID of the concerned account.bank.statement | 122 | :param int/long statement_id: ID of the concerned account.bank.statement |
3121 | 126 | :return : dict of vals that will be passed to create method of statement line. | 123 | :return: dict of vals that will be passed to create method of statement line. |
3122 | 127 | """ | 124 | """ |
3123 | 128 | statement_obj = self.pool.get('account.bank.statement') | 125 | statement_obj = self.pool.get('account.bank.statement') |
3124 | 129 | values = parser_vals | 126 | values = parser_vals |
3133 | 130 | values['statement_id']= statement_id | 127 | values['statement_id'] = statement_id |
3134 | 131 | values['account_id'] = statement_obj.get_account_for_counterpart( | 128 | values['account_id'] = statement_obj.get_account_for_counterpart(cr, |
3135 | 132 | cursor, | 129 | uid, |
3136 | 133 | uid, | 130 | parser_vals['amount'], |
3137 | 134 | parser_vals['amount'], | 131 | account_receivable, |
3138 | 135 | account_receivable, | 132 | account_payable) |
3139 | 136 | account_payable | 133 | |
3140 | 137 | ) | 134 | date = values.get('date') |
3141 | 135 | period_memoizer = context.get('period_memoizer') | ||
3142 | 136 | if not period_memoizer: | ||
3143 | 137 | period_memoizer = {} | ||
3144 | 138 | context['period_memoizer'] = period_memoizer | ||
3145 | 139 | if period_memoizer.get(date): | ||
3146 | 140 | values['period_id'] = period_memoizer[date] | ||
3147 | 141 | else: | ||
3148 | 142 | # This is awfully slow... | ||
3149 | 143 | periods = self.pool.get('account.period').find(cr, uid, | ||
3150 | 144 | dt=values.get('date'), | ||
3151 | 145 | context=context) | ||
3152 | 146 | values['period_id'] = periods[0] | ||
3153 | 147 | period_memoizer[date] = periods[0] | ||
3154 | 148 | values['type'] = 'general' | ||
3155 | 138 | return values | 149 | return values |
3158 | 139 | 150 | ||
3159 | 140 | def statement_import(self, cursor, uid, ids, profile_id, file_stream, ftype="csv", context=None): | 151 | def statement_import(self, cr, uid, ids, profile_id, file_stream, ftype="csv", context=None): |
3160 | 141 | """ | 152 | """ |
3161 | 142 | Create a bank statement with the given profile and parser. It will fullfill the bank statement | 153 | Create a bank statement with the given profile and parser. It will fullfill the bank statement |
3162 | 143 | with the values of the file providen, but will not complete data (like finding the partner, or | 154 | with the values of the file providen, but will not complete data (like finding the partner, or |
3163 | 144 | the right account). This will be done in a second step with the completion rules. | 155 | the right account). This will be done in a second step with the completion rules. |
3164 | 145 | It will also create the commission line if it apply and record the providen file as | 156 | It will also create the commission line if it apply and record the providen file as |
3165 | 146 | an attachement of the bank statement. | 157 | an attachement of the bank statement. |
3167 | 147 | 158 | ||
3168 | 148 | :param int/long profile_id: ID of the profile used to import the file | 159 | :param int/long profile_id: ID of the profile used to import the file |
3169 | 149 | :param filebuffer file_stream: binary of the providen file | 160 | :param filebuffer file_stream: binary of the providen file |
3170 | 150 | :param char: ftype represent the file exstension (csv by default) | 161 | :param char: ftype represent the file exstension (csv by default) |
3171 | 151 | :return: ID of the created account.bank.statemênt | 162 | :return: ID of the created account.bank.statemênt |
3172 | 152 | """ | 163 | """ |
3173 | 153 | context = context or {} | ||
3174 | 154 | statement_obj = self.pool.get('account.bank.statement') | 164 | statement_obj = self.pool.get('account.bank.statement') |
3175 | 155 | statement_line_obj = self.pool.get('account.bank.statement.line') | 165 | statement_line_obj = self.pool.get('account.bank.statement.line') |
3176 | 156 | attachment_obj = self.pool.get('ir.attachment') | 166 | attachment_obj = self.pool.get('ir.attachment') |
3177 | 157 | prof_obj = self.pool.get("account.statement.profile") | 167 | prof_obj = self.pool.get("account.statement.profile") |
3178 | 158 | if not profile_id: | 168 | if not profile_id: |
3184 | 159 | raise osv.except_osv( | 169 | raise osv.except_osv(_("No Profile!"), |
3185 | 160 | _("No Profile !"), | 170 | _("You must provide a valid profile to import a bank statement!")) |
3186 | 161 | _("You must provide a valid profile to import a bank statement !")) | 171 | prof = prof_obj.browse(cr, uid, profile_id, context=context) |
3187 | 162 | prof = prof_obj.browse(cursor,uid,profile_id,context) | 172 | |
3183 | 163 | |||
3188 | 164 | parser = new_bank_statement_parser(prof.import_type, ftype=ftype) | 173 | parser = new_bank_statement_parser(prof.import_type, ftype=ftype) |
3189 | 165 | result_row_list = parser.parse(file_stream) | 174 | result_row_list = parser.parse(file_stream) |
3191 | 166 | # Check all key are present in account.bank.statement.line !! | 175 | # Check all key are present in account.bank.statement.line!! |
3192 | 176 | if not result_row_list: | ||
3193 | 177 | raise osv.except_osv(_("Nothing to import"), | ||
3194 | 178 | _("The file is empty")) | ||
3195 | 167 | parsed_cols = parser.get_st_line_vals(result_row_list[0]).keys() | 179 | parsed_cols = parser.get_st_line_vals(result_row_list[0]).keys() |
3196 | 168 | for col in parsed_cols: | 180 | for col in parsed_cols: |
3197 | 169 | if col not in statement_line_obj._columns: | 181 | if col not in statement_line_obj._columns: |
3204 | 170 | raise osv.except_osv( | 182 | raise osv.except_osv(_("Missing column!"), |
3205 | 171 | _("Missing column !"), | 183 | _("Column %s you try to import is not " |
3206 | 172 | _("Column %s you try to import is not present in the bank statement line !") %(col)) | 184 | "present in the bank statement line!") % col) |
3207 | 173 | 185 | ||
3208 | 174 | statement_id = statement_obj.create(cursor,uid,{'profile_id':prof.id,},context) | 186 | statement_id = statement_obj.create(cr, uid, |
3209 | 175 | account_receivable, account_payable = statement_obj.get_default_pay_receiv_accounts(cursor, uid, context) | 187 | {'profile_id': prof.id}, |
3210 | 188 | context=context) | ||
3211 | 189 | if prof.receivable_account_id: | ||
3212 | 190 | account_receivable = account_payable = prof.receivable_account_id.id | ||
3213 | 191 | else: | ||
3214 | 192 | account_receivable, account_payable = statement_obj.get_default_pay_receiv_accounts( | ||
3215 | 193 | cr, uid, context) | ||
3216 | 176 | try: | 194 | try: |
3217 | 177 | # Record every line in the bank statement and compute the global commission | 195 | # Record every line in the bank statement and compute the global commission |
3218 | 178 | # based on the commission_amount column | 196 | # based on the commission_amount column |
3219 | 197 | statement_store = [] | ||
3220 | 179 | for line in result_row_list: | 198 | for line in result_row_list: |
3221 | 180 | parser_vals = parser.get_st_line_vals(line) | 199 | parser_vals = parser.get_st_line_vals(line) |
3226 | 181 | values = self.prepare_statetement_lines_vals(cursor, uid, parser_vals, account_payable, | 200 | values = self.prepare_statetement_lines_vals(cr, uid, parser_vals, account_payable, |
3227 | 182 | account_receivable, statement_id, context) | 201 | account_receivable, statement_id, context) |
3228 | 183 | # we finally create the line in system | 202 | statement_store.append(values) |
3229 | 184 | statement_line_obj.create(cursor, uid, values, context=context) | 203 | # Hack to bypass ORM poor perfomance. Sob... |
3230 | 204 | statement_line_obj._insert_lines(cr, uid, statement_store, context=context) | ||
3231 | 205 | |||
3232 | 185 | # Build and create the global commission line for the whole statement | 206 | # Build and create the global commission line for the whole statement |
3234 | 186 | comm_vals = self.prepare_global_commission_line_vals(cursor, uid, parser, result_row_list, prof, statement_id, context) | 207 | comm_vals = self.prepare_global_commission_line_vals(cr, uid, parser, result_row_list, |
3235 | 208 | prof, statement_id, context) | ||
3236 | 187 | if comm_vals: | 209 | if comm_vals: |
3253 | 188 | res = statement_line_obj.create(cursor, uid, comm_vals,context=context) | 210 | statement_line_obj.create(cr, uid, comm_vals, context=context) |
3254 | 189 | 211 | else: | |
3255 | 190 | attachment_obj.create( | 212 | # Trigger store field computation if someone has better idea |
3256 | 191 | cursor, | 213 | start_bal = statement_obj.read(cr, uid, statement_id, |
3257 | 192 | uid, | 214 | ['balance_start'], |
3258 | 193 | { | 215 | context=context) |
3259 | 194 | 'name': 'statement file', | 216 | start_bal = start_bal['balance_start'] |
3260 | 195 | 'datas': file_stream, | 217 | statement_obj.write(cr, uid, [statement_id], |
3261 | 196 | 'datas_fname': "%s.%s"%(datetime.datetime.now().date(), | 218 | {'balance_start': start_bal}) |
3262 | 197 | ftype), | 219 | |
3263 | 198 | 'res_model': 'account.bank.statement', | 220 | attachment_obj.create(cr, |
3264 | 199 | 'res_id': statement_id, | 221 | uid, |
3265 | 200 | }, | 222 | {'name': 'statement file', |
3266 | 201 | context=context | 223 | 'datas': file_stream, |
3267 | 202 | ) | 224 | 'datas_fname': "%s.%s" % ( |
3268 | 203 | # If user ask to launch completion at end of import, do it ! | 225 | datetime.datetime.now().date(), |
3269 | 226 | ftype), | ||
3270 | 227 | 'res_model': 'account.bank.statement', | ||
3271 | 228 | 'res_id': statement_id}, | ||
3272 | 229 | context=context) | ||
3273 | 230 | |||
3274 | 231 | # If user ask to launch completion at end of import, do it! | ||
3275 | 204 | if prof.launch_import_completion: | 232 | if prof.launch_import_completion: |
3278 | 205 | statement_obj.button_auto_completion(cursor, uid, [statement_id], context) | 233 | statement_obj.button_auto_completion(cr, uid, [statement_id], context) |
3279 | 206 | 234 | ||
3280 | 207 | # Write the needed log infos on profile | 235 | # Write the needed log infos on profile |
3286 | 208 | self.write_logs_after_import(cursor, uid, prof.id, statement_id, | 236 | self.write_logs_after_import(cr, uid, prof.id, |
3287 | 209 | len(result_row_list), context) | 237 | statement_id, |
3288 | 210 | 238 | len(result_row_list), | |
3289 | 211 | except Exception, exc: | 239 | context) |
3290 | 212 | statement_obj.unlink(cursor, uid, [statement_id]) | 240 | |
3291 | 241 | except Exception: | ||
3292 | 242 | statement_obj.unlink(cr, uid, [statement_id], context=context) | ||
3293 | 213 | error_type, error_value, trbk = sys.exc_info() | 243 | error_type, error_value, trbk = sys.exc_info() |
3294 | 214 | st = "Error: %s\nDescription: %s\nTraceback:" % (error_type.__name__, error_value) | 244 | st = "Error: %s\nDescription: %s\nTraceback:" % (error_type.__name__, error_value) |
3295 | 215 | st += ''.join(traceback.format_tb(trbk, 30)) | 245 | st += ''.join(traceback.format_tb(trbk, 30)) |
3299 | 216 | raise osv.except_osv( | 246 | raise osv.except_osv(_("Statement import error"), |
3300 | 217 | _("Statement import error"), | 247 | _("The statement cannot be created: %s") % st) |
3298 | 218 | _("The statement cannot be created : %s") %(st)) | ||
3301 | 219 | return statement_id | 248 | return statement_id |
3302 | 220 | |||
3303 | 221 | 249 | ||
3304 | 222 | 250 | ||
3305 | 223 | class AccountStatementLine(Model): | 251 | class AccountStatementLine(Model): |
3306 | @@ -228,8 +256,48 @@ | |||
3307 | 228 | """ | 256 | """ |
3308 | 229 | _inherit = "account.bank.statement.line" | 257 | _inherit = "account.bank.statement.line" |
3309 | 230 | 258 | ||
3312 | 231 | _columns={ | 259 | def _get_available_columns(self, statement_store): |
3313 | 232 | 'commission_amount': fields.sparse(type='float', string='Line Commission Amount', | 260 | """Return writeable by SQL columns""" |
3314 | 261 | statement_line_obj = self.pool['account.bank.statement.line'] | ||
3315 | 262 | model_cols = statement_line_obj._columns | ||
3316 | 263 | avail = [k for k, col in model_cols.iteritems() if not hasattr(col, '_fnct')] | ||
3317 | 264 | keys = [k for k in statement_store[0].keys() if k in avail] | ||
3318 | 265 | keys.sort() | ||
3319 | 266 | return keys | ||
3320 | 267 | |||
3321 | 268 | def _insert_lines(self, cr, uid, statement_store, context=None): | ||
3322 | 269 | """ Do raw insert into database because ORM is awfully slow | ||
3323 | 270 | when doing batch write. It is a shame that batch function | ||
3324 | 271 | does not exist""" | ||
3325 | 272 | statement_line_obj = self.pool['account.bank.statement.line'] | ||
3326 | 273 | statement_line_obj.check_access_rule(cr, uid, [], 'create') | ||
3327 | 274 | statement_line_obj.check_access_rights(cr, uid, 'create', raise_exception=True) | ||
3328 | 275 | cols = self._get_available_columns(statement_store) | ||
3329 | 276 | tmp_vals = (', '.join(cols), ', '.join(['%%(%s)s' % i for i in cols])) | ||
3330 | 277 | sql = "INSERT INTO account_bank_statement_line (%s) VALUES (%s);" % tmp_vals | ||
3331 | 278 | try: | ||
3332 | 279 | cr.executemany(sql, tuple(statement_store)) | ||
3333 | 280 | except psycopg2.Error as sql_err: | ||
3334 | 281 | cr.rollback() | ||
3335 | 282 | raise osv.except_osv(_("ORM bypass error"), | ||
3336 | 283 | sql_err.pgerror) | ||
3337 | 284 | |||
3338 | 285 | def _update_line(self, cr, uid, vals, context=None): | ||
3339 | 286 | """ Do raw update into database because ORM is awfully slow | ||
3340 | 287 | when cheking security.""" | ||
3341 | 288 | cols = self._get_available_columns([vals]) | ||
3342 | 289 | tmp_vals = (', '.join(['%s = %%(%s)s' % (i, i) for i in cols])) | ||
3343 | 290 | sql = "UPDATE account_bank_statement_line SET %s where id = %%(id)s;" % tmp_vals | ||
3344 | 291 | try: | ||
3345 | 292 | cr.execute(sql, vals) | ||
3346 | 293 | except psycopg2.Error as sql_err: | ||
3347 | 294 | cr.rollback() | ||
3348 | 295 | raise osv.except_osv(_("ORM bypass error"), | ||
3349 | 296 | sql_err.pgerror) | ||
3350 | 297 | |||
3351 | 298 | _columns = { | ||
3352 | 299 | 'commission_amount': fields.sparse( | ||
3353 | 300 | type='float', | ||
3354 | 301 | string='Line Commission Amount', | ||
3355 | 233 | serialization_field='additionnal_bank_fields'), | 302 | serialization_field='additionnal_bank_fields'), |
3356 | 234 | |||
3357 | 235 | } | 303 | } |
3358 | 236 | 304 | ||
3359 | === modified file 'account_statement_base_import/statement_view.xml' | |||
3360 | --- account_statement_base_import/statement_view.xml 2012-08-02 12:46:12 +0000 | |||
3361 | +++ account_statement_base_import/statement_view.xml 2013-06-10 07:05:32 +0000 | |||
3362 | @@ -16,10 +16,12 @@ | |||
3363 | 16 | <field name="import_type"/> | 16 | <field name="import_type"/> |
3364 | 17 | <button name="%(account_statement_base_import.statement_importer_action)d" | 17 | <button name="%(account_statement_base_import.statement_importer_action)d" |
3365 | 18 | string="Import Bank Statement" | 18 | string="Import Bank Statement" |
3367 | 19 | type="action" icon="gtk-ok" | 19 | type="action" icon="gtk-ok" |
3368 | 20 | colspan = "2"/> | 20 | colspan = "2"/> |
3371 | 21 | <separator colspan="4" string="Import Logs"/> | 21 | <group attrs="{'invisible': [('rec_log', '=', False)]}"> |
3372 | 22 | <field name="rec_log" colspan="4" nolabel="1"/> | 22 | <separator colspan="4" string="Historical Import Logs"/> |
3373 | 23 | <field name="rec_log" colspan="4" nolabel="1" /> | ||
3374 | 24 | </group> | ||
3375 | 23 | </field> | 25 | </field> |
3376 | 24 | </field> | 26 | </field> |
3377 | 25 | </record> | 27 | </record> |
3378 | @@ -32,13 +34,13 @@ | |||
3379 | 32 | <field eval="20" name="priority"/> | 34 | <field eval="20" name="priority"/> |
3380 | 33 | <field name="arch" type="xml"> | 35 | <field name="arch" type="xml"> |
3381 | 34 | <data> | 36 | <data> |
3383 | 35 | <xpath expr="/form/notebook/page/field[@name='line_ids']/form/field[@name='label']" position="after"> | 37 | <xpath expr="/form/sheet/notebook/page/field[@name='line_ids']/form/group/field[@name='label']" position="after"> |
3384 | 36 | <field name="commission_amount" /> | 38 | <field name="commission_amount" /> |
3385 | 37 | </xpath> | 39 | </xpath> |
3386 | 38 | </data> | 40 | </data> |
3387 | 39 | </field> | 41 | </field> |
3388 | 40 | </record> | 42 | </record> |
3389 | 41 | 43 | ||
3391 | 42 | 44 | ||
3392 | 43 | </data> | 45 | </data> |
3393 | 44 | </openerp> | 46 | </openerp> |
3394 | 45 | 47 | ||
3395 | === modified file 'account_statement_base_import/wizard/import_statement.py' | |||
3396 | --- account_statement_base_import/wizard/import_statement.py 2012-11-27 10:51:47 +0000 | |||
3397 | +++ account_statement_base_import/wizard/import_statement.py 2013-06-10 07:05:32 +0000 | |||
3398 | @@ -23,15 +23,18 @@ | |||
3399 | 23 | Wizard to import financial institute date in bank statement | 23 | Wizard to import financial institute date in bank statement |
3400 | 24 | """ | 24 | """ |
3401 | 25 | 25 | ||
3404 | 26 | from osv import fields, osv | 26 | from openerp.osv import orm, fields |
3405 | 27 | from tools.translate import _ | 27 | |
3406 | 28 | from openerp.tools.translate import _ | ||
3407 | 28 | import os | 29 | import os |
3408 | 29 | 30 | ||
3410 | 30 | class CreditPartnerStatementImporter(osv.osv_memory): | 31 | |
3411 | 32 | class CreditPartnerStatementImporter(orm.TransientModel): | ||
3412 | 31 | _name = "credit.statement.import" | 33 | _name = "credit.statement.import" |
3414 | 32 | 34 | ||
3415 | 33 | def default_get(self, cr, uid, fields, context=None): | 35 | def default_get(self, cr, uid, fields, context=None): |
3417 | 34 | if context is None: context = {} | 36 | if context is None: |
3418 | 37 | context = {} | ||
3419 | 35 | res = {} | 38 | res = {} |
3420 | 36 | if (context.get('active_model', False) == 'account.statement.profile' and | 39 | if (context.get('active_model', False) == 'account.statement.profile' and |
3421 | 37 | context.get('active_ids', False)): | 40 | context.get('active_ids', False)): |
3422 | @@ -39,80 +42,81 @@ | |||
3423 | 39 | assert len(ids) == 1, 'You cannot use this on more than one profile !' | 42 | assert len(ids) == 1, 'You cannot use this on more than one profile !' |
3424 | 40 | res['profile_id'] = ids[0] | 43 | res['profile_id'] = ids[0] |
3425 | 41 | other_vals = self.onchange_profile_id(cr, uid, [], res['profile_id'], context=context) | 44 | other_vals = self.onchange_profile_id(cr, uid, [], res['profile_id'], context=context) |
3427 | 42 | res.update(other_vals.get('value',{})) | 45 | res.update(other_vals.get('value', {})) |
3428 | 43 | return res | 46 | return res |
3430 | 44 | 47 | ||
3431 | 45 | _columns = { | 48 | _columns = { |
3432 | 46 | 'profile_id': fields.many2one('account.statement.profile', | 49 | 'profile_id': fields.many2one('account.statement.profile', |
3433 | 47 | 'Import configuration parameter', | 50 | 'Import configuration parameter', |
3434 | 48 | required=True), | 51 | required=True), |
3435 | 49 | 'input_statement': fields.binary('Statement file', required=True), | 52 | 'input_statement': fields.binary('Statement file', required=True), |
3436 | 50 | 'partner_id': fields.many2one('res.partner', | 53 | 'partner_id': fields.many2one('res.partner', |
3439 | 51 | 'Credit insitute partner', | 54 | 'Credit insitute partner'), |
3438 | 52 | ), | ||
3440 | 53 | 'journal_id': fields.many2one('account.journal', | 55 | 'journal_id': fields.many2one('account.journal', |
3444 | 54 | 'Financial journal to use transaction', | 56 | 'Financial journal to use transaction'), |
3442 | 55 | ), | ||
3443 | 56 | 'input_statement': fields.binary('Statement file', required=True), | ||
3445 | 57 | 'file_name': fields.char('File Name', size=128), | 57 | 'file_name': fields.char('File Name', size=128), |
3446 | 58 | 'commission_account_id': fields.many2one('account.account', | 58 | 'commission_account_id': fields.many2one('account.account', |
3449 | 59 | 'Commission account', | 59 | 'Commission account'), |
3448 | 60 | ), | ||
3450 | 61 | 'commission_analytic_id': fields.many2one('account.analytic.account', | 60 | 'commission_analytic_id': fields.many2one('account.analytic.account', |
3453 | 62 | 'Commission analytic account', | 61 | 'Commission analytic account'), |
3452 | 63 | ), | ||
3454 | 64 | 'receivable_account_id': fields.many2one('account.account', | 62 | 'receivable_account_id': fields.many2one('account.account', |
3455 | 65 | 'Force Receivable/Payable Account'), | 63 | 'Force Receivable/Payable Account'), |
3466 | 66 | 'force_partner_on_bank': fields.boolean('Force partner on bank move', | 64 | 'force_partner_on_bank': fields.boolean( |
3467 | 67 | help="Tic that box if you want to use the credit insitute partner\ | 65 | 'Force partner on bank move', |
3468 | 68 | in the counterpart of the treasury/banking move." | 66 | help="Tic that box if you want to use the credit insitute partner " |
3469 | 69 | ), | 67 | "in the counterpart of the treasury/banking move."), |
3470 | 70 | 'balance_check': fields.boolean('Balance check', | 68 | 'balance_check': fields.boolean( |
3471 | 71 | help="Tic that box if you want OpenERP to control the start/end balance\ | 69 | 'Balance check', |
3472 | 72 | before confirming a bank statement. If don't ticked, no balance control will be done." | 70 | help="Tic that box if you want OpenERP to control the " |
3473 | 73 | ), | 71 | "start/end balance before confirming a bank statement. " |
3474 | 74 | } | 72 | "If don't ticked, no balance control will be done."), |
3475 | 75 | 73 | } | |
3476 | 74 | |||
3477 | 76 | def onchange_profile_id(self, cr, uid, ids, profile_id, context=None): | 75 | def onchange_profile_id(self, cr, uid, ids, profile_id, context=None): |
3479 | 77 | res={} | 76 | res = {} |
3480 | 78 | if profile_id: | 77 | if profile_id: |
3489 | 79 | c = self.pool.get("account.statement.profile").browse(cr,uid,profile_id) | 78 | c = self.pool.get("account.statement.profile").browse( |
3490 | 80 | res = {'value': {'partner_id': c.partner_id and c.partner_id.id or False, | 79 | cr, uid, profile_id, context=context) |
3491 | 81 | 'journal_id': c.journal_id and c.journal_id.id or False, 'commission_account_id': \ | 80 | res = {'value': |
3492 | 82 | c.commission_account_id and c.commission_account_id.id or False, | 81 | {'partner_id': c.partner_id and c.partner_id.id or False, |
3493 | 83 | 'receivable_account_id': c.receivable_account_id and c.receivable_account_id.id or False, | 82 | 'journal_id': c.journal_id and c.journal_id.id or False, |
3494 | 84 | 'commission_a':c.commission_analytic_id and c.commission_analytic_id.id or False, | 83 | 'commission_account_id': |
3495 | 85 | 'force_partner_on_bank':c.force_partner_on_bank, | 84 | c.commission_account_id and c.commission_account_id.id or False, |
3496 | 86 | 'balance_check':c.balance_check,}} | 85 | 'receivable_account_id': c.receivable_account_id and c.receivable_account_id.id or False, |
3497 | 86 | 'commission_a': c.commission_analytic_id and c.commission_analytic_id.id or False, | ||
3498 | 87 | 'force_partner_on_bank': c.force_partner_on_bank, | ||
3499 | 88 | 'balance_check': c.balance_check, | ||
3500 | 89 | } | ||
3501 | 90 | } | ||
3502 | 87 | return res | 91 | return res |
3503 | 88 | 92 | ||
3504 | 89 | def _check_extension(self, filename): | 93 | def _check_extension(self, filename): |
3506 | 90 | (shortname, ftype) = os.path.splitext(filename) | 94 | (__, ftype) = os.path.splitext(filename) |
3507 | 91 | if not ftype: | 95 | if not ftype: |
3508 | 92 | #We do not use osv exception we do not want to have it logged | 96 | #We do not use osv exception we do not want to have it logged |
3509 | 93 | raise Exception(_('Please use a file with an extention')) | 97 | raise Exception(_('Please use a file with an extention')) |
3510 | 94 | return ftype | 98 | return ftype |
3511 | 95 | 99 | ||
3513 | 96 | def import_statement(self, cursor, uid, req_id, context=None): | 100 | def import_statement(self, cr, uid, req_id, context=None): |
3514 | 97 | """This Function import credit card agency statement""" | 101 | """This Function import credit card agency statement""" |
3515 | 98 | context = context or {} | 102 | context = context or {} |
3516 | 99 | if isinstance(req_id, list): | 103 | if isinstance(req_id, list): |
3517 | 100 | req_id = req_id[0] | 104 | req_id = req_id[0] |
3519 | 101 | importer = self.browse(cursor, uid, req_id, context) | 105 | importer = self.browse(cr, uid, req_id, context) |
3520 | 102 | ftype = self._check_extension(importer.file_name) | 106 | ftype = self._check_extension(importer.file_name) |
3521 | 103 | sid = self.pool.get( | 107 | sid = self.pool.get( |
3522 | 104 | 'account.statement.profile').statement_import( | 108 | 'account.statement.profile').statement_import( |
3524 | 105 | cursor, | 109 | cr, |
3525 | 106 | uid, | 110 | uid, |
3526 | 107 | False, | 111 | False, |
3527 | 108 | importer.profile_id.id, | 112 | importer.profile_id.id, |
3528 | 109 | importer.input_statement, | 113 | importer.input_statement, |
3530 | 110 | ftype.replace('.',''), | 114 | ftype.replace('.', ''), |
3531 | 111 | context=context | 115 | context=context |
3532 | 112 | ) | 116 | ) |
3533 | 113 | model_obj = self.pool.get('ir.model.data') | 117 | model_obj = self.pool.get('ir.model.data') |
3534 | 114 | action_obj = self.pool.get('ir.actions.act_window') | 118 | action_obj = self.pool.get('ir.actions.act_window') |
3537 | 115 | action_id = model_obj.get_object_reference(cursor, uid, 'account', 'action_bank_statement_tree')[1] | 119 | action_id = model_obj.get_object_reference(cr, uid, 'account', 'action_bank_statement_tree')[1] |
3538 | 116 | res = action_obj.read(cursor, uid, action_id) | 120 | res = action_obj.read(cr, uid, action_id) |
3539 | 117 | res['domain'] = res['domain'][:-1] + ",('id', '=', %d)]" % sid | 121 | res['domain'] = res['domain'][:-1] + ",('id', '=', %d)]" % sid |
3540 | 118 | return res | 122 | return res |
3541 | 119 | 123 | ||
3542 | === modified file 'account_statement_completion_voucher/__init__.py' | |||
3543 | --- account_statement_completion_voucher/__init__.py 2012-06-27 07:58:32 +0000 | |||
3544 | +++ account_statement_completion_voucher/__init__.py 2013-06-10 07:05:32 +0000 | |||
3545 | @@ -18,4 +18,3 @@ | |||
3546 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
3547 | 19 | # | 19 | # |
3548 | 20 | ############################################################################## | 20 | ############################################################################## |
3549 | 21 | |||
3550 | 22 | 21 | ||
3551 | === modified file 'account_statement_completion_voucher/__openerp__.py' | |||
3552 | --- account_statement_completion_voucher/__openerp__.py 2012-06-27 07:58:32 +0000 | |||
3553 | +++ account_statement_completion_voucher/__openerp__.py 2013-06-10 07:05:32 +0000 | |||
3554 | @@ -24,8 +24,11 @@ | |||
3555 | 24 | 'author': 'Camptocamp', | 24 | 'author': 'Camptocamp', |
3556 | 25 | 'maintainer': 'Camptocamp', | 25 | 'maintainer': 'Camptocamp', |
3557 | 26 | 'category': 'Finance', | 26 | 'category': 'Finance', |
3560 | 27 | 'complexity': 'normal', #easy, normal, expert | 27 | 'complexity': 'normal', |
3561 | 28 | 'depends': ['account_statement_base_completion','account_voucher'], | 28 | 'depends': [ |
3562 | 29 | 'account_statement_base_completion', | ||
3563 | 30 | 'account_voucher' | ||
3564 | 31 | ], | ||
3565 | 29 | 'description': """ | 32 | 'description': """ |
3566 | 30 | This module is only needed when using account_statement_base_completion with voucher in order adapt the view correctly. | 33 | This module is only needed when using account_statement_base_completion with voucher in order adapt the view correctly. |
3567 | 31 | """, | 34 | """, |
3568 | @@ -36,9 +39,8 @@ | |||
3569 | 36 | ], | 39 | ], |
3570 | 37 | 'demo_xml': [], | 40 | 'demo_xml': [], |
3571 | 38 | 'test': [], | 41 | 'test': [], |
3573 | 39 | 'installable': True, | 42 | 'installable': False, |
3574 | 40 | 'images': [], | 43 | 'images': [], |
3576 | 41 | 'auto_install': True, | 44 | 'auto_install': False, |
3577 | 42 | 'license': 'AGPL-3', | 45 | 'license': 'AGPL-3', |
3578 | 43 | 'active': False, | ||
3579 | 44 | } | 46 | } |
3580 | 45 | 47 | ||
3581 | === modified file 'account_statement_completion_voucher/statement_view.xml' | |||
3582 | --- account_statement_completion_voucher/statement_view.xml 2012-06-27 07:58:32 +0000 | |||
3583 | +++ account_statement_completion_voucher/statement_view.xml 2013-06-10 07:05:32 +0000 | |||
3584 | @@ -3,19 +3,19 @@ | |||
3585 | 3 | <data> | 3 | <data> |
3586 | 4 | 4 | ||
3587 | 5 | <!-- Override what we have in account_statement_base_completion to replace the one in the voucher --> | 5 | <!-- Override what we have in account_statement_base_completion to replace the one in the voucher --> |
3589 | 6 | <record id="account_statement_base_completion.bank_statement_view_form2" model="ir.ui.view"> | 6 | <!-- <record id="account_statement_base_completion.bank_statement_view_form2" model="ir.ui.view"> |
3590 | 7 | <field name="name">account_bank_statement_import_base.bank_statement.auto_cmpl</field> | 7 | <field name="name">account_bank_statement_import_base.bank_statement.auto_cmpl</field> |
3591 | 8 | <field name="model">account.bank.statement</field> | 8 | <field name="model">account.bank.statement</field> |
3592 | 9 | <field name="inherit_id" ref="account_voucher.view_bank_statement_tree_voucher" /> | 9 | <field name="inherit_id" ref="account_voucher.view_bank_statement_tree_voucher" /> |
3593 | 10 | <field name="type">form</field> | 10 | <field name="type">form</field> |
3594 | 11 | <field name="arch" type="xml"> | 11 | <field name="arch" type="xml"> |
3595 | 12 | <data> | 12 | <data> |
3597 | 13 | <xpath expr="/form/notebook/page/field[@name='line_ids']/tree/field[@name='voucher_id']" position="after"> | 13 | <xpath expr="/form/sheet/notebook/page/field[@name='line_ids']/tree/field[@name='voucher_id']" position="after"> |
3598 | 14 | <field name="already_completed" /> | 14 | <field name="already_completed" /> |
3599 | 15 | </xpath> | 15 | </xpath> |
3600 | 16 | </data> | 16 | </data> |
3601 | 17 | </field> | 17 | </field> |
3603 | 18 | </record> | 18 | </record> --> |
3604 | 19 | 19 | ||
3605 | 20 | </data> | 20 | </data> |
3606 | 21 | </openerp> | 21 | </openerp> |
3607 | 22 | 22 | ||
3608 | === modified file 'account_statement_ext/__init__.py' | |||
3609 | --- account_statement_ext/__init__.py 2012-06-20 14:10:01 +0000 | |||
3610 | +++ account_statement_ext/__init__.py 2013-06-10 07:05:32 +0000 | |||
3611 | @@ -21,4 +21,5 @@ | |||
3612 | 21 | 21 | ||
3613 | 22 | import statement | 22 | import statement |
3614 | 23 | import report | 23 | import report |
3615 | 24 | import account | ||
3616 | 25 | \ No newline at end of file | 24 | \ No newline at end of file |
3617 | 25 | import account | ||
3618 | 26 | import voucher | ||
3619 | 26 | \ No newline at end of file | 27 | \ No newline at end of file |
3620 | 27 | 28 | ||
3621 | === modified file 'account_statement_ext/__openerp__.py' | |||
3622 | --- account_statement_ext/__openerp__.py 2013-05-15 21:12:19 +0000 | |||
3623 | +++ account_statement_ext/__openerp__.py 2013-06-10 07:05:32 +0000 | |||
3624 | @@ -2,7 +2,7 @@ | |||
3625 | 2 | ############################################################################## | 2 | ############################################################################## |
3626 | 3 | # | 3 | # |
3627 | 4 | # Author: Nicolas Bessi, Joel Grand-Guillaume | 4 | # Author: Nicolas Bessi, Joel Grand-Guillaume |
3629 | 5 | # Copyright 2011-2012 Camptocamp SA | 5 | # Copyright 2011-2013 Camptocamp SA |
3630 | 6 | # | 6 | # |
3631 | 7 | # This program is free software: you can redistribute it and/or modify | 7 | # This program is free software: you can redistribute it and/or modify |
3632 | 8 | # it under the terms of the GNU Affero General Public License as | 8 | # it under the terms of the GNU Affero General Public License as |
3633 | @@ -20,12 +20,19 @@ | |||
3634 | 20 | ############################################################################## | 20 | ############################################################################## |
3635 | 21 | 21 | ||
3636 | 22 | {'name': "Bank statement extension and profiles", | 22 | {'name': "Bank statement extension and profiles", |
3638 | 23 | 'version': '1.1', | 23 | 'version': '1.3.0', |
3639 | 24 | 'author': 'Camptocamp', | 24 | 'author': 'Camptocamp', |
3640 | 25 | 'maintainer': 'Camptocamp', | 25 | 'maintainer': 'Camptocamp', |
3641 | 26 | 'category': 'Finance', | 26 | 'category': 'Finance', |
3642 | 27 | <<<<<<< TREE | ||
3643 | 27 | 'complexity': 'normal', #easy, normal, expert | 28 | 'complexity': 'normal', #easy, normal, expert |
3644 | 28 | 'depends': ['account','report_webkit'], | 29 | 'depends': ['account','report_webkit'], |
3645 | 30 | ======= | ||
3646 | 31 | 'complexity': 'normal', | ||
3647 | 32 | 'depends': ['account', | ||
3648 | 33 | 'report_webkit', | ||
3649 | 34 | 'account_voucher'], | ||
3650 | 35 | >>>>>>> MERGE-SOURCE | ||
3651 | 29 | 'description': """ | 36 | 'description': """ |
3652 | 30 | Improve the basic bank statement, by adding various new features, | 37 | Improve the basic bank statement, by adding various new features, |
3653 | 31 | and help dealing with huge volume of reconciliation through payment offices such as Paypal, Lazer, | 38 | and help dealing with huge volume of reconciliation through payment offices such as Paypal, Lazer, |
3654 | @@ -59,6 +66,7 @@ | |||
3655 | 59 | all the erronous line in a same popup instead of raising and crashing on every step. | 66 | all the erronous line in a same popup instead of raising and crashing on every step. |
3656 | 60 | 67 | ||
3657 | 61 | 4) Remove the period on the bank statement, and compute it for each line based on their date instead. | 68 | 4) Remove the period on the bank statement, and compute it for each line based on their date instead. |
3658 | 69 | It also adds this feature in the voucher in order to compute the period correctly. | ||
3659 | 62 | 70 | ||
3660 | 63 | 5) Cancelling a bank statement is much more easy and will cancel all related entries, unreconcile them, | 71 | 5) Cancelling a bank statement is much more easy and will cancel all related entries, unreconcile them, |
3661 | 64 | and finally delete them. | 72 | and finally delete them. |
3662 | @@ -70,13 +78,11 @@ | |||
3663 | 70 | 78 | ||
3664 | 71 | """, | 79 | """, |
3665 | 72 | 'website': 'http://www.camptocamp.com', | 80 | 'website': 'http://www.camptocamp.com', |
3673 | 73 | 'init_xml': [], | 81 | 'data': ['statement_view.xml', |
3674 | 74 | 'update_xml': [ | 82 | 'report/bank_statement_webkit_header.xml', |
3675 | 75 | 'statement_view.xml', | 83 | 'report.xml', |
3676 | 76 | 'report/bank_statement_webkit_header.xml', | 84 | 'security/ir.model.access.csv', |
3677 | 77 | 'report.xml', | 85 | 'security/ir_rule.xml'], |
3671 | 78 | 'security/ir.model.access.csv', | ||
3672 | 79 | ], | ||
3678 | 80 | 'demo_xml': [], | 86 | 'demo_xml': [], |
3679 | 81 | 'test': [], | 87 | 'test': [], |
3680 | 82 | 'installable': True, | 88 | 'installable': True, |
3681 | @@ -84,4 +90,4 @@ | |||
3682 | 84 | 'auto_install': False, | 90 | 'auto_install': False, |
3683 | 85 | 'license': 'AGPL-3', | 91 | 'license': 'AGPL-3', |
3684 | 86 | 'active': False, | 92 | 'active': False, |
3686 | 87 | } | 93 | } |
3687 | 88 | 94 | ||
3688 | === modified file 'account_statement_ext/account.py' | |||
3689 | --- account_statement_ext/account.py 2012-06-20 14:10:01 +0000 | |||
3690 | +++ account_statement_ext/account.py 2013-06-10 07:05:32 +0000 | |||
3691 | @@ -18,13 +18,14 @@ | |||
3692 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
3693 | 19 | # | 19 | # |
3694 | 20 | ############################################################################## | 20 | ############################################################################## |
3698 | 21 | import netsvc | 21 | |
3699 | 22 | logger = netsvc.Logger() | 22 | from openerp.osv.orm import Model |
3700 | 23 | from openerp.osv.orm import Model, fields | 23 | from openerp.osv import fields |
3701 | 24 | |||
3702 | 24 | 25 | ||
3703 | 25 | class account_move(Model): | 26 | class account_move(Model): |
3706 | 26 | _inherit='account.move' | 27 | _inherit = 'account.move' |
3707 | 27 | 28 | ||
3708 | 28 | def unlink(self, cr, uid, ids, context=None): | 29 | def unlink(self, cr, uid, ids, context=None): |
3709 | 29 | """ | 30 | """ |
3710 | 30 | Delete the reconciliation when we delete the moves. This | 31 | Delete the reconciliation when we delete the moves. This |
3711 | @@ -35,6 +36,3 @@ | |||
3712 | 35 | if move_line.reconcile_id: | 36 | if move_line.reconcile_id: |
3713 | 36 | move_line.reconcile_id.unlink(context=context) | 37 | move_line.reconcile_id.unlink(context=context) |
3714 | 37 | return super(account_move, self).unlink(cr, uid, ids, context=context) | 38 | return super(account_move, self).unlink(cr, uid, ids, context=context) |
3715 | 38 | |||
3716 | 39 | |||
3717 | 40 | |||
3718 | 41 | 39 | ||
3719 | === modified file 'account_statement_ext/i18n/fr.po' | |||
3720 | --- account_statement_ext/i18n/fr.po 2012-12-13 13:57:29 +0000 | |||
3721 | +++ account_statement_ext/i18n/fr.po 2013-06-10 07:05:32 +0000 | |||
3722 | @@ -41,7 +41,7 @@ | |||
3723 | 41 | #. module: account_statement_ext | 41 | #. module: account_statement_ext |
3724 | 42 | #: code:addons/account_statement_ext/statement.py:361 | 42 | #: code:addons/account_statement_ext/statement.py:361 |
3725 | 43 | #, python-format | 43 | #, python-format |
3727 | 44 | msgid "Configuration Error !" | 44 | msgid "Configuration Error!" |
3728 | 45 | msgstr "Erreur de configuration !" | 45 | msgstr "Erreur de configuration !" |
3729 | 46 | 46 | ||
3730 | 47 | #. module: account_statement_ext | 47 | #. module: account_statement_ext |
3731 | @@ -64,7 +64,7 @@ | |||
3732 | 64 | #: code:addons/account_statement_ext/statement.py:307 | 64 | #: code:addons/account_statement_ext/statement.py:307 |
3733 | 65 | #: code:addons/account_statement_ext/statement.py:372 | 65 | #: code:addons/account_statement_ext/statement.py:372 |
3734 | 66 | #, python-format | 66 | #, python-format |
3736 | 67 | msgid "Error !" | 67 | msgid "Error!" |
3737 | 68 | msgstr "Erreur !" | 68 | msgstr "Erreur !" |
3738 | 69 | 69 | ||
3739 | 70 | #. module: account_statement_ext | 70 | #. module: account_statement_ext |
3740 | 71 | 71 | ||
3741 | === modified file 'account_statement_ext/report/__init__.py' | |||
3742 | --- account_statement_ext/report/__init__.py 2012-06-20 14:10:01 +0000 | |||
3743 | +++ account_statement_ext/report/__init__.py 2013-06-10 07:05:32 +0000 | |||
3744 | @@ -1,9 +1,4 @@ | |||
3751 | 1 | # -*- encoding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- |
3746 | 2 | # | ||
3747 | 3 | # __init__.py | ||
3748 | 4 | # | ||
3749 | 5 | # Copyright (c) 2009 CamptoCamp. All rights reserved. | ||
3750 | 6 | ############################################################################## | ||
3752 | 7 | # | 2 | # |
3753 | 8 | # WARNING: This program as such is intended to be used by professional | 3 | # WARNING: This program as such is intended to be used by professional |
3754 | 9 | # programmers who take the whole responsability of assessing all potential | 4 | # programmers who take the whole responsability of assessing all potential |
3755 | @@ -28,4 +23,4 @@ | |||
3756 | 28 | # | 23 | # |
3757 | 29 | ############################################################################## | 24 | ############################################################################## |
3758 | 30 | 25 | ||
3759 | 31 | import bank_statement_report | ||
3760 | 32 | \ No newline at end of file | 26 | \ No newline at end of file |
3761 | 27 | import bank_statement_report | ||
3762 | 33 | 28 | ||
3763 | === modified file 'account_statement_ext/report/bank_statement_report.py' | |||
3764 | --- account_statement_ext/report/bank_statement_report.py 2012-06-20 14:10:01 +0000 | |||
3765 | +++ account_statement_ext/report/bank_statement_report.py 2013-06-10 07:05:32 +0000 | |||
3766 | @@ -1,4 +1,4 @@ | |||
3768 | 1 | # -*- encoding: utf-8 -*- | 1 | # -*- coding utf-8 -*- |
3769 | 2 | ############################################################################## | 2 | ############################################################################## |
3770 | 3 | # | 3 | # |
3771 | 4 | # Author: Nicolas Bessi. Copyright Camptocamp SA | 4 | # Author: Nicolas Bessi. Copyright Camptocamp SA |
3772 | @@ -18,33 +18,29 @@ | |||
3773 | 18 | # | 18 | # |
3774 | 19 | ############################################################################## | 19 | ############################################################################## |
3775 | 20 | 20 | ||
3784 | 21 | import time | 21 | from openerp.report import report_sxw |
3785 | 22 | 22 | from openerp.tools.translate import _ | |
3786 | 23 | from report import report_sxw | 23 | from openerp import pooler |
3779 | 24 | from osv import osv | ||
3780 | 25 | from tools.translate import _ | ||
3781 | 26 | import pooler | ||
3782 | 27 | from operator import add, itemgetter | ||
3783 | 28 | from itertools import groupby | ||
3787 | 29 | from datetime import datetime | 24 | from datetime import datetime |
3788 | 30 | from report_webkit import webkit_report | 25 | from report_webkit import webkit_report |
3789 | 31 | 26 | ||
3790 | 27 | |||
3791 | 32 | class BankStatementWebkit(report_sxw.rml_parse): | 28 | class BankStatementWebkit(report_sxw.rml_parse): |
3792 | 33 | 29 | ||
3795 | 34 | def __init__(self, cursor, uid, name, context): | 30 | def __init__(self, cr, uid, name, context): |
3796 | 35 | super(BankStatementWebkit, self).__init__(cursor, uid, name, context=context) | 31 | super(BankStatementWebkit, self).__init__(cr, uid, name, context=context) |
3797 | 36 | self.pool = pooler.get_pool(self.cr.dbname) | 32 | self.pool = pooler.get_pool(self.cr.dbname) |
3798 | 37 | self.cursor = self.cr | 33 | self.cursor = self.cr |
3799 | 38 | 34 | ||
3801 | 39 | company = self.pool.get('res.users').browse(self.cr, uid, uid, context=context).company_id | 35 | company = self.pool.get('res.users').browse( |
3802 | 36 | self.cr, uid, uid, context=context).company_id | ||
3803 | 40 | header_report_name = ' - '.join((_('BORDEREAU DE REMISE DE CHEQUES'), | 37 | header_report_name = ' - '.join((_('BORDEREAU DE REMISE DE CHEQUES'), |
3804 | 41 | company.name, company.currency_id.name)) | 38 | company.name, company.currency_id.name)) |
3805 | 42 | statement = self.pool.get('account.bank.statement').browse(cursor,uid,context['active_id']); | ||
3806 | 43 | footer_date_time = self.formatLang(str(datetime.today())[:19], date_time=True) | 39 | footer_date_time = self.formatLang(str(datetime.today())[:19], date_time=True) |
3807 | 44 | self.localcontext.update({ | 40 | self.localcontext.update({ |
3809 | 45 | 'cr': cursor, | 41 | 'cr': cr, |
3810 | 46 | 'uid': uid, | 42 | 'uid': uid, |
3812 | 47 | 'get_bank_statement' : self._get_bank_statement_data, | 43 | 'get_bank_statement': self._get_bank_statement_data, |
3813 | 48 | 'report_name': _('BORDEREAU DE REMISE DE CHEQUES'), | 44 | 'report_name': _('BORDEREAU DE REMISE DE CHEQUES'), |
3814 | 49 | 'additional_args': [ | 45 | 'additional_args': [ |
3815 | 50 | ('--header-font-name', 'Helvetica'), | 46 | ('--header-font-name', 'Helvetica'), |
3816 | @@ -58,10 +54,15 @@ | |||
3817 | 58 | ('--footer-line',), | 54 | ('--footer-line',), |
3818 | 59 | ], | 55 | ], |
3819 | 60 | }) | 56 | }) |
3821 | 61 | def _get_bank_statement_data(self,statement): | 57 | |
3822 | 58 | def _get_bank_statement_data(self, statement): | ||
3823 | 62 | statement_obj = self.pool.get('account.bank.statement.line') | 59 | statement_obj = self.pool.get('account.bank.statement.line') |
3826 | 63 | statement_line_ids = statement_obj.search(self.cr,self.uid,[['statement_id','=',statement.id]]) | 60 | statement_line_ids = statement_obj.search( |
3827 | 64 | statement_lines = statement_obj.browse(self.cr,self.uid,statement_line_ids) | 61 | self.cr, |
3828 | 62 | self.uid, | ||
3829 | 63 | [('statement_id', '=', statement.id)]) | ||
3830 | 64 | statement_lines = statement_obj.browse( | ||
3831 | 65 | self.cr, self.uid, statement_line_ids) | ||
3832 | 65 | return statement_lines | 66 | return statement_lines |
3833 | 66 | 67 | ||
3834 | 67 | webkit_report.WebKitParser('report.bank_statement_webkit', | 68 | webkit_report.WebKitParser('report.bank_statement_webkit', |
3835 | 68 | 69 | ||
3836 | === modified file 'account_statement_ext/security/ir.model.access.csv' | |||
3837 | --- account_statement_ext/security/ir.model.access.csv 2012-09-20 08:37:42 +0000 | |||
3838 | +++ account_statement_ext/security/ir.model.access.csv 2013-06-10 07:05:32 +0000 | |||
3839 | @@ -1,3 +1,3 @@ | |||
3840 | 1 | id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | 1 | id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
3842 | 2 | access_account_bank_st_profile_user,account.statement.profile,model_account_statement_profile,account.group_account_user,1,0,0,0 | 2 | access_account_bank_st_profile_user,account.statement.profile,model_account_statement_profile,account.group_account_user,1,1,0,0 |
3843 | 3 | access_account_bank_st_profile_manager,account.statement.profile,model_account_statement_profile,account.group_account_manager,1,1,1,1 | 3 | access_account_bank_st_profile_manager,account.statement.profile,model_account_statement_profile,account.group_account_manager,1,1,1,1 |
3844 | 4 | 4 | ||
3845 | === added file 'account_statement_ext/security/ir_rule.xml' | |||
3846 | --- account_statement_ext/security/ir_rule.xml 1970-01-01 00:00:00 +0000 | |||
3847 | +++ account_statement_ext/security/ir_rule.xml 2013-06-10 07:05:32 +0000 | |||
3848 | @@ -0,0 +1,10 @@ | |||
3849 | 1 | <openerp> | ||
3850 | 2 | <data noupdate="1"> | ||
3851 | 3 | <record id="account_bank_statement_profile_rule" model="ir.rule"> | ||
3852 | 4 | <field name="name">Bank statement profile multi-company</field> | ||
3853 | 5 | <field name="model_id" ref="model_account_statement_profile"/> | ||
3854 | 6 | <field name="global" eval="True"/> | ||
3855 | 7 | <field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> | ||
3856 | 8 | </record> | ||
3857 | 9 | </data> | ||
3858 | 10 | </openerp> | ||
3859 | 0 | \ No newline at end of file | 11 | \ No newline at end of file |
3860 | 1 | 12 | ||
3861 | === modified file 'account_statement_ext/statement.py' | |||
3862 | --- account_statement_ext/statement.py 2013-04-04 11:14:03 +0000 | |||
3863 | +++ account_statement_ext/statement.py 2013-06-10 07:05:32 +0000 | |||
3864 | @@ -18,13 +18,25 @@ | |||
3865 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
3866 | 19 | # | 19 | # |
3867 | 20 | ############################################################################## | 20 | ############################################################################## |
3874 | 21 | 21 | import openerp.addons.account.account_bank_statement as stat_mod | |
3875 | 22 | from tools.translate import _ | 22 | from openerp.osv.orm import Model |
3870 | 23 | import datetime | ||
3871 | 24 | import netsvc | ||
3872 | 25 | logger = netsvc.Logger() | ||
3873 | 26 | from openerp.osv.orm import Model, fields | ||
3876 | 27 | from openerp.osv import fields, osv | 23 | from openerp.osv import fields, osv |
3877 | 24 | from openerp.tools.translate import _ | ||
3878 | 25 | |||
3879 | 26 | |||
3880 | 27 | # Monkey patch to fix bad write implementation... | ||
3881 | 28 | def fixed_write(self, cr, uid, ids, vals, context=None): | ||
3882 | 29 | """ Fix performance desing of original function | ||
3883 | 30 | Ideally we should use a real PostgreSQL sequence or serial fields. | ||
3884 | 31 | I will do it when I have time.""" | ||
3885 | 32 | res = super(stat_mod.account_bank_statement, self).write(cr, uid, ids, | ||
3886 | 33 | vals, context=context) | ||
3887 | 34 | cr.execute("UPDATE account_bank_statement_line" | ||
3888 | 35 | " SET sequence = account_bank_statement_line.id + 1" | ||
3889 | 36 | " where statement_id in %s", (tuple(ids),)) | ||
3890 | 37 | return res | ||
3891 | 38 | stat_mod.account_bank_statement.write = fixed_write | ||
3892 | 39 | |||
3893 | 28 | 40 | ||
3894 | 29 | class AccountStatementProfil(Model): | 41 | class AccountStatementProfil(Model): |
3895 | 30 | """ | 42 | """ |
3896 | @@ -33,38 +45,55 @@ | |||
3897 | 33 | journal to use, the partner and commision account and so on. | 45 | journal to use, the partner and commision account and so on. |
3898 | 34 | """ | 46 | """ |
3899 | 35 | _name = "account.statement.profile" | 47 | _name = "account.statement.profile" |
3900 | 48 | _inherit = ['mail.thread'] | ||
3901 | 49 | |||
3902 | 36 | _description = "Statement Profil" | 50 | _description = "Statement Profil" |
3904 | 37 | 51 | ||
3905 | 38 | _columns = { | 52 | _columns = { |
3934 | 39 | 'name': fields.char('Name', size=128, required=True), | 53 | 'name': fields.char('Name', required=True), |
3935 | 40 | 'partner_id': fields.many2one('res.partner', | 54 | 'partner_id': fields.many2one( |
3936 | 41 | 'Bank/Payment Office partner', | 55 | 'res.partner', |
3937 | 42 | help="Put a partner if you want to have it on the commission move \ | 56 | 'Bank/Payment Office partner', |
3938 | 43 | (and optionaly on the counterpart of the intermediate/banking move \ | 57 | help="Put a partner if you want to have it on the " |
3939 | 44 | if you tic the corresponding checkbox)."), | 58 | "commission move (and optionaly on the counterpart " |
3940 | 45 | 'journal_id': fields.many2one('account.journal', | 59 | "of the intermediate/banking move if you tick the " |
3941 | 46 | 'Financial journal to use for transaction', | 60 | "corresponding checkbox)."), |
3942 | 47 | required=True), | 61 | |
3943 | 48 | 'commission_account_id': fields.many2one('account.account', | 62 | 'journal_id': fields.many2one( |
3944 | 49 | 'Commission account', | 63 | 'account.journal', |
3945 | 50 | required=True), | 64 | 'Financial journal to use for transaction', |
3946 | 51 | 'commission_analytic_id': fields.many2one('account.analytic.account', | 65 | required=True), |
3947 | 52 | 'Commission analytic account'), | 66 | |
3948 | 53 | 'receivable_account_id': fields.many2one('account.account', | 67 | 'commission_account_id': fields.many2one( |
3949 | 54 | 'Force Receivable/Payable Account', | 68 | 'account.account', |
3950 | 55 | help="Choose a receivable account to force the default\ | 69 | 'Commission account', |
3951 | 56 | debit/credit account (eg. an intermediat bank account instead of\ | 70 | required=True), |
3952 | 57 | default debitors)."), | 71 | |
3953 | 58 | 'force_partner_on_bank': fields.boolean('Force partner on bank move', | 72 | 'commission_analytic_id': fields.many2one( |
3954 | 59 | help="Tic that box if you want to use the credit insitute partner\ | 73 | 'account.analytic.account', |
3955 | 60 | in the counterpart of the intermediat/banking move." | 74 | 'Commission analytic account'), |
3956 | 61 | ), | 75 | |
3957 | 62 | 'balance_check': fields.boolean('Balance check', | 76 | 'receivable_account_id': fields.many2one( |
3958 | 63 | help="Tic that box if you want OpenERP to control the start/end \ | 77 | 'account.account', |
3959 | 64 | balance before confirming a bank statement. If don't ticked, no \ | 78 | 'Force Receivable/Payable Account', |
3960 | 65 | balance control will be done." | 79 | help="Choose a receivable account to force the default " |
3961 | 66 | ), | 80 | "debit/credit account (eg. an intermediat bank account " |
3962 | 81 | "instead of default debitors)."), | ||
3963 | 82 | |||
3964 | 83 | 'force_partner_on_bank': fields.boolean( | ||
3965 | 84 | 'Force partner on bank move', | ||
3966 | 85 | help="Tick that box if you want to use the credit " | ||
3967 | 86 | "institute partner in the counterpart of the " | ||
3968 | 87 | "intermediate/banking move."), | ||
3969 | 88 | |||
3970 | 89 | 'balance_check': fields.boolean( | ||
3971 | 90 | 'Balance check', | ||
3972 | 91 | help="Tick that box if you want OpenERP to control " | ||
3973 | 92 | "the start/end balance before confirming a bank statement. " | ||
3974 | 93 | "If don't ticked, no balance control will be done."), | ||
3975 | 94 | |||
3976 | 67 | 'bank_statement_prefix': fields.char('Bank Statement Prefix', size=32), | 95 | 'bank_statement_prefix': fields.char('Bank Statement Prefix', size=32), |
3977 | 96 | <<<<<<< TREE | ||
3978 | 68 | 'bank_statement_ids': fields.one2many('account.bank.statement', 'profile_id', 'Bank Statement Imported'), | 97 | 'bank_statement_ids': fields.one2many('account.bank.statement', 'profile_id', 'Bank Statement Imported'), |
3979 | 69 | 'internal_account_transfer_id': fields.many2one('account.account', | 98 | 'internal_account_transfer_id': fields.many2one('account.account', |
3980 | 70 | 'Internal Account Transfer', | 99 | 'Internal Account Transfer', |
3981 | @@ -72,80 +101,115 @@ | |||
3982 | 72 | bank transfer") | 101 | bank transfer") |
3983 | 73 | 102 | ||
3984 | 74 | 103 | ||
3985 | 104 | ======= | ||
3986 | 105 | |||
3987 | 106 | 'bank_statement_ids': fields.one2many('account.bank.statement', | ||
3988 | 107 | 'profile_id', | ||
3989 | 108 | 'Bank Statement Imported'), | ||
3990 | 109 | 'company_id': fields.many2one('res.company', 'Company'), | ||
3991 | 110 | >>>>>>> MERGE-SOURCE | ||
3992 | 75 | } | 111 | } |
3994 | 76 | 112 | ||
3995 | 77 | def _check_partner(self, cr, uid, ids, context=None): | 113 | def _check_partner(self, cr, uid, ids, context=None): |
3996 | 78 | obj = self.browse(cr, uid, ids[0], context=context) | 114 | obj = self.browse(cr, uid, ids[0], context=context) |
3998 | 79 | if obj.partner_id == False and obj.force_partner_on_bank: | 115 | if obj.partner_id is False and obj.force_partner_on_bank: |
3999 | 80 | return False | 116 | return False |
4000 | 81 | return True | 117 | return True |
4001 | 82 | 118 | ||
4002 | 83 | _constraints = [ | 119 | _constraints = [ |
4004 | 84 | (_check_partner, "You need to put a partner if you tic the 'Force partner on bank move' !", []), | 120 | (_check_partner, "You need to put a partner if you tic the 'Force partner on bank move'!", []), |
4005 | 85 | ] | 121 | ] |
4006 | 86 | 122 | ||
4007 | 87 | 123 | ||
4008 | 88 | class AccountBankStatement(Model): | 124 | class AccountBankStatement(Model): |
4009 | 89 | """ | 125 | """ |
4012 | 90 | We improve the bank statement class mostly for : | 126 | We improve the bank statement class mostly for : |
4013 | 91 | - Removing the period and compute it from the date of each line. | 127 | - Removing the period and compute it from the date of each line. |
4014 | 92 | - Allow to remove the balance check depending on the chosen profile | 128 | - Allow to remove the balance check depending on the chosen profile |
4015 | 93 | - Report errors on confirmation all at once instead of crashing onr by one | 129 | - Report errors on confirmation all at once instead of crashing onr by one |
4017 | 94 | - Add a profile notion that can change the generated entries on statement | 130 | - Add a profile notion that can change the generated entries on statement |
4018 | 95 | confirmation. | 131 | confirmation. |
4019 | 96 | For this, we had to override quite some long method and we'll need to maintain | 132 | For this, we had to override quite some long method and we'll need to maintain |
4020 | 97 | them up to date. Changes are point up by '#Chg' comment. | 133 | them up to date. Changes are point up by '#Chg' comment. |
4021 | 98 | """ | 134 | """ |
4022 | 99 | 135 | ||
4023 | 100 | _inherit = "account.bank.statement" | 136 | _inherit = "account.bank.statement" |
4025 | 101 | 137 | ||
4026 | 138 | def _default_period(self, cr, uid, context=None): | ||
4027 | 139 | """ | ||
4028 | 140 | Statement default period | ||
4029 | 141 | """ | ||
4030 | 142 | if context is None: | ||
4031 | 143 | context = {} | ||
4032 | 144 | period_obj = self.pool.get('account.period') | ||
4033 | 145 | periods = period_obj.find(cr, uid, dt=context.get('date'), context=context) | ||
4034 | 146 | return periods and periods[0] or False | ||
4035 | 147 | |||
4036 | 102 | _columns = { | 148 | _columns = { |
4039 | 103 | 'profile_id': fields.many2one('account.statement.profile', | 149 | 'profile_id': fields.many2one( |
4040 | 104 | 'Profil', required=True, readonly=True, states={'draft': [('readonly', False)]}), | 150 | 'account.statement.profile', |
4041 | 151 | 'Profil', | ||
4042 | 152 | required=True, | ||
4043 | 153 | readonly=True, | ||
4044 | 154 | states={'draft': [('readonly', False)]}), | ||
4045 | 105 | 'credit_partner_id': fields.related( | 155 | 'credit_partner_id': fields.related( |
4052 | 106 | 'profile_id', | 156 | 'profile_id', |
4053 | 107 | 'partner_id', | 157 | 'partner_id', |
4054 | 108 | type='many2one', | 158 | type='many2one', |
4055 | 109 | relation='res.partner', | 159 | relation='res.partner', |
4056 | 110 | string='Financial Partner', | 160 | string='Financial Partner', |
4057 | 111 | store=True, readonly=True), | 161 | store=True, |
4058 | 162 | readonly=True), | ||
4059 | 112 | 'balance_check': fields.related( | 163 | 'balance_check': fields.related( |
4068 | 113 | 'profile_id', | 164 | 'profile_id', |
4069 | 114 | 'balance_check', | 165 | 'balance_check', |
4070 | 115 | type='boolean', | 166 | type='boolean', |
4071 | 116 | string='Balance check', | 167 | string='Balance check', |
4072 | 117 | store=True, readonly=True), | 168 | store=True, |
4073 | 118 | 'journal_id': fields.related( | 169 | readonly=True), |
4074 | 119 | 'profile_id', | 170 | 'journal_id': fields.related( |
4075 | 120 | 'journal_id', | 171 | 'profile_id', |
4076 | 172 | 'journal_id', | ||
4077 | 121 | type='many2one', | 173 | type='many2one', |
4082 | 122 | relation='account.journal', | 174 | relation='account.journal', |
4083 | 123 | string='Journal', | 175 | string='Journal', |
4084 | 124 | store=True, readonly=True), | 176 | store=True, |
4085 | 125 | 'period_id': fields.many2one('account.period', 'Period', required=False, readonly=True), | 177 | readonly=True), |
4086 | 178 | 'period_id': fields.many2one( | ||
4087 | 179 | 'account.period', | ||
4088 | 180 | 'Period', | ||
4089 | 181 | required=False, | ||
4090 | 182 | readonly=False, | ||
4091 | 183 | invisible=True), | ||
4092 | 126 | } | 184 | } |
4093 | 127 | 185 | ||
4094 | 128 | _defaults = { | 186 | _defaults = { |
4096 | 129 | 'period_id': lambda *a: False, | 187 | 'period_id': _default_period, |
4097 | 130 | } | 188 | } |
4099 | 131 | 189 | ||
4100 | 132 | def create(self, cr, uid, vals, context=None): | 190 | def create(self, cr, uid, vals, context=None): |
4101 | 133 | """Need to pass the journal_id in vals anytime because of account.cash.statement | 191 | """Need to pass the journal_id in vals anytime because of account.cash.statement |
4102 | 134 | need it.""" | 192 | need it.""" |
4103 | 135 | if 'profile_id' in vals: | 193 | if 'profile_id' in vals: |
4104 | 136 | profile_obj = self.pool.get('account.statement.profile') | 194 | profile_obj = self.pool.get('account.statement.profile') |
4106 | 137 | profile = profile_obj.browse(cr,uid,vals['profile_id'],context) | 195 | profile = profile_obj.browse(cr, uid, vals['profile_id'], context=context) |
4107 | 138 | vals['journal_id'] = profile.journal_id.id | 196 | vals['journal_id'] = profile.journal_id.id |
4108 | 197 | <<<<<<< TREE | ||
4109 | 139 | return super(AccountBankStatement, self).create(cr, uid, vals, context=context) | 198 | return super(AccountBankStatement, self).create(cr, uid, vals, context=context) |
4110 | 140 | 199 | ||
4111 | 141 | def _get_period(self, cursor, uid, date, context=None): | 200 | def _get_period(self, cursor, uid, date, context=None): |
4112 | 201 | ======= | ||
4113 | 202 | return super(AccountBankSatement, self).create(cr, uid, vals, context=context) | ||
4114 | 203 | |||
4115 | 204 | def _get_period(self, cr, uid, date, context=None): | ||
4116 | 205 | >>>>>>> MERGE-SOURCE | ||
4117 | 142 | """ | 206 | """ |
4118 | 143 | Find matching period for date, used in the statement line creation. | 207 | Find matching period for date, used in the statement line creation. |
4119 | 144 | """ | 208 | """ |
4120 | 145 | period_obj = self.pool.get('account.period') | 209 | period_obj = self.pool.get('account.period') |
4122 | 146 | periods = period_obj.find(cursor, uid, dt=date, context=context) | 210 | periods = period_obj.find(cr, uid, dt=date, context=context) |
4123 | 147 | return periods and periods[0] or False | 211 | return periods and periods[0] or False |
4125 | 148 | 212 | ||
4126 | 149 | def _check_company_id(self, cr, uid, ids, context=None): | 213 | def _check_company_id(self, cr, uid, ids, context=None): |
4127 | 150 | """ | 214 | """ |
4128 | 151 | Adapt this constraint method from the account module to reflect the | 215 | Adapt this constraint method from the account module to reflect the |
4129 | @@ -153,184 +217,111 @@ | |||
4130 | 153 | """ | 217 | """ |
4131 | 154 | for statement in self.browse(cr, uid, ids, context=context): | 218 | for statement in self.browse(cr, uid, ids, context=context): |
4132 | 155 | if (statement.period_id and | 219 | if (statement.period_id and |
4134 | 156 | statement.company_id.id != statement.period_id.company_id.id): | 220 | statement.company_id.id != statement.period_id.company_id.id): |
4135 | 157 | return False | 221 | return False |
4136 | 158 | for line in statement.line_ids: | 222 | for line in statement.line_ids: |
4137 | 159 | if (line.period_id and | 223 | if (line.period_id and |
4139 | 160 | statement.company_id.id != line.period_id.company_id.id): | 224 | statement.company_id.id != line.period_id.company_id.id): |
4140 | 161 | return False | 225 | return False |
4141 | 162 | return True | 226 | return True |
4142 | 163 | 227 | ||
4143 | 164 | _constraints = [ | 228 | _constraints = [ |
4145 | 165 | (_check_company_id, 'The journal and period chosen have to belong to the same company.', ['journal_id','period_id']), | 229 | (_check_company_id, |
4146 | 230 | 'The journal and period chosen have to belong to the same company.', | ||
4147 | 231 | ['journal_id', 'period_id']), | ||
4148 | 166 | ] | 232 | ] |
4149 | 167 | 233 | ||
4175 | 168 | def button_cancel(self, cr, uid, ids, context={}): | 234 | def _prepare_move(self, cr, uid, st_line, st_line_number, context=None): |
4176 | 169 | """ | 235 | """Add the period_id from the statement line date to the move preparation. |
4177 | 170 | We cancel the related move, delete them and finally put the | 236 | Originaly, it was taken from the statement period_id |
4178 | 171 | statement in draft state. So no need to unreconcile all entries, | 237 | :param browse_record st_line: account.bank.statement.line record to |
4179 | 172 | then unpost them, then finaly cancel the bank statement. | 238 | create the move from. |
4180 | 173 | """ | 239 | :param char st_line_number: will be used as the name of the generated account move |
4181 | 174 | done = [] | 240 | :return: dict of value to create() the account.move |
4182 | 175 | for st in self.browse(cr, uid, ids, context=context): | 241 | """ |
4183 | 176 | if st.state=='draft': | 242 | if context is None: |
4184 | 177 | continue | 243 | context = {} |
4185 | 178 | ids = [] | 244 | res = super(AccountBankSatement, self)._prepare_move( |
4186 | 179 | for line in st.line_ids: | 245 | cr, uid, st_line, st_line_number, context=context) |
4187 | 180 | for move in line.move_ids: | 246 | ctx = context.copy() |
4188 | 181 | if move.state <> 'draft': | 247 | ctx['company_id'] = st_line.company_id.id |
4189 | 182 | move.button_cancel(context=context) | 248 | period_id = self._get_period(cr, uid, st_line.date, context=ctx) |
4190 | 183 | move.unlink(context=context) | 249 | res.update({'period_id': period_id}) |
4191 | 184 | done.append(st.id) | 250 | return res |
4192 | 185 | self.write(cr, uid, done, {'state':'draft'}, context=context) | 251 | |
4193 | 186 | return True | 252 | def _prepare_move_line_vals( |
4194 | 187 | 253 | self, cr, uid, st_line, move_id, debit, credit, currency_id=False, | |
4195 | 188 | def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, st_line_number, context=None): | 254 | amount_currency=False, account_id=False, analytic_id=False, |
4196 | 189 | """ | 255 | partner_id=False, context=None): |
4197 | 190 | Override a large portion of the code to compute the periode for each line instead of | 256 | """Add the period_id from the statement line date to the move preparation. |
4198 | 191 | taking the period of the whole statement. | 257 | Originaly, it was taken from the statement period_id |
4199 | 192 | Remove the entry posting on generated account moves. | 258 | |
4200 | 259 | :param browse_record st_line: account.bank.statement.line record to | ||
4201 | 260 | create the move from. | ||
4202 | 261 | :param int/long move_id: ID of the account.move to link the move line | ||
4203 | 262 | :param float debit: debit amount of the move line | ||
4204 | 263 | :param float credit: credit amount of the move line | ||
4205 | 264 | :param int/long currency_id: ID of currency of the move line to create | ||
4206 | 265 | :param float amount_currency: amount of the debit/credit expressed in the currency_id | ||
4207 | 266 | :param int/long account_id: ID of the account to use in the move line if different | ||
4208 | 267 | from the statement line account ID | ||
4209 | 268 | :param int/long analytic_id: ID of analytic account to put on the move line | ||
4210 | 269 | :param int/long partner_id: ID of the partner to put on the move line | ||
4211 | 270 | :return: dict of value to create() the account.move.line | ||
4212 | 271 | """ | ||
4213 | 272 | if context is None: | ||
4214 | 273 | context = {} | ||
4215 | 274 | res = super(AccountBankSatement, self)._prepare_move_line_vals( | ||
4216 | 275 | cr, uid, st_line, move_id, debit, credit, | ||
4217 | 276 | currency_id=currency_id, | ||
4218 | 277 | amount_currency=amount_currency, | ||
4219 | 278 | account_id=account_id, | ||
4220 | 279 | analytic_id=analytic_id, | ||
4221 | 280 | partner_id=partner_id, context=context) | ||
4222 | 281 | ctx = context.copy() | ||
4223 | 282 | ctx['company_id'] = st_line.company_id.id | ||
4224 | 283 | period_id = self._get_period(cr, uid, st_line.date, context=ctx) | ||
4225 | 284 | res.update({'period_id': period_id}) | ||
4226 | 285 | return res | ||
4227 | 286 | |||
4228 | 287 | def _get_counter_part_partner(self, cr, uid, st_line, context=None): | ||
4229 | 288 | """ | ||
4230 | 193 | We change the move line generated from the lines depending on the profile: | 289 | We change the move line generated from the lines depending on the profile: |
4231 | 194 | - If receivable_account_id is set, we'll use it instead of the "partner" one | ||
4232 | 195 | - If partner_id is set, we'll us it for the commission (when imported throufh the wizard) | ||
4233 | 196 | - If partner_id is set and force_partner_on_bank is ticked, we'll let the partner of each line | 290 | - If partner_id is set and force_partner_on_bank is ticked, we'll let the partner of each line |
4234 | 197 | for the debit line, but we'll change it on the credit move line for the choosen partner_id | 291 | for the debit line, but we'll change it on the credit move line for the choosen partner_id |
4235 | 198 | => This will ease the reconciliation process with the bank as the partner will match the bank | 292 | => This will ease the reconciliation process with the bank as the partner will match the bank |
4236 | 199 | statement line | 293 | statement line |
4242 | 200 | 294 | :param browse_record st_line: account.bank.statement.line record to | |
4243 | 201 | :param int/long: st_line_id: account.bank.statement.line ID | 295 | create the move from. |
4244 | 202 | :param int/long: company_currency_id: res.currency ID | 296 | :return: int/long of the res.partner to use as counterpart |
4240 | 203 | :param char: st_line_number: that will be used as the name of the generated account move | ||
4241 | 204 | :return: int/long: ID of the created account.move | ||
4245 | 205 | """ | 297 | """ |
4357 | 206 | if context is None: | 298 | bank_partner_id = super(AccountBankSatement, self)._get_counter_part_partner(cr, |
4358 | 207 | context = {} | 299 | uid, |
4359 | 208 | res_currency_obj = self.pool.get('res.currency') | 300 | st_line, |
4360 | 209 | account_move_obj = self.pool.get('account.move') | 301 | context=context) |
4361 | 210 | account_move_line_obj = self.pool.get('account.move.line') | 302 | # get the right partner according to the chosen profil |
4362 | 211 | account_bank_statement_line_obj = self.pool.get('account.bank.statement.line') # Chg | 303 | if st_line.statement_id.profile_id.force_partner_on_bank: |
4363 | 212 | st_line = account_bank_statement_line_obj.browse(cr, uid, st_line_id, context=context) # Chg | 304 | bank_partner_id = st_line.statement_id.profile_id.partner_id.id |
4364 | 213 | st = st_line.statement_id | 305 | return bank_partner_id |
4254 | 214 | |||
4255 | 215 | context.update({'date': st_line.date}) | ||
4256 | 216 | ctx = context.copy() # Chg | ||
4257 | 217 | ctx['company_id'] = st_line.company_id.id # Chg | ||
4258 | 218 | period_id = self._get_period( # Chg | ||
4259 | 219 | cr, uid, st_line.date, context=ctx) | ||
4260 | 220 | |||
4261 | 221 | move_id = account_move_obj.create(cr, uid, { | ||
4262 | 222 | 'journal_id': st.journal_id.id, | ||
4263 | 223 | 'period_id': period_id, # Chg | ||
4264 | 224 | 'date': st_line.date, | ||
4265 | 225 | 'name': st_line_number, | ||
4266 | 226 | 'ref': st_line.ref, | ||
4267 | 227 | }, context=context) | ||
4268 | 228 | account_bank_statement_line_obj.write(cr, uid, [st_line.id], { # Chg | ||
4269 | 229 | 'move_ids': [(4, move_id, False)] | ||
4270 | 230 | }) | ||
4271 | 231 | |||
4272 | 232 | torec = [] | ||
4273 | 233 | if st_line.amount >= 0: | ||
4274 | 234 | account_id = st.journal_id.default_credit_account_id.id | ||
4275 | 235 | else: | ||
4276 | 236 | account_id = st.journal_id.default_debit_account_id.id | ||
4277 | 237 | |||
4278 | 238 | acc_cur = ((st_line.amount<=0) and st.journal_id.default_debit_account_id) or st_line.account_id | ||
4279 | 239 | context.update({ | ||
4280 | 240 | 'res.currency.compute.account': acc_cur, | ||
4281 | 241 | }) | ||
4282 | 242 | amount = res_currency_obj.compute(cr, uid, st.currency.id, | ||
4283 | 243 | company_currency_id, st_line.amount, context=context) | ||
4284 | 244 | |||
4285 | 245 | val = { | ||
4286 | 246 | 'name': st_line.name, | ||
4287 | 247 | 'date': st_line.date, | ||
4288 | 248 | 'ref': st_line.ref, | ||
4289 | 249 | 'move_id': move_id, | ||
4290 | 250 | 'partner_id': ((st_line.partner_id) and st_line.partner_id.id) or False, | ||
4291 | 251 | 'account_id': (st_line.account_id) and st_line.account_id.id, | ||
4292 | 252 | 'credit': ((amount>0) and amount) or 0.0, | ||
4293 | 253 | 'debit': ((amount<0) and -amount) or 0.0, | ||
4294 | 254 | # Replace with the treasury one instead of bank #Chg | ||
4295 | 255 | 'statement_id': st.id, | ||
4296 | 256 | 'journal_id': st.journal_id.id, | ||
4297 | 257 | 'period_id': period_id, #Chg | ||
4298 | 258 | 'currency_id': st.currency.id, | ||
4299 | 259 | 'analytic_account_id': st_line.analytic_account_id and st_line.analytic_account_id.id or False | ||
4300 | 260 | } | ||
4301 | 261 | |||
4302 | 262 | if st.currency.id <> company_currency_id: | ||
4303 | 263 | amount_cur = res_currency_obj.compute(cr, uid, company_currency_id, | ||
4304 | 264 | st.currency.id, amount, context=context) | ||
4305 | 265 | val['amount_currency'] = -amount_cur | ||
4306 | 266 | |||
4307 | 267 | if st_line.account_id and st_line.account_id.currency_id and st_line.account_id.currency_id.id <> company_currency_id: | ||
4308 | 268 | val['currency_id'] = st_line.account_id.currency_id.id | ||
4309 | 269 | amount_cur = res_currency_obj.compute(cr, uid, company_currency_id, | ||
4310 | 270 | st_line.account_id.currency_id.id, amount, context=context) | ||
4311 | 271 | val['amount_currency'] = -amount_cur | ||
4312 | 272 | |||
4313 | 273 | move_line_id = account_move_line_obj.create(cr, uid, val, context=context) | ||
4314 | 274 | torec.append(move_line_id) | ||
4315 | 275 | |||
4316 | 276 | # Fill the secondary amount/currency | ||
4317 | 277 | # if currency is not the same than the company | ||
4318 | 278 | amount_currency = False | ||
4319 | 279 | currency_id = False | ||
4320 | 280 | if st.currency.id <> company_currency_id: | ||
4321 | 281 | amount_currency = st_line.amount | ||
4322 | 282 | currency_id = st.currency.id | ||
4323 | 283 | # GET THE RIGHT PARTNER ACCORDING TO THE CHOSEN PROFIL # Chg | ||
4324 | 284 | if st.profile_id.force_partner_on_bank: # Chg | ||
4325 | 285 | bank_parrtner_id = st.profile_id.partner_id.id # Chg | ||
4326 | 286 | else: # Chg | ||
4327 | 287 | bank_parrtner_id = ((st_line.partner_id) and st_line.partner_id.id) or False # Chg | ||
4328 | 288 | |||
4329 | 289 | account_move_line_obj.create(cr, uid, { | ||
4330 | 290 | 'name': st_line.name, | ||
4331 | 291 | 'date': st_line.date, | ||
4332 | 292 | 'ref': st_line.ref, | ||
4333 | 293 | 'move_id': move_id, | ||
4334 | 294 | 'partner_id': bank_parrtner_id, # Chg | ||
4335 | 295 | 'account_id': account_id, | ||
4336 | 296 | 'credit': ((amount < 0) and -amount) or 0.0, | ||
4337 | 297 | 'debit': ((amount > 0) and amount) or 0.0, | ||
4338 | 298 | # Replace with the treasury one instead of bank #Chg | ||
4339 | 299 | 'statement_id': st.id, | ||
4340 | 300 | 'journal_id': st.journal_id.id, | ||
4341 | 301 | 'period_id': period_id, #Chg | ||
4342 | 302 | 'amount_currency': amount_currency, | ||
4343 | 303 | 'currency_id': currency_id, | ||
4344 | 304 | }, context=context) | ||
4345 | 305 | |||
4346 | 306 | for line in account_move_line_obj.browse(cr, uid, [x.id for x in | ||
4347 | 307 | account_move_obj.browse(cr, uid, move_id, | ||
4348 | 308 | context=context).line_id], | ||
4349 | 309 | context=context): | ||
4350 | 310 | if line.state <> 'valid': | ||
4351 | 311 | raise osv.except_osv(_('Error !'), | ||
4352 | 312 | _('Journal item "%s" is not valid.') % line.name) | ||
4353 | 313 | |||
4354 | 314 | # Bank statements will not consider boolean on journal entry_posted | ||
4355 | 315 | account_move_obj.post(cr, uid, [move_id], context=context) | ||
4356 | 316 | return move_id | ||
4365 | 317 | 306 | ||
4366 | 318 | def _get_st_number_period_profile(self, cr, uid, date, profile_id): | 307 | def _get_st_number_period_profile(self, cr, uid, date, profile_id): |
4367 | 319 | """ | 308 | """ |
4369 | 320 | Retrieve the name of bank statement from sequence, according to the period | 309 | Retrieve the name of bank statement from sequence, according to the period |
4370 | 321 | corresponding to the date passed in args. Add a prefix if set in the profile. | 310 | corresponding to the date passed in args. Add a prefix if set in the profile. |
4372 | 322 | 311 | ||
4373 | 323 | :param: date: date of the statement used to compute the right period | 312 | :param: date: date of the statement used to compute the right period |
4374 | 324 | :param: int/long: profile_id: the account.statement.profile ID from which to take the | 313 | :param: int/long: profile_id: the account.statement.profile ID from which to take the |
4375 | 325 | bank_statement_prefix for the name | 314 | bank_statement_prefix for the name |
4376 | 326 | :return: char: name of the bank statement (st_number) | 315 | :return: char: name of the bank statement (st_number) |
4378 | 327 | 316 | ||
4379 | 328 | """ | 317 | """ |
4382 | 329 | year = self.pool.get('account.period').browse(cr, uid, self._get_period(cr, uid, date)).fiscalyear_id.id | 318 | year = self.pool.get('account.period').browse( |
4383 | 330 | profile = self.pool.get('account.statement.profile').browse(cr,uid, profile_id) | 319 | cr, uid, self._get_period(cr, uid, date)).fiscalyear_id.id |
4384 | 320 | profile = self.pool.get('account.statement.profile').browse(cr, uid, profile_id) | ||
4385 | 331 | c = {'fiscalyear_id': year} | 321 | c = {'fiscalyear_id': year} |
4386 | 332 | obj_seq = self.pool.get('ir.sequence') | 322 | obj_seq = self.pool.get('ir.sequence') |
4388 | 333 | journal_sequence_id = profile.journal_id.sequence_id and profile.journal_id.sequence_id.id or False | 323 | journal_sequence_id = (profile.journal_id.sequence_id and |
4389 | 324 | profile.journal_id.sequence_id.id or False) | ||
4390 | 334 | if journal_sequence_id: | 325 | if journal_sequence_id: |
4391 | 335 | st_number = obj_seq.next_by_id(cr, uid, journal_sequence_id, context=c) | 326 | st_number = obj_seq.next_by_id(cr, uid, journal_sequence_id, context=c) |
4392 | 336 | else: | 327 | else: |
4393 | @@ -346,47 +337,48 @@ | |||
4394 | 346 | instead of having them pop one by one. | 337 | instead of having them pop one by one. |
4395 | 347 | We have to copy paste a big block of code, changing the error | 338 | We have to copy paste a big block of code, changing the error |
4396 | 348 | stack + managing period from date. | 339 | stack + managing period from date. |
4399 | 349 | 340 | ||
4400 | 350 | TODO: Log the error in a bank statement field instead of using a popup ! | 341 | TODO: Log the error in a bank statement field instead of using a popup! |
4401 | 351 | """ | 342 | """ |
4402 | 352 | # obj_seq = self.pool.get('irerrors_stack.sequence') | ||
4403 | 353 | if context is None: | ||
4404 | 354 | context = {} | ||
4405 | 355 | for st in self.browse(cr, uid, ids, context=context): | 343 | for st in self.browse(cr, uid, ids, context=context): |
4406 | 356 | 344 | ||
4407 | 357 | j_type = st.journal_id.type | 345 | j_type = st.journal_id.type |
4408 | 358 | company_currency_id = st.journal_id.company_id.currency_id.id | 346 | company_currency_id = st.journal_id.company_id.currency_id.id |
4409 | 359 | if not self.check_status_condition(cr, uid, st.state, journal_type=j_type): | 347 | if not self.check_status_condition(cr, uid, st.state, journal_type=j_type): |
4410 | 360 | continue | 348 | continue |
4412 | 361 | 349 | ||
4413 | 362 | self.balance_check(cr, uid, st.id, journal_type=j_type, context=context) | 350 | self.balance_check(cr, uid, st.id, journal_type=j_type, context=context) |
4414 | 363 | if (not st.journal_id.default_credit_account_id) \ | 351 | if (not st.journal_id.default_credit_account_id) \ |
4415 | 364 | or (not st.journal_id.default_debit_account_id): | 352 | or (not st.journal_id.default_debit_account_id): |
4418 | 365 | raise osv.except_osv(_('Configuration Error !'), | 353 | raise osv.except_osv(_('Configuration Error!'), |
4419 | 366 | _('Please verify that an account is defined in the journal.')) | 354 | _('Please verify that an account is defined in the journal.')) |
4420 | 367 | 355 | ||
4421 | 368 | if not st.name == '/': | 356 | if not st.name == '/': |
4422 | 369 | st_number = st.name | 357 | st_number = st.name |
4423 | 370 | else: | 358 | else: |
4425 | 371 | # Begin Changes | 359 | # Begin Changes |
4426 | 372 | st_number = self._get_st_number_period_profile(cr, uid, st.date, st.profile_id.id) | 360 | st_number = self._get_st_number_period_profile(cr, uid, st.date, st.profile_id.id) |
4428 | 373 | # End Changes | 361 | # End Changes |
4429 | 374 | for line in st.move_line_ids: | 362 | for line in st.move_line_ids: |
4433 | 375 | if line.state <> 'valid': | 363 | if line.state != 'valid': |
4434 | 376 | raise osv.except_osv(_('Error !'), | 364 | raise osv.except_osv(_('Error!'), |
4435 | 377 | _('The account entries lines are not in valid state.')) | 365 | _('The account entries lines are not in valid state.')) |
4436 | 378 | # begin changes | 366 | # begin changes |
4437 | 379 | errors_stack = [] | 367 | errors_stack = [] |
4438 | 380 | for st_line in st.line_ids: | 368 | for st_line in st.line_ids: |
4439 | 381 | try: | 369 | try: |
4440 | 382 | if st_line.analytic_account_id: | 370 | if st_line.analytic_account_id: |
4441 | 383 | if not st.journal_id.analytic_journal_id: | 371 | if not st.journal_id.analytic_journal_id: |
4444 | 384 | raise osv.except_osv(_('No Analytic Journal !'), | 372 | raise osv.except_osv(_('No Analytic Journal!'), |
4445 | 385 | _("You have to assign an analytic journal on the '%s' journal!") % (st.journal_id.name,)) | 373 | _("You have to assign an analytic" |
4446 | 374 | " journal on the '%s' journal!") % st.journal_id.name) | ||
4447 | 386 | if not st_line.amount: | 375 | if not st_line.amount: |
4448 | 387 | continue | 376 | continue |
4449 | 388 | st_line_number = self.get_next_st_line_number(cr, uid, st_number, st_line, context) | 377 | st_line_number = self.get_next_st_line_number(cr, uid, st_number, st_line, context) |
4451 | 389 | self.create_move_from_st_line(cr, uid, st_line.id, company_currency_id, st_line_number, context) | 378 | self.create_move_from_st_line(cr, uid, st_line.id, |
4452 | 379 | company_currency_id, | ||
4453 | 380 | st_line_number, | ||
4454 | 381 | context) | ||
4455 | 390 | except osv.except_osv, exc: | 382 | except osv.except_osv, exc: |
4456 | 391 | msg = "Line ID %s with ref %s had following error: %s" % (st_line.id, st_line.ref, exc.value) | 383 | msg = "Line ID %s with ref %s had following error: %s" % (st_line.id, st_line.ref, exc.value) |
4457 | 392 | errors_stack.append(msg) | 384 | errors_stack.append(msg) |
4458 | @@ -397,72 +389,128 @@ | |||
4459 | 397 | msg = u"\n".join(errors_stack) | 389 | msg = u"\n".join(errors_stack) |
4460 | 398 | raise osv.except_osv(_('Error'), msg) | 390 | raise osv.except_osv(_('Error'), msg) |
4461 | 399 | #end changes | 391 | #end changes |
4471 | 400 | self.write(cr, uid, [st.id], { | 392 | self.write(cr, uid, [st.id], |
4472 | 401 | 'name': st_number, | 393 | {'name': st_number, |
4473 | 402 | 'balance_end_real': st.balance_end | 394 | 'balance_end_real': st.balance_end}, |
4474 | 403 | }, context=context) | 395 | context=context) |
4475 | 404 | self.log(cr, uid, st.id, _('Statement %s is confirmed, journal items are created.') % (st_number,)) | 396 | body = _('Statement %s confirmed, journal items were created.') % st_number |
4476 | 405 | return self.write(cr, uid, ids, {'state':'confirm'}, context=context) | 397 | self.message_post(cr, uid, [st.id], |
4477 | 406 | 398 | body, | |
4478 | 407 | def get_account_for_counterpart(self, cursor, uid, | 399 | context=context) |
4479 | 408 | amount, account_receivable, account_payable): | 400 | return self.write(cr, uid, ids, {'state': 'confirm'}, context=context) |
4480 | 401 | |||
4481 | 402 | def get_account_for_counterpart(self, cr, uid, amount, account_receivable, account_payable): | ||
4482 | 403 | """For backward compatibility.""" | ||
4483 | 404 | account_id, type = self.get_account_and_type_for_counterpart(cr, uid, amount, | ||
4484 | 405 | account_receivable, | ||
4485 | 406 | account_payable) | ||
4486 | 407 | return account_id | ||
4487 | 408 | |||
4488 | 409 | def _compute_type_from_partner_profile(self, cr, uid, partner_id, | ||
4489 | 410 | default_type, context=None): | ||
4490 | 411 | """Compute the statement line type | ||
4491 | 412 | from partner profile (customer, supplier)""" | ||
4492 | 413 | obj_partner = self.pool.get('res.partner') | ||
4493 | 414 | part = obj_partner.browse(cr, uid, partner_id, context=context) | ||
4494 | 415 | if part.supplier == part.customer: | ||
4495 | 416 | return default_type | ||
4496 | 417 | if part.supplier: | ||
4497 | 418 | return 'supplier' | ||
4498 | 419 | else: | ||
4499 | 420 | return 'customer' | ||
4500 | 421 | |||
4501 | 422 | def _compute_type_from_amount(self, cr, uid, amount): | ||
4502 | 423 | """Compute the statement type based on amount""" | ||
4503 | 424 | if amount in (None, False): | ||
4504 | 425 | return 'general' | ||
4505 | 426 | if amount < 0: | ||
4506 | 427 | return 'supplier' | ||
4507 | 428 | return 'customer' | ||
4508 | 429 | |||
4509 | 430 | def get_type_for_counterpart(self, cr, uid, amount, partner_id=False): | ||
4510 | 431 | """Give the amount and receive the type to use for the line. | ||
4511 | 432 | The rules are: | ||
4512 | 433 | - If the customer checkbox is checked on the found partner, type customer | ||
4513 | 434 | - If the supplier checkbox is checked on the found partner, typewill be supplier | ||
4514 | 435 | - If both checkbox are checked or none of them, it'll be based on the amount : | ||
4515 | 436 | If amount is positif the type customer, | ||
4516 | 437 | If amount is negativ, the type supplier | ||
4517 | 438 | :param float: amount of the line | ||
4518 | 439 | :param int/long: partner_id the partner id | ||
4519 | 440 | :return: type as string: the default type to use: 'customer' or 'supplier'. | ||
4520 | 441 | """ | ||
4521 | 442 | s_line_type = self._compute_type_from_amount(cr, uid, amount) | ||
4522 | 443 | if partner_id: | ||
4523 | 444 | s_line_type = self._compute_type_from_partner_profile(cr, uid, | ||
4524 | 445 | partner_id, s_line_type) | ||
4525 | 446 | return s_line_type | ||
4526 | 447 | |||
4527 | 448 | def get_account_and_type_for_counterpart(self, cr, uid, amount, account_receivable, | ||
4528 | 449 | account_payable, partner_id=False): | ||
4529 | 409 | """ | 450 | """ |
4530 | 410 | Give the amount, payable and receivable account (that can be found using | 451 | Give the amount, payable and receivable account (that can be found using |
4531 | 411 | get_default_pay_receiv_accounts method) and receive the one to use. This method | 452 | get_default_pay_receiv_accounts method) and receive the one to use. This method |
4532 | 412 | should be use when there is no other way to know which one to take. | 453 | should be use when there is no other way to know which one to take. |
4534 | 413 | 454 | The rules are: | |
4535 | 455 | - If the customer checkbox is checked on the found partner, type and account will be customer and receivable | ||
4536 | 456 | - If the supplier checkbox is checked on the found partner, type and account will be supplier and payable | ||
4537 | 457 | - If both checkbox are checked or none of them, it'll be based on the amount : | ||
4538 | 458 | If amount is positive, the type and account will be customer and receivable, | ||
4539 | 459 | If amount is negative, the type and account will be supplier and payable | ||
4540 | 460 | Note that we return the payable or receivable account from agrs and not from the optional partner_id | ||
4541 | 461 | given! | ||
4542 | 462 | |||
4543 | 414 | :param float: amount of the line | 463 | :param float: amount of the line |
4548 | 415 | :param int/long: account_receivable the receivable account | 464 | :param int/long: account_receivable the receivable account |
4549 | 416 | :param int/long: account_payable the payable account | 465 | :param int/long: account_payable the payable account |
4550 | 417 | :return: int/long :the default account to be used by statement line as the counterpart | 466 | :param int/long: partner_id the partner id |
4551 | 418 | of the journal account depending on the amount. | 467 | :return: dict with [account_id as int/long,type as string]: the default account to be used by |
4552 | 468 | statement line as the counterpart of the journal account depending on the amount and the type | ||
4553 | 469 | as 'customer' or 'supplier'. | ||
4554 | 419 | """ | 470 | """ |
4555 | 420 | account_id = False | 471 | account_id = False |
4557 | 421 | if amount >= 0: | 472 | ltype = self.get_type_for_counterpart(cr, uid, amount, partner_id=partner_id) |
4558 | 473 | if ltype == 'supplier': | ||
4559 | 474 | account_id = account_payable | ||
4560 | 475 | else: | ||
4561 | 422 | account_id = account_receivable | 476 | account_id = account_receivable |
4562 | 423 | else: | ||
4563 | 424 | account_id = account_payable | ||
4564 | 425 | if not account_id: | 477 | if not account_id: |
4565 | 426 | raise osv.except_osv( | 478 | raise osv.except_osv( |
4566 | 427 | _('Can not determine account'), | 479 | _('Can not determine account'), |
4567 | 428 | _('Please ensure that minimal properties are set') | 480 | _('Please ensure that minimal properties are set') |
4568 | 429 | ) | 481 | ) |
4570 | 430 | return account_id | 482 | return [account_id, ltype] |
4571 | 431 | 483 | ||
4573 | 432 | def get_default_pay_receiv_accounts(self, cursor, uid, context=None): | 484 | def get_default_pay_receiv_accounts(self, cr, uid, context=None): |
4574 | 433 | """ | 485 | """ |
4575 | 434 | We try to determine default payable/receivable accounts to be used as counterpart | 486 | We try to determine default payable/receivable accounts to be used as counterpart |
4578 | 435 | from the company default propoerty. This is to be used if there is no otherway to | 487 | from the company default propoerty. This is to be used if there is no otherway to |
4579 | 436 | find the good one, or to find a default value that will be overriden by a completion | 488 | find the good one, or to find a default value that will be overriden by a completion |
4580 | 437 | method (rules of account_statement_base_completion) afterwards. | 489 | method (rules of account_statement_base_completion) afterwards. |
4582 | 438 | 490 | ||
4583 | 439 | :return: tuple of int/long ID that give account_receivable, account_payable based on | 491 | :return: tuple of int/long ID that give account_receivable, account_payable based on |
4584 | 440 | company default. | 492 | company default. |
4585 | 441 | """ | 493 | """ |
4586 | 442 | account_receivable = False | 494 | account_receivable = False |
4587 | 443 | account_payable = False | 495 | account_payable = False |
4588 | 444 | context = context or {} | ||
4589 | 445 | property_obj = self.pool.get('ir.property') | 496 | property_obj = self.pool.get('ir.property') |
4590 | 446 | model_fields_obj = self.pool.get('ir.model.fields') | 497 | model_fields_obj = self.pool.get('ir.model.fields') |
4591 | 447 | model_fields_ids = model_fields_obj.search( | 498 | model_fields_ids = model_fields_obj.search( |
4593 | 448 | cursor, | 499 | cr, |
4594 | 449 | uid, | 500 | uid, |
4595 | 450 | [('name', 'in', ['property_account_receivable', | 501 | [('name', 'in', ['property_account_receivable', |
4596 | 451 | 'property_account_payable']), | 502 | 'property_account_payable']), |
4598 | 452 | ('model', '=', 'res.partner'),], | 503 | ('model', '=', 'res.partner')], |
4599 | 453 | context=context | 504 | context=context |
4600 | 454 | ) | 505 | ) |
4612 | 455 | property_ids = property_obj.search( | 506 | property_ids = property_obj.search(cr, |
4613 | 456 | cursor, | 507 | uid, |
4614 | 457 | uid, [ | 508 | [('fields_id', 'in', model_fields_ids), |
4615 | 458 | ('fields_id', 'in', model_fields_ids), | 509 | ('res_id', '=', False)], |
4616 | 459 | ('res_id', '=', False), | 510 | context=context) |
4617 | 460 | ], | 511 | |
4618 | 461 | context=context | 512 | for erp_property in property_obj.browse( |
4619 | 462 | ) | 513 | cr, uid, property_ids, context=context): |
4609 | 463 | |||
4610 | 464 | for erp_property in property_obj.browse(cursor, uid, | ||
4611 | 465 | property_ids, context=context): | ||
4620 | 466 | if erp_property.fields_id.name == 'property_account_receivable': | 514 | if erp_property.fields_id.name == 'property_account_receivable': |
4621 | 467 | account_receivable = erp_property.value_reference.id | 515 | account_receivable = erp_property.value_reference.id |
4622 | 468 | elif erp_property.fields_id.name == 'property_account_payable': | 516 | elif erp_property.fields_id.name == 'property_account_payable': |
4623 | @@ -473,56 +521,64 @@ | |||
4624 | 473 | """ | 521 | """ |
4625 | 474 | Balance check depends on the profile. If no check for this profile is required, | 522 | Balance check depends on the profile. If no check for this profile is required, |
4626 | 475 | return True and do nothing, otherwise call super. | 523 | return True and do nothing, otherwise call super. |
4629 | 476 | 524 | ||
4630 | 477 | :param int/long st_id: ID of the concerned account.bank.statement | 525 | :param int/long st_id: ID of the concerned account.bank.statement |
4631 | 478 | :param char: journal_type that concern the bank statement | 526 | :param char: journal_type that concern the bank statement |
4632 | 479 | :return: True | 527 | :return: True |
4633 | 480 | """ | 528 | """ |
4634 | 481 | st = self.browse(cr, uid, st_id, context=context) | 529 | st = self.browse(cr, uid, st_id, context=context) |
4635 | 482 | if st.balance_check: | 530 | if st.balance_check: |
4636 | 531 | <<<<<<< TREE | ||
4637 | 483 | return super(AccountBankStatement,self).balance_check(cr, uid, st_id, journal_type, context) | 532 | return super(AccountBankStatement,self).balance_check(cr, uid, st_id, journal_type, context) |
4638 | 533 | ======= | ||
4639 | 534 | return super(AccountBankSatement, self).balance_check( | ||
4640 | 535 | cr, uid, st_id, journal_type, context=context) | ||
4641 | 536 | >>>>>>> MERGE-SOURCE | ||
4642 | 484 | else: | 537 | else: |
4643 | 485 | return True | 538 | return True |
4644 | 486 | 539 | ||
4645 | 487 | def onchange_imp_config_id(self, cr, uid, ids, profile_id, context=None): | 540 | def onchange_imp_config_id(self, cr, uid, ids, profile_id, context=None): |
4646 | 488 | """ | 541 | """ |
4647 | 489 | Compute values on the change of the profile. | 542 | Compute values on the change of the profile. |
4649 | 490 | 543 | ||
4650 | 491 | :param: int/long: profile_id that changed | 544 | :param: int/long: profile_id that changed |
4651 | 492 | :return dict of dict with key = name of the field | 545 | :return dict of dict with key = name of the field |
4652 | 493 | """ | 546 | """ |
4653 | 494 | if not profile_id: | 547 | if not profile_id: |
4654 | 495 | return {} | 548 | return {} |
4656 | 496 | import_config = self.pool.get("account.statement.profile").browse(cr,uid,profile_id) | 549 | import_config = self.pool.get("account.statement.profile").browse( |
4657 | 550 | cr, uid, profile_id, context=context) | ||
4658 | 497 | journal_id = import_config.journal_id.id | 551 | journal_id = import_config.journal_id.id |
4659 | 498 | account_id = import_config.journal_id.default_debit_account_id.id | 552 | account_id = import_config.journal_id.default_debit_account_id.id |
4660 | 499 | credit_partner_id = import_config.partner_id and import_config.partner_id.id or False | 553 | credit_partner_id = import_config.partner_id and import_config.partner_id.id or False |
4665 | 500 | return {'value': {'journal_id':journal_id, 'account_id': account_id, | 554 | return {'value': {'journal_id': journal_id, |
4666 | 501 | 'balance_check':import_config.balance_check, | 555 | 'account_id': account_id, |
4667 | 502 | 'credit_partner_id':credit_partner_id, | 556 | 'balance_check': import_config.balance_check, |
4668 | 503 | }} | 557 | 'credit_partner_id': credit_partner_id}} |
4669 | 504 | 558 | ||
4670 | 505 | 559 | ||
4671 | 506 | class AccountBankStatementLine(Model): | 560 | class AccountBankStatementLine(Model): |
4672 | 507 | """ | 561 | """ |
4673 | 508 | Override to compute the period from the date of the line, add a method to retrieve | 562 | Override to compute the period from the date of the line, add a method to retrieve |
4676 | 509 | the values for a line from the profile. Override the on_change method to take care of | 563 | the values for a line from the profile. Override the on_change method to take care of |
4677 | 510 | the profile when fullfilling the bank statement manually. Set the reference to 64 | 564 | the profile when fullfilling the bank statement manually. Set the reference to 64 |
4678 | 511 | Char long instead 32. | 565 | Char long instead 32. |
4679 | 512 | """ | 566 | """ |
4680 | 513 | _inherit = "account.bank.statement.line" | 567 | _inherit = "account.bank.statement.line" |
4681 | 514 | 568 | ||
4683 | 515 | def _get_period(self, cursor, user, context=None): | 569 | def _get_period(self, cr, uid, context=None): |
4684 | 516 | """ | 570 | """ |
4685 | 517 | Return a period from a given date in the context. | 571 | Return a period from a given date in the context. |
4686 | 518 | """ | 572 | """ |
4689 | 519 | date = context.get('date', None) | 573 | if context is None: |
4690 | 520 | periods = self.pool.get('account.period').find(cursor, user, dt=date) | 574 | context = {} |
4691 | 575 | date = context.get('date') | ||
4692 | 576 | periods = self.pool.get('account.period').find(cr, uid, dt=date) | ||
4693 | 521 | return periods and periods[0] or False | 577 | return periods and periods[0] or False |
4694 | 522 | 578 | ||
4698 | 523 | def _get_default_account(self, cursor, user, context=None): | 579 | def _get_default_account(self, cr, uid, context=None): |
4699 | 524 | return self.get_values_for_line(cursor, user, context = context)['account_id'] | 580 | return self.get_values_for_line(cr, uid, context=context)['account_id'] |
4700 | 525 | 581 | ||
4701 | 526 | _columns = { | 582 | _columns = { |
4702 | 527 | # Set them as required + 64 char instead of 32 | 583 | # Set them as required + 64 char instead of 32 |
4703 | 528 | 'ref': fields.char('Reference', size=64, required=True), | 584 | 'ref': fields.char('Reference', size=64, required=True), |
4704 | @@ -532,19 +588,25 @@ | |||
4705 | 532 | 'period_id': _get_period, | 588 | 'period_id': _get_period, |
4706 | 533 | 'account_id': _get_default_account, | 589 | 'account_id': _get_default_account, |
4707 | 534 | } | 590 | } |
4710 | 535 | 591 | ||
4711 | 536 | def get_values_for_line(self, cr, uid, profile_id = False, partner_id = False, line_type = False, amount = False, context = None): | 592 | def get_values_for_line(self, cr, uid, profile_id=False, partner_id=False, line_type=False, amount=False, master_account_id=None, context=None): |
4712 | 537 | """ | 593 | """ |
4713 | 538 | Return the account_id to be used in the line of a bank statement. It'll base the result as follow: | 594 | Return the account_id to be used in the line of a bank statement. It'll base the result as follow: |
4714 | 539 | - If a receivable_account_id is set in the profile, return this value and type = general | 595 | - If a receivable_account_id is set in the profile, return this value and type = general |
4716 | 540 | - Elif line_type is given, take the partner receivable/payable property (payable if type= supplier, receivable | 596 | # TODO |
4717 | 597 | - Elif how_get_type_account is set to force_supplier or force_customer, will take respectively payable and type=supplier, | ||
4718 | 598 | receivable and type=customer otherwise | ||
4719 | 599 | # END TODO | ||
4720 | 600 | - Elif line_type is given, take the partner receivable/payable property (payable if type=supplier, receivable | ||
4721 | 541 | otherwise) | 601 | otherwise) |
4725 | 542 | - Elif amount is given, take the partner receivable/payable property (receivable if amount >= 0.0, | 602 | - Elif amount is given: |
4726 | 543 | payable otherwise). In that case, we also fullfill the type (receivable = customer, payable = supplier) | 603 | - If the customer checkbox is checked on the found partner, type and account will be customer and receivable |
4727 | 544 | so it is easier for the accountant to know why the receivable/payable has been chosen | 604 | - If the supplier checkbox is checked on the found partner, type and account will be supplier and payable |
4728 | 605 | - If both checkbox are checked or none of them, it'll be based on the amount : | ||
4729 | 606 | If amount is positive, the type and account will be customer and receivable, | ||
4730 | 607 | If amount is negative, the type and account will be supplier an payable | ||
4731 | 545 | - Then, if no partner are given we look and take the property from the company so we always give a value | 608 | - Then, if no partner are given we look and take the property from the company so we always give a value |
4732 | 546 | for account_id. Note that in that case, we return the receivable one. | 609 | for account_id. Note that in that case, we return the receivable one. |
4733 | 547 | |||
4734 | 548 | :param int/long profile_id of the related bank statement | 610 | :param int/long profile_id of the related bank statement |
4735 | 549 | :param int/long partner_id of the line | 611 | :param int/long partner_id of the line |
4736 | 550 | :param char line_type: a value from: 'general', 'supplier', 'customer' | 612 | :param char line_type: a value from: 'general', 'supplier', 'customer' |
4737 | @@ -557,20 +619,32 @@ | |||
4738 | 557 | ... | 619 | ... |
4739 | 558 | } | 620 | } |
4740 | 559 | """ | 621 | """ |
4741 | 560 | if context is None: | ||
4742 | 561 | context = {} | ||
4743 | 562 | res = {} | 622 | res = {} |
4744 | 563 | obj_partner = self.pool.get('res.partner') | 623 | obj_partner = self.pool.get('res.partner') |
4745 | 564 | obj_stat = self.pool.get('account.bank.statement') | 624 | obj_stat = self.pool.get('account.bank.statement') |
4746 | 565 | receiv_account = pay_account = account_id = False | 625 | receiv_account = pay_account = account_id = False |
4747 | 566 | # If profile has a receivable_account_id, we return it in any case | 626 | # If profile has a receivable_account_id, we return it in any case |
4750 | 567 | if profile_id: | 627 | if master_account_id: |
4751 | 568 | profile = self.pool.get("account.statement.profile").browse(cr,uid,profile_id) | 628 | res['account_id'] = master_account_id |
4752 | 629 | # We return general as default instead of get_type_for_counterpart | ||
4753 | 630 | # for perfomance reasons as line_type is not a meaningfull value | ||
4754 | 631 | # as account is forced | ||
4755 | 632 | res['type'] = line_type if line_type else 'general' | ||
4756 | 633 | return res | ||
4757 | 634 | # To optimize we consider passing false means there is no account | ||
4758 | 635 | # on profile | ||
4759 | 636 | if profile_id and master_account_id is None: | ||
4760 | 637 | profile = self.pool.get("account.statement.profile").browse( | ||
4761 | 638 | cr, uid, profile_id, context=context) | ||
4762 | 569 | if profile.receivable_account_id: | 639 | if profile.receivable_account_id: |
4765 | 570 | res['account_id'] = profile.receivable_account_id.id | 640 | res['account_id'] = profile.receivable_account_id.id |
4766 | 571 | res['type'] = 'general' | 641 | # We return general as default instead of get_type_for_counterpart |
4767 | 642 | # for perfomance reasons as line_type is not a meaningfull value | ||
4768 | 643 | # as account is forced | ||
4769 | 644 | res['type'] = line_type if line_type else 'general' | ||
4770 | 572 | return res | 645 | return res |
4772 | 573 | # If partner -> take from him | 646 | # If no account is available on profile you have to do the lookup |
4773 | 647 | # This can be quite a performance killer as we read ir.properity fields | ||
4774 | 574 | if partner_id: | 648 | if partner_id: |
4775 | 575 | part = obj_partner.browse(cr, uid, partner_id, context=context) | 649 | part = obj_partner.browse(cr, uid, partner_id, context=context) |
4776 | 576 | pay_account = part.property_account_payable.id | 650 | pay_account = part.property_account_payable.id |
4777 | @@ -578,62 +652,53 @@ | |||
4778 | 578 | # If no value, look on the default company property | 652 | # If no value, look on the default company property |
4779 | 579 | if not pay_account or not receiv_account: | 653 | if not pay_account or not receiv_account: |
4780 | 580 | receiv_account, pay_account = obj_stat.get_default_pay_receiv_accounts(cr, uid, context=None) | 654 | receiv_account, pay_account = obj_stat.get_default_pay_receiv_accounts(cr, uid, context=None) |
4797 | 581 | # Now we have both pay and receive account, choose the one to use | 655 | account_id, comp_line_type = obj_stat.get_account_and_type_for_counterpart(cr, uid, amount, |
4798 | 582 | # based on line_type first, then amount, otherwise take receivable one. | 656 | receiv_account, pay_account, |
4799 | 583 | if line_type is not False: | 657 | partner_id=partner_id) |
4800 | 584 | if line_type == 'supplier': | 658 | res['account_id'] = account_id if account_id else receiv_account |
4801 | 585 | res['account_id'] = pay_account | 659 | res['type'] = line_type if line_type else comp_line_type |
4786 | 586 | else: | ||
4787 | 587 | res['account_id'] = receiv_account | ||
4788 | 588 | elif amount is not False: | ||
4789 | 589 | if amount >= 0: | ||
4790 | 590 | res['account_id'] = receiv_account | ||
4791 | 591 | res['type'] = 'customer' | ||
4792 | 592 | else: | ||
4793 | 593 | res['account_id'] = pay_account | ||
4794 | 594 | res['type'] = 'supplier' | ||
4795 | 595 | if not account_id: | ||
4796 | 596 | res['account_id'] = receiv_account | ||
4802 | 597 | return res | 660 | return res |
4806 | 598 | 661 | ||
4807 | 599 | 662 | def onchange_partner_id(self, cr, uid, ids, partner_id, profile_id=None, context=None): | |
4805 | 600 | def onchange_partner_id(self, cr, uid, ids, partner_id, profile_id, context=None): | ||
4808 | 601 | """ | 663 | """ |
4809 | 602 | Override of the basic method as we need to pass the profile_id in the on_change_type | 664 | Override of the basic method as we need to pass the profile_id in the on_change_type |
4810 | 603 | call. | 665 | call. |
4811 | 666 | Moreover, we now call the get_account_and_type_for_counterpart method now to get the | ||
4812 | 667 | type to use. | ||
4813 | 604 | """ | 668 | """ |
4817 | 605 | obj_partner = self.pool.get('res.partner') | 669 | obj_stat = self.pool.get('account.bank.statement') |
4815 | 606 | if context is None: | ||
4816 | 607 | context = {} | ||
4818 | 608 | if not partner_id: | 670 | if not partner_id: |
4819 | 609 | return {} | 671 | return {} |
4831 | 610 | part = obj_partner.browse(cr, uid, partner_id, context=context) | 672 | line_type = obj_stat.get_type_for_counterpart(cr, uid, 0.0, partner_id=partner_id) |
4832 | 611 | if not part.supplier and not part.customer: | 673 | res_type = self.onchange_type(cr, uid, ids, partner_id, line_type, profile_id, context=context) |
4822 | 612 | type = 'general' | ||
4823 | 613 | elif part.supplier and part.customer: | ||
4824 | 614 | type = 'general' | ||
4825 | 615 | else: | ||
4826 | 616 | if part.supplier == True: | ||
4827 | 617 | type = 'supplier' | ||
4828 | 618 | if part.customer == True: | ||
4829 | 619 | type = 'customer' | ||
4830 | 620 | res_type = self.onchange_type(cr, uid, ids, partner_id, type, profile_id, context=context) # Chg | ||
4833 | 621 | if res_type['value'] and res_type['value'].get('account_id', False): | 674 | if res_type['value'] and res_type['value'].get('account_id', False): |
4838 | 622 | return {'value': {'type': type, 'account_id': res_type['value']['account_id']}} | 675 | return {'value': {'type': line_type, |
4839 | 623 | return {'value': {'type': type}} | 676 | 'account_id': res_type['value']['account_id'], |
4840 | 624 | 677 | 'voucher_id': False}} | |
4841 | 625 | def onchange_type(self, cr, uid, line_id, partner_id, type, profile_id, context=None): | 678 | return {'value': {'type': line_type}} |
4842 | 679 | |||
4843 | 680 | def onchange_type(self, cr, uid, line_id, partner_id, line_type, profile_id, context=None): | ||
4844 | 626 | """ | 681 | """ |
4845 | 627 | Keep the same features as in standard and call super. If an account is returned, | 682 | Keep the same features as in standard and call super. If an account is returned, |
4846 | 628 | call the method to compute line values. | 683 | call the method to compute line values. |
4847 | 629 | """ | 684 | """ |
4848 | 685 | <<<<<<< TREE | ||
4849 | 630 | if context is None: | 686 | if context is None: |
4850 | 631 | context = {} | 687 | context = {} |
4851 | 632 | res = super(AccountBankStatementLine,self).onchange_type(cr, uid, line_id, partner_id, type, context) | 688 | res = super(AccountBankStatementLine,self).onchange_type(cr, uid, line_id, partner_id, type, context) |
4852 | 689 | ======= | ||
4853 | 690 | res = super(AccountBankSatementLine, self).onchange_type(cr, uid, | ||
4854 | 691 | line_id, | ||
4855 | 692 | partner_id, | ||
4856 | 693 | line_type, | ||
4857 | 694 | context=context) | ||
4858 | 695 | >>>>>>> MERGE-SOURCE | ||
4859 | 633 | if 'account_id' in res['value']: | 696 | if 'account_id' in res['value']: |
4862 | 634 | result = self.get_values_for_line(cr, uid, profile_id = profile_id, | 697 | result = self.get_values_for_line(cr, uid, |
4863 | 635 | partner_id = partner_id, line_type = type, context = context) | 698 | profile_id=profile_id, |
4864 | 699 | partner_id=partner_id, | ||
4865 | 700 | line_type=line_type, | ||
4866 | 701 | context=context) | ||
4867 | 636 | if result: | 702 | if result: |
4869 | 637 | res['value'].update({'account_id':result['account_id']}) | 703 | res['value'].update({'account_id': result['account_id']}) |
4870 | 638 | return res | 704 | return res |
4871 | 639 | |||
4872 | 640 | 705 | ||
4873 | === modified file 'account_statement_ext/statement_view.xml' | |||
4874 | --- account_statement_ext/statement_view.xml 2013-04-04 11:14:03 +0000 | |||
4875 | +++ account_statement_ext/statement_view.xml 2013-06-10 07:05:32 +0000 | |||
4876 | @@ -2,6 +2,7 @@ | |||
4877 | 2 | <openerp> | 2 | <openerp> |
4878 | 3 | <data> | 3 | <data> |
4879 | 4 | 4 | ||
4880 | 5 | <<<<<<< TREE | ||
4881 | 5 | <!-- Account Move Line : add statement_treasury_id --> | 6 | <!-- Account Move Line : add statement_treasury_id --> |
4882 | 6 | <record id="view_move_line_tree" model="ir.ui.view"> | 7 | <record id="view_move_line_tree" model="ir.ui.view"> |
4883 | 7 | <field name="name">account.move.line.tree</field> | 8 | <field name="name">account.move.line.tree</field> |
4884 | @@ -27,6 +28,8 @@ | |||
4885 | 27 | </field> | 28 | </field> |
4886 | 28 | </record> | 29 | </record> |
4887 | 29 | 30 | ||
4888 | 31 | ======= | ||
4889 | 32 | >>>>>>> MERGE-SOURCE | ||
4890 | 30 | <record id="statement_importer_view_form" model="ir.ui.view"> | 33 | <record id="statement_importer_view_form" model="ir.ui.view"> |
4891 | 31 | <field name="name">account.statement.profile.view</field> | 34 | <field name="name">account.statement.profile.view</field> |
4892 | 32 | <field name="model">account.statement.profile</field> | 35 | <field name="model">account.statement.profile</field> |
4893 | @@ -36,6 +39,7 @@ | |||
4894 | 36 | <separator string="" colspan="4"/> | 39 | <separator string="" colspan="4"/> |
4895 | 37 | <field name="name" select="1" /> | 40 | <field name="name" select="1" /> |
4896 | 38 | <field name="partner_id" select="1"/> | 41 | <field name="partner_id" select="1"/> |
4897 | 42 | <field name="company_id" select="1" groups="base.group_multi_company"/> | ||
4898 | 39 | <field name="journal_id" select="1"/> | 43 | <field name="journal_id" select="1"/> |
4899 | 40 | <field name="commission_account_id" /> | 44 | <field name="commission_account_id" /> |
4900 | 41 | <field name="commission_analytic_id" /> | 45 | <field name="commission_analytic_id" /> |
4901 | @@ -44,6 +48,7 @@ | |||
4902 | 44 | <field name="force_partner_on_bank"/> | 48 | <field name="force_partner_on_bank"/> |
4903 | 45 | <field name="balance_check"/> | 49 | <field name="balance_check"/> |
4904 | 46 | <field name="bank_statement_prefix"/> | 50 | <field name="bank_statement_prefix"/> |
4905 | 51 | <field name="message_ids" widget="mail_thread" placeholder="Share a note..." colspan="4"/> | ||
4906 | 47 | </form> | 52 | </form> |
4907 | 48 | </field> | 53 | </field> |
4908 | 49 | </record> | 54 | </record> |
4909 | @@ -56,6 +61,7 @@ | |||
4910 | 56 | <tree string="Import statement"> | 61 | <tree string="Import statement"> |
4911 | 57 | <field name="name" /> | 62 | <field name="name" /> |
4912 | 58 | <field name="partner_id" /> | 63 | <field name="partner_id" /> |
4913 | 64 | <field name="company_id" groups="base.group_multi_company"/> | ||
4914 | 59 | <field name="journal_id" /> | 65 | <field name="journal_id" /> |
4915 | 60 | <field name="commission_account_id" /> | 66 | <field name="commission_account_id" /> |
4916 | 61 | <field name="commission_analytic_id" /> | 67 | <field name="commission_analytic_id" /> |
4917 | @@ -72,6 +78,7 @@ | |||
4918 | 72 | <field name="view_mode">tree,form</field> | 78 | <field name="view_mode">tree,form</field> |
4919 | 73 | </record> | 79 | </record> |
4920 | 74 | 80 | ||
4921 | 81 | <<<<<<< TREE | ||
4922 | 75 | <menuitem string="Bank Statements Profile" action="action_treasury_statement_profile_tree" id="menu_treasury_statement_profile_tree" parent="account.menu_configuration_misc" sequence="30"/> | 82 | <menuitem string="Bank Statements Profile" action="action_treasury_statement_profile_tree" id="menu_treasury_statement_profile_tree" parent="account.menu_configuration_misc" sequence="30"/> |
4923 | 76 | 83 | ||
4924 | 77 | <record model="ir.ui.view" id="id_in_statement_line"> | 84 | <record model="ir.ui.view" id="id_in_statement_line"> |
4925 | @@ -87,19 +94,24 @@ | |||
4926 | 87 | </record> | 94 | </record> |
4927 | 88 | 95 | ||
4928 | 89 | 96 | ||
4929 | 97 | ======= | ||
4930 | 98 | <menuitem string="Bank Statements Profile" action="action_treasury_statement_profile_tree" id="menu_treasury_statement_profile_tree" parent="account.menu_configuration_misc" sequence="30"/> | ||
4931 | 99 | |||
4932 | 100 | |||
4933 | 101 | |||
4934 | 102 | >>>>>>> MERGE-SOURCE | ||
4935 | 90 | <record id="view_treasury_statement_search" model="ir.ui.view"> | 103 | <record id="view_treasury_statement_search" model="ir.ui.view"> |
4936 | 91 | <field name="name">account.bank.statement.search</field> | 104 | <field name="name">account.bank.statement.search</field> |
4937 | 92 | <field name="model">account.bank.statement</field> | 105 | <field name="model">account.bank.statement</field> |
4938 | 93 | <field name="inherit_id" ref="account.view_bank_statement_search"/> | 106 | <field name="inherit_id" ref="account.view_bank_statement_search"/> |
4939 | 94 | <field name="type">search</field> | ||
4940 | 95 | <field name="arch" type="xml"> | 107 | <field name="arch" type="xml"> |
4942 | 96 | <xpath expr="/search/group/field[@name='name']" position="before"> | 108 | <xpath expr="/search/field[@name='name']" position="before"> |
4943 | 97 | <field name="id"/> | 109 | <field name="id"/> |
4944 | 98 | <field name="profile_id"/> | 110 | <field name="profile_id"/> |
4945 | 99 | <field name="credit_partner_id"/> | 111 | <field name="credit_partner_id"/> |
4946 | 100 | <separator orientation="vertical"/> | 112 | <separator orientation="vertical"/> |
4947 | 101 | </xpath> | 113 | </xpath> |
4949 | 102 | <xpath expr="/search/group/field[@name='period_id']" position="replace"> | 114 | <xpath expr="/search/field[@name='period_id']" position="replace"> |
4950 | 103 | </xpath> | 115 | </xpath> |
4951 | 104 | <xpath expr="/search/group/filter[@string='Period']" position="replace"> | 116 | <xpath expr="/search/group/filter[@string='Period']" position="replace"> |
4952 | 105 | <filter string="Financial Partner" context="{'group_by': 'credit_partner_id'}" icon="terp-partner"/> | 117 | <filter string="Financial Partner" context="{'group_by': 'credit_partner_id'}" icon="terp-partner"/> |
4953 | @@ -125,6 +137,7 @@ | |||
4954 | 125 | </field> | 137 | </field> |
4955 | 126 | </record> | 138 | </record> |
4956 | 127 | 139 | ||
4957 | 140 | <<<<<<< TREE | ||
4958 | 128 | 141 | ||
4959 | 129 | <record id="view_treasury_statement_form" model="ir.ui.view"> | 142 | <record id="view_treasury_statement_form" model="ir.ui.view"> |
4960 | 130 | <field name="name">account.bank.statement.form</field> | 143 | <field name="name">account.bank.statement.form</field> |
4961 | @@ -197,6 +210,68 @@ | |||
4962 | 197 | </record> | 210 | </record> |
4963 | 198 | 211 | ||
4964 | 199 | 212 | ||
4965 | 213 | ======= | ||
4966 | 214 | |||
4967 | 215 | <record id="view_treasury_statement_form" model="ir.ui.view"> | ||
4968 | 216 | <field name="name">account.bank.statement.form</field> | ||
4969 | 217 | <field name="model">account.bank.statement</field> | ||
4970 | 218 | <field name="inherit_id" ref="account.view_bank_statement_form"/> | ||
4971 | 219 | <field name="type">form</field> | ||
4972 | 220 | <field name="arch" type="xml"> | ||
4973 | 221 | |||
4974 | 222 | <!-- Add before the group : profile and related infos --> | ||
4975 | 223 | <xpath expr="/form/sheet/group/group/field[@name='journal_id']" position="replace"> | ||
4976 | 224 | </xpath> | ||
4977 | 225 | |||
4978 | 226 | <xpath expr="/form/sheet/group" position="after"> | ||
4979 | 227 | <group> | ||
4980 | 228 | <field name="profile_id" select="1" required="1" on_change="onchange_imp_config_id(profile_id)" widget="selection"/> | ||
4981 | 229 | <separator string="Profile Details" colspan="4"/> | ||
4982 | 230 | <field name="journal_id" domain="[('type', '=', 'bank')]" on_change="onchange_journal_id(journal_id)" widget="selection"/> | ||
4983 | 231 | <field name="credit_partner_id"/> | ||
4984 | 232 | <field name="account_id" invisible="1"/> | ||
4985 | 233 | <field name="balance_check" invisible="1"/> | ||
4986 | 234 | </group> | ||
4987 | 235 | </xpath> | ||
4988 | 236 | |||
4989 | 237 | # Make balance visible or not depending on profile | ||
4990 | 238 | <xpath expr="/form/sheet/group/group/field[@name='balance_start']" position="attributes"> | ||
4991 | 239 | <attribute name="attrs">{'invisible':[('balance_check','=',False)]}</attribute> | ||
4992 | 240 | </xpath> | ||
4993 | 241 | <xpath expr="/form/sheet/group/group/field[@name='balance_end_real']" position="attributes"> | ||
4994 | 242 | <attribute name="attrs">{'invisible':[('balance_check','=',False)]}</attribute> | ||
4995 | 243 | </xpath> | ||
4996 | 244 | <xpath expr="/form/sheet/group/group/field[@name='balance_end_real']" position="after"> | ||
4997 | 245 | <field name="balance_end" widget="monetary" options='{"currency_field" : "currency"}' attrs="{'invisible':[('balance_check','=',False)]}"/> | ||
4998 | 246 | </xpath> | ||
4999 | 247 | |||
5000 | 248 | <xpath expr="/form/sheet/notebook/page/field/tree/field[@name='sequence']" position="after"> |