Merge lp:~sebastien.beau/c2c-financial-addons/c2c-financial-addons-fix-rule-m2m into lp:c2c-financial-addons
- c2c-financial-addons-fix-rule-m2m
- Merge into trunk
Proposed by
Sébastien BEAU - http://www.akretion.com
Status: | Superseded |
---|---|
Proposed branch: | lp:~sebastien.beau/c2c-financial-addons/c2c-financial-addons-fix-rule-m2m |
Merge into: | lp:c2c-financial-addons |
Diff against target: |
3107 lines (+2882/-2) 41 files modified
account_credit_management/__init__.py (+28/-0) account_credit_management/__openerp__.py (+47/-0) account_credit_management/credit_management_account.py (+220/-0) account_credit_management/credit_management_account_view.xml (+41/-0) account_credit_management/credit_management_company.py (+28/-0) account_credit_management/credit_management_company_view.xml (+15/-0) account_credit_management/credit_management_demo.xml (+33/-0) account_credit_management/credit_management_line.py (+181/-0) account_credit_management/credit_management_line_view.xml (+145/-0) account_credit_management/credit_management_partner.py (+36/-0) account_credit_management/credit_management_partner_view.xml (+25/-0) account_credit_management/credit_management_profile.py (+292/-0) account_credit_management/credit_management_profile_view.xml (+118/-0) account_credit_management/credit_management_run.py (+150/-0) account_credit_management/credit_management_run_view.xml (+65/-0) account_credit_management/data.xml (+173/-0) account_credit_management/report/__init__.py (+1/-0) account_credit_management/report/credit_management_summary.html.mako (+19/-0) account_credit_management/report/credit_management_summary.py (+37/-0) account_credit_management/report/report.xml (+12/-0) account_credit_management/scenarios/credit_management/00_credit_management_param.feature (+23/-0) account_credit_management/scenarios/credit_management/01_credit_management_partners.feature (+60/-0) account_credit_management/scenarios/credit_management/credit_management_01_data.feature (+224/-0) account_credit_management/scenarios/credit_management/credit_management_02_run.feature (+33/-0) account_credit_management/scenarios/credit_management/credit_management_03_run.feature (+26/-0) account_credit_management/scenarios/credit_management/step_definitions/credit_management.rb (+115/-0) account_credit_management/scenarios/run_command.txt (+1/-0) account_credit_management/security/ir.model.access.csv (+27/-0) account_credit_management/wizard/__init__.py (+24/-0) account_credit_management/wizard/credit_management_communication.py (+178/-0) account_credit_management/wizard/credit_management_mailer.py (+64/-0) account_credit_management/wizard/credit_management_mailer_view.xml (+44/-0) account_credit_management/wizard/credit_management_marker.py (+83/-0) account_credit_management/wizard/credit_management_marker_view.xml (+44/-0) account_credit_management/wizard/credit_management_printer.py (+74/-0) account_credit_management/wizard/credit_management_printer_view.xml (+47/-0) account_fiscal_position_rule_m2m/fiscal_rules.py (+2/-2) account_payment_ext/__init__.py (+32/-0) account_payment_ext/__openerp__.py (+50/-0) account_payment_ext/account_payment.py (+47/-0) account_payment_ext/account_payment_view.xml (+18/-0) |
To merge this branch: | bzr merge lp:~sebastien.beau/c2c-financial-addons/c2c-financial-addons-fix-rule-m2m |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Guewen Baconnier @ Camptocamp | Approve | ||
Alexandre Fayolle - camptocamp | Needs Fixing | ||
Review via email: mp+129642@code.launchpad.net |
This proposal has been superseded by a proposal from 2012-10-23.
Commit message
Description of the change
FIX a bug
To post a comment you must log in.
Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
review:
Needs Fixing
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
Hi Sébastien,
I merged your fix (slightly modified) from the revision 90 in our 6.1 branch.
Thanks
Guewen
review:
Approve
Unmerged revisions
- 90. By Sébastien BEAU - http://www.akretion.com
-
[FIX] account_
fiscal_ position_ rule_m2m: fix wizard to generate rule from template - 89. By Vincent Renaville@camptocamp
-
[ADD] account_payment ext
- 88. By Vincent Renaville@camptocamp
-
[MERGE] credit management
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'account_credit_management' | |||
2 | === added file 'account_credit_management/__init__.py' | |||
3 | --- account_credit_management/__init__.py 1970-01-01 00:00:00 +0000 | |||
4 | +++ account_credit_management/__init__.py 2012-10-15 10:14:35 +0000 | |||
5 | @@ -0,0 +1,28 @@ | |||
6 | 1 | # -*- coding: utf-8 -*- | ||
7 | 2 | ############################################################################## | ||
8 | 3 | # | ||
9 | 4 | # Author: Nicolas Bessi | ||
10 | 5 | # Copyright 2012 Camptocamp SA | ||
11 | 6 | # | ||
12 | 7 | # This program is free software: you can redistribute it and/or modify | ||
13 | 8 | # it under the terms of the GNU Affero General Public License as | ||
14 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
15 | 10 | # License, or (at your option) any later version. | ||
16 | 11 | # | ||
17 | 12 | # This program is distributed in the hope that it will be useful, | ||
18 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | 15 | # GNU Affero General Public License for more details. | ||
21 | 16 | # | ||
22 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
23 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
24 | 19 | # | ||
25 | 20 | ############################################################################## | ||
26 | 21 | from . import credit_management_run | ||
27 | 22 | from . import credit_management_line | ||
28 | 23 | from . import credit_management_account | ||
29 | 24 | from . import credit_management_partner | ||
30 | 25 | from . import credit_management_profile | ||
31 | 26 | from . import credit_management_company | ||
32 | 27 | import wizard | ||
33 | 28 | import report | ||
34 | 0 | 29 | ||
35 | === added file 'account_credit_management/__openerp__.py' | |||
36 | --- account_credit_management/__openerp__.py 1970-01-01 00:00:00 +0000 | |||
37 | +++ account_credit_management/__openerp__.py 2012-10-15 10:14:35 +0000 | |||
38 | @@ -0,0 +1,47 @@ | |||
39 | 1 | # -*- coding: utf-8 -*- | ||
40 | 2 | ############################################################################## | ||
41 | 3 | # | ||
42 | 4 | # Author: Nicolas Bessi | ||
43 | 5 | # Copyright 2012 Camptocamp SA | ||
44 | 6 | # | ||
45 | 7 | # This program is free software: you can redistribute it and/or modify | ||
46 | 8 | # it under the terms of the GNU Affero General Public License as | ||
47 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
48 | 10 | # License, or (at your option) any later version. | ||
49 | 11 | # | ||
50 | 12 | # This program is distributed in the hope that it will be useful, | ||
51 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
52 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
53 | 15 | # GNU Affero General Public License for more details. | ||
54 | 16 | # | ||
55 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
56 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
57 | 19 | # | ||
58 | 20 | ############################################################################## | ||
59 | 21 | {'name' : 'Account Credit Management', | ||
60 | 22 | 'version' : '0.1', | ||
61 | 23 | 'author' : 'Camptocamp', | ||
62 | 24 | 'maintainer': 'Camptocamp', | ||
63 | 25 | 'category': 'Finance', | ||
64 | 26 | 'complexity': "normal", # easy, normal, expert | ||
65 | 27 | 'depends' : ['base', 'account', 'email_template', 'report_webkit'], | ||
66 | 28 | 'description': """Credit control management TODO""", | ||
67 | 29 | 'website': 'http://www.camptocamp.com', | ||
68 | 30 | 'init_xml': ["data.xml"], | ||
69 | 31 | 'update_xml': ["credit_management_line_view.xml", | ||
70 | 32 | "credit_management_account_view.xml", | ||
71 | 33 | "credit_management_partner_view.xml", | ||
72 | 34 | "credit_management_profile_view.xml", | ||
73 | 35 | "credit_management_run_view.xml", | ||
74 | 36 | "credit_management_company_view.xml", | ||
75 | 37 | "wizard/credit_management_mailer_view.xml", | ||
76 | 38 | "wizard/credit_management_marker_view.xml", | ||
77 | 39 | "wizard/credit_management_printer_view.xml", | ||
78 | 40 | "report/report.xml", | ||
79 | 41 | "security/ir.model.access.csv",], | ||
80 | 42 | #"credit_management_demo.xml"], | ||
81 | 43 | 'demo_xml': ["credit_management_demo.xml"], | ||
82 | 44 | 'tests': [], | ||
83 | 45 | 'installable': True, | ||
84 | 46 | 'license': 'AGPL-3', | ||
85 | 47 | 'application': True} | ||
86 | 0 | 48 | ||
87 | === added file 'account_credit_management/credit_management_account.py' | |||
88 | --- account_credit_management/credit_management_account.py 1970-01-01 00:00:00 +0000 | |||
89 | +++ account_credit_management/credit_management_account.py 2012-10-15 10:14:35 +0000 | |||
90 | @@ -0,0 +1,220 @@ | |||
91 | 1 | # -*- coding: utf-8 -*- | ||
92 | 2 | ############################################################################## | ||
93 | 3 | # | ||
94 | 4 | # Author: Nicolas Bessi | ||
95 | 5 | # Copyright 2012 Camptocamp SA | ||
96 | 6 | # | ||
97 | 7 | # This program is free software: you can redistribute it and/or modify | ||
98 | 8 | # it under the terms of the GNU Affero General Public License as | ||
99 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
100 | 10 | # License, or (at your option) any later version. | ||
101 | 11 | # | ||
102 | 12 | # This program is distributed in the hope that it will be useful, | ||
103 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
104 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
105 | 15 | # GNU Affero General Public License for more details. | ||
106 | 16 | # | ||
107 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
108 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
109 | 19 | # | ||
110 | 20 | ############################################################################## | ||
111 | 21 | from datetime import datetime | ||
112 | 22 | import operator | ||
113 | 23 | from openerp.osv.orm import Model, fields | ||
114 | 24 | from openerp.tools.translate import _ | ||
115 | 25 | from openerp.addons.account_credit_management import credit_management_run | ||
116 | 26 | |||
117 | 27 | class AccountAccount(Model): | ||
118 | 28 | """Add a link to a credit management profile on account account""" | ||
119 | 29 | |||
120 | 30 | |||
121 | 31 | def _check_account_type_compatibility(self, cursor, uid, acc_ids, context=None): | ||
122 | 32 | """We check that account is of type reconcile""" | ||
123 | 33 | if not isinstance(acc_ids, list): | ||
124 | 34 | acc_ids = [acc_ids] | ||
125 | 35 | for acc in self.browse(cursor, uid, acc_ids, context): | ||
126 | 36 | if acc.credit_profile_id and not acc.reconcile: | ||
127 | 37 | return False | ||
128 | 38 | return True | ||
129 | 39 | |||
130 | 40 | _inherit = "account.account" | ||
131 | 41 | _description = """Add a link to a credit profile""" | ||
132 | 42 | _columns = {'credit_profile_id': fields.many2one('credit.management.profile', | ||
133 | 43 | 'Credit management profile', | ||
134 | 44 | help=("Define global credit profile" | ||
135 | 45 | "order is account partner invoice")), | ||
136 | 46 | |||
137 | 47 | 'credit_management_line_ids': fields.one2many('credit.management.line', | ||
138 | 48 | 'account_id', | ||
139 | 49 | string='Credit Lines', | ||
140 | 50 | readonly=True)} | ||
141 | 51 | |||
142 | 52 | _constraints = [(_check_account_type_compatibility, | ||
143 | 53 | _('You can not set a credit profile on a non reconciliable account'), | ||
144 | 54 | ['credit_profile_id'])] | ||
145 | 55 | |||
146 | 56 | class AccountInvoice(Model): | ||
147 | 57 | """Add a link to a credit management profile on account account""" | ||
148 | 58 | |||
149 | 59 | _inherit = "account.invoice" | ||
150 | 60 | _description = """Add a link to a credit profile""" | ||
151 | 61 | _columns = {'credit_profile_id': fields.many2one('credit.management.profile', | ||
152 | 62 | 'Credit management profile', | ||
153 | 63 | help=("Define global credit profile" | ||
154 | 64 | "order is account partner invoice")), | ||
155 | 65 | |||
156 | 66 | 'credit_management_line_ids': fields.one2many('credit.management.line', | ||
157 | 67 | 'account_id', | ||
158 | 68 | string='Credit Lines', | ||
159 | 69 | readonly=True)} | ||
160 | 70 | |||
161 | 71 | def action_move_create(self, cursor, uid, ids, context=None): | ||
162 | 72 | """We ensure writing of invoice id in move line because | ||
163 | 73 | Trigger field may not work without account_voucher addon""" | ||
164 | 74 | res = super(AccountInvoice, self).action_move_create(cursor, uid, ids, context=context) | ||
165 | 75 | for inv in self.browse(cursor, uid, ids, context=context): | ||
166 | 76 | if inv.move_id: | ||
167 | 77 | for line in inv.move_id.line_id: | ||
168 | 78 | line.write({'invoice_id': inv.id}) | ||
169 | 79 | return res | ||
170 | 80 | |||
171 | 81 | |||
172 | 82 | class AccountMoveLine(Model): | ||
173 | 83 | """Add a function that compute the residual amount using a follow up date | ||
174 | 84 | Add relation between move line and invoicex""" | ||
175 | 85 | |||
176 | 86 | _inherit = "account.move.line" | ||
177 | 87 | # Store fields has strange behavior with voucher module we had to overwrite invoice | ||
178 | 88 | |||
179 | 89 | |||
180 | 90 | # def _invoice_id(self, cursor, user, ids, name, arg, context=None): | ||
181 | 91 | # #Code taken from OpenERP account addon | ||
182 | 92 | # invoice_obj = self.pool.get('account.invoice') | ||
183 | 93 | # res = {} | ||
184 | 94 | # for line_id in ids: | ||
185 | 95 | # res[line_id] = False | ||
186 | 96 | # cursor.execute('SELECT l.id, i.id ' \ | ||
187 | 97 | # 'FROM account_move_line l, account_invoice i ' \ | ||
188 | 98 | # 'WHERE l.move_id = i.move_id ' \ | ||
189 | 99 | # 'AND l.id IN %s', | ||
190 | 100 | # (tuple(ids),)) | ||
191 | 101 | # invoice_ids = [] | ||
192 | 102 | # for line_id, invoice_id in cursor.fetchall(): | ||
193 | 103 | # res[line_id] = invoice_id | ||
194 | 104 | # invoice_ids.append(invoice_id) | ||
195 | 105 | # invoice_names = {False: ''} | ||
196 | 106 | # for invoice_id, name in invoice_obj.name_get(cursor, user, invoice_ids, context=context): | ||
197 | 107 | # invoice_names[invoice_id] = name | ||
198 | 108 | # for line_id in res.keys(): | ||
199 | 109 | # invoice_id = res[line_id] | ||
200 | 110 | # res[line_id] = (invoice_id, invoice_names[invoice_id]) | ||
201 | 111 | # return res | ||
202 | 112 | |||
203 | 113 | # def _get_invoice(self, cursor, uid, ids, context=None): | ||
204 | 114 | # result = set() | ||
205 | 115 | # for line in self.pool.get('account.invoice').browse(cursor, uid, ids, context=context): | ||
206 | 116 | # if line.move_id: | ||
207 | 117 | # ids = [x.id for x in line.move_id.line_id or []] | ||
208 | 118 | # return list(result) | ||
209 | 119 | |||
210 | 120 | # _columns = {'invoice_id': fields.function(_invoice_id, string='Invoice', | ||
211 | 121 | # type='many2one', relation='account.invoice', | ||
212 | 122 | # store={'account.invoice': (_get_invoice, ['move_id'], 20)})} | ||
213 | 123 | |||
214 | 124 | _columns = {'invoice_id': fields.many2one('account.invoice', 'Invoice')} | ||
215 | 125 | |||
216 | 126 | def _get_payment_and_credit_lines(self, moveline_array, lookup_date): | ||
217 | 127 | credit_lines = [] | ||
218 | 128 | payment_lines = [] | ||
219 | 129 | for line in moveline_array: | ||
220 | 130 | if self._should_exlude_line(line): | ||
221 | 131 | continue | ||
222 | 132 | if line.account_id.type == 'receivable' and line.debit: | ||
223 | 133 | credit_lines.append(line) | ||
224 | 134 | else: | ||
225 | 135 | if line.reconcile_partial_id: | ||
226 | 136 | payment_lines.append(line) | ||
227 | 137 | credit_lines.sort(key=operator.attrgetter('date')) | ||
228 | 138 | payment_lines.sort(key=operator.attrgetter('date')) | ||
229 | 139 | return (credit_lines, payment_lines) | ||
230 | 140 | |||
231 | 141 | def _validate_line_currencies(self, credit_lines): | ||
232 | 142 | """Raise an excpetion if there is lines with different currency""" | ||
233 | 143 | if len(credit_lines) == 0: | ||
234 | 144 | return True | ||
235 | 145 | currency = credit_lines[0].currency_id.id | ||
236 | 146 | if not all(obj.currency_id.id == currency for obj in credit_lines): | ||
237 | 147 | raise Exception('Not all line of move line are in the same currency') | ||
238 | 148 | |||
239 | 149 | def _get_value_amount(self, mv_line_br): | ||
240 | 150 | if mv_line_br.currency_id: | ||
241 | 151 | return mv_line_br.amount_currency | ||
242 | 152 | else: | ||
243 | 153 | return mv_line_br.debit - mv_line_br.credit | ||
244 | 154 | |||
245 | 155 | def _validate_partial(self, credit_lines): | ||
246 | 156 | if len(credit_lines) == 0: | ||
247 | 157 | return True | ||
248 | 158 | else: | ||
249 | 159 | line_with_partial = 0 | ||
250 | 160 | for line in credit_lines: | ||
251 | 161 | if not line.reconcile_partial_id: | ||
252 | 162 | line_with_partial += 1 | ||
253 | 163 | if line_with_partial and line_with_partial != len(credit_lines): | ||
254 | 164 | raise Exception('Can not compute credit line if multiple' | ||
255 | 165 | ' lines are not all linked to a partial') | ||
256 | 166 | |||
257 | 167 | def _get_applicable_payment_lines(self, credit_line, payment_lines): | ||
258 | 168 | applicable_payment = [] | ||
259 | 169 | for pay_line in payment_lines: | ||
260 | 170 | if datetime.strptime(pay_line.date, "%Y-%m-%d").date() \ | ||
261 | 171 | <= datetime.strptime(credit_line.date, "%Y-%m-%d").date(): | ||
262 | 172 | applicable_payment.append(pay_line) | ||
263 | 173 | return applicable_payment | ||
264 | 174 | |||
265 | 175 | def _compute_partial_reconcile_residual(self, move_lines, lookup_date, move_id, memoizer): | ||
266 | 176 | """ Compute open amount of multiple credit lines linked to multiple payment lines""" | ||
267 | 177 | credit_lines, payment_lines = self._get_payment_and_credit_lines(move_lines, lookup_date, memoizer) | ||
268 | 178 | self._validate_line_currencies(credit_lines) | ||
269 | 179 | self._validate_line_currencies(payment_lines) | ||
270 | 180 | self._validate_partial(credit_lines) | ||
271 | 181 | # memoizer structure move_id : {move_line_id: open_amount} | ||
272 | 182 | # paymnent line and credit line are sorted by date | ||
273 | 183 | rest = 0.0 | ||
274 | 184 | for credit_line in credit_lines: | ||
275 | 185 | applicable_payment = self._get_applicable_payment_lines(credit_line, payment_lines) | ||
276 | 186 | paid_amount = 0.0 | ||
277 | 187 | for pay_line in applicable_payment: | ||
278 | 188 | paid_amount += self._get_value_amount(pay_line) | ||
279 | 189 | balance_amount = self._get_value_amount(credit_lines) - (paid_amount + rest) | ||
280 | 190 | memoizer[move_id][credit_line.id] = balance_amount | ||
281 | 191 | if balance_amount < 0.0: | ||
282 | 192 | rest = balance_amount | ||
283 | 193 | else: | ||
284 | 194 | rest = 0.0 | ||
285 | 195 | return memoizer | ||
286 | 196 | |||
287 | 197 | def _compute_fully_open_amount(self, move_lines, lookup_date, move_id, memoizer): | ||
288 | 198 | for move_line in move_lines: | ||
289 | 199 | memoizer[move_id][move_line.id] = self._get_value_amount(move_line) | ||
290 | 200 | return memoizer | ||
291 | 201 | |||
292 | 202 | |||
293 | 203 | def _amount_residual_from_date(self, cursor, uid, mv_line_br, lookup_date, context=None): | ||
294 | 204 | """ | ||
295 | 205 | Code from function _amount_residual of account/account_move_line.py does not take | ||
296 | 206 | in account mulitple line payment and reconciliation. We have to rewrite it | ||
297 | 207 | Code computes residual amount at lookup date for mv_line_br in entry | ||
298 | 208 | """ | ||
299 | 209 | memoizer = credit_management_run.memoizers['credit_line_residuals'] | ||
300 | 210 | move_id = mv_line_br.move_id.id | ||
301 | 211 | if mv_line_br.move_id.id in memoizer: | ||
302 | 212 | pass # get back value | ||
303 | 213 | else: | ||
304 | 214 | memoizer[move_id] = {} | ||
305 | 215 | move_lines = mv_line_br.move_id.line_id | ||
306 | 216 | if mv_line_br.reconcile_partial_id: | ||
307 | 217 | self._compute_partial_reconcile_residual(move_lines, lookup_date, move_id, memoizer) | ||
308 | 218 | else: | ||
309 | 219 | self._compute_fully_open_amount(move_lines, lookup_date, move_id, memoizer) | ||
310 | 220 | return memoizer[move_id][mv_line_br.id] | ||
311 | 0 | 221 | ||
312 | === added file 'account_credit_management/credit_management_account_view.xml' | |||
313 | --- account_credit_management/credit_management_account_view.xml 1970-01-01 00:00:00 +0000 | |||
314 | +++ account_credit_management/credit_management_account_view.xml 2012-10-15 10:14:35 +0000 | |||
315 | @@ -0,0 +1,41 @@ | |||
316 | 1 | <openerp> | ||
317 | 2 | <data> | ||
318 | 3 | |||
319 | 4 | <record id="account_followup_form_view" model="ir.ui.view"> | ||
320 | 5 | <field name="name">account.followup.form.view</field> | ||
321 | 6 | <field name="model">account.account</field> | ||
322 | 7 | <field name="inherit_id" ref="account.view_account_form" /> | ||
323 | 8 | <field name="type">form</field> | ||
324 | 9 | <field name="arch" type="xml"> | ||
325 | 10 | <field name="reconcile" position="after"> | ||
326 | 11 | <field name="credit_profile_id" groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_user"/> | ||
327 | 12 | </field> | ||
328 | 13 | </field> | ||
329 | 14 | </record> | ||
330 | 15 | |||
331 | 16 | <act_window | ||
332 | 17 | id="act_account_credit_relation_relation" | ||
333 | 18 | name="Credit lines" | ||
334 | 19 | groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_user" | ||
335 | 20 | domain="[('account_id', '=', active_id)]" | ||
336 | 21 | res_model="credit.management.line" | ||
337 | 22 | src_model="account.account"/> | ||
338 | 23 | |||
339 | 24 | <record id="invoice_followup_form_view" model="ir.ui.view"> | ||
340 | 25 | <field name="name">invoice.followup.form.view</field> | ||
341 | 26 | <field name="model">account.invoice</field> | ||
342 | 27 | <field name="inherit_id" ref="account.invoice_form" /> | ||
343 | 28 | <field name="type">form</field> | ||
344 | 29 | <field name="arch" type="xml"> | ||
345 | 30 | <notebook position="inside"> | ||
346 | 31 | <page string="Credit Management" | ||
347 | 32 | groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_user,group_account_credit_management_info"> | ||
348 | 33 | <field name="credit_profile_id"/> | ||
349 | 34 | <field name="credit_management_line_ids" colspan="4" nolabel="1"/> | ||
350 | 35 | </page> | ||
351 | 36 | </notebook> | ||
352 | 37 | </field> | ||
353 | 38 | </record> | ||
354 | 39 | |||
355 | 40 | </data> | ||
356 | 41 | </openerp> | ||
357 | 0 | 42 | ||
358 | === added file 'account_credit_management/credit_management_company.py' | |||
359 | --- account_credit_management/credit_management_company.py 1970-01-01 00:00:00 +0000 | |||
360 | +++ account_credit_management/credit_management_company.py 2012-10-15 10:14:35 +0000 | |||
361 | @@ -0,0 +1,28 @@ | |||
362 | 1 | # -*- coding: utf-8 -*- | ||
363 | 2 | ############################################################################## | ||
364 | 3 | # | ||
365 | 4 | # Author: Nicolas Bessi | ||
366 | 5 | # Copyright 2012 Camptocamp SA | ||
367 | 6 | # | ||
368 | 7 | # This program is free software: you can redistribute it and/or modify | ||
369 | 8 | # it under the terms of the GNU Affero General Public License as | ||
370 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
371 | 10 | # License, or (at your option) any later version. | ||
372 | 11 | # | ||
373 | 12 | # This program is distributed in the hope that it will be useful, | ||
374 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
375 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
376 | 15 | # GNU Affero General Public License for more details. | ||
377 | 16 | # | ||
378 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
379 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
380 | 19 | # | ||
381 | 20 | ############################################################################## | ||
382 | 21 | from openerp.osv.orm import Model, fields | ||
383 | 22 | |||
384 | 23 | class ResCompany(Model): | ||
385 | 24 | _inherit = "res.company" | ||
386 | 25 | |||
387 | 26 | _columns = {"credit_management_tolerance": fields.float('Credit Tolerance')} | ||
388 | 27 | |||
389 | 28 | _defaults = {"credit_management_tolerance": 0.1} | ||
390 | 0 | 29 | ||
391 | === added file 'account_credit_management/credit_management_company_view.xml' | |||
392 | --- account_credit_management/credit_management_company_view.xml 1970-01-01 00:00:00 +0000 | |||
393 | +++ account_credit_management/credit_management_company_view.xml 2012-10-15 10:14:35 +0000 | |||
394 | @@ -0,0 +1,15 @@ | |||
395 | 1 | <openerp> | ||
396 | 2 | <data> | ||
397 | 3 | <record id="credit_management_company_form" model="ir.ui.view"> | ||
398 | 4 | <field name="name">credit.management.company.form</field> | ||
399 | 5 | <field name="model">res.company</field> | ||
400 | 6 | <field name="type">form</field> | ||
401 | 7 | <field name="inherit_id" ref="base.view_company_form"/> | ||
402 | 8 | <field name="arch" type="xml"> | ||
403 | 9 | <field name="currency_id" position="after"> | ||
404 | 10 | <field name="credit_management_tolerance"/> | ||
405 | 11 | </field> | ||
406 | 12 | </field> | ||
407 | 13 | </record> | ||
408 | 14 | </data> | ||
409 | 15 | </openerp> | ||
410 | 0 | 16 | ||
411 | === added file 'account_credit_management/credit_management_demo.xml' | |||
412 | --- account_credit_management/credit_management_demo.xml 1970-01-01 00:00:00 +0000 | |||
413 | +++ account_credit_management/credit_management_demo.xml 2012-10-15 10:14:35 +0000 | |||
414 | @@ -0,0 +1,33 @@ | |||
415 | 1 | <openerp> | ||
416 | 2 | <data> | ||
417 | 3 | <record id="a_recv_1" model="account.account"> | ||
418 | 4 | <field name="code">X11002-a</field> | ||
419 | 5 | <field name="name">B2B Debtors - (test)</field> | ||
420 | 6 | <field ref="account.cas" name="parent_id"/> | ||
421 | 7 | <field name="type">receivable</field> | ||
422 | 8 | <field eval="True" name="reconcile"/> | ||
423 | 9 | <field name="credit_profile_id" ref="credit_management_no_follow"/> | ||
424 | 10 | <field name="user_type" ref="account.data_account_type_receivable"/> | ||
425 | 11 | </record> | ||
426 | 12 | |||
427 | 13 | <record id="a_recv_2" model="account.account"> | ||
428 | 14 | <field name="code">X11002-b</field> | ||
429 | 15 | <field name="name">B2C Debtors - (test)</field> | ||
430 | 16 | <field ref="account.cas" name="parent_id"/> | ||
431 | 17 | <field name="type">receivable</field> | ||
432 | 18 | <field eval="True" name="reconcile"/> | ||
433 | 19 | <field name="credit_profile_id" ref="credit_management_2_time"/> | ||
434 | 20 | <field name="user_type" ref="account.data_account_type_receivable"/> | ||
435 | 21 | </record> | ||
436 | 22 | |||
437 | 23 | <record id="a_recv_3" model="account.account"> | ||
438 | 24 | <field name="code">X11002-c</field> | ||
439 | 25 | <field name="name">New Debtors - (test)</field> | ||
440 | 26 | <field ref="account.cas" name="parent_id"/> | ||
441 | 27 | <field name="type">receivable</field> | ||
442 | 28 | <field eval="True" name="reconcile"/> | ||
443 | 29 | <field name="credit_profile_id" ref="credit_management_3_time"/> | ||
444 | 30 | <field name="user_type" ref="account.data_account_type_receivable"/> | ||
445 | 31 | </record> | ||
446 | 32 | </data> | ||
447 | 33 | </openerp> | ||
448 | 0 | 34 | ||
449 | === added file 'account_credit_management/credit_management_line.py' | |||
450 | --- account_credit_management/credit_management_line.py 1970-01-01 00:00:00 +0000 | |||
451 | +++ account_credit_management/credit_management_line.py 2012-10-15 10:14:35 +0000 | |||
452 | @@ -0,0 +1,181 @@ | |||
453 | 1 | # -*- coding: utf-8 -*- | ||
454 | 2 | ############################################################################## | ||
455 | 3 | # | ||
456 | 4 | # Author: Nicolas Bessi | ||
457 | 5 | # Copyright 2012 Camptocamp SA | ||
458 | 6 | # | ||
459 | 7 | # This program is free software: you can redistribute it and/or modify | ||
460 | 8 | # it under the terms of the GNU Affero General Public License as | ||
461 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
462 | 10 | # License, or (at your option) any later version. | ||
463 | 11 | # | ||
464 | 12 | # This program is distributed in the hope that it will be useful, | ||
465 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
466 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
467 | 15 | # GNU Affero General Public License for more details. | ||
468 | 16 | # | ||
469 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
470 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
471 | 19 | # | ||
472 | 20 | ############################################################################## | ||
473 | 21 | import logging | ||
474 | 22 | |||
475 | 23 | from openerp.osv.orm import Model, fields | ||
476 | 24 | import pooler | ||
477 | 25 | #from datetime import datetime | ||
478 | 26 | |||
479 | 27 | logger = logging.getLogger('credit.line.management') | ||
480 | 28 | |||
481 | 29 | class CreditManagementLine (Model): | ||
482 | 30 | """A credit Management line decribe a line of amount due by a customer. | ||
483 | 31 | It is linked to all required financial account. | ||
484 | 32 | It has various state draft open to be send send. For more information about | ||
485 | 33 | usage please read __openerp__.py file""" | ||
486 | 34 | |||
487 | 35 | _name = "credit.management.line" | ||
488 | 36 | _description = """A credit Management line""" | ||
489 | 37 | _rec_name = "id" | ||
490 | 38 | |||
491 | 39 | _columns = {'date': fields.date('Controlling date', required=True), | ||
492 | 40 | # maturity date of related move line we do not use a related field in order to | ||
493 | 41 | # allow manual changes | ||
494 | 42 | 'date_due': fields.date('Due date', | ||
495 | 43 | required=True, | ||
496 | 44 | readonly=True, | ||
497 | 45 | states={'draft': [('readonly', False)]}), | ||
498 | 46 | |||
499 | 47 | 'date_sent': fields.date('Sent date', | ||
500 | 48 | readonly=True, | ||
501 | 49 | states={'draft': [('readonly', False)]}), | ||
502 | 50 | |||
503 | 51 | 'state': fields.selection([('draft', 'Draft'), | ||
504 | 52 | ('to_be_sent', 'To be sent'), | ||
505 | 53 | ('sent', 'Done'), | ||
506 | 54 | ('error', 'Error'), | ||
507 | 55 | ('mail_error', 'Mailing Error')], | ||
508 | 56 | 'State', required=True, readonly=True), | ||
509 | 57 | |||
510 | 58 | 'canal': fields.selection([('manual', 'Manual'), | ||
511 | 59 | ('mail', 'Mail')], | ||
512 | 60 | 'Canal', required=True, | ||
513 | 61 | readonly=True, | ||
514 | 62 | states={'draft': [('readonly', False)]}), | ||
515 | 63 | |||
516 | 64 | 'invoice_id': fields.many2one('account.invoice', 'Invoice', readonly=True), | ||
517 | 65 | 'partner_id': fields.many2one('res.partner', "Partner", required=True), | ||
518 | 66 | 'amount_due': fields.float('Due Amount Tax inc.', required=True, readonly=True), | ||
519 | 67 | 'balance_due': fields.float('Due balance', required=True, readonly=True), | ||
520 | 68 | 'mail_message_id': fields.many2one('mail.message', 'Sent mail', readonly=True), | ||
521 | 69 | |||
522 | 70 | 'move_line_id': fields.many2one('account.move.line', 'Move line', | ||
523 | 71 | required=True, readonly=True), | ||
524 | 72 | |||
525 | 73 | 'account_id': fields.related('move_line_id', 'account_id', type='many2one', | ||
526 | 74 | relation='account.account', string='Account', | ||
527 | 75 | store=True, readonly=True), | ||
528 | 76 | |||
529 | 77 | 'currency_id': fields.related('move_line_id', 'currency_id', type='many2one', | ||
530 | 78 | relation='res.currency', string='Currency', | ||
531 | 79 | store=True, readonly=True), | ||
532 | 80 | |||
533 | 81 | 'company_id': fields.related('move_line_id', 'company_id', type='many2one', | ||
534 | 82 | relation='res.company', string='Company', | ||
535 | 83 | store=True, readonly=True), | ||
536 | 84 | |||
537 | 85 | # we can allow a manual change of profile in draft state | ||
538 | 86 | 'profile_rule_id':fields.many2one('credit.management.profile.rule', | ||
539 | 87 | 'Overdue Rule', required=True, readonly=True, | ||
540 | 88 | states={'draft': [('readonly', False)]}), | ||
541 | 89 | |||
542 | 90 | 'profile_id': fields.related('profile_rule_id', 'profile_id', type='many2one', | ||
543 | 91 | relation='credit.management.profile', string='Profile', | ||
544 | 92 | store=True, readonly=True), | ||
545 | 93 | |||
546 | 94 | 'level': fields.related('profile_rule_id', 'level', type='float', | ||
547 | 95 | relation='credit.management.profile', string='Level', | ||
548 | 96 | store=True, readonly=True),} | ||
549 | 97 | |||
550 | 98 | |||
551 | 99 | _defaults = {'state': 'draft'} | ||
552 | 100 | |||
553 | 101 | def _update_from_mv_line(self, cursor, uid, ids, mv_line_br, rule_br, | ||
554 | 102 | lookup_date, context=None): | ||
555 | 103 | """hook function to update line if required""" | ||
556 | 104 | context = context or {} | ||
557 | 105 | return [] | ||
558 | 106 | |||
559 | 107 | def _create_from_mv_line(self, cursor, uid, ids, mv_line_br, | ||
560 | 108 | rule_br, lookup_date, context=None): | ||
561 | 109 | """Create credit line""" | ||
562 | 110 | acc_line_obj = self.pool.get('account.move.line') | ||
563 | 111 | context = context or {} | ||
564 | 112 | data_dict = {} | ||
565 | 113 | data_dict['date'] = lookup_date | ||
566 | 114 | data_dict['date_due'] = mv_line_br.date_maturity | ||
567 | 115 | data_dict['state'] = 'draft' | ||
568 | 116 | data_dict['canal'] = rule_br.canal | ||
569 | 117 | data_dict['invoice_id'] = (mv_line_br.invoice_id and mv_line_br.invoice_id.id | ||
570 | 118 | or False) | ||
571 | 119 | data_dict['partner_id'] = mv_line_br.partner_id.id | ||
572 | 120 | data_dict['amount_due'] = (mv_line_br.amount_currency or mv_line_br.debit | ||
573 | 121 | or mv_line_br.credit) | ||
574 | 122 | data_dict['balance_due'] = acc_line_obj._amount_residual_from_date(cursor, uid, mv_line_br, | ||
575 | 123 | lookup_date, context=context) | ||
576 | 124 | data_dict['profile_rule_id'] = rule_br.id | ||
577 | 125 | data_dict['company_id'] = mv_line_br.company_id.id | ||
578 | 126 | data_dict['move_line_id'] = mv_line_br.id | ||
579 | 127 | return [self.create(cursor, uid, data_dict)] | ||
580 | 128 | |||
581 | 129 | |||
582 | 130 | def create_or_update_from_mv_lines(self, cursor, uid, ids, lines, | ||
583 | 131 | rule_id, lookup_date, errors=None, context=None): | ||
584 | 132 | """Create or update line base on rules""" | ||
585 | 133 | context = context or {} | ||
586 | 134 | currency_obj = self.pool.get('res.currency') | ||
587 | 135 | rule_obj = self.pool.get('credit.management.profile.rule') | ||
588 | 136 | ml_obj = self.pool.get('account.move.line') | ||
589 | 137 | rule = rule_obj.browse(cursor, uid, rule_id, context) | ||
590 | 138 | current_lvl = rule.level | ||
591 | 139 | credit_line_ids = [] | ||
592 | 140 | user = self.pool.get('res.users').browse(cursor, uid, uid) | ||
593 | 141 | tolerance_base = user.company_id.credit_management_tolerance | ||
594 | 142 | tolerance = {} | ||
595 | 143 | currency_ids = currency_obj.search(cursor, uid, []) | ||
596 | 144 | |||
597 | 145 | acc_line_obj = self.pool.get('account.move.line') | ||
598 | 146 | for c_id in currency_ids: | ||
599 | 147 | tmp = currency_obj.compute(cursor, uid, c_id, | ||
600 | 148 | user.company_id.currency_id.id, tolerance_base) | ||
601 | 149 | tolerance[c_id] = tmp | ||
602 | 150 | |||
603 | 151 | existings = self.search(cursor, uid, [('move_line_id', 'in', lines), | ||
604 | 152 | ('level', '=', current_lvl)]) | ||
605 | 153 | db, pool = pooler.get_db_and_pool(cursor.dbname) | ||
606 | 154 | for line in ml_obj.browse(cursor, uid, lines, context): | ||
607 | 155 | # we want to create as many line as possible | ||
608 | 156 | local_cr = db.cursor() | ||
609 | 157 | try: | ||
610 | 158 | if line.id in existings: | ||
611 | 159 | # does nothing just a hook | ||
612 | 160 | credit_line_ids += self._update_from_mv_line(local_cr, uid, ids, | ||
613 | 161 | line, rule, lookup_date, | ||
614 | 162 | context=context) | ||
615 | 163 | else: | ||
616 | 164 | # as we use memoizer pattern this has almost no cost to get it | ||
617 | 165 | # multiple time | ||
618 | 166 | open_amount = acc_line_obj._amount_residual_from_date(cursor, uid, line, | ||
619 | 167 | lookup_date, context=context) | ||
620 | 168 | |||
621 | 169 | if open_amount > tolerance.get(line.currency_id.id, tolerance_base): | ||
622 | 170 | credit_line_ids += self._create_from_mv_line(local_cr, uid, ids, | ||
623 | 171 | line, rule, lookup_date, | ||
624 | 172 | context=context) | ||
625 | 173 | except Exception, exc: | ||
626 | 174 | logger.error(exc) | ||
627 | 175 | if errors: | ||
628 | 176 | errors.append(unicode(exc)) #obj-c common pattern | ||
629 | 177 | local_cr.rollback() | ||
630 | 178 | finally: | ||
631 | 179 | local_cr.commit() | ||
632 | 180 | local_cr.close() | ||
633 | 181 | return credit_line_ids | ||
634 | 0 | 182 | ||
635 | === added file 'account_credit_management/credit_management_line_view.xml' | |||
636 | --- account_credit_management/credit_management_line_view.xml 1970-01-01 00:00:00 +0000 | |||
637 | +++ account_credit_management/credit_management_line_view.xml 2012-10-15 10:14:35 +0000 | |||
638 | @@ -0,0 +1,145 @@ | |||
639 | 1 | <openerp> | ||
640 | 2 | <data> | ||
641 | 3 | <record id="credit_management_line_form" model="ir.ui.view"> | ||
642 | 4 | <field name="name">credit.management.line.form</field> | ||
643 | 5 | <field name="model">credit.management.line</field> | ||
644 | 6 | <field name="type">form</field> | ||
645 | 7 | <field name="arch" type="xml"> | ||
646 | 8 | <form> | ||
647 | 9 | <field name="date"/> | ||
648 | 10 | <field name="date_due"/> | ||
649 | 11 | <field name="date_sent"/> | ||
650 | 12 | <field name="level"/> | ||
651 | 13 | <field name="state"/> | ||
652 | 14 | <field name="canal"/> | ||
653 | 15 | <field name="invoice_id"/> | ||
654 | 16 | <field name="partner_id"/> | ||
655 | 17 | <!-- <field name="address_id" domain="[('partner_id', '=', partner_id)]"/> --> | ||
656 | 18 | <field name="amount_due"/> | ||
657 | 19 | <field name="balance_due"/> | ||
658 | 20 | <field name="currency_id"/> | ||
659 | 21 | <field name="move_line_id"/> | ||
660 | 22 | <field name="account_id"/> | ||
661 | 23 | <field name="profile_rule_id"/> | ||
662 | 24 | <field name="profile_id"/> | ||
663 | 25 | <field name="mail_message_id"/> | ||
664 | 26 | </form> | ||
665 | 27 | </field> | ||
666 | 28 | </record> | ||
667 | 29 | |||
668 | 30 | <record id="credit_management_line_search" model="ir.ui.view"> | ||
669 | 31 | <field name="name">Credit lines</field> | ||
670 | 32 | <field name="model">credit.management.lines</field> | ||
671 | 33 | <field name="type">search</field> | ||
672 | 34 | <field name="arch" type="xml"> | ||
673 | 35 | <search string="Search credit lines Items"> | ||
674 | 36 | <group> | ||
675 | 37 | <filter icon="terp-document-new" string="New" | ||
676 | 38 | domain="[('state', '=', 'draft')]" | ||
677 | 39 | help="New lines"/> | ||
678 | 40 | <filter icon="terp-dolar_ok!" string="To be sent" | ||
679 | 41 | domain="[('state', '=', 'to_be_sent')]" | ||
680 | 42 | help="New lines"/> | ||
681 | 43 | <filter icon="terp-check" string="Sent" | ||
682 | 44 | domain="[('state', '=', 'sent')]" | ||
683 | 45 | help="New lines"/> | ||
684 | 46 | <separator orientation="vertical"/> | ||
685 | 47 | <filter icon="terp-gtk-stop" string="Error" | ||
686 | 48 | domain="[('state', 'in', ('error', 'mail_error'))]" | ||
687 | 49 | help="New lines"/> | ||
688 | 50 | <separator orientation="vertical"/> | ||
689 | 51 | |||
690 | 52 | <field name="date"/> | ||
691 | 53 | <field name="level"/> | ||
692 | 54 | <field name="partner_id"/> | ||
693 | 55 | <field name="account_id"/> | ||
694 | 56 | <newline/> | ||
695 | 57 | <field name="invoice_id"/> | ||
696 | 58 | <field name="profile_id"/> | ||
697 | 59 | <field name="profile_rule_id"/> | ||
698 | 60 | <field name ="canal" /> | ||
699 | 61 | </group> | ||
700 | 62 | <newline/> | ||
701 | 63 | |||
702 | 64 | <group expand="0" string="Group By..."> | ||
703 | 65 | <separator orientation="vertical"/> | ||
704 | 66 | <filter domain='[]' context="{'group_by': 'date'}" | ||
705 | 67 | icon="terp-go-month" string="Run date"/> | ||
706 | 68 | <separator orientation="vertical"/> | ||
707 | 69 | <filter domain='[]' context="{'group_by': 'level'}" | ||
708 | 70 | icon="terp-gtk-jump-to-rtl" string="Level"/> | ||
709 | 71 | <separator orientation="vertical"/> | ||
710 | 72 | <filter domain='[]' context="{'group_by': 'partner_id'}" | ||
711 | 73 | icon="terp-partner" string="Partner"/> | ||
712 | 74 | <separator orientation="vertical"/> | ||
713 | 75 | <filter domain='[]' context="{'group_by': 'account_id'}" | ||
714 | 76 | icon="terp-folder-green" string="Account"/> | ||
715 | 77 | <separator orientation="vertical"/> | ||
716 | 78 | <filter domain='[]' context="{'group_by': 'invoice_id'}" | ||
717 | 79 | icon="terp-document-new" string="Invoice"/> | ||
718 | 80 | <separator orientation="vertical"/> | ||
719 | 81 | <filter domain='[]' context="{'group_by': 'profile_id'}" | ||
720 | 82 | icon="terp-document-new" string="Credit Profile"/> | ||
721 | 83 | <separator orientation="vertical"/> | ||
722 | 84 | <filter domain='[]' context="{'group_by': 'profile_rule_id'}" | ||
723 | 85 | icon="terp-document-new" string="Credit Profile rule"/> | ||
724 | 86 | <separator orientation="vertical"/> | ||
725 | 87 | <filter domain='[]' context="{'group_by': 'canal'}" | ||
726 | 88 | icon="terp-document-new" string="Canal"/> | ||
727 | 89 | </group> | ||
728 | 90 | <newline/> | ||
729 | 91 | </search> | ||
730 | 92 | </field> | ||
731 | 93 | </record> | ||
732 | 94 | |||
733 | 95 | <record id="credit_management_line_tree" model="ir.ui.view"> | ||
734 | 96 | <field name="name">credit.management.line.tree</field> | ||
735 | 97 | <field name="model">credit.management.line</field> | ||
736 | 98 | <field name="type">tree</field> | ||
737 | 99 | <field name="arch" type="xml"> | ||
738 | 100 | <tree editable="bottom" colors="green:state == 'sent';red:state in ('error', 'mail_error');"> | ||
739 | 101 | <field name="date"/> | ||
740 | 102 | <field name="date_due"/> | ||
741 | 103 | <field name="level"/> | ||
742 | 104 | <field name="state"/> | ||
743 | 105 | <field name="canal"/> | ||
744 | 106 | <field name="invoice_id"/> | ||
745 | 107 | <field name="partner_id"/> | ||
746 | 108 | <field name="amount_due"/> | ||
747 | 109 | <field name="balance_due"/> | ||
748 | 110 | <field name="currency_id"/> | ||
749 | 111 | <field name="move_line_id"/> | ||
750 | 112 | <field name="account_id"/> | ||
751 | 113 | <field name="profile_rule_id"/> | ||
752 | 114 | <field name="profile_id"/> | ||
753 | 115 | <field name="mail_message_id"/> | ||
754 | 116 | </tree> | ||
755 | 117 | </field> | ||
756 | 118 | </record> | ||
757 | 119 | |||
758 | 120 | <menuitem | ||
759 | 121 | name="Credit management" | ||
760 | 122 | parent="account.menu_finance_periodical_processing" | ||
761 | 123 | id="base_credit_management_menu"/> | ||
762 | 124 | |||
763 | 125 | <record model="ir.actions.act_window" id="credit_management_line_action"> | ||
764 | 126 | <field name="name">Credit lines</field> | ||
765 | 127 | <field name="type">ir.actions.act_window</field> | ||
766 | 128 | <field name="res_model">credit.management.line</field> | ||
767 | 129 | <field name="domain"></field> | ||
768 | 130 | <field name="view_type">form</field> | ||
769 | 131 | <field name="view_mode">tree,form</field> | ||
770 | 132 | <field name="view_id" ref="credit_management_line_tree"/> | ||
771 | 133 | <field name="search_view_id" ref="credit_management_line_search"/> | ||
772 | 134 | </record> | ||
773 | 135 | |||
774 | 136 | |||
775 | 137 | <menuitem | ||
776 | 138 | name="Credit lines" | ||
777 | 139 | parent="base_credit_management_menu" | ||
778 | 140 | action="credit_management_line_action" | ||
779 | 141 | id="credit_management_line_action_menu"/> | ||
780 | 142 | |||
781 | 143 | |||
782 | 144 | </data> | ||
783 | 145 | </openerp> | ||
784 | 0 | 146 | ||
785 | === added file 'account_credit_management/credit_management_partner.py' | |||
786 | --- account_credit_management/credit_management_partner.py 1970-01-01 00:00:00 +0000 | |||
787 | +++ account_credit_management/credit_management_partner.py 2012-10-15 10:14:35 +0000 | |||
788 | @@ -0,0 +1,36 @@ | |||
789 | 1 | # -*- coding: utf-8 -*- | ||
790 | 2 | ############################################################################## | ||
791 | 3 | # | ||
792 | 4 | # Author: Nicolas Bessi | ||
793 | 5 | # Copyright 2012 Camptocamp SA | ||
794 | 6 | # | ||
795 | 7 | # This program is free software: you can redistribute it and/or modify | ||
796 | 8 | # it under the terms of the GNU Affero General Public License as | ||
797 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
798 | 10 | # License, or (at your option) any later version. | ||
799 | 11 | # | ||
800 | 12 | # This program is distributed in the hope that it will be useful, | ||
801 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
802 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
803 | 15 | # GNU Affero General Public License for more details. | ||
804 | 16 | # | ||
805 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
806 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
807 | 19 | # | ||
808 | 20 | ############################################################################## | ||
809 | 21 | from openerp.osv.orm import Model, fields | ||
810 | 22 | |||
811 | 23 | class ResPartner(Model): | ||
812 | 24 | """Add a link to a credit management profile on account account""" | ||
813 | 25 | |||
814 | 26 | _inherit = "res.partner" | ||
815 | 27 | _description = """Add a link to a credit profile""" | ||
816 | 28 | _columns = {'credit_profile_id': fields.many2one('credit.management.profile', | ||
817 | 29 | 'Credit management profile', | ||
818 | 30 | help=("Define global credit profile" | ||
819 | 31 | "order is account partner invoice")), | ||
820 | 32 | |||
821 | 33 | 'credit_management_line_ids': fields.one2many('credit.management.line', | ||
822 | 34 | 'invoice_id', | ||
823 | 35 | string='Credit Lines', | ||
824 | 36 | readonly=True)} | ||
825 | 0 | 37 | ||
826 | === added file 'account_credit_management/credit_management_partner_view.xml' | |||
827 | --- account_credit_management/credit_management_partner_view.xml 1970-01-01 00:00:00 +0000 | |||
828 | +++ account_credit_management/credit_management_partner_view.xml 2012-10-15 10:14:35 +0000 | |||
829 | @@ -0,0 +1,25 @@ | |||
830 | 1 | <openerp> | ||
831 | 2 | <data> | ||
832 | 3 | <record id="partner_followup_form_view" model="ir.ui.view"> | ||
833 | 4 | <field name="name">partner.credit_management.form.view</field> | ||
834 | 5 | <field name="model">res.partner</field> | ||
835 | 6 | <field name="inherit_id" ref="base.view_partner_form" /> | ||
836 | 7 | <field name="type">form</field> | ||
837 | 8 | <field name="arch" type="xml"> | ||
838 | 9 | <field name="last_reconciliation_date" position="after"> | ||
839 | 10 | <field name="credit_profile_id" | ||
840 | 11 | groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_use"/> | ||
841 | 12 | </field> | ||
842 | 13 | </field> | ||
843 | 14 | </record> | ||
844 | 15 | |||
845 | 16 | <act_window | ||
846 | 17 | id="act_partner_credit_relation_relation" | ||
847 | 18 | name="Credit lines" | ||
848 | 19 | groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_user" | ||
849 | 20 | domain="[('partner_id', '=', active_id)]" | ||
850 | 21 | res_model="credit.management.line" | ||
851 | 22 | src_model="res.partner"/> | ||
852 | 23 | |||
853 | 24 | </data> | ||
854 | 25 | </openerp> | ||
855 | 0 | 26 | ||
856 | === added file 'account_credit_management/credit_management_profile.py' | |||
857 | --- account_credit_management/credit_management_profile.py 1970-01-01 00:00:00 +0000 | |||
858 | +++ account_credit_management/credit_management_profile.py 2012-10-15 10:14:35 +0000 | |||
859 | @@ -0,0 +1,292 @@ | |||
860 | 1 | # -*- coding: utf-8 -*- | ||
861 | 2 | ############################################################################## | ||
862 | 3 | # | ||
863 | 4 | # Author: Nicolas Bessi | ||
864 | 5 | # Copyright 2012 Camptocamp SA | ||
865 | 6 | # | ||
866 | 7 | # This program is free software: you can redistribute it and/or modify | ||
867 | 8 | # it under the terms of the GNU Affero General Public License as | ||
868 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
869 | 10 | # License, or (at your option) any later version. | ||
870 | 11 | # | ||
871 | 12 | # This program is distributed in the hope that it will be useful, | ||
872 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
873 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
874 | 15 | # GNU Affero General Public License for more details. | ||
875 | 16 | # | ||
876 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
877 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
878 | 19 | # | ||
879 | 20 | ############################################################################## | ||
880 | 21 | from openerp.osv.orm import Model, fields | ||
881 | 22 | from openerp.tools.translate import _ | ||
882 | 23 | |||
883 | 24 | class CreditManagementProfile(Model): | ||
884 | 25 | """Define a profile of reminder""" | ||
885 | 26 | |||
886 | 27 | _name = "credit.management.profile" | ||
887 | 28 | _description = """Define a reminder profile""" | ||
888 | 29 | _columns = {'name': fields.char('Name', required=True, size=128), | ||
889 | 30 | |||
890 | 31 | 'profile_rule_ids' : fields.one2many('credit.management.profile.rule', | ||
891 | 32 | 'profile_id', | ||
892 | 33 | 'Profile Rules'), | ||
893 | 34 | |||
894 | 35 | 'do_nothing' : fields.boolean('Do nothing', | ||
895 | 36 | help=('For profiling who should not ' | ||
896 | 37 | 'generate lines or are obsolete')), | ||
897 | 38 | |||
898 | 39 | 'company_id' : fields.many2one('res.company', 'Company') | ||
899 | 40 | } | ||
900 | 41 | |||
901 | 42 | |||
902 | 43 | def _get_account_related_lines(self, cursor, uid, profile_id, lookup_date, lines, context=None): | ||
903 | 44 | """ We get all the lines related to accounts with given credit profile. | ||
904 | 45 | We try not to use direct SQL in order to respect security rules. | ||
905 | 46 | As we define the first set it is important, The date is used to do a prefilter. | ||
906 | 47 | !!!We take the asumption that only receivable lines have a maturity date | ||
907 | 48 | and account must be reconcillable""" | ||
908 | 49 | context = context or {} | ||
909 | 50 | move_l_obj = self.pool.get('account.move.line') | ||
910 | 51 | account_obj = self.pool.get('account.account') | ||
911 | 52 | acc_ids = account_obj.search(cursor, uid, [('credit_profile_id', '=', profile_id)]) | ||
912 | 53 | if not acc_ids: | ||
913 | 54 | return lines | ||
914 | 55 | move_ids = move_l_obj.search(cursor, uid, [('account_id', 'in', acc_ids), | ||
915 | 56 | ('date_maturity', '<=', lookup_date), | ||
916 | 57 | ('reconcile_id', '=', False), | ||
917 | 58 | ('partner_id', '!=', False)]) | ||
918 | 59 | |||
919 | 60 | lines += move_ids | ||
920 | 61 | return lines | ||
921 | 62 | |||
922 | 63 | |||
923 | 64 | def _get_sum_reduce_range(self, cursor, uid, profile_id, lookup_date, lines, model, | ||
924 | 65 | move_relation_field, context=None): | ||
925 | 66 | """ We get all the lines related to the model with given credit profile. | ||
926 | 67 | We also reduce from the global set (lines) the move line to be excluded. | ||
927 | 68 | We try not to use direct SQL in order to respect security rules. | ||
928 | 69 | As we define the first set it is important. | ||
929 | 70 | The profile relation field MUST be named credit_profile_id | ||
930 | 71 | and the model must have a relation | ||
931 | 72 | with account move line. | ||
932 | 73 | !!! We take the asumption that only receivable lines have a maturity date | ||
933 | 74 | and account must be reconcillable""" | ||
934 | 75 | # MARK possible place for a good optimisation | ||
935 | 76 | context = context or {} | ||
936 | 77 | my_obj = self.pool.get(model) | ||
937 | 78 | move_l_obj = self.pool.get('account.move.line') | ||
938 | 79 | add_obj_ids = my_obj.search(cursor, uid, [('credit_profile_id', '=', profile_id)]) | ||
939 | 80 | if add_obj_ids: | ||
940 | 81 | add_lines = move_l_obj.search(cursor, uid, [(move_relation_field, 'in', add_obj_ids), | ||
941 | 82 | ('date_maturity', '<=', lookup_date), | ||
942 | 83 | ('partner_id', '!=', False), | ||
943 | 84 | ('reconcile_id', '=', False)]) | ||
944 | 85 | lines = list(set(lines + add_lines)) | ||
945 | 86 | # we get all the lines that must be excluded at partner_level | ||
946 | 87 | # from the global set (even the one included at account level) | ||
947 | 88 | neg_obj_ids = my_obj.search(cursor, uid, [('credit_profile_id', '!=', profile_id), | ||
948 | 89 | ('credit_profile_id', '!=', False)]) | ||
949 | 90 | if neg_obj_ids: | ||
950 | 91 | # should we add ('id', 'in', lines) in domain ? it may give a veeery long SQL... | ||
951 | 92 | neg_lines = move_l_obj.search(cursor, uid, [(move_relation_field, 'in', neg_obj_ids), | ||
952 | 93 | ('date_maturity', '<=', lookup_date), | ||
953 | 94 | ('partner_id', '!=', False), | ||
954 | 95 | ('reconcile_id', '=', False)]) | ||
955 | 96 | if neg_lines: | ||
956 | 97 | lines = list(set(lines) - set(neg_lines)) | ||
957 | 98 | return lines | ||
958 | 99 | |||
959 | 100 | |||
960 | 101 | def _get_partner_related_lines(self, cursor, uid, profile_id, lookup_date, lines, context=None): | ||
961 | 102 | return self._get_sum_reduce_range(cursor, uid, profile_id, lookup_date, lines, | ||
962 | 103 | 'res.partner', 'partner_id', context=context) | ||
963 | 104 | |||
964 | 105 | |||
965 | 106 | def _get_invoice_related_lines(self, cursor, uid, profile_id, lookup_date, lines, context=None): | ||
966 | 107 | return self._get_sum_reduce_range(cursor, uid, profile_id, lookup_date, lines, | ||
967 | 108 | 'account.invoice', 'invoice', context=context) | ||
968 | 109 | |||
969 | 110 | |||
970 | 111 | def _get_moves_line_to_process(self, cursor, uid, profile_id, lookup_date, context=None): | ||
971 | 112 | """Retrive all the move line to be procces for current profile. | ||
972 | 113 | This function is planned to be use only on one id. | ||
973 | 114 | Priority of inclustion, exlusion is account, partner, invoice""" | ||
974 | 115 | context = context or {} | ||
975 | 116 | lines = [] | ||
976 | 117 | if isinstance(profile_id, list): | ||
977 | 118 | profile_id = profile_id[0] | ||
978 | 119 | # order of call MUST be respected priority is account, partner, invoice | ||
979 | 120 | lines = self._get_account_related_lines(cursor, uid, profile_id, | ||
980 | 121 | lookup_date, lines, context=context) | ||
981 | 122 | lines = self._get_partner_related_lines(cursor, uid, profile_id, | ||
982 | 123 | lookup_date, lines, context=context) | ||
983 | 124 | lines = self._get_invoice_related_lines(cursor, uid, profile_id, | ||
984 | 125 | lookup_date, lines, context=context) | ||
985 | 126 | return lines | ||
986 | 127 | |||
987 | 128 | def _check_lines_profiles(self, cursor, uid, profile_id, lines, context=None): | ||
988 | 129 | """ Check if there is credit line related to same move line but | ||
989 | 130 | related to an other profile""" | ||
990 | 131 | context = context or {} | ||
991 | 132 | if not lines: | ||
992 | 133 | return [] | ||
993 | 134 | if isinstance(profile_id, list): | ||
994 | 135 | profile_id = profile_id[0] | ||
995 | 136 | cursor.execute("SELECT move_line_id FROM credit_management_line" | ||
996 | 137 | " WHERE profile_id != %s and move_line_id in %s", | ||
997 | 138 | (profile_id, tuple(lines))) | ||
998 | 139 | res = cursor.fetchall() | ||
999 | 140 | if res: | ||
1000 | 141 | return [x[0] for x in res] | ||
1001 | 142 | else: | ||
1002 | 143 | return [] | ||
1003 | 144 | |||
1004 | 145 | |||
1005 | 146 | |||
1006 | 147 | class CreditManagementProfileRule (Model): | ||
1007 | 148 | """Define a profile rule. A rule allows to determine if | ||
1008 | 149 | a move line is due and the level of overdue of the line""" | ||
1009 | 150 | |||
1010 | 151 | _name = "credit.management.profile.rule" | ||
1011 | 152 | _order = 'level' | ||
1012 | 153 | _description = """A credit management profile rule""" | ||
1013 | 154 | _columns = {'profile_id': fields.many2one('credit.management.profile', | ||
1014 | 155 | 'Related Policy', required=True), | ||
1015 | 156 | 'name': fields.char('Name', size=128, required=True), | ||
1016 | 157 | 'level': fields.float('level', required=True), | ||
1017 | 158 | |||
1018 | 159 | 'computation_mode': fields.selection([('net_days', 'Due date'), | ||
1019 | 160 | ('end_of_month', 'Due Date: end of Month'), | ||
1020 | 161 | ('previous_date', 'Previous reminder')], | ||
1021 | 162 | 'Compute mode', | ||
1022 | 163 | required=True), | ||
1023 | 164 | |||
1024 | 165 | 'delay_days': fields.integer('Delay in day', required='True'), | ||
1025 | 166 | 'mail_template_id': fields.many2one('email.template', 'Mail template', | ||
1026 | 167 | required=True), | ||
1027 | 168 | 'canal': fields.selection([('manual', 'Manual'), | ||
1028 | 169 | ('mail', 'Mail')], | ||
1029 | 170 | 'Canal', required=True), | ||
1030 | 171 | 'custom_text': fields.text('Custom message', required=True, translate=True), | ||
1031 | 172 | } | ||
1032 | 173 | |||
1033 | 174 | |||
1034 | 175 | def _check_level_mode(self, cursor, uid, rids, context=None): | ||
1035 | 176 | """We check that the smallest level is not based | ||
1036 | 177 | on a rule using previous_date mode""" | ||
1037 | 178 | if not isinstance(rids, list): | ||
1038 | 179 | rids = [rids] | ||
1039 | 180 | for rule in self.browse(cursor, uid, rids, context): | ||
1040 | 181 | smallest_rule_id = self.search(cursor, uid, [('profile_id', '=', rule.profile_id.id)], | ||
1041 | 182 | order='level asc', limit=1, context=context) | ||
1042 | 183 | smallest_rule = self.browse(cursor, uid, smallest_rule_id[0], context) | ||
1043 | 184 | if smallest_rule.computation_mode == 'previous_date': | ||
1044 | 185 | return False | ||
1045 | 186 | return True | ||
1046 | 187 | |||
1047 | 188 | |||
1048 | 189 | |||
1049 | 190 | _sql_constraint = [('unique level', | ||
1050 | 191 | 'UNIQUE (profile_id, level)', | ||
1051 | 192 | 'Level must be unique per profile')] | ||
1052 | 193 | |||
1053 | 194 | _constraints = [(_check_level_mode, | ||
1054 | 195 | 'The smallest level can not be of type Previous reminder', | ||
1055 | 196 | ['level'])] | ||
1056 | 197 | |||
1057 | 198 | def _is_first_level(self, cursor, uid, rule_br, context=None): | ||
1058 | 199 | """Check if rule has the smallest priority""" | ||
1059 | 200 | first_rule = self.search(cursor, uid, [('profile_id', '=', rule_br.profile_id.id)], | ||
1060 | 201 | order='level asc', limit=1, context=context) | ||
1061 | 202 | return first_rule[0] == rule_br.id | ||
1062 | 203 | # ----- time related functions --------- | ||
1063 | 204 | |||
1064 | 205 | def _net_days_get_boundary(self): | ||
1065 | 206 | return " (mv_line.date_maturity + %(delay)s)::date <= date(%(lookup_date)s)" | ||
1066 | 207 | |||
1067 | 208 | def _end_of_month_get_boundary(self): | ||
1068 | 209 | return ("(date_trunc('MONTH', (mv_line.date_maturity + %(delay)s))+INTERVAL '1 MONTH - 1 day')::date" | ||
1069 | 210 | "<= date(%(lookup_date)s)") | ||
1070 | 211 | |||
1071 | 212 | def _previous_date_get_boundary(self): | ||
1072 | 213 | return "(cr_line.date + %(delay)s)::date <= date(%(lookup_date)s)" | ||
1073 | 214 | |||
1074 | 215 | def _get_sql_date_boundary_for_computation_mode(self, cursor, uid, rule_br, lookup_date, context=None): | ||
1075 | 216 | """Return a where clauses statement for the given | ||
1076 | 217 | lookup date and computation mode of the rule""" | ||
1077 | 218 | fname = "_%s_get_boundary" % (rule_br.computation_mode,) | ||
1078 | 219 | if hasattr(self, fname): | ||
1079 | 220 | fnc = getattr(self, fname) | ||
1080 | 221 | return fnc() | ||
1081 | 222 | else: | ||
1082 | 223 | raise NotImplementedError(_('Can not get function for computation mode: ' | ||
1083 | 224 | '%s is not implemented') % (fname,)) | ||
1084 | 225 | |||
1085 | 226 | # ----------------------------------------- | ||
1086 | 227 | |||
1087 | 228 | def _get_first_level_lines(self, cursor, uid, rule_br, lookup_date, lines, context=None): | ||
1088 | 229 | if not lines: | ||
1089 | 230 | return [] | ||
1090 | 231 | """Retrieve all the line that are linked to a frist level rules. | ||
1091 | 232 | We use Raw SQL for perf. Security rule where applied in | ||
1092 | 233 | profile object when line where retrieved""" | ||
1093 | 234 | sql = ("SELECT DISTINCT mv_line.id\n" | ||
1094 | 235 | " FROM account_move_line mv_line\n" | ||
1095 | 236 | " WHERE mv_line.id in %(line_ids)s\n" | ||
1096 | 237 | " AND NOT EXISTS (SELECT cr_line.id from credit_management_line cr_line\n" | ||
1097 | 238 | " WHERE cr_line.move_line_id = mv_line.id)") | ||
1098 | 239 | sql += " AND" + self._get_sql_date_boundary_for_computation_mode(cursor, | ||
1099 | 240 | uid, rule_br, | ||
1100 | 241 | lookup_date, context) | ||
1101 | 242 | data_dict = {'lookup_date': lookup_date, 'line_ids': tuple(lines), | ||
1102 | 243 | 'delay': rule_br.delay_days} | ||
1103 | 244 | |||
1104 | 245 | cursor.execute(sql, data_dict) | ||
1105 | 246 | res = cursor.fetchall() | ||
1106 | 247 | if not res: | ||
1107 | 248 | return [] | ||
1108 | 249 | return [x[0] for x in res] | ||
1109 | 250 | |||
1110 | 251 | |||
1111 | 252 | def _get_other_level_lines(self, cursor, uid, rule_br, lookup_date, lines, context=None): | ||
1112 | 253 | # We filter line that have a level smaller than current one | ||
1113 | 254 | # TODO if code fits need refactor _get_first_level_lines and _get_other_level_lines | ||
1114 | 255 | # Code is not DRY | ||
1115 | 256 | if not lines: | ||
1116 | 257 | return [] | ||
1117 | 258 | sql = ("SELECT mv_line.id\n" | ||
1118 | 259 | " FROM account_move_line mv_line\n" | ||
1119 | 260 | " JOIN credit_management_line cr_line\n" | ||
1120 | 261 | " ON (mv_line.id = cr_line.move_line_id)\n" | ||
1121 | 262 | " WHERE cr_line.id = (SELECT credit_management_line.id FROM credit_management_line\n" | ||
1122 | 263 | " WHERE credit_management_line.move_line_id = mv_line.id\n" | ||
1123 | 264 | " ORDER BY credit_management_line.level desc limit 1)\n" | ||
1124 | 265 | " AND cr_line.level < %(level)s\n" | ||
1125 | 266 | " AND mv_line.id in %(line_ids)s\n") | ||
1126 | 267 | sql += " AND " + self._get_sql_date_boundary_for_computation_mode(cursor, | ||
1127 | 268 | uid, rule_br, | ||
1128 | 269 | lookup_date, context) | ||
1129 | 270 | data_dict = {'lookup_date': lookup_date, 'line_ids': tuple(lines), | ||
1130 | 271 | 'delay': rule_br.delay_days, 'level': rule_br.level} | ||
1131 | 272 | |||
1132 | 273 | cursor.execute(sql, data_dict) | ||
1133 | 274 | res = cursor.fetchall() | ||
1134 | 275 | if not res: | ||
1135 | 276 | return [] | ||
1136 | 277 | return [x[0] for x in res] | ||
1137 | 278 | |||
1138 | 279 | def get_rule_lines(self, cursor, uid, rule_id, lookup_date, lines, context=None): | ||
1139 | 280 | """get all move lines in entry lines that match the current rule""" | ||
1140 | 281 | if isinstance(rule_id, list): | ||
1141 | 282 | rule_id = rule_id[0] | ||
1142 | 283 | matching_lines = [] | ||
1143 | 284 | rule = self.browse(cursor, uid, rule_id, context=context) | ||
1144 | 285 | if self._is_first_level(cursor, uid, rule): | ||
1145 | 286 | matching_lines += self._get_first_level_lines(cursor, uid, rule, lookup_date, | ||
1146 | 287 | lines, context=context) | ||
1147 | 288 | else: | ||
1148 | 289 | matching_lines += self._get_other_level_lines(cursor, uid, rule, lookup_date, | ||
1149 | 290 | lines, context=context) | ||
1150 | 291 | |||
1151 | 292 | return matching_lines | ||
1152 | 0 | 293 | ||
1153 | === added file 'account_credit_management/credit_management_profile_view.xml' | |||
1154 | --- account_credit_management/credit_management_profile_view.xml 1970-01-01 00:00:00 +0000 | |||
1155 | +++ account_credit_management/credit_management_profile_view.xml 2012-10-15 10:14:35 +0000 | |||
1156 | @@ -0,0 +1,118 @@ | |||
1157 | 1 | <openerp> | ||
1158 | 2 | <data> | ||
1159 | 3 | |||
1160 | 4 | <record id="credit_management_profile_form" model="ir.ui.view"> | ||
1161 | 5 | <field name="name">credit.management.profile.form</field> | ||
1162 | 6 | <field name="model">credit.management.profile</field> | ||
1163 | 7 | <field name="type">form</field> | ||
1164 | 8 | <field name="arch" type="xml"> | ||
1165 | 9 | <form> <!-- editable="bottom" --> | ||
1166 | 10 | <field name="name"/> | ||
1167 | 11 | <field name="do_nothing"/> | ||
1168 | 12 | <field name="company_id"/> | ||
1169 | 13 | <notebook colspan="4"> | ||
1170 | 14 | <page string="Rules"> | ||
1171 | 15 | <field name="profile_rule_ids" colspan="4" > | ||
1172 | 16 | <tree editable="bottom"> | ||
1173 | 17 | <field name="name"/> | ||
1174 | 18 | <field name="level"/> | ||
1175 | 19 | <field name="canal"/> | ||
1176 | 20 | <field name="delay_days"/> | ||
1177 | 21 | <field name="computation_mode"/> | ||
1178 | 22 | <field name="mail_template_id"/> | ||
1179 | 23 | </tree> | ||
1180 | 24 | <form> | ||
1181 | 25 | <field name="name"/> | ||
1182 | 26 | <notebook colspan="4"> | ||
1183 | 27 | <page string="Delay Setting"> | ||
1184 | 28 | <field name="level"/> | ||
1185 | 29 | <field name="canal"/> | ||
1186 | 30 | <field name="delay_days"/> | ||
1187 | 31 | <field name="computation_mode"/> | ||
1188 | 32 | </page> | ||
1189 | 33 | <page string="Mail and reporting"> | ||
1190 | 34 | <field name="mail_template_id"/> | ||
1191 | 35 | <field name="custom_text"/> | ||
1192 | 36 | </page> | ||
1193 | 37 | </notebook> | ||
1194 | 38 | </form> | ||
1195 | 39 | </field> | ||
1196 | 40 | </page> | ||
1197 | 41 | </notebook> | ||
1198 | 42 | </form> | ||
1199 | 43 | </field> | ||
1200 | 44 | </record> | ||
1201 | 45 | |||
1202 | 46 | <record id="credit_management_profile_tree" model="ir.ui.view"> | ||
1203 | 47 | <field name="name">credit.management.profile.tree</field> | ||
1204 | 48 | <field name="model">credit.management.profile</field> | ||
1205 | 49 | <field name="type">tree</field> | ||
1206 | 50 | <field name="arch" type="xml"> | ||
1207 | 51 | <tree> <!-- editable="bottom" --> | ||
1208 | 52 | <field name="name"/> | ||
1209 | 53 | <field name="do_nothing"/> | ||
1210 | 54 | </tree> | ||
1211 | 55 | </field> | ||
1212 | 56 | </record> | ||
1213 | 57 | |||
1214 | 58 | <menuitem | ||
1215 | 59 | name="Credit management configuration" | ||
1216 | 60 | parent="account.menu_finance_configuration" | ||
1217 | 61 | id="base_credit_management_configuration_menu"/> | ||
1218 | 62 | |||
1219 | 63 | <record model="ir.actions.act_window" id="credit_profile_configuration_action"> | ||
1220 | 64 | <field name="name">Credit profiles</field> | ||
1221 | 65 | <field name="type">ir.actions.act_window</field> | ||
1222 | 66 | <field name="res_model">credit.management.profile</field> | ||
1223 | 67 | <field name="domain"></field> | ||
1224 | 68 | <field name="view_type">form</field> | ||
1225 | 69 | <field name="view_mode">tree,form</field> | ||
1226 | 70 | <field name="view_id" ref="credit_management_profile_tree"/> | ||
1227 | 71 | </record> | ||
1228 | 72 | |||
1229 | 73 | <menuitem | ||
1230 | 74 | name="Credit profiles" | ||
1231 | 75 | parent="base_credit_management_configuration_menu" | ||
1232 | 76 | action="credit_profile_configuration_action" | ||
1233 | 77 | id="credit_profile_configuration_action_menu"/> | ||
1234 | 78 | |||
1235 | 79 | <record id="credit_mangement_profile_rule_form" model="ir.ui.view"> | ||
1236 | 80 | <field name="name">credit.mangement.profile.rule.form</field> | ||
1237 | 81 | <field name="model">credit.management.profile.rule</field> | ||
1238 | 82 | <field name="type">form</field> | ||
1239 | 83 | <field name="arch" type="xml"> | ||
1240 | 84 | <form> <!-- editable="bottom" --> | ||
1241 | 85 | <field name="name"/> | ||
1242 | 86 | <notebook colspan="4"> | ||
1243 | 87 | <page string="Delay Setting"> | ||
1244 | 88 | <field name="level"/> | ||
1245 | 89 | <field name="canal"/> | ||
1246 | 90 | <field name="delay_days"/> | ||
1247 | 91 | <field name="computation_mode"/> | ||
1248 | 92 | </page> | ||
1249 | 93 | <page string="Mail and reporting"> | ||
1250 | 94 | <field name="mail_template_id"/> | ||
1251 | 95 | <field name="custom_text"/> | ||
1252 | 96 | </page> | ||
1253 | 97 | </notebook> | ||
1254 | 98 | </form> | ||
1255 | 99 | </field> | ||
1256 | 100 | </record> | ||
1257 | 101 | |||
1258 | 102 | <record id="credit_management_profile_rule_tree" model="ir.ui.view"> | ||
1259 | 103 | <field name="name">credit.management.profile.rule.tree</field> | ||
1260 | 104 | <field name="model">credit.management.profile.rule</field> | ||
1261 | 105 | <field name="type">tree</field> | ||
1262 | 106 | <field name="arch" type="xml"> | ||
1263 | 107 | <tree editable="bottom"> | ||
1264 | 108 | <field name="name"/> | ||
1265 | 109 | <field name="level"/> | ||
1266 | 110 | <field name="canal"/> | ||
1267 | 111 | <field name="delay_days"/> | ||
1268 | 112 | <field name="computation_mode"/> | ||
1269 | 113 | <field name="mail_template_id"/> | ||
1270 | 114 | </tree> | ||
1271 | 115 | </field> | ||
1272 | 116 | </record> | ||
1273 | 117 | </data> | ||
1274 | 118 | </openerp> | ||
1275 | 0 | 119 | ||
1276 | === added file 'account_credit_management/credit_management_run.py' | |||
1277 | --- account_credit_management/credit_management_run.py 1970-01-01 00:00:00 +0000 | |||
1278 | +++ account_credit_management/credit_management_run.py 2012-10-15 10:14:35 +0000 | |||
1279 | @@ -0,0 +1,150 @@ | |||
1280 | 1 | # -*- coding: utf-8 -*- | ||
1281 | 2 | ############################################################################## | ||
1282 | 3 | # | ||
1283 | 4 | # Author: Nicolas Bessi | ||
1284 | 5 | # Copyright 2012 Camptocamp SA | ||
1285 | 6 | # | ||
1286 | 7 | # This program is free software: you can redistribute it and/or modify | ||
1287 | 8 | # it under the terms of the GNU Affero General Public License as | ||
1288 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
1289 | 10 | # License, or (at your option) any later version. | ||
1290 | 11 | # | ||
1291 | 12 | # This program is distributed in the hope that it will be useful, | ||
1292 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1293 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1294 | 15 | # GNU Affero General Public License for more details. | ||
1295 | 16 | # | ||
1296 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
1297 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1298 | 19 | # | ||
1299 | 20 | ############################################################################## | ||
1300 | 21 | import sys | ||
1301 | 22 | import traceback | ||
1302 | 23 | import logging | ||
1303 | 24 | |||
1304 | 25 | from openerp.osv.orm import Model, fields | ||
1305 | 26 | from openerp.tools.translate import _ | ||
1306 | 27 | from openerp.osv.osv import except_osv | ||
1307 | 28 | |||
1308 | 29 | logger = logging.getLogger('Credit management run') | ||
1309 | 30 | |||
1310 | 31 | memoizers = {} | ||
1311 | 32 | |||
1312 | 33 | |||
1313 | 34 | class CreditManagementRun(Model): | ||
1314 | 35 | """Credit management run generate all credit management lines and reject""" | ||
1315 | 36 | |||
1316 | 37 | _name = "credit.management.run" | ||
1317 | 38 | _rec_name = 'date' | ||
1318 | 39 | _description = """Credit management line generator""" | ||
1319 | 40 | _columns = {'date': fields.date('Lookup date', required=True), | ||
1320 | 41 | 'profile_ids': fields.many2many('credit.management.profile', | ||
1321 | 42 | rel="credit_run_profile_rel", | ||
1322 | 43 | string='Profiles', | ||
1323 | 44 | readonly=True, | ||
1324 | 45 | help="If nothing set all profile will be used", | ||
1325 | 46 | |||
1326 | 47 | states={'draft': [('readonly', False)]}), | ||
1327 | 48 | |||
1328 | 49 | 'report': fields.text('Report', readonly=True), | ||
1329 | 50 | |||
1330 | 51 | 'state': fields.selection([('draft', 'Draft'), | ||
1331 | 52 | ('running', 'Running'), | ||
1332 | 53 | ('done', 'Done'), | ||
1333 | 54 | ('error', 'Error')], | ||
1334 | 55 | string='State', | ||
1335 | 56 | required=True, | ||
1336 | 57 | readonly=True), | ||
1337 | 58 | |||
1338 | 59 | 'manual_ids': fields.many2many('account.move.line', | ||
1339 | 60 | rel="credit_runreject_rel", | ||
1340 | 61 | string='Line to be handled manually', | ||
1341 | 62 | readonly=True), | ||
1342 | 63 | } | ||
1343 | 64 | |||
1344 | 65 | _defaults = {'state': 'draft'} | ||
1345 | 66 | |||
1346 | 67 | def check_run_date(self, cursor, uid, ids, lookup_date, context=None): | ||
1347 | 68 | """Ensure that there is no credit line in the future using lookup_date""" | ||
1348 | 69 | line_obj = self.pool.get('credit.management.line') | ||
1349 | 70 | lines = line_obj.search(cursor, uid, [('date', '>', lookup_date)], | ||
1350 | 71 | order='date DESC', limit=1) | ||
1351 | 72 | if lines: | ||
1352 | 73 | line = line_obj.browse(cursor, uid, lines[0]) | ||
1353 | 74 | raise except_osv(_('A run was already executed in a greater date'), | ||
1354 | 75 | _('Run date should be >= %s') % (line.date)) | ||
1355 | 76 | |||
1356 | 77 | |||
1357 | 78 | def _generate_credit_lines(self, cursor, uid, run_id, context=None): | ||
1358 | 79 | """ Generate credit line. Function can be a little dryer but | ||
1359 | 80 | it does almost noting, initalise variable maange error and call | ||
1360 | 81 | real know how method""" | ||
1361 | 82 | memoizers['credit_line_residuals'] = {} | ||
1362 | 83 | cr_line_obj = self.pool.get('credit.management.line') | ||
1363 | 84 | if isinstance(run_id, list): | ||
1364 | 85 | run_id = run_id[0] | ||
1365 | 86 | run = self.browse(cursor, uid, run_id, context=context) | ||
1366 | 87 | errors = [] | ||
1367 | 88 | manualy_managed_lines = [] #line who changed profile | ||
1368 | 89 | credit_line_ids = [] # generated lines | ||
1369 | 90 | run.check_run_date(run.date, context=context) | ||
1370 | 91 | profile_ids = run.profile_ids | ||
1371 | 92 | if not profile_ids: | ||
1372 | 93 | profile_obj = self.pool.get('credit.management.profile') | ||
1373 | 94 | profile_ids_ids = profile_obj.search(cursor, uid, []) | ||
1374 | 95 | profile_ids = profile_obj.browse(cursor, uid, profile_ids_ids) | ||
1375 | 96 | for profile in profile_ids: | ||
1376 | 97 | if profile.do_nothing: | ||
1377 | 98 | continue | ||
1378 | 99 | try: | ||
1379 | 100 | lines = profile._get_moves_line_to_process(run.date, context=context) | ||
1380 | 101 | tmp_manual = profile._check_lines_profiles(lines, context=context) | ||
1381 | 102 | lines = list(set(lines) - set(tmp_manual)) | ||
1382 | 103 | manualy_managed_lines += tmp_manual | ||
1383 | 104 | if not lines: | ||
1384 | 105 | continue | ||
1385 | 106 | # profile rules are sorted by level so iteration is in the correct order | ||
1386 | 107 | for rule in profile.profile_rule_ids: | ||
1387 | 108 | rule_lines = rule.get_rule_lines(run.date, lines) | ||
1388 | 109 | #only this write action own a separate cursor | ||
1389 | 110 | credit_line_ids += cr_line_obj.create_or_update_from_mv_lines(cursor, uid, [], | ||
1390 | 111 | rule_lines, rule.id, | ||
1391 | 112 | run.date, errors=errors, | ||
1392 | 113 | context=context) | ||
1393 | 114 | lines = list(set(lines) - set(rule_lines)) | ||
1394 | 115 | except Exception, exc: | ||
1395 | 116 | cursor.rollback() | ||
1396 | 117 | error_type, error_value, trbk = sys.exc_info() | ||
1397 | 118 | st = "Error: %s\nDescription: %s\nTraceback:" % (error_type.__name__, error_value) | ||
1398 | 119 | st += ''.join(traceback.format_tb(trbk, 30)) | ||
1399 | 120 | logger.error(st) | ||
1400 | 121 | self.write(cursor, uid, [run.id], {'report':st, 'state': 'error'}) | ||
1401 | 122 | return False | ||
1402 | 123 | vals = {'report': u"Number of generated lines : %s \n" % (len(credit_line_ids),), | ||
1403 | 124 | 'state': 'done', | ||
1404 | 125 | 'manual_ids': [(6, 0, manualy_managed_lines)]} | ||
1405 | 126 | if errors: | ||
1406 | 127 | vals['report'] += u"Following line generation errors appends:" | ||
1407 | 128 | vals['report'] += u"----\n".join(errors) | ||
1408 | 129 | vals['state'] = 'done' | ||
1409 | 130 | run.write(vals) | ||
1410 | 131 | # lines will correspond to line that where not treated | ||
1411 | 132 | return lines | ||
1412 | 133 | |||
1413 | 134 | |||
1414 | 135 | |||
1415 | 136 | def generate_credit_lines(self, cursor, uid, run_id, context=None): | ||
1416 | 137 | """Generate credit management lines""" | ||
1417 | 138 | context = context or {} | ||
1418 | 139 | # we do a little magical tips in order to ensure non concurrent run | ||
1419 | 140 | # of the function generate_credit_lines | ||
1420 | 141 | try: | ||
1421 | 142 | cursor.execute('SELECT id FROM credit_management_run' | ||
1422 | 143 | ' LIMIT 1 FOR UPDATE NOWAIT' ) | ||
1423 | 144 | except Exception, exc: | ||
1424 | 145 | cursor.rollback() | ||
1425 | 146 | raise except_osv(_('A credit management run is allready running' | ||
1426 | 147 | ' in background please try later'), | ||
1427 | 148 | str(exc)) | ||
1428 | 149 | # in case of exception openerp will do a rollback for us and free the lock | ||
1429 | 150 | return self._generate_credit_lines(cursor, uid, run_id, context) | ||
1430 | 0 | 151 | ||
1431 | === added file 'account_credit_management/credit_management_run_view.xml' | |||
1432 | --- account_credit_management/credit_management_run_view.xml 1970-01-01 00:00:00 +0000 | |||
1433 | +++ account_credit_management/credit_management_run_view.xml 2012-10-15 10:14:35 +0000 | |||
1434 | @@ -0,0 +1,65 @@ | |||
1435 | 1 | <openerp> | ||
1436 | 2 | <data> | ||
1437 | 3 | |||
1438 | 4 | <record id="credit_management_run_tree" model="ir.ui.view"> | ||
1439 | 5 | <field name="name">credit.management.run.tree</field> | ||
1440 | 6 | <field name="model">credit.management.run</field> | ||
1441 | 7 | <field name="type">tree</field> | ||
1442 | 8 | <field name="arch" type="xml"> | ||
1443 | 9 | <tree> <!-- editable="bottom" --> | ||
1444 | 10 | <field name="date"/> | ||
1445 | 11 | <field name="state"/> | ||
1446 | 12 | </tree> | ||
1447 | 13 | </field> | ||
1448 | 14 | </record> | ||
1449 | 15 | |||
1450 | 16 | <record id="credit_management_run_form" model="ir.ui.view"> | ||
1451 | 17 | <field name="name">credit.management.run.form</field> | ||
1452 | 18 | <field name="model">credit.management.run</field> | ||
1453 | 19 | <field name="type">form</field> | ||
1454 | 20 | <field name="arch" type="xml"> | ||
1455 | 21 | <form> <!-- editable="bottom" --> | ||
1456 | 22 | <field name="date"/> | ||
1457 | 23 | <newline/> | ||
1458 | 24 | <notebook colspan="4"> | ||
1459 | 25 | <page string="Profile"> | ||
1460 | 26 | <field name="profile_ids" colspan="4" nolabel="1"/> | ||
1461 | 27 | </page> | ||
1462 | 28 | <page string="Report and Errors"> | ||
1463 | 29 | <field name="report" colspan="4" nolabel="1"/> | ||
1464 | 30 | <separator string="Move lines To be treated manually"/> | ||
1465 | 31 | <field name="manual_ids" colspan="4" nolabel="1"/> | ||
1466 | 32 | </page> | ||
1467 | 33 | </notebook> | ||
1468 | 34 | <group col="3" colspan="4"> | ||
1469 | 35 | <button name="generate_credit_lines" | ||
1470 | 36 | string="Compute credit lines" | ||
1471 | 37 | colspan="1" | ||
1472 | 38 | type="object" icon="gtk-execute" | ||
1473 | 39 | attrs="{'invisible': [('state', '!=', 'draft')]}"/> | ||
1474 | 40 | </group> | ||
1475 | 41 | <field name="state"/> | ||
1476 | 42 | </form> | ||
1477 | 43 | </field> | ||
1478 | 44 | </record> | ||
1479 | 45 | |||
1480 | 46 | |||
1481 | 47 | <record model="ir.actions.act_window" id="credit_management_run"> | ||
1482 | 48 | <field name="name">Credit management run</field> | ||
1483 | 49 | <field name="type">ir.actions.act_window</field> | ||
1484 | 50 | <field name="res_model">credit.management.run</field> | ||
1485 | 51 | <field name="domain"></field> | ||
1486 | 52 | <field name="view_type">form</field> | ||
1487 | 53 | <field name="view_mode">tree,form</field> | ||
1488 | 54 | <field name="view_id" ref="credit_management_run_tree"/> | ||
1489 | 55 | </record> | ||
1490 | 56 | |||
1491 | 57 | |||
1492 | 58 | <menuitem | ||
1493 | 59 | name="Credit management run" | ||
1494 | 60 | parent="base_credit_management_menu" | ||
1495 | 61 | action="credit_management_run" | ||
1496 | 62 | id="credit_management_run_menu"/> | ||
1497 | 63 | |||
1498 | 64 | </data> | ||
1499 | 65 | </openerp> | ||
1500 | 0 | 66 | ||
1501 | === added file 'account_credit_management/data.xml' | |||
1502 | --- account_credit_management/data.xml 1970-01-01 00:00:00 +0000 | |||
1503 | +++ account_credit_management/data.xml 2012-10-15 10:14:35 +0000 | |||
1504 | @@ -0,0 +1,173 @@ | |||
1505 | 1 | <openerp> | ||
1506 | 2 | <data noupdate="1"> | ||
1507 | 3 | <!--Email template --> | ||
1508 | 4 | <record id="email_template_credit_management_base" model="email.template"> | ||
1509 | 5 | <field name="name">Credit Management demo mail</field> | ||
1510 | 6 | <field name="email_from">noreply@localhost</field> | ||
1511 | 7 | <field name="subject">Credit Management Invoice (${object.current_profile_rule.level or 'n/a' })</field> | ||
1512 | 8 | <field name="email_to">${object.get_mail() or ''}</field> | ||
1513 | 9 | <field name="model_id" ref="model_credit_management_communication"/> | ||
1514 | 10 | <field name="auto_delete" eval="True"/> | ||
1515 | 11 | <field name="body_html"><![CDATA[ | ||
1516 | 12 | <%page args="object, mode" /> | ||
1517 | 13 | %if mode != 'pdf': | ||
1518 | 14 | <!-- your css here --> | ||
1519 | 15 | <style type="text/css"> | ||
1520 | 16 | </style> | ||
1521 | 17 | %endif | ||
1522 | 18 | <div> | ||
1523 | 19 | |||
1524 | 20 | <p>Dear ${object.partner_id.name or ''},</p> | ||
1525 | 21 | |||
1526 | 22 | <pre class="custom_text">${object.current_profile_rule.level.custom_text}</pre> | ||
1527 | 23 | |||
1528 | 24 | <table style="border: 1px solid" width="100%"> | ||
1529 | 25 | <caption><b>Summary</b></caption> | ||
1530 | 26 | <tr> | ||
1531 | 27 | <th>date due</th> | ||
1532 | 28 | <th>Amount due</th> | ||
1533 | 29 | <th>Amount balance</th> | ||
1534 | 30 | <th>Invoice number</th> | ||
1535 | 31 | </tr> | ||
1536 | 32 | %for line in object.credit_lines: | ||
1537 | 33 | <tr> | ||
1538 | 34 | <td>${line.date_due}</td> | ||
1539 | 35 | <td>${line.amount_due}</td> | ||
1540 | 36 | <td>${line.balance_due}</td> | ||
1541 | 37 | %if line.invoice_id: | ||
1542 | 38 | <td>${line.invoice_id.number}</td> | ||
1543 | 39 | %else: | ||
1544 | 40 | <td>n/a</td> | ||
1545 | 41 | %endif | ||
1546 | 42 | %endfor | ||
1547 | 43 | </table> | ||
1548 | 44 | <br/> | ||
1549 | 45 | <br/> | ||
1550 | 46 | |||
1551 | 47 | <p> If you have any question, do not hesitate to contact us.</p> | ||
1552 | 48 | |||
1553 | 49 | |||
1554 | 50 | <p>Thank you for choosing ${object.company_id.name}! </p> | ||
1555 | 51 | |||
1556 | 52 | -- more info here -- | ||
1557 | 53 | <p>${object.user_id.name} ${object.user_id.user_email and '<%s>'%(object.user_id.user_email) or ''}<br/> | ||
1558 | 54 | ${object.company_id.name}<br/> | ||
1559 | 55 | % if object.company_id.street: | ||
1560 | 56 | ${object.company_id.street or ''}<br/> | ||
1561 | 57 | |||
1562 | 58 | % endif | ||
1563 | 59 | |||
1564 | 60 | % if object.company_id.street2: | ||
1565 | 61 | ${object.company_id.street2}<br/> | ||
1566 | 62 | % endif | ||
1567 | 63 | % if object.company_id.city or object.company_id.zip: | ||
1568 | 64 | ${object.company_id.zip or ''} ${object.company_id.city or ''}<br/> | ||
1569 | 65 | % endif | ||
1570 | 66 | % if object.company_id.country_id: | ||
1571 | 67 | ${object.company_id.state_id and ('%s, ' % object.company_id.state_id.name) or ''} ${object.company_id.country_id.name or ''}<br/> | ||
1572 | 68 | % endif | ||
1573 | 69 | % if object.company_id.phone: | ||
1574 | 70 | Phone: ${object.company_id.phone}<br/> | ||
1575 | 71 | % endif | ||
1576 | 72 | % if object.company_id.website: | ||
1577 | 73 | ${object.company_id.website or ''}<br/> | ||
1578 | 74 | % endif | ||
1579 | 75 | ]]></field> | ||
1580 | 76 | </record> | ||
1581 | 77 | |||
1582 | 78 | <!-- profile no follow --> | ||
1583 | 79 | <record model="credit.management.profile" | ||
1584 | 80 | id="credit_management_no_follow"> | ||
1585 | 81 | <field name="name">No follow</field> | ||
1586 | 82 | <field name="do_nothing" eval="1"/> | ||
1587 | 83 | </record> | ||
1588 | 84 | |||
1589 | 85 | <!-- profile 1 --> | ||
1590 | 86 | <record model="credit.management.profile" | ||
1591 | 87 | id="credit_management_3_time"> | ||
1592 | 88 | <field name="name">3 time policy</field> | ||
1593 | 89 | </record> | ||
1594 | 90 | |||
1595 | 91 | <record model="credit.management.profile.rule" | ||
1596 | 92 | id="3_time_1"> | ||
1597 | 93 | <field name="name">10 days net</field> | ||
1598 | 94 | <field name="level" eval="1"/> | ||
1599 | 95 | <field name="computation_mode">net_days</field> | ||
1600 | 96 | <field name="delay_days" eval="10"/> | ||
1601 | 97 | <field name="mail_template_id" ref="email_template_credit_management_base"/> | ||
1602 | 98 | <field name="profile_id" ref="credit_management_3_time"/> | ||
1603 | 99 | <field name="canal">mail</field> | ||
1604 | 100 | <field name="custom_text">Replace this text in rule by your message</field> | ||
1605 | 101 | </record> | ||
1606 | 102 | |||
1607 | 103 | <record model="credit.management.profile.rule" | ||
1608 | 104 | id="3_time_2"> | ||
1609 | 105 | <field name="name">30 days end of month</field> | ||
1610 | 106 | <field name="level" eval="2"/> | ||
1611 | 107 | <field name="computation_mode">end_of_month</field> | ||
1612 | 108 | <field name="delay_days" eval="30"/> | ||
1613 | 109 | <field name="mail_template_id" ref="email_template_credit_management_base"/> | ||
1614 | 110 | <field name="profile_id" ref="credit_management_3_time"/> | ||
1615 | 111 | <field name="canal">mail</field> | ||
1616 | 112 | <field name="custom_text">Replace this text in rule by your message</field> | ||
1617 | 113 | </record> | ||
1618 | 114 | |||
1619 | 115 | <record model="credit.management.profile.rule" | ||
1620 | 116 | id="3_time_3"> | ||
1621 | 117 | <field name="name">10 days sommation</field> | ||
1622 | 118 | <field name="level" eval="3"/> | ||
1623 | 119 | <field name="computation_mode">previous_date</field> | ||
1624 | 120 | <field name="delay_days" eval="10"/> | ||
1625 | 121 | <field name="mail_template_id" ref="email_template_credit_management_base"/> | ||
1626 | 122 | <field name="profile_id" ref="credit_management_3_time"/> | ||
1627 | 123 | <field name="canal">manual</field> | ||
1628 | 124 | <field name="custom_text">Replace this text in rule by your message</field> | ||
1629 | 125 | </record> | ||
1630 | 126 | |||
1631 | 127 | <!-- profile 2 --> | ||
1632 | 128 | <record model="credit.management.profile" | ||
1633 | 129 | id="credit_management_2_time"> | ||
1634 | 130 | <field name="name">2 time policy</field> | ||
1635 | 131 | </record> | ||
1636 | 132 | |||
1637 | 133 | <record model="credit.management.profile.rule" | ||
1638 | 134 | id="2_time_1"> | ||
1639 | 135 | <field name="name">30 days end of month</field> | ||
1640 | 136 | <field name="level" eval="1"/> | ||
1641 | 137 | <field name="computation_mode">end_of_month</field> | ||
1642 | 138 | <field name="delay_days" eval="30"/> | ||
1643 | 139 | <field name="mail_template_id" ref="email_template_credit_management_base"/> | ||
1644 | 140 | <field name="profile_id" ref="credit_management_2_time"/> | ||
1645 | 141 | <field name="canal">mail</field> | ||
1646 | 142 | <field name="custom_text">Replace this text in rule by your message</field> | ||
1647 | 143 | </record> | ||
1648 | 144 | |||
1649 | 145 | <record model="credit.management.profile.rule" | ||
1650 | 146 | id="2_time_2"> | ||
1651 | 147 | <field name="name">60 days sommation</field> | ||
1652 | 148 | <field name="level" eval="2"/> | ||
1653 | 149 | <field name="computation_mode">previous_date</field> | ||
1654 | 150 | <field name="delay_days" eval="60"/> | ||
1655 | 151 | <field name="mail_template_id" ref="email_template_credit_management_base"/> | ||
1656 | 152 | <field name="profile_id" ref="credit_management_2_time"/> | ||
1657 | 153 | <field name="canal">manual</field> | ||
1658 | 154 | <field name="custom_text">Replace this text in rule by your message</field> | ||
1659 | 155 | </record> | ||
1660 | 156 | |||
1661 | 157 | <record id="group_account_credit_management_manager" model="res.groups"> | ||
1662 | 158 | <field name="name">Credit Management manager</field> | ||
1663 | 159 | <field name="category_id" ref="base.module_category_accounting_and_finance"/> | ||
1664 | 160 | </record> | ||
1665 | 161 | |||
1666 | 162 | <record id="group_account_credit_management_user" model="res.groups" context="{'noadmin':True}"> | ||
1667 | 163 | <field name="name">Credit Management user</field> | ||
1668 | 164 | <field name="category_id" ref="base.module_category_accounting_and_finance"/> | ||
1669 | 165 | </record> | ||
1670 | 166 | |||
1671 | 167 | <record id="group_account_credit_management_info" model="res.groups" context="{'noadmin':True}"> | ||
1672 | 168 | <field name="name">Credit Management info</field> | ||
1673 | 169 | <field name="category_id" ref="base.module_category_accounting_and_finance"/> | ||
1674 | 170 | </record> | ||
1675 | 171 | |||
1676 | 172 | </data> | ||
1677 | 173 | </openerp> | ||
1678 | 0 | 174 | ||
1679 | === added directory 'account_credit_management/i18n' | |||
1680 | === added directory 'account_credit_management/report' | |||
1681 | === added file 'account_credit_management/report/__init__.py' | |||
1682 | --- account_credit_management/report/__init__.py 1970-01-01 00:00:00 +0000 | |||
1683 | +++ account_credit_management/report/__init__.py 2012-10-15 10:14:35 +0000 | |||
1684 | @@ -0,0 +1,1 @@ | |||
1685 | 1 | from . import credit_management_summary | ||
1686 | 0 | 2 | ||
1687 | === added file 'account_credit_management/report/credit_management_summary.html.mako' | |||
1688 | --- account_credit_management/report/credit_management_summary.html.mako 1970-01-01 00:00:00 +0000 | |||
1689 | +++ account_credit_management/report/credit_management_summary.html.mako 2012-10-15 10:14:35 +0000 | |||
1690 | @@ -0,0 +1,19 @@ | |||
1691 | 1 | <html> | ||
1692 | 2 | <head> | ||
1693 | 3 | <style type="text/css"> | ||
1694 | 4 | ${css} | ||
1695 | 5 | </style> | ||
1696 | 6 | </head> | ||
1697 | 7 | <body> | ||
1698 | 8 | %for comm in objects : | ||
1699 | 9 | ${setLang(comm.partner_id.lang)} | ||
1700 | 10 | <% | ||
1701 | 11 | current_uri = '%s_profile_template' % (comm.partner_id.lang) | ||
1702 | 12 | if not context.lookup.has_template(current_uri): | ||
1703 | 13 | context.lookup.put_string(current_uri, comm.current_profile_rule.mail_template_id.body_html) | ||
1704 | 14 | %> | ||
1705 | 15 | <%include file="${current_uri}" args="object=comm,mode='pdf'"/> | ||
1706 | 16 | </br> | ||
1707 | 17 | %endfor | ||
1708 | 18 | </body> | ||
1709 | 19 | </html> | ||
1710 | 0 | 20 | ||
1711 | === added file 'account_credit_management/report/credit_management_summary.py' | |||
1712 | --- account_credit_management/report/credit_management_summary.py 1970-01-01 00:00:00 +0000 | |||
1713 | +++ account_credit_management/report/credit_management_summary.py 2012-10-15 10:14:35 +0000 | |||
1714 | @@ -0,0 +1,37 @@ | |||
1715 | 1 | # -*- coding: utf-8 -*- | ||
1716 | 2 | ############################################################################## | ||
1717 | 3 | # | ||
1718 | 4 | # Author: Nicolas Bessi | ||
1719 | 5 | # Copyright 2012 Camptocamp SA | ||
1720 | 6 | # | ||
1721 | 7 | # This program is free software: you can redistribute it and/or modify | ||
1722 | 8 | # it under the terms of the GNU Affero General Public License as | ||
1723 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
1724 | 10 | # License, or (at your option) any later version. | ||
1725 | 11 | # | ||
1726 | 12 | # This program is distributed in the hope that it will be useful, | ||
1727 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1728 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1729 | 15 | # GNU Affero General Public License for more details. | ||
1730 | 16 | # | ||
1731 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
1732 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1733 | 19 | # | ||
1734 | 20 | ############################################################################## | ||
1735 | 21 | import time | ||
1736 | 22 | |||
1737 | 23 | from openerp.report import report_sxw | ||
1738 | 24 | |||
1739 | 25 | class CreditSummaryReport(report_sxw.rml_parse): | ||
1740 | 26 | def __init__(self, cr, uid, name, context): | ||
1741 | 27 | super(CreditSummaryReport, self).__init__(cr, uid, name, context=context) | ||
1742 | 28 | self.localcontext.update({ | ||
1743 | 29 | 'time': time, | ||
1744 | 30 | 'cr':cr, | ||
1745 | 31 | 'uid': uid, | ||
1746 | 32 | }) | ||
1747 | 33 | |||
1748 | 34 | report_sxw.report_sxw('report.credit_management_summary', | ||
1749 | 35 | 'credit.management.communication', | ||
1750 | 36 | 'addons/account_credit_management/report/credit_management_summary.html.mako', | ||
1751 | 37 | parser=CreditSummaryReport) | ||
1752 | 0 | 38 | ||
1753 | === added file 'account_credit_management/report/report.xml' | |||
1754 | --- account_credit_management/report/report.xml 1970-01-01 00:00:00 +0000 | |||
1755 | +++ account_credit_management/report/report.xml 2012-10-15 10:14:35 +0000 | |||
1756 | @@ -0,0 +1,12 @@ | |||
1757 | 1 | <openerp> | ||
1758 | 2 | <data> | ||
1759 | 3 | <report auto="False" | ||
1760 | 4 | id="report_webkit_html" | ||
1761 | 5 | model="credit.management.communication" | ||
1762 | 6 | name="credit_management_summary" | ||
1763 | 7 | file="account_credit_management/report/credit_management_summary.html.mako" | ||
1764 | 8 | string="Credit Summary" | ||
1765 | 9 | report_type="webkit" | ||
1766 | 10 | webkit_header="report_webkit.ir_header_webkit_basesample0"/> | ||
1767 | 11 | </data> | ||
1768 | 12 | </openerp> | ||
1769 | 0 | 13 | ||
1770 | === added directory 'account_credit_management/scenarios' | |||
1771 | === added directory 'account_credit_management/scenarios/credit_management' | |||
1772 | === added file 'account_credit_management/scenarios/credit_management/00_credit_management_param.feature' | |||
1773 | --- account_credit_management/scenarios/credit_management/00_credit_management_param.feature 1970-01-01 00:00:00 +0000 | |||
1774 | +++ account_credit_management/scenarios/credit_management/00_credit_management_param.feature 2012-10-15 10:14:35 +0000 | |||
1775 | @@ -0,0 +1,23 @@ | |||
1776 | 1 | ############################################################################### | ||
1777 | 2 | # | ||
1778 | 3 | # OERPScenario, OpenERP Functional Tests | ||
1779 | 4 | # Copyright 2009 Camptocamp SA | ||
1780 | 5 | # | ||
1781 | 6 | ############################################################################## | ||
1782 | 7 | ############################################################################## | ||
1783 | 8 | # Branch # Module # Processes # System | ||
1784 | 9 | @credit_management_module @credit_management_param | ||
1785 | 10 | |||
1786 | 11 | Feature: In order to validate account voucher behavious as an admin user I prepare data | ||
1787 | 12 | @credit_management_addon_install | ||
1788 | 13 | Scenario: Install module | ||
1789 | 14 | Given I need a "ir.module.module" with name: account_voucher | ||
1790 | 15 | And having: | ||
1791 | 16 | |name | value | | ||
1792 | 17 | | demo | 0 | | ||
1793 | 18 | |||
1794 | 19 | Given I do not want all demo data to be loaded on install | ||
1795 | 20 | And I install the required modules with dependencies: | ||
1796 | 21 | | name | | ||
1797 | 22 | | account_credit_management | | ||
1798 | 23 | Then my modules should have been installed and models reloaded | ||
1799 | 0 | \ No newline at end of file | 24 | \ No newline at end of file |
1800 | 1 | 25 | ||
1801 | === added file 'account_credit_management/scenarios/credit_management/01_credit_management_partners.feature' | |||
1802 | --- account_credit_management/scenarios/credit_management/01_credit_management_partners.feature 1970-01-01 00:00:00 +0000 | |||
1803 | +++ account_credit_management/scenarios/credit_management/01_credit_management_partners.feature 2012-10-15 10:14:35 +0000 | |||
1804 | @@ -0,0 +1,60 @@ | |||
1805 | 1 | ############################################################################### | ||
1806 | 2 | # | ||
1807 | 3 | # OERPScenario, OpenERP Functional Tests | ||
1808 | 4 | # Copyright 2009 Camptocamp SA | ||
1809 | 5 | # | ||
1810 | 6 | ############################################################################## | ||
1811 | 7 | ############################################################################## | ||
1812 | 8 | # Branch # Module # Processes # System | ||
1813 | 9 | @credit_management_module @credit_management_partner | ||
1814 | 10 | |||
1815 | 11 | Feature: I add profile to partners already created | ||
1816 | 12 | @credit_management_partner_1 | ||
1817 | 13 | Scenario: Partner_1 | ||
1818 | 14 | Given I need a "res.partner" with oid: scen.partner_1 | ||
1819 | 15 | And having: | ||
1820 | 16 | | name | value | | ||
1821 | 17 | | name | partner_1 | | ||
1822 | 18 | | credit_profile_id | by name: No follow | | ||
1823 | 19 | |||
1824 | 20 | @credit_management_customer_1 | ||
1825 | 21 | Scenario: Customer_1 | ||
1826 | 22 | Given I need a "res.partner" with oid: scen.customer_1 | ||
1827 | 23 | And having: | ||
1828 | 24 | | name | value | | ||
1829 | 25 | | name | customer_1 | | ||
1830 | 26 | | credit_profile_id | by name: 2 time policy| | ||
1831 | 27 | |||
1832 | 28 | @credit_management_customer_2 | ||
1833 | 29 | Scenario: Customer_2 | ||
1834 | 30 | Given I need a "res.partner" with oid: scen.customer_2 | ||
1835 | 31 | And having: | ||
1836 | 32 | | name | value | | ||
1837 | 33 | | name | customer_2 | | ||
1838 | 34 | | credit_profile_id | by name: 2 time policy| | ||
1839 | 35 | |||
1840 | 36 | @credit_management_customer_3 | ||
1841 | 37 | Scenario: Customer_3 | ||
1842 | 38 | Given I need a "res.partner" with oid: scen.customer_3 | ||
1843 | 39 | And having: | ||
1844 | 40 | | name | value | | ||
1845 | 41 | | name | customer_3 | | ||
1846 | 42 | | credit_profile_id | by name: 2 time policy| | ||
1847 | 43 | |||
1848 | 44 | @credit_management_customer_4 | ||
1849 | 45 | Scenario: Customer_4 | ||
1850 | 46 | Given I need a "res.partner" with oid: scen.customer_4 | ||
1851 | 47 | And having: | ||
1852 | 48 | | name | value | | ||
1853 | 49 | | name | customer_4 | | ||
1854 | 50 | | credit_profile_id | by name: 3 time policy| | ||
1855 | 51 | |||
1856 | 52 | @credit_management_customer_5 | ||
1857 | 53 | Scenario: Customer_5 | ||
1858 | 54 | Given I need a "res.partner" with oid: scen.customer_5 | ||
1859 | 55 | And having: | ||
1860 | 56 | | name | value | | ||
1861 | 57 | | name | customer_5_usd | | ||
1862 | 58 | | credit_profile_id | by name: 3 time policy| | ||
1863 | 59 | |||
1864 | 60 | |||
1865 | 0 | 61 | ||
1866 | === added file 'account_credit_management/scenarios/credit_management/credit_management_01_data.feature' | |||
1867 | --- account_credit_management/scenarios/credit_management/credit_management_01_data.feature 1970-01-01 00:00:00 +0000 | |||
1868 | +++ account_credit_management/scenarios/credit_management/credit_management_01_data.feature 2012-10-15 10:14:35 +0000 | |||
1869 | @@ -0,0 +1,224 @@ | |||
1870 | 1 | ############################################################################### | ||
1871 | 2 | # | ||
1872 | 3 | # OERPScenario, OpenERP Functional Tests | ||
1873 | 4 | # Copyright 2012 Camptocamp SA | ||
1874 | 5 | # Author Nicolas Bessi | ||
1875 | 6 | ############################################################################## | ||
1876 | 7 | |||
1877 | 8 | # Features Generic tags (none for all) | ||
1878 | 9 | ############################################################################## | ||
1879 | 10 | |||
1880 | 11 | @credit_management_module @credit_management_base_data | ||
1881 | 12 | |||
1882 | 13 | Feature: Ensure that mail credit management is correct | ||
1883 | 14 | |||
1884 | 15 | |||
1885 | 16 | @credit_management_data | ||
1886 | 17 | Scenario: Create data | ||
1887 | 18 | Given I need a "ir.module.module" with name: account_credit_management | ||
1888 | 19 | And having: | ||
1889 | 20 | |name|value| | ||
1890 | 21 | | demo | 1 | | ||
1891 | 22 | Given I install the required modules with dependencies: | ||
1892 | 23 | | name | | ||
1893 | 24 | | account_credit_management | | ||
1894 | 25 | Given I need a "res.partner" with oid: credit_management.trusted_partner | ||
1895 | 26 | And having: | ||
1896 | 27 | | name | value | | ||
1897 | 28 | | name | Credit m. trusted partner | | ||
1898 | 29 | | customer | 1 | | ||
1899 | 30 | | credit_profile_id | by name: No follow | | ||
1900 | 31 | |||
1901 | 32 | Given I need a "res.partner.address" with oid: credit_management.trusted_address | ||
1902 | 33 | And having: | ||
1903 | 34 | | name | value | | ||
1904 | 35 | | name | Luc Maurer | | ||
1905 | 36 | | zip | 1015 | | ||
1906 | 37 | | city | lausanne | | ||
1907 | 38 | | email | openerp@locahost.dummy | | ||
1908 | 39 | | phone | +41 21 619 10 12 | | ||
1909 | 40 | | street | PSE-A, EPF | | ||
1910 | 41 | | partner_id | by oid: credit_management.trusted_partner | | ||
1911 | 42 | |||
1912 | 43 | |||
1913 | 44 | Given I need a "res.partner" with oid: credit_management.not_so_trusted_partner | ||
1914 | 45 | And having: | ||
1915 | 46 | | name | value | | ||
1916 | 47 | | name | Credit m. not so trusted partner | | ||
1917 | 48 | | customer | 1 | | ||
1918 | 49 | | credit_profile_id | by name: 2 time policy | | ||
1919 | 50 | |||
1920 | 51 | Given I need a "res.partner.address" with oid: credit_management.not_so_trusted_address | ||
1921 | 52 | And having: | ||
1922 | 53 | | name | value | | ||
1923 | 54 | | name | Not so trusted | | ||
1924 | 55 | | zip | 1015 | | ||
1925 | 56 | | city | lausanne | | ||
1926 | 57 | | email | openerp@locahost.dummy | | ||
1927 | 58 | | phone | +41 21 619 10 12 | | ||
1928 | 59 | | street | PSE-A, EPF | | ||
1929 | 60 | | partner_id | by oid: credit_management.not_so_trusted_partner | | ||
1930 | 61 | |||
1931 | 62 | |||
1932 | 63 | Given I need a "res.partner" with oid: credit_management.untrusted_partner | ||
1933 | 64 | And having: | ||
1934 | 65 | | name | value | | ||
1935 | 66 | | name | Credit m. untrusted partner | | ||
1936 | 67 | | customer | 1 | | ||
1937 | 68 | | credit_profile_id | by name: 3 time policy | | ||
1938 | 69 | |||
1939 | 70 | Given I need a "res.partner.address" with oid: credit_management.untrusted_address | ||
1940 | 71 | And having: | ||
1941 | 72 | | name | value | | ||
1942 | 73 | | name | Untrusted | | ||
1943 | 74 | | zip | 1015 | | ||
1944 | 75 | | city | lausanne | | ||
1945 | 76 | | email | openerp@locahost.dummy | | ||
1946 | 77 | | phone | +41 21 619 10 12 | | ||
1947 | 78 | | street | PSE-A, EPF | | ||
1948 | 79 | | partner_id | by oid: credit_management.untrusted_partner | | ||
1949 | 80 | |||
1950 | 81 | |||
1951 | 82 | Given I need a "res.partner" with oid: credit_management.lambda_partner | ||
1952 | 83 | And having: | ||
1953 | 84 | | name | value | | ||
1954 | 85 | | name | Credit m. lambda partner | | ||
1955 | 86 | | customer | 1 | | ||
1956 | 87 | |||
1957 | 88 | Given I need a "res.partner.address" with oid: credit_management.lambda_address | ||
1958 | 89 | And having: | ||
1959 | 90 | | name | value | | ||
1960 | 91 | | name | Lambda | | ||
1961 | 92 | | zip | 1015 | | ||
1962 | 93 | | city | lausanne | | ||
1963 | 94 | | email | openerp@locahost.dummy | | ||
1964 | 95 | | phone | +41 21 619 10 12 | | ||
1965 | 96 | | street | PSE-A, EPF | | ||
1966 | 97 | | partner_id | by oid: credit_management.lambda_partner | | ||
1967 | 98 | |||
1968 | 99 | |||
1969 | 100 | |||
1970 | 101 | @inv1 | ||
1971 | 102 | Scenario: invoices | ||
1972 | 103 | # trusted invoice on trusted partner no follow | ||
1973 | 104 | Given I need a "account.invoice" with oid: credit_management.inv1 | ||
1974 | 105 | And having: | ||
1975 | 106 | | name | value | | ||
1976 | 107 | | name | trusted invoice 1 | | ||
1977 | 108 | | date_invoice | 2012-01-01 | | ||
1978 | 109 | | date_due | 2012-02-15 | | ||
1979 | 110 | | address_invoice_id | by oid: credit_management.trusted_address | | ||
1980 | 111 | | partner_id | by oid: credit_management.trusted_partner | | ||
1981 | 112 | | account_id | by name: Trusted Debtors - (test) | | ||
1982 | 113 | | journal_id | by name: Sales Journal - (test) | | ||
1983 | 114 | |||
1984 | 115 | |||
1985 | 116 | Given I need a "account.invoice.line" with oid: credit_management.inv_line1 | ||
1986 | 117 | And having: | ||
1987 | 118 | | name | value | | ||
1988 | 119 | | name | trusted invoice line 1 | | ||
1989 | 120 | | quantity | 1 | | ||
1990 | 121 | | price_unit | 100 | | ||
1991 | 122 | | account_id | by name: Product Sales - (test) | | ||
1992 | 123 | | invoice_id | by oid: credit_management.inv1 | | ||
1993 | 124 | Given I find a "account.invoice" with oid: credit_management.inv1 | ||
1994 | 125 | And I open the credit invoice | ||
1995 | 126 | |||
1996 | 127 | |||
1997 | 128 | |||
1998 | 129 | Given I need a "account.invoice" with oid: credit_management.inv2 | ||
1999 | 130 | And having: | ||
2000 | 131 | | name | value | | ||
2001 | 132 | | name | lambda invoice 1 | | ||
2002 | 133 | | date_invoice | 2012-01-01 | | ||
2003 | 134 | | date_due | 2012-02-15 | | ||
2004 | 135 | | address_invoice_id | by oid: credit_management.lambda_address | | ||
2005 | 136 | | partner_id | by oid: credit_management.lambda_partner | | ||
2006 | 137 | | account_id | by name: Not so trusted Debtors - (test) | | ||
2007 | 138 | | journal_id | by name: Sales Journal - (test) | | ||
2008 | 139 | |||
2009 | 140 | Given I need a "account.invoice.line" with oid: credit_management.inv_line2 | ||
2010 | 141 | And having: | ||
2011 | 142 | | name | value | | ||
2012 | 143 | | name | lambda invoice line 1 | | ||
2013 | 144 | | quantity | 1 | | ||
2014 | 145 | | price_unit | 130 | | ||
2015 | 146 | | account_id | by name: Product Sales - (test) | | ||
2016 | 147 | | invoice_id | by oid: credit_management.inv2 | | ||
2017 | 148 | Given I find a "account.invoice" with oid: credit_management.inv2 | ||
2018 | 149 | And I open the credit invoice | ||
2019 | 150 | |||
2020 | 151 | |||
2021 | 152 | Given I need a "account.invoice" with oid: credit_management.inv3 | ||
2022 | 153 | And having: | ||
2023 | 154 | | name | value | | ||
2024 | 155 | | name | Not so trusted invoice | | ||
2025 | 156 | | date_invoice | 2012-01-01 | | ||
2026 | 157 | | date_due | 2012-02-15 | | ||
2027 | 158 | | address_invoice_id | by oid: credit_management.not_so_trusted_address | | ||
2028 | 159 | | partner_id | by oid: credit_management.not_so_trusted_partner | | ||
2029 | 160 | | account_id | by name: Not so trusted Debtors - (test) | | ||
2030 | 161 | | journal_id | by name: Sales Journal - (test) | | ||
2031 | 162 | |||
2032 | 163 | |||
2033 | 164 | Given I need a "account.invoice.line" with oid: credit_management.inv_line3 | ||
2034 | 165 | And having: | ||
2035 | 166 | | name | value | | ||
2036 | 167 | | name | Not so trusted invoice line 1 | | ||
2037 | 168 | | quantity | 1 | | ||
2038 | 169 | | price_unit | 150 | | ||
2039 | 170 | | account_id | by name: Product Sales - (test) | | ||
2040 | 171 | | invoice_id | by oid: credit_management.inv3 | | ||
2041 | 172 | Given I find a "account.invoice" with oid: credit_management.inv3 | ||
2042 | 173 | And I open the credit invoice | ||
2043 | 174 | |||
2044 | 175 | |||
2045 | 176 | |||
2046 | 177 | |||
2047 | 178 | Given I need a "account.invoice" with oid: credit_management.inv4 | ||
2048 | 179 | And having: | ||
2049 | 180 | | name | value | | ||
2050 | 181 | | name | Untrusted invoice | | ||
2051 | 182 | | date_invoice | 2012-01-01 | | ||
2052 | 183 | | date_due | 2012-02-15 | | ||
2053 | 184 | | address_invoice_id | by oid: credit_management.untrusted_address | | ||
2054 | 185 | | partner_id | by oid: credit_management.untrusted_partner | | ||
2055 | 186 | | account_id | by name: Not so trusted Debtors - (test) | | ||
2056 | 187 | | journal_id | by name: Sales Journal - (test) | | ||
2057 | 188 | |||
2058 | 189 | |||
2059 | 190 | Given I need a "account.invoice.line" with oid: credit_management.inv_line4 | ||
2060 | 191 | And having: | ||
2061 | 192 | | name | value | | ||
2062 | 193 | | name | Un trusted invoice line 1 | | ||
2063 | 194 | | quantity | 1 | | ||
2064 | 195 | | price_unit | 170 | | ||
2065 | 196 | | account_id | by name: Product Sales - (test) | | ||
2066 | 197 | | invoice_id | by oid: credit_management.inv4 | | ||
2067 | 198 | Given I find a "account.invoice" with oid: credit_management.inv4 | ||
2068 | 199 | And I open the credit invoice | ||
2069 | 200 | |||
2070 | 201 | |||
2071 | 202 | Given I need a "account.invoice" with oid: credit_management.inv5 | ||
2072 | 203 | And having: | ||
2073 | 204 | | name | value | | ||
2074 | 205 | | name | lamba invoice with untrusted policy | | ||
2075 | 206 | | date_invoice | 2012-01-01 | | ||
2076 | 207 | | date_due | 2012-02-15 | | ||
2077 | 208 | | address_invoice_id | by oid: credit_management.lambda_address | | ||
2078 | 209 | | partner_id | by oid: credit_management.lambda_partner | | ||
2079 | 210 | | account_id | by name: Not so trusted Debtors - (test) | | ||
2080 | 211 | | journal_id | by name: Sales Journal - (test) | | ||
2081 | 212 | | credit_profile_id | by name: 3 time policy | | ||
2082 | 213 | |||
2083 | 214 | |||
2084 | 215 | Given I need a "account.invoice.line" with oid: credit_management.inv_line5 | ||
2085 | 216 | And having: | ||
2086 | 217 | | name | value | | ||
2087 | 218 | | name | Un trusted invoice line 1 | | ||
2088 | 219 | | quantity | 1 | | ||
2089 | 220 | | price_unit | 200 | | ||
2090 | 221 | | account_id | by name: Product Sales - (test) | | ||
2091 | 222 | | invoice_id | by oid: credit_management.inv5 | | ||
2092 | 223 | Given I find a "account.invoice" with oid: credit_management.inv5 | ||
2093 | 224 | And I open the credit invoice | ||
2094 | 0 | 225 | ||
2095 | === added file 'account_credit_management/scenarios/credit_management/credit_management_02_run.feature' | |||
2096 | --- account_credit_management/scenarios/credit_management/credit_management_02_run.feature 1970-01-01 00:00:00 +0000 | |||
2097 | +++ account_credit_management/scenarios/credit_management/credit_management_02_run.feature 2012-10-15 10:14:35 +0000 | |||
2098 | @@ -0,0 +1,33 @@ | |||
2099 | 1 | ############################################################################### | ||
2100 | 2 | # | ||
2101 | 3 | # OERPScenario, OpenERP Functional Tests | ||
2102 | 4 | # Copyright 2012 Camptocamp SA | ||
2103 | 5 | # Author Nicolas Bessi | ||
2104 | 6 | ############################################################################## | ||
2105 | 7 | |||
2106 | 8 | # Features Generic tags (none for all) | ||
2107 | 9 | ############################################################################## | ||
2108 | 10 | |||
2109 | 11 | @credit_management_module | ||
2110 | 12 | |||
2111 | 13 | Feature: Ensure that mail credit line generation first pass is correct | ||
2112 | 14 | |||
2113 | 15 | |||
2114 | 16 | @credit_management_first_run | ||
2115 | 17 | Scenario: clean data | ||
2116 | 18 | Given I clean all the credit lines | ||
2117 | 19 | #Given I unreconcile and clean all move line | ||
2118 | 20 | |||
2119 | 21 | @credit_management_first_run | ||
2120 | 22 | Scenario: Create run | ||
2121 | 23 | Given I need a "credit.management.run" with oid: credit_management.run1 | ||
2122 | 24 | And having: | ||
2123 | 25 | | name | value | | ||
2124 | 26 | | date | 2012-03-01 | | ||
2125 | 27 | When I launch the credit run | ||
2126 | 28 | Then my credit run should be in state "done" | ||
2127 | 29 | And I should have "2" credit lines of level "1" | ||
2128 | 30 | And credit lines should have following values: | ||
2129 | 31 | | balance | date due | account | profile | date | partner | canal | level | move line | profile rule | state | amount due | currency | | ||
2130 | 32 | | 170 | 2012-02-15 | B2C Debtors - (test) | 3 time policy | 2012-03-01 | Credit m. untrusted partner | mail | 1.00 | Untrusted invoice | 10 days net | draft | 170 | | | ||
2131 | 33 | | 200 | 2012-02-15 | B2C Debtors - (test) | 3 time policy | 2012-03-01 | Credit m. lambda partner | mail | 1.00 | lamba invoice with untrusted policy | 10 days net | draft | 200 | | | ||
2132 | 0 | 34 | ||
2133 | === added file 'account_credit_management/scenarios/credit_management/credit_management_03_run.feature' | |||
2134 | --- account_credit_management/scenarios/credit_management/credit_management_03_run.feature 1970-01-01 00:00:00 +0000 | |||
2135 | +++ account_credit_management/scenarios/credit_management/credit_management_03_run.feature 2012-10-15 10:14:35 +0000 | |||
2136 | @@ -0,0 +1,26 @@ | |||
2137 | 1 | ############################################################################### | ||
2138 | 2 | # | ||
2139 | 3 | # OERPScenario, OpenERP Functional Tests | ||
2140 | 4 | # Copyright 2012 Camptocamp SA | ||
2141 | 5 | # Author Nicolas Bessi | ||
2142 | 6 | ############################################################################## | ||
2143 | 7 | |||
2144 | 8 | # Features Generic tags (none for all) | ||
2145 | 9 | ############################################################################## | ||
2146 | 10 | |||
2147 | 11 | @credit_management_mark_mail | ||
2148 | 12 | |||
2149 | 13 | Feature: Ensure that mail credit line generation first pass is correct | ||
2150 | 14 | |||
2151 | 15 | |||
2152 | 16 | @credit_management_mark | ||
2153 | 17 | Scenario: mark lines | ||
2154 | 18 | Given there is "draft" credit lines | ||
2155 | 19 | And I mark all draft mail to state "to_be_sent" | ||
2156 | 20 | Then the draft line should be in state "to_be_sent" | ||
2157 | 21 | |||
2158 | 22 | @credit_management_mail | ||
2159 | 23 | Scenario: mail lines | ||
2160 | 24 | Given there is "to_be_sent" credit lines | ||
2161 | 25 | And I mail all ready lines | ||
2162 | 26 | Then All sent lines should be linked to a mail and in mail status "sent" | ||
2163 | 0 | 27 | ||
2164 | === added directory 'account_credit_management/scenarios/credit_management/step_definitions' | |||
2165 | === added file 'account_credit_management/scenarios/credit_management/step_definitions/credit_management.rb' | |||
2166 | --- account_credit_management/scenarios/credit_management/step_definitions/credit_management.rb 1970-01-01 00:00:00 +0000 | |||
2167 | +++ account_credit_management/scenarios/credit_management/step_definitions/credit_management.rb 2012-10-15 10:14:35 +0000 | |||
2168 | @@ -0,0 +1,115 @@ | |||
2169 | 1 | # Given /^I open the credit invoice$/ do | ||
2170 | 2 | # @found_item.should_not be_nil, | ||
2171 | 3 | # "no invoice found" | ||
2172 | 4 | # ['draft', 'open'].should include(@found_item.state), | ||
2173 | 5 | # "Invoice is not draf or open" | ||
2174 | 6 | # if @found_item.state == 'draft' | ||
2175 | 7 | # @found_item.wkf_action('invoice_open') | ||
2176 | 8 | # end | ||
2177 | 9 | # end | ||
2178 | 10 | |||
2179 | 11 | Then /^I launch the credit run$/ do | ||
2180 | 12 | @found_item.should_not be_nil, | ||
2181 | 13 | "no run found" | ||
2182 | 14 | @found_item.generate_credit_lines() | ||
2183 | 15 | end | ||
2184 | 16 | |||
2185 | 17 | Given /^there is "(.*?)" credit lines$/ do |state| | ||
2186 | 18 | @credit_lines = CreditManagementLine.find_all_by_state(state) | ||
2187 | 19 | @credit_lines.should_not be_empty, | ||
2188 | 20 | "not #{state} lines found" | ||
2189 | 21 | end | ||
2190 | 22 | |||
2191 | 23 | Given /^I mark all draft mail to state "(.*?)"$/ do | state | | ||
2192 | 24 | wiz = CreditManagementMarker.new | ||
2193 | 25 | wiz.name = state | ||
2194 | 26 | wiz.mark_all = true | ||
2195 | 27 | wiz.save | ||
2196 | 28 | wiz.mark_lines | ||
2197 | 29 | end | ||
2198 | 30 | |||
2199 | 31 | Then /^the draft line should be in state "(.*?)"$/ do | state | | ||
2200 | 32 | @credit_lines.should_not be_nil, | ||
2201 | 33 | "no line where stored" | ||
2202 | 34 | @credit_lines.each do |line| | ||
2203 | 35 | line = CreditManagementLine.find(line.id) | ||
2204 | 36 | line.state.should eql(state), | ||
2205 | 37 | "The line #{line.id} is not in state #{state} he is is in state #{line.state} " | ||
2206 | 38 | end | ||
2207 | 39 | |||
2208 | 40 | end | ||
2209 | 41 | |||
2210 | 42 | Given /^I mail all ready lines$/ do | ||
2211 | 43 | @credit_lines.should_not be_nil, | ||
2212 | 44 | "no line where stored" | ||
2213 | 45 | wiz = CreditManagementMailer.new | ||
2214 | 46 | wiz.mail_all = true | ||
2215 | 47 | wiz.save | ||
2216 | 48 | wiz.mail_lines | ||
2217 | 49 | end | ||
2218 | 50 | |||
2219 | 51 | Given /^I clean all the credit lines$/ do | ||
2220 | 52 | CreditManagementLine.find(:all).each do | line | | ||
2221 | 53 | line.destroy | ||
2222 | 54 | end | ||
2223 | 55 | end | ||
2224 | 56 | |||
2225 | 57 | Then /^my credit run should be in state "(.*?)"$/ do |state| | ||
2226 | 58 | @found_item.should_not be nil | ||
2227 | 59 | @run = CreditManagementRun.find(@found_item.id) | ||
2228 | 60 | @run.state.should eq(state), | ||
2229 | 61 | "Run state is in state #{@run.state} instead of #{state}" | ||
2230 | 62 | end | ||
2231 | 63 | |||
2232 | 64 | |||
2233 | 65 | Then /^All sent lines should be linked to a mail and in mail status "(.*?)"$/ do |status| | ||
2234 | 66 | @credit_lines.should_not be_nil, | ||
2235 | 67 | "no line where stored" | ||
2236 | 68 | @credit_lines.each do |line| | ||
2237 | 69 | line = CreditManagementLine.find(line.id) | ||
2238 | 70 | line.state.should eql(status), | ||
2239 | 71 | "The line #{line.id} is has no mail status #{status} but #{line.state}" | ||
2240 | 72 | end | ||
2241 | 73 | end | ||
2242 | 74 | |||
2243 | 75 | Then /^I should have "(.*?)" credit lines of level "(.*?)"$/ do |number, level| | ||
2244 | 76 | CreditManagementLine.find_all_by_level(level).length.should eq (number.to_i) | ||
2245 | 77 | end | ||
2246 | 78 | |||
2247 | 79 | Then /^credit lines should have following values:$/ do |table| | ||
2248 | 80 | h_list = table.hashes | ||
2249 | 81 | h_list.each do | h | | ||
2250 | 82 | h.delete_if {|k, v| v.empty?} | ||
2251 | 83 | end | ||
2252 | 84 | errors = [] | ||
2253 | 85 | h_list.each do | row | | ||
2254 | 86 | account = AccountAccount.find_by_name(row['account'], :fields=>['id']) | ||
2255 | 87 | account.should_not be_nil, "no account named #{row['account']} found" | ||
2256 | 88 | |||
2257 | 89 | profile = CreditManagementProfile.find_by_name(row['profile'], :fields=>['id']) | ||
2258 | 90 | profile.should_not be_nil, "No account #{row['account']} found" | ||
2259 | 91 | |||
2260 | 92 | partner = ResPartner.find_by_name(row['partner'], :fields=>['id']) | ||
2261 | 93 | partner.should_not be_nil, "No partner #{row['partner']} found" | ||
2262 | 94 | |||
2263 | 95 | move_line = AccountMoveLine.find_by_name(row['move line'], :fields=>['id']) | ||
2264 | 96 | move_line.should_not be_nil, "No move line #{row['move line']} found" | ||
2265 | 97 | |||
2266 | 98 | rule = CreditManagementProfileRule.find_by_name(row['profile rule'], :fields=>['id']) | ||
2267 | 99 | rule.should_not be_nil, "No profile rune #{row['profile rule']} found" | ||
2268 | 100 | |||
2269 | 101 | domain = [['account_id', '=', account.id], ['profile_id', '=', profile.id], | ||
2270 | 102 | ['partner_id', '=', partner.id], ['move_line_id', '=', move_line.id], | ||
2271 | 103 | ['profile_rule_id', '=', rule.id], ['amount_due', '=', row.fetch('amount due', 0.0)], | ||
2272 | 104 | ['state', '=', row.fetch('state')], ['level', '=', row.fetch('level', 0.0)], | ||
2273 | 105 | ['canal', '=', row.fetch('canal')], ['balance_due', '=', row.fetch('balance', 0.0)], | ||
2274 | 106 | ['date_due', '=', row.fetch('date due')], ['date', '=', row.fetch('date')]] | ||
2275 | 107 | if row['currency'] | ||
2276 | 108 | curreny = ResCurrency.find_by_name(row['currency'], :fields=>['id']) | ||
2277 | 109 | domain.push ['currency_id', '=', curreny.id] | ||
2278 | 110 | end | ||
2279 | 111 | pp domain | ||
2280 | 112 | line = CreditManagementLine.find(:first, :domain=>domain) | ||
2281 | 113 | line.should_not be_nil, "Can not find line #{row.inspect}" | ||
2282 | 114 | end | ||
2283 | 115 | end | ||
2284 | 0 | 116 | ||
2285 | === added file 'account_credit_management/scenarios/run_command.txt' | |||
2286 | --- account_credit_management/scenarios/run_command.txt 1970-01-01 00:00:00 +0000 | |||
2287 | +++ account_credit_management/scenarios/run_command.txt 2012-10-15 10:14:35 +0000 | |||
2288 | @@ -0,0 +1,1 @@ | |||
2289 | 1 | cucumber CONF=nbessi.conf --tags=@credit_management_first_run features /opt/openerp_geoengine/src/c2c-financial-addons/account_credit_management/scenarios/ | ||
2290 | 0 | 2 | ||
2291 | === added directory 'account_credit_management/security' | |||
2292 | === added file 'account_credit_management/security/ir.model.access.csv' | |||
2293 | --- account_credit_management/security/ir.model.access.csv 1970-01-01 00:00:00 +0000 | |||
2294 | +++ account_credit_management/security/ir.model.access.csv 2012-10-15 10:14:35 +0000 | |||
2295 | @@ -0,0 +1,27 @@ | |||
2296 | 1 | "id","perm_create","perm_unlink","group_id/id","name","model_id/id","perm_read","perm_write" | ||
2297 | 2 | "account_credit_management.ir_model_access_270",1,1,"group_account_credit_management_manager","credit_management_manager_line","account_credit_management.model_credit_management_line",1,1 | ||
2298 | 3 | "account_credit_management.ir_model_access_271",1,1,"group_account_credit_management_user","credit_management_user_line","account_credit_management.model_credit_management_line",1,1 | ||
2299 | 4 | "account_credit_management.ir_model_access_272",0,0,"group_account_credit_management_info","credit_management_info_line","account_credit_management.model_credit_management_line",1,0 | ||
2300 | 5 | "account_credit_management.ir_model_access_273",1,1,"group_account_credit_management_manager","credit_management_manager_mail_template","email_template.model_email_template",1,1 | ||
2301 | 6 | "account_credit_management.ir_model_access_274",1,1,"group_account_credit_management_manager","credit_management_manager_mail_template_preview","email_template.model_email_template_preview",1,1 | ||
2302 | 7 | "account_credit_management.ir_model_access_275",1,1,"group_account_credit_management_manager","credit_management_manager_mail_message","mail.model_mail_message",1,1 | ||
2303 | 8 | "account_credit_management.ir_model_access_276",1,0,"group_account_credit_management_user","credit_management_user_mail_message","mail.model_mail_message",1,1 | ||
2304 | 9 | "account_credit_management.ir_model_access_277",0,0,"group_account_credit_management_info","credit_management_info_mail_message","mail.model_mail_message",1,0 | ||
2305 | 10 | "account_credit_management.ir_model_access_278",1,1,"group_account_credit_management_manager","credit_management_manager_comm","account_credit_management.model_credit_management_communication",1,1 | ||
2306 | 11 | "account_credit_management.ir_model_access_279",1,1,"base.group_sale_salesman","credit_management_user_comm","account_credit_management.model_credit_management_communication",1,1 | ||
2307 | 12 | "account_credit_management.ir_model_access_280",0,0,"group_account_credit_management_info","credit_management_info_comm","account_credit_management.model_credit_management_communication",1,0 | ||
2308 | 13 | "account_credit_management.ir_model_access_281",1,1,"group_account_credit_management_manager","credit_management_mananger_run","account_credit_management.model_credit_management_run",1,1 | ||
2309 | 14 | "account_credit_management.ir_model_access_282",1,1,"group_account_credit_management_user","credit_management_user_run","account_credit_management.model_credit_management_run",1,1 | ||
2310 | 15 | "account_credit_management.ir_model_access_283",0,0,"group_account_credit_management_info","credit_management_info_run","account_credit_management.model_credit_management_run",1,0 | ||
2311 | 16 | "account_credit_management.ir_model_access_284",1,1,"group_account_credit_management_manager","credit_management_manager_profile","account_credit_management.model_credit_management_profile",1,1 | ||
2312 | 17 | "account_credit_management.ir_model_access_285",0,0,"group_account_credit_management_user","credit_management_user_profile","account_credit_management.model_credit_management_profile",1,0 | ||
2313 | 18 | "account_credit_management.ir_model_access_286",0,0,"group_account_credit_management_info","credit_management_info_profile","account_credit_management.model_credit_management_profile",1,0 | ||
2314 | 19 | "account_credit_management.ir_model_access_287",1,1,"group_account_credit_management_manager","credit_management_manager_rule","account_credit_management.model_credit_management_profile_rule",1,1 | ||
2315 | 20 | "account_credit_management.ir_model_access_288",0,0,"group_account_credit_management_user","credit_management_user_rule","account_credit_management.model_credit_management_profile_rule",1,0 | ||
2316 | 21 | "account_credit_management.ir_model_access_289",0,0,"group_account_credit_management_info","credit_management_info_rule","account_credit_management.model_credit_management_profile_rule",1,0 | ||
2317 | 22 | "account_credit_management.ir_model_access_290",1,1,"group_account_credit_management_manager","credit_management_manager_mailer","account_credit_management.model_credit_management_mailer",1,1 | ||
2318 | 23 | "account_credit_management.ir_model_access_291",1,1,"group_account_credit_management_user","credit_management_user_mailer","account_credit_management.model_credit_management_mailer",1,1 | ||
2319 | 24 | "account_credit_management.ir_model_access_292",1,1,"group_account_credit_management_manager","credit_management_manager_marker","account_credit_management.model_credit_management_marker",1,1 | ||
2320 | 25 | "account_credit_management.ir_model_access_293",1,1,"group_account_credit_management_user","credit_management_user_marker","account_credit_management.model_credit_management_marker",1,1 | ||
2321 | 26 | "account_credit_management.ir_model_access_294",1,1,"group_account_credit_management_manager","credit_management_manager_printer","account_credit_management.model_credit_management_printer",1,1 | ||
2322 | 27 | "account_credit_management.ir_model_access_295",1,1,"group_account_credit_management_user","credit_management_user_printer","account_credit_management.model_credit_management_printer",1,1 | ||
2323 | 0 | 28 | ||
2324 | === added directory 'account_credit_management/wizard' | |||
2325 | === added file 'account_credit_management/wizard/__init__.py' | |||
2326 | --- account_credit_management/wizard/__init__.py 1970-01-01 00:00:00 +0000 | |||
2327 | +++ account_credit_management/wizard/__init__.py 2012-10-15 10:14:35 +0000 | |||
2328 | @@ -0,0 +1,24 @@ | |||
2329 | 1 | # -*- coding: utf-8 -*- | ||
2330 | 2 | ############################################################################## | ||
2331 | 3 | # | ||
2332 | 4 | # Author: Nicolas Bessi | ||
2333 | 5 | # Copyright 2012 Camptocamp SA | ||
2334 | 6 | # | ||
2335 | 7 | # This program is free software: you can redistribute it and/or modify | ||
2336 | 8 | # it under the terms of the GNU Affero General Public License as | ||
2337 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
2338 | 10 | # License, or (at your option) any later version. | ||
2339 | 11 | # | ||
2340 | 12 | # This program is distributed in the hope that it will be useful, | ||
2341 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2342 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2343 | 15 | # GNU Affero General Public License for more details. | ||
2344 | 16 | # | ||
2345 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
2346 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2347 | 19 | # | ||
2348 | 20 | ############################################################################## | ||
2349 | 21 | from . import credit_management_mailer | ||
2350 | 22 | from . import credit_management_marker | ||
2351 | 23 | from . import credit_management_printer | ||
2352 | 24 | from . import credit_management_communication | ||
2353 | 0 | 25 | ||
2354 | === added file 'account_credit_management/wizard/credit_management_communication.py' | |||
2355 | --- account_credit_management/wizard/credit_management_communication.py 1970-01-01 00:00:00 +0000 | |||
2356 | +++ account_credit_management/wizard/credit_management_communication.py 2012-10-15 10:14:35 +0000 | |||
2357 | @@ -0,0 +1,178 @@ | |||
2358 | 1 | # -*- coding: utf-8 -*- | ||
2359 | 2 | ############################################################################## | ||
2360 | 3 | # | ||
2361 | 4 | # Author: Nicolas Bessi | ||
2362 | 5 | # Copyright 2012 Camptocamp SA | ||
2363 | 6 | # | ||
2364 | 7 | # This program is free software: you can redistribute it and/or modify | ||
2365 | 8 | # it under the terms of the GNU Affero General Public License as | ||
2366 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
2367 | 10 | # License, or (at your option) any later version. | ||
2368 | 11 | # | ||
2369 | 12 | # This program is distributed in the hope that it will be useful, | ||
2370 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2371 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2372 | 15 | # GNU Affero General Public License for more details. | ||
2373 | 16 | # | ||
2374 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
2375 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2376 | 19 | # | ||
2377 | 20 | ############################################################################## | ||
2378 | 21 | from openerp.osv.orm import TransientModel, fields | ||
2379 | 22 | from openerp.osv.osv import except_osv | ||
2380 | 23 | from openerp.tools.translate import _ | ||
2381 | 24 | import netsvc | ||
2382 | 25 | import logging | ||
2383 | 26 | |||
2384 | 27 | logger = logging.getLogger('credit.line.management mailing') | ||
2385 | 28 | |||
2386 | 29 | |||
2387 | 30 | class CreditCommunication(TransientModel): | ||
2388 | 31 | """Shell calss used to provide a base model to email template and reporting. | ||
2389 | 32 | Il use this approche in version 7 a browse record will exist even if not saved""" | ||
2390 | 33 | _name = "credit.management.communication" | ||
2391 | 34 | _description = "credit management communication" | ||
2392 | 35 | _rec_name = 'partner_id' | ||
2393 | 36 | _columns = {'partner_id': fields.many2one('res.partner', 'Partner', required=True), | ||
2394 | 37 | |||
2395 | 38 | 'current_profile_rule': fields.many2one('credit.management.profile.rule', | ||
2396 | 39 | 'Rule', required=True), | ||
2397 | 40 | |||
2398 | 41 | 'credit_lines': fields.many2many('credit.management.line', | ||
2399 | 42 | rel='comm_credit_rel', | ||
2400 | 43 | string='Credit Lines'), | ||
2401 | 44 | |||
2402 | 45 | 'company_id': fields.many2one('res.company', 'Company', | ||
2403 | 46 | required=True), | ||
2404 | 47 | |||
2405 | 48 | 'user_id': fields.many2one('res.users', 'User')} | ||
2406 | 49 | |||
2407 | 50 | _defaults = {'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get( | ||
2408 | 51 | cr, uid, 'credit.management.profile', context=c), | ||
2409 | 52 | 'user_id': lambda s, cr, uid, c: uid} | ||
2410 | 53 | |||
2411 | 54 | def get_address(self, cursor, uid, com_id, context=None): | ||
2412 | 55 | """Return a valid address for customer""" | ||
2413 | 56 | |||
2414 | 57 | context = context or {} | ||
2415 | 58 | if isinstance(com_id, list): | ||
2416 | 59 | com_id = com_id[0] | ||
2417 | 60 | current = self.browse(cursor, uid, com_id, context=context) | ||
2418 | 61 | part_obj = self.pool.get('res.partner') | ||
2419 | 62 | adds = part_obj.address_get(cursor, uid, [current.partner_id.id], | ||
2420 | 63 | adr_pref=['invoice', 'default']) | ||
2421 | 64 | |||
2422 | 65 | add = adds.get('invoice', adds.get('default')) | ||
2423 | 66 | if not add: | ||
2424 | 67 | raise except_osv(_('No address for partner %s') % (current.partner_id.name), | ||
2425 | 68 | _('Please set one')) | ||
2426 | 69 | add_obj = self.pool.get('res.partner.address') | ||
2427 | 70 | return add_obj.browse(cursor, uid, add, context=context) | ||
2428 | 71 | |||
2429 | 72 | |||
2430 | 73 | def get_mail(self, cursor, uid, com_id, context=None): | ||
2431 | 74 | """Return a valid email for customer""" | ||
2432 | 75 | context = context or {} | ||
2433 | 76 | if isinstance(com_id, list): | ||
2434 | 77 | com_id = com_id[0] | ||
2435 | 78 | current = self.browse(cursor, uid, com_id, context=context) | ||
2436 | 79 | email = current.get_address().email | ||
2437 | 80 | if not email: | ||
2438 | 81 | raise except_osv(_('No invoicing or default email for partner %s') % | ||
2439 | 82 | (current.partner_id.name), | ||
2440 | 83 | _('Please set one')) | ||
2441 | 84 | return email | ||
2442 | 85 | |||
2443 | 86 | def _get_credit_lines(self, cursor, uid, line_ids, partner_id, rule_id, context=None): | ||
2444 | 87 | """Return credit lines related to a partner and a profile rule""" | ||
2445 | 88 | cr_line_obj = self.pool.get('credit.management.line') | ||
2446 | 89 | cr_l_ids = cr_line_obj.search(cursor, | ||
2447 | 90 | uid, | ||
2448 | 91 | [('id', 'in', line_ids), | ||
2449 | 92 | ('partner_id', '=', partner_id), | ||
2450 | 93 | ('profile_rule_id', '=', rule_id)], | ||
2451 | 94 | context=context) | ||
2452 | 95 | #return cr_line_obj.browse(cursor, uid, cr_l_ids, context=context) | ||
2453 | 96 | return cr_l_ids | ||
2454 | 97 | |||
2455 | 98 | def _generate_comm_from_credit_line_ids(self, cursor, uid, line_ids, context=None): | ||
2456 | 99 | if not line_ids: | ||
2457 | 100 | return [] | ||
2458 | 101 | comms = [] | ||
2459 | 102 | sql = ("SELECT distinct partner_id, profile_rule_id, credit_management_profile_rule.level" | ||
2460 | 103 | " FROM credit_management_line JOIN credit_management_profile_rule " | ||
2461 | 104 | " ON (credit_management_line.profile_rule_id = credit_management_profile_rule.id)" | ||
2462 | 105 | " WHERE credit_management_line.id in %s" | ||
2463 | 106 | " ORDER by credit_management_profile_rule.level") | ||
2464 | 107 | |||
2465 | 108 | cursor.execute(sql, (tuple(line_ids),)) | ||
2466 | 109 | res = cursor.dictfetchall() | ||
2467 | 110 | for rule_assoc in res: | ||
2468 | 111 | data = {} | ||
2469 | 112 | data['credit_lines'] = [(6, 0, self._get_credit_lines(cursor, uid, line_ids, | ||
2470 | 113 | rule_assoc['partner_id'], | ||
2471 | 114 | rule_assoc['profile_rule_id'], | ||
2472 | 115 | context=context))] | ||
2473 | 116 | data['partner_id'] = rule_assoc['partner_id'] | ||
2474 | 117 | data['current_profile_rule'] = rule_assoc['profile_rule_id'] | ||
2475 | 118 | comm_id = self.create(cursor, uid, data, context=context) | ||
2476 | 119 | |||
2477 | 120 | |||
2478 | 121 | comms.append(self.browse(cursor, uid, comm_id, context=context)) | ||
2479 | 122 | return comms | ||
2480 | 123 | |||
2481 | 124 | def _generate_mails(self, cursor, uid, comms, context=None): | ||
2482 | 125 | """Generate mail message using template related to rule""" | ||
2483 | 126 | cr_line_obj = self.pool.get('credit.management.line') | ||
2484 | 127 | mail_temp_obj = self.pool.get('email.template') | ||
2485 | 128 | mail_message_obj = self.pool.get('mail.message') | ||
2486 | 129 | mail_ids = [] | ||
2487 | 130 | for comm in comms: | ||
2488 | 131 | # we want to use a local cursor in order to send the maximum | ||
2489 | 132 | # of email | ||
2490 | 133 | try: | ||
2491 | 134 | template = comm.current_profile_rule.mail_template_id.id | ||
2492 | 135 | |||
2493 | 136 | mvalues = mail_temp_obj.generate_email(cursor, uid, | ||
2494 | 137 | template, | ||
2495 | 138 | comm.id, | ||
2496 | 139 | context=context) | ||
2497 | 140 | essential_values = ['subject', 'body_html', | ||
2498 | 141 | 'email_from', 'email_to'] | ||
2499 | 142 | for val in essential_values: | ||
2500 | 143 | if not mvalues.get(val): | ||
2501 | 144 | raise Exception('Mail generation error with %s', val) | ||
2502 | 145 | mail_id = mail_message_obj.create(cursor, uid, mvalues, context=context) | ||
2503 | 146 | |||
2504 | 147 | cl_ids = [cl.id for cl in comm.credit_lines] | ||
2505 | 148 | |||
2506 | 149 | # we do not use local cusros else we have a lock | ||
2507 | 150 | cr_line_obj.write(cursor, uid, cl_ids, | ||
2508 | 151 | {'mail_message_id': mail_id, | ||
2509 | 152 | 'state': 'sent'}) | ||
2510 | 153 | mail_ids.append(mail_id) | ||
2511 | 154 | except Exception, exc: | ||
2512 | 155 | logger.error(exc) | ||
2513 | 156 | cursor.rollback() | ||
2514 | 157 | cl_ids = [cl.id for cl in comm.credit_lines] | ||
2515 | 158 | # we do not use local cusros else we have a lock | ||
2516 | 159 | cr_line_obj.write(cursor, uid, cl_ids, | ||
2517 | 160 | {'state': 'mail_error'}) | ||
2518 | 161 | finally: | ||
2519 | 162 | cursor.commit() | ||
2520 | 163 | return mail_ids | ||
2521 | 164 | |||
2522 | 165 | def _generate_report(self, cursor, uid, comms, context=None): | ||
2523 | 166 | """Will generate a report by inserting mako template of related profile template""" | ||
2524 | 167 | service = netsvc.LocalService('report.credit_management_summary') | ||
2525 | 168 | ids = [x.id for x in comms] | ||
2526 | 169 | result, format = service.create(cursor, uid, ids, {}, {}) | ||
2527 | 170 | return result | ||
2528 | 171 | |||
2529 | 172 | def _mark_credit_line_as_sent(self, cursor, uid, comms, context=None): | ||
2530 | 173 | line_ids = [] | ||
2531 | 174 | for comm in comms: | ||
2532 | 175 | line_ids += [x.id for x in comm.credit_lines] | ||
2533 | 176 | l_obj = self.pool.get('credit.management.line') | ||
2534 | 177 | l_obj.write(cursor, uid, line_ids, {'state': 'sent'}, context=context) | ||
2535 | 178 | return line_ids | ||
2536 | 0 | 179 | ||
2537 | === added file 'account_credit_management/wizard/credit_management_mailer.py' | |||
2538 | --- account_credit_management/wizard/credit_management_mailer.py 1970-01-01 00:00:00 +0000 | |||
2539 | +++ account_credit_management/wizard/credit_management_mailer.py 2012-10-15 10:14:35 +0000 | |||
2540 | @@ -0,0 +1,64 @@ | |||
2541 | 1 | # -*- coding: utf-8 -*- | ||
2542 | 2 | ############################################################################## | ||
2543 | 3 | # | ||
2544 | 4 | # Author: Nicolas Bessi | ||
2545 | 5 | # Copyright 2012 Camptocamp SA | ||
2546 | 6 | # | ||
2547 | 7 | # This program is free software: you can redistribute it and/or modify | ||
2548 | 8 | # it under the terms of the GNU Affero General Public License as | ||
2549 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
2550 | 10 | # License, or (at your option) any later version. | ||
2551 | 11 | # | ||
2552 | 12 | # This program is distributed in the hope that it will be useful, | ||
2553 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2554 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2555 | 15 | # GNU Affero General Public License for more details. | ||
2556 | 16 | # | ||
2557 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
2558 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2559 | 19 | # | ||
2560 | 20 | ############################################################################## | ||
2561 | 21 | from openerp.osv.orm import TransientModel, fields | ||
2562 | 22 | from openerp.osv.osv import except_osv | ||
2563 | 23 | from openerp.tools.translate import _ | ||
2564 | 24 | |||
2565 | 25 | class CreditManagementMailer(TransientModel): | ||
2566 | 26 | """Change the state of lines in mass""" | ||
2567 | 27 | |||
2568 | 28 | _name = "credit.management.mailer" | ||
2569 | 29 | _description = """Mass credit line mailer""" | ||
2570 | 30 | _rec_name = 'id' | ||
2571 | 31 | |||
2572 | 32 | _columns = {'mail_all': fields.boolean('Mail all ready lines')} | ||
2573 | 33 | |||
2574 | 34 | |||
2575 | 35 | def _get_lids(self, cursor, uid, mail_all, active_ids, context=None): | ||
2576 | 36 | """get line to be marked filter done lines""" | ||
2577 | 37 | # TODO DRY with printer | ||
2578 | 38 | line_obj = self.pool.get('credit.management.line') | ||
2579 | 39 | if mail_all: | ||
2580 | 40 | domain = [('state', '=', 'to_be_sent'), | ||
2581 | 41 | ('canal', '=', 'mail')] | ||
2582 | 42 | else: | ||
2583 | 43 | domain = [('state', '=', 'to_be_sent'), | ||
2584 | 44 | ('id', 'in', active_ids), | ||
2585 | 45 | ('canal', '=', 'mail')] | ||
2586 | 46 | return line_obj.search(cursor, uid, domain, context=context) | ||
2587 | 47 | |||
2588 | 48 | |||
2589 | 49 | def mail_lines(self, cursor, uid, wiz_id, context=None): | ||
2590 | 50 | comm_obj = self.pool.get('credit.management.communication') | ||
2591 | 51 | context = context or {} | ||
2592 | 52 | if isinstance(wiz_id, list): | ||
2593 | 53 | wiz_id = wiz_id[0] | ||
2594 | 54 | current = self.browse(cursor, uid, wiz_id, context) | ||
2595 | 55 | lines_ids = context.get('active_ids') | ||
2596 | 56 | |||
2597 | 57 | if not lines_ids and not current.mail_all: | ||
2598 | 58 | raise except_osv(_('Not lines ids are selected'), | ||
2599 | 59 | _('You may check "Mail all ready lines"')) | ||
2600 | 60 | filtered_ids = self._get_lids(cursor, uid, current.mail_all, lines_ids, context) | ||
2601 | 61 | comms = comm_obj._generate_comm_from_credit_line_ids(cursor, uid, filtered_ids, | ||
2602 | 62 | context=context) | ||
2603 | 63 | comm_obj._generate_mails(cursor, uid, comms, context=context) | ||
2604 | 64 | return {} | ||
2605 | 0 | 65 | ||
2606 | === added file 'account_credit_management/wizard/credit_management_mailer_view.xml' | |||
2607 | --- account_credit_management/wizard/credit_management_mailer_view.xml 1970-01-01 00:00:00 +0000 | |||
2608 | +++ account_credit_management/wizard/credit_management_mailer_view.xml 2012-10-15 10:14:35 +0000 | |||
2609 | @@ -0,0 +1,44 @@ | |||
2610 | 1 | <openerp> | ||
2611 | 2 | <data> | ||
2612 | 3 | |||
2613 | 4 | <record id="credit_line_mailer_form" model="ir.ui.view"> | ||
2614 | 5 | <field name="name">credit.line.mailer.form</field> | ||
2615 | 6 | <field name="model">credit.management.mailer</field> | ||
2616 | 7 | <field name="type">form</field> | ||
2617 | 8 | <field name="arch" type="xml"> | ||
2618 | 9 | <form> <!-- editable="bottom" --> | ||
2619 | 10 | <separator string="Mail selected lines. Sucessfuly mailed lines will be in state done. Related email will be linked to the line" colspan="4"/> | ||
2620 | 11 | <newline/> | ||
2621 | 12 | <field name="mail_all" colspan="4"/> | ||
2622 | 13 | <newline/> | ||
2623 | 14 | <group colspan="4"> | ||
2624 | 15 | <button name="mail_lines" string="Mail lines" type="object" icon="gtk-execute"/> | ||
2625 | 16 | <button special="cancel" string="Cancel" icon='gtk-cancel'/> | ||
2626 | 17 | </group> | ||
2627 | 18 | </form> | ||
2628 | 19 | </field> | ||
2629 | 20 | </record> | ||
2630 | 21 | |||
2631 | 22 | <!-- for menu --> | ||
2632 | 23 | <act_window name="Mail lines" | ||
2633 | 24 | res_model="credit.management.mailer" | ||
2634 | 25 | src_model="credit.management.line" | ||
2635 | 26 | view_mode="form" | ||
2636 | 27 | target="new" | ||
2637 | 28 | key2="client_action_multi" | ||
2638 | 29 | id="open_credit_line_mailer_wizard_menu_action"/> | ||
2639 | 30 | |||
2640 | 31 | <!-- for button --> | ||
2641 | 32 | <record id="open_credit_line_mailer_wizard" model="ir.actions.act_window"> | ||
2642 | 33 | <field name="name">Mail lines</field> | ||
2643 | 34 | <field name="res_model">credit.management.mailer</field> | ||
2644 | 35 | <field name="view_type">form</field> | ||
2645 | 36 | <field name="view_mode">form</field> | ||
2646 | 37 | <field name="view_id" ref="credit_line_mailer_form"/> | ||
2647 | 38 | <field name="target">new</field> | ||
2648 | 39 | <field name="help">Mail all marked lines</field> | ||
2649 | 40 | </record> | ||
2650 | 41 | |||
2651 | 42 | |||
2652 | 43 | </data> | ||
2653 | 44 | </openerp> | ||
2654 | 0 | 45 | ||
2655 | === added file 'account_credit_management/wizard/credit_management_marker.py' | |||
2656 | --- account_credit_management/wizard/credit_management_marker.py 1970-01-01 00:00:00 +0000 | |||
2657 | +++ account_credit_management/wizard/credit_management_marker.py 2012-10-15 10:14:35 +0000 | |||
2658 | @@ -0,0 +1,83 @@ | |||
2659 | 1 | # -*- coding: utf-8 -*- | ||
2660 | 2 | ############################################################################## | ||
2661 | 3 | # | ||
2662 | 4 | # Author: Nicolas Bessi | ||
2663 | 5 | # Copyright 2012 Camptocamp SA | ||
2664 | 6 | # | ||
2665 | 7 | # This program is free software: you can redistribute it and/or modify | ||
2666 | 8 | # it under the terms of the GNU Affero General Public License as | ||
2667 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
2668 | 10 | # License, or (at your option) any later version. | ||
2669 | 11 | # | ||
2670 | 12 | # This program is distributed in the hope that it will be useful, | ||
2671 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2672 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2673 | 15 | # GNU Affero General Public License for more details. | ||
2674 | 16 | # | ||
2675 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
2676 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2677 | 19 | # | ||
2678 | 20 | ############################################################################## | ||
2679 | 21 | from openerp.osv.orm import TransientModel, fields | ||
2680 | 22 | from openerp.osv.osv import except_osv | ||
2681 | 23 | from openerp.tools.translate import _ | ||
2682 | 24 | |||
2683 | 25 | class CreditManagementMarker(TransientModel): | ||
2684 | 26 | """Change the state of lines in mass""" | ||
2685 | 27 | |||
2686 | 28 | _name = "credit.management.marker" | ||
2687 | 29 | _description = """Mass marker""" | ||
2688 | 30 | _columns = {'name': fields.selection([('to_be_sent', 'To be sent'), | ||
2689 | 31 | ('sent', 'Done')], | ||
2690 | 32 | 'Mark as', required=True), | ||
2691 | 33 | |||
2692 | 34 | 'mark_all': fields.boolean('Mark all draft lines')} | ||
2693 | 35 | |||
2694 | 36 | _defaults = {'name': 'to_be_sent'} | ||
2695 | 37 | |||
2696 | 38 | def _get_lids(self, cursor, uid, mark_all, active_ids, context=None): | ||
2697 | 39 | """get line to be marked filter done lines""" | ||
2698 | 40 | line_obj = self.pool.get('credit.management.line') | ||
2699 | 41 | if mark_all: | ||
2700 | 42 | domain = [('state', '=', 'draft')] | ||
2701 | 43 | else: | ||
2702 | 44 | domain = [('state', '!=', 'sent'), ('id', 'in', active_ids)] | ||
2703 | 45 | return line_obj.search(cursor, uid, domain, context=context) | ||
2704 | 46 | |||
2705 | 47 | def _mark_lines(self, cursor, uid, filtered_ids, state, context=None): | ||
2706 | 48 | """write hook""" | ||
2707 | 49 | line_obj = self.pool.get('credit.management.line') | ||
2708 | 50 | if not state: | ||
2709 | 51 | raise ValueError(_('state can not be empty')) | ||
2710 | 52 | line_obj.write(cursor, uid, filtered_ids, {'state': state}) | ||
2711 | 53 | return filtered_ids | ||
2712 | 54 | |||
2713 | 55 | |||
2714 | 56 | |||
2715 | 57 | def mark_lines(self, cursor, uid, wiz_id, context=None): | ||
2716 | 58 | """Write state of selected credit lines to the one in entry | ||
2717 | 59 | done credit line will be ignored""" | ||
2718 | 60 | context = context or {} | ||
2719 | 61 | if isinstance(wiz_id, list): | ||
2720 | 62 | wiz_id = wiz_id[0] | ||
2721 | 63 | current = self.browse(cursor, uid, wiz_id, context) | ||
2722 | 64 | lines_ids = context.get('active_ids') | ||
2723 | 65 | |||
2724 | 66 | if not lines_ids and not current.mark_all: | ||
2725 | 67 | raise except_osv(_('Not lines ids are selected'), | ||
2726 | 68 | _('You may check "Mark all draft lines"')) | ||
2727 | 69 | filtered_ids = self._get_lids(cursor, uid, current.mark_all, lines_ids, context) | ||
2728 | 70 | if not filtered_ids: | ||
2729 | 71 | raise except_osv(_('No lines will be changed'), | ||
2730 | 72 | _('All selected lines are allready done')) | ||
2731 | 73 | |||
2732 | 74 | # hook function a simple write should be enought | ||
2733 | 75 | self._mark_lines(cursor, uid, filtered_ids, current.name, context) | ||
2734 | 76 | |||
2735 | 77 | return {'domain': "[('id','in',%s)]" % (filtered_ids,), | ||
2736 | 78 | 'name': _('%s marked line') % (current.name,), | ||
2737 | 79 | 'view_type': 'form', | ||
2738 | 80 | 'view_mode': 'tree,form', | ||
2739 | 81 | 'view_id': False, | ||
2740 | 82 | 'res_model': 'credit.management.line', | ||
2741 | 83 | 'type': 'ir.actions.act_window'} | ||
2742 | 0 | 84 | ||
2743 | === added file 'account_credit_management/wizard/credit_management_marker_view.xml' | |||
2744 | --- account_credit_management/wizard/credit_management_marker_view.xml 1970-01-01 00:00:00 +0000 | |||
2745 | +++ account_credit_management/wizard/credit_management_marker_view.xml 2012-10-15 10:14:35 +0000 | |||
2746 | @@ -0,0 +1,44 @@ | |||
2747 | 1 | <openerp> | ||
2748 | 2 | <data> | ||
2749 | 3 | |||
2750 | 4 | <record id="credit_line_marker_form" model="ir.ui.view"> | ||
2751 | 5 | <field name="name">credit.line.marker.form</field> | ||
2752 | 6 | <field name="model">credit.management.marker</field> | ||
2753 | 7 | <field name="type">form</field> | ||
2754 | 8 | <field name="arch" type="xml"> | ||
2755 | 9 | <form> <!-- editable="bottom" --> | ||
2756 | 10 | <separator string="This wizard will mark selected draft lines to the selected state. Done Lines will be ignored " colspan="4"/> | ||
2757 | 11 | <newline/> | ||
2758 | 12 | <field name="name"/> | ||
2759 | 13 | <field name="mark_all"/> | ||
2760 | 14 | <newline/> | ||
2761 | 15 | <group colspan="4"> | ||
2762 | 16 | <button name="mark_lines" string="Mark lines" type="object" icon="gtk-execute"/> | ||
2763 | 17 | <button special="cancel" string="Cancel" icon='gtk-cancel'/> | ||
2764 | 18 | </group> | ||
2765 | 19 | </form> | ||
2766 | 20 | </field> | ||
2767 | 21 | </record> | ||
2768 | 22 | |||
2769 | 23 | <!-- for menu --> | ||
2770 | 24 | <act_window name="Mark lines" | ||
2771 | 25 | res_model="credit.management.marker" | ||
2772 | 26 | src_model="credit.management.line" | ||
2773 | 27 | view_mode="form" | ||
2774 | 28 | target="new" | ||
2775 | 29 | key2="client_action_multi" | ||
2776 | 30 | id="open_credit_line_marker_wizard_menu_action"/> | ||
2777 | 31 | |||
2778 | 32 | <record id="open_credit_line_marker_wizard" model="ir.actions.act_window"> | ||
2779 | 33 | <field name="name">Mark lines</field> | ||
2780 | 34 | <field name="res_model">credit.management.marker</field> | ||
2781 | 35 | <field name="src_model">credit.management.line</field> | ||
2782 | 36 | <field name="view_type">form</field> | ||
2783 | 37 | <field name="view_mode">form</field> | ||
2784 | 38 | <field name="view_id" ref="credit_line_marker_form"/> | ||
2785 | 39 | <field name="target">new</field> | ||
2786 | 40 | <field name="help">Mark all lines. You can the send marked lines</field> | ||
2787 | 41 | </record> | ||
2788 | 42 | |||
2789 | 43 | </data> | ||
2790 | 44 | </openerp> | ||
2791 | 0 | 45 | ||
2792 | === added file 'account_credit_management/wizard/credit_management_printer.py' | |||
2793 | --- account_credit_management/wizard/credit_management_printer.py 1970-01-01 00:00:00 +0000 | |||
2794 | +++ account_credit_management/wizard/credit_management_printer.py 2012-10-15 10:14:35 +0000 | |||
2795 | @@ -0,0 +1,74 @@ | |||
2796 | 1 | # -*- coding: utf-8 -*- | ||
2797 | 2 | ############################################################################## | ||
2798 | 3 | # | ||
2799 | 4 | # Author: Nicolas Bessi | ||
2800 | 5 | # Copyright 2012 Camptocamp SA | ||
2801 | 6 | # | ||
2802 | 7 | # This program is free software: you can redistribute it and/or modify | ||
2803 | 8 | # it under the terms of the GNU Affero General Public License as | ||
2804 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
2805 | 10 | # License, or (at your option) any later version. | ||
2806 | 11 | # | ||
2807 | 12 | # This program is distributed in the hope that it will be useful, | ||
2808 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2809 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2810 | 15 | # GNU Affero General Public License for more details. | ||
2811 | 16 | # | ||
2812 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
2813 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2814 | 19 | # | ||
2815 | 20 | ############################################################################## | ||
2816 | 21 | import base64 | ||
2817 | 22 | |||
2818 | 23 | from openerp.osv.orm import TransientModel, fields | ||
2819 | 24 | from openerp.osv.osv import except_osv | ||
2820 | 25 | from openerp.tools.translate import _ | ||
2821 | 26 | |||
2822 | 27 | class CreditManagementPrinter(TransientModel): | ||
2823 | 28 | """Change the state of lines in mass""" | ||
2824 | 29 | |||
2825 | 30 | _name = "credit.management.printer" | ||
2826 | 31 | _rec_name = 'id' | ||
2827 | 32 | _description = """Mass printer""" | ||
2828 | 33 | _columns = {'mark_as_sent': fields.boolean('Mark lines as send', | ||
2829 | 34 | help="Lines to emailed will be ignored"), | ||
2830 | 35 | 'print_all': fields.boolean('Print all ready lines'), | ||
2831 | 36 | 'report_file': fields.binary('Generated Report'), | ||
2832 | 37 | 'state': fields.char('state', size=32)} | ||
2833 | 38 | |||
2834 | 39 | def _get_lids(self, cursor, uid, print_all, active_ids, context=None): | ||
2835 | 40 | """get line to be marked filter done lines""" | ||
2836 | 41 | # TODO Dry with mailer maybe in comm | ||
2837 | 42 | line_obj = self.pool.get('credit.management.line') | ||
2838 | 43 | if print_all: | ||
2839 | 44 | domain = [('state', '=', 'to_be_sent'), | ||
2840 | 45 | ('canal', '=', 'manual')] | ||
2841 | 46 | else: | ||
2842 | 47 | domain = [('state', '=', 'to_be_sent'), | ||
2843 | 48 | ('id', 'in', active_ids), | ||
2844 | 49 | ('canal', '=', 'manual')] | ||
2845 | 50 | return line_obj.search(cursor, uid, domain, context=context) | ||
2846 | 51 | |||
2847 | 52 | |||
2848 | 53 | def print_lines(self, cursor, uid, wiz_id, context=None): | ||
2849 | 54 | comm_obj = self.pool.get('credit.management.communication') | ||
2850 | 55 | context = context or {} | ||
2851 | 56 | if isinstance(wiz_id, list): | ||
2852 | 57 | wiz_id = wiz_id[0] | ||
2853 | 58 | current = self.browse(cursor, uid, wiz_id, context) | ||
2854 | 59 | lines_ids = context.get('active_ids') | ||
2855 | 60 | if not lines_ids and not current.print_all: | ||
2856 | 61 | raise except_osv(_('Not lines ids are selected'), | ||
2857 | 62 | _('You may check "Print all ready lines"')) | ||
2858 | 63 | if current.print_all: | ||
2859 | 64 | filtered_ids = self._get_lids(cursor, uid, current.print_all, lines_ids, context) | ||
2860 | 65 | else: | ||
2861 | 66 | filtered_ids = lines_ids | ||
2862 | 67 | comms = comm_obj._generate_comm_from_credit_line_ids(cursor, uid, filtered_ids, | ||
2863 | 68 | context=context) | ||
2864 | 69 | report_file = comm_obj._generate_report(cursor, uid, comms, context=context) | ||
2865 | 70 | current.write({'report_file': base64.b64encode(report_file), 'state': 'done'}) | ||
2866 | 71 | if current.mark_as_sent: | ||
2867 | 72 | filtered_ids = self._get_lids(cursor, uid, False, lines_ids, context) | ||
2868 | 73 | comm_obj._mark_credit_line_as_sent(cursor, uid, comms, context=context) | ||
2869 | 74 | return False | ||
2870 | 0 | 75 | ||
2871 | === added file 'account_credit_management/wizard/credit_management_printer_view.xml' | |||
2872 | --- account_credit_management/wizard/credit_management_printer_view.xml 1970-01-01 00:00:00 +0000 | |||
2873 | +++ account_credit_management/wizard/credit_management_printer_view.xml 2012-10-15 10:14:35 +0000 | |||
2874 | @@ -0,0 +1,47 @@ | |||
2875 | 1 | <openerp> | ||
2876 | 2 | <data> | ||
2877 | 3 | |||
2878 | 4 | <record id="credit_line_printer_form" model="ir.ui.view"> | ||
2879 | 5 | <field name="name">credit.line.printer.form</field> | ||
2880 | 6 | <field name="model">credit.management.printer</field> | ||
2881 | 7 | <field name="type">form</field> | ||
2882 | 8 | <field name="arch" type="xml"> | ||
2883 | 9 | <form> <!-- editable="bottom" --> | ||
2884 | 10 | <separator colspan="4" string="This wizard will print all manual lines. Mark lines, lines will pass lines to state done. Lines with canal email will not be passed to state done"/> | ||
2885 | 11 | <newline/> | ||
2886 | 12 | <field name="mark_as_sent"/> | ||
2887 | 13 | <field name="print_all"/> | ||
2888 | 14 | <newline/> | ||
2889 | 15 | <field name="report_file" attrs="{'readonly': [('state', '!=', 'done')]}" colspan="4"/> | ||
2890 | 16 | <field name="state" invisible="1" /> | ||
2891 | 17 | <newline/> | ||
2892 | 18 | <group colspan="4"> | ||
2893 | 19 | <button name="print_lines" string="Print lines" type="object" icon="gtk-execute"/> | ||
2894 | 20 | <button special="cancel" string="Cancel" icon='gtk-cancel'/> | ||
2895 | 21 | </group> | ||
2896 | 22 | </form> | ||
2897 | 23 | </field> | ||
2898 | 24 | </record> | ||
2899 | 25 | |||
2900 | 26 | <!-- for menu --> | ||
2901 | 27 | <act_window name="Print lines" | ||
2902 | 28 | res_model="credit.management.printer" | ||
2903 | 29 | src_model="credit.management.line" | ||
2904 | 30 | view_mode="form" | ||
2905 | 31 | target="new" | ||
2906 | 32 | key2="client_action_multi" | ||
2907 | 33 | id="open_credit_line_printer_wizard_menu_action"/> | ||
2908 | 34 | |||
2909 | 35 | <record id="open_credit_line_printer_wizard" model="ir.actions.act_window"> | ||
2910 | 36 | <field name="name">Print lines</field> | ||
2911 | 37 | <field name="res_model">credit.management.printer</field> | ||
2912 | 38 | <field name="src_model">credit.management.line</field> | ||
2913 | 39 | <field name="view_type">form</field> | ||
2914 | 40 | <field name="view_mode">form</field> | ||
2915 | 41 | <field name="view_id" ref="credit_line_printer_form"/> | ||
2916 | 42 | <field name="target">new</field> | ||
2917 | 43 | <field name="help">Print all lines</field> | ||
2918 | 44 | </record> | ||
2919 | 45 | |||
2920 | 46 | </data> | ||
2921 | 47 | </openerp> | ||
2922 | 0 | 48 | ||
2923 | === modified file 'account_fiscal_position_rule_m2m/fiscal_rules.py' | |||
2924 | --- account_fiscal_position_rule_m2m/fiscal_rules.py 2012-04-03 14:27:22 +0000 | |||
2925 | +++ account_fiscal_position_rule_m2m/fiscal_rules.py 2012-10-15 10:14:35 +0000 | |||
2926 | @@ -177,8 +177,8 @@ | |||
2927 | 177 | ) | 177 | ) |
2928 | 178 | 178 | ||
2929 | 179 | for field in account_fiscal_position_rule.m2o_replaced_fields: | 179 | for field in account_fiscal_position_rule.m2o_replaced_fields: |
2932 | 180 | field_ids = [item.id for item in template[field]] | 180 | field_ids = [item.id for item in template["%s_ids"%field]] |
2933 | 181 | vals[field] = [(6, 0, field_ids)] | 181 | vals["%s_ids"%field] = [(6, 0, field_ids)] |
2934 | 182 | 182 | ||
2935 | 183 | return vals | 183 | return vals |
2936 | 184 | 184 | ||
2937 | 185 | 185 | ||
2938 | === added directory 'account_payment_ext' | |||
2939 | === added file 'account_payment_ext/__init__.py' | |||
2940 | --- account_payment_ext/__init__.py 1970-01-01 00:00:00 +0000 | |||
2941 | +++ account_payment_ext/__init__.py 2012-10-15 10:14:35 +0000 | |||
2942 | @@ -0,0 +1,32 @@ | |||
2943 | 1 | # -*- encoding: utf-8 -*- | ||
2944 | 2 | # | ||
2945 | 3 | # c2c_scan_bvr | ||
2946 | 4 | # | ||
2947 | 5 | # Created by Nicolas Bessi and Vincent Renaville | ||
2948 | 6 | # | ||
2949 | 7 | # Copyright (c) 2012 CamptoCamp. All rights reserved. | ||
2950 | 8 | ############################################################################## | ||
2951 | 9 | # | ||
2952 | 10 | # WARNING: This program as such is intended to be used by professional | ||
2953 | 11 | # programmers who take the whole responsability of assessing all potential | ||
2954 | 12 | # consequences resulting from its eventual inadequacies and bugs | ||
2955 | 13 | # End users who are looking for a ready-to-use solution with commercial | ||
2956 | 14 | # garantees and support are strongly adviced to contract a Free Software | ||
2957 | 15 | # Service Company | ||
2958 | 16 | # | ||
2959 | 17 | # This program is Free Software; you can redistribute it and/or | ||
2960 | 18 | # modify it under the terms of the GNU General Public License | ||
2961 | 19 | # as published by the Free Software Foundation; either version 2 | ||
2962 | 20 | # of the License, or (at your option) any later version. | ||
2963 | 21 | # | ||
2964 | 22 | # This program is distributed in the hope that it will be useful, | ||
2965 | 23 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2966 | 24 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2967 | 25 | # GNU General Public License for more details. | ||
2968 | 26 | # | ||
2969 | 27 | # You should have received a copy of the GNU General Public License | ||
2970 | 28 | # along with this program; if not, write to the Free Software | ||
2971 | 29 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
2972 | 30 | # | ||
2973 | 31 | ############################################################################## | ||
2974 | 32 | import account_payment | ||
2975 | 0 | \ No newline at end of file | 33 | \ No newline at end of file |
2976 | 1 | 34 | ||
2977 | === added file 'account_payment_ext/__openerp__.py' | |||
2978 | --- account_payment_ext/__openerp__.py 1970-01-01 00:00:00 +0000 | |||
2979 | +++ account_payment_ext/__openerp__.py 2012-10-15 10:14:35 +0000 | |||
2980 | @@ -0,0 +1,50 @@ | |||
2981 | 1 | # -*- encoding: utf-8 -*- | ||
2982 | 2 | # | ||
2983 | 3 | # c2c_scan_bvr | ||
2984 | 4 | # | ||
2985 | 5 | # Created by Nicolas Bessi and Vincent Renaville | ||
2986 | 6 | # | ||
2987 | 7 | # Copyright (c) 2012 CamptoCamp. All rights reserved. | ||
2988 | 8 | ############################################################################## | ||
2989 | 9 | # | ||
2990 | 10 | # WARNING: This program as such is intended to be used by professional | ||
2991 | 11 | # programmers who take the whole responsability of assessing all potential | ||
2992 | 12 | # consequences resulting from its eventual inadequacies and bugs | ||
2993 | 13 | # End users who are looking for a ready-to-use solution with commercial | ||
2994 | 14 | # garantees and support are strongly adviced to contract a Free Software | ||
2995 | 15 | # Service Company | ||
2996 | 16 | # | ||
2997 | 17 | # This program is Free Software; you can redistribute it and/or | ||
2998 | 18 | # modify it under the terms of the GNU General Public License | ||
2999 | 19 | # as published by the Free Software Foundation; either version 2 | ||
3000 | 20 | # of the License, or (at your option) any later version. | ||
3001 | 21 | # | ||
3002 | 22 | # This program is distributed in the hope that it will be useful, | ||
3003 | 23 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3004 | 24 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3005 | 25 | # GNU General Public License for more details. | ||
3006 | 26 | # | ||
3007 | 27 | # You should have received a copy of the GNU General Public License | ||
3008 | 28 | # along with this program; if not, write to the Free Software | ||
3009 | 29 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
3010 | 30 | # | ||
3011 | 31 | ############################################################################## | ||
3012 | 32 | { | ||
3013 | 33 | "name" : "Account Payment improvement", | ||
3014 | 34 | "description" : """In case of a payment order | ||
3015 | 35 | set to pay directly , when the payment will pass to stade done, it will set payment line date to the current date | ||
3016 | 36 | """, | ||
3017 | 37 | "version" : "1.0", | ||
3018 | 38 | "author" : "Camptocamp", | ||
3019 | 39 | "category" : "Generic Modules/Others", | ||
3020 | 40 | "website": "http://www.camptocamp.com", | ||
3021 | 41 | "depends" : [ | ||
3022 | 42 | "account_payment" | ||
3023 | 43 | ], | ||
3024 | 44 | "init_xml" : [], | ||
3025 | 45 | "update_xml" : [ | ||
3026 | 46 | 'account_payment_view.xml' | ||
3027 | 47 | ], | ||
3028 | 48 | "active": False, | ||
3029 | 49 | "installable": True | ||
3030 | 50 | } | ||
3031 | 0 | 51 | ||
3032 | === added file 'account_payment_ext/account_payment.py' | |||
3033 | --- account_payment_ext/account_payment.py 1970-01-01 00:00:00 +0000 | |||
3034 | +++ account_payment_ext/account_payment.py 2012-10-15 10:14:35 +0000 | |||
3035 | @@ -0,0 +1,47 @@ | |||
3036 | 1 | # -*- coding: utf-8 -*- | ||
3037 | 2 | ############################################################################## | ||
3038 | 3 | # | ||
3039 | 4 | # OpenERP, Open Source Management Solution | ||
3040 | 5 | # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). | ||
3041 | 6 | # | ||
3042 | 7 | # This program is free software: you can redistribute it and/or modify | ||
3043 | 8 | # it under the terms of the GNU Affero General Public License as | ||
3044 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
3045 | 10 | # License, or (at your option) any later version. | ||
3046 | 11 | # | ||
3047 | 12 | # This program is distributed in the hope that it will be useful, | ||
3048 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3049 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3050 | 15 | # GNU Affero General Public License for more details. | ||
3051 | 16 | # | ||
3052 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
3053 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
3054 | 19 | # | ||
3055 | 20 | ############################################################################## | ||
3056 | 21 | |||
3057 | 22 | import time | ||
3058 | 23 | |||
3059 | 24 | from osv import osv, fields | ||
3060 | 25 | import netsvc | ||
3061 | 26 | |||
3062 | 27 | |||
3063 | 28 | class payment_order(osv.osv): | ||
3064 | 29 | _inherit = 'payment.order' | ||
3065 | 30 | ### It will set the date | ||
3066 | 31 | def action_open(self, cr, uid, ids, *args): | ||
3067 | 32 | return_code = super(payment_order,self).action_open(cr, uid, ids, args) | ||
3068 | 33 | payment_line_obj = self.pool.get('payment.line') | ||
3069 | 34 | if return_code: | ||
3070 | 35 | for order in self.browse(cr,uid,ids): | ||
3071 | 36 | ### In the case of a date prefered to Directy , we set the current date into the bank statement | ||
3072 | 37 | if order.date_prefered == 'now': | ||
3073 | 38 | for line in order.line_ids: | ||
3074 | 39 | ## in case of no date defined on line | ||
3075 | 40 | if not line.date: | ||
3076 | 41 | payment_line_obj.write(cr, uid, [line.id], {'date': time.strftime('%Y-%m-%d')}) | ||
3077 | 42 | return return_code | ||
3078 | 43 | |||
3079 | 44 | payment_order() | ||
3080 | 45 | |||
3081 | 46 | |||
3082 | 47 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: | ||
3083 | 0 | 48 | ||
3084 | === added file 'account_payment_ext/account_payment_view.xml' | |||
3085 | --- account_payment_ext/account_payment_view.xml 1970-01-01 00:00:00 +0000 | |||
3086 | +++ account_payment_ext/account_payment_view.xml 2012-10-15 10:14:35 +0000 | |||
3087 | @@ -0,0 +1,18 @@ | |||
3088 | 1 | <?xml version="1.0" encoding="utf-8"?> | ||
3089 | 2 | <openerp> | ||
3090 | 3 | <data> | ||
3091 | 4 | |||
3092 | 5 | <record id="view_payment_order_form_date_required" model="ir.ui.view"> | ||
3093 | 6 | <field name="name">payment.order.form</field> | ||
3094 | 7 | <field name="model">payment.order</field> | ||
3095 | 8 | <field name="inherit_id" ref="account_payment.view_payment_order_form"/> | ||
3096 | 9 | <field name="type">form</field> | ||
3097 | 10 | <field name="arch" type="xml"> | ||
3098 | 11 | <xpath expr='//field[@name="date_scheduled"]' position='replace'> | ||
3099 | 12 | <field name="date_scheduled" select="1" attrs="{'readonly':[('date_prefered','!=','fixed')],'required':[('date_prefered','=','fixed')]}" /> | ||
3100 | 13 | </xpath> | ||
3101 | 14 | </field> | ||
3102 | 15 | </record> | ||
3103 | 16 | |||
3104 | 17 | </data> | ||
3105 | 18 | </openerp> | ||
3106 | 0 | 19 | ||
3107 | === added directory 'account_payment_ext/i18n' |
The merge is huge for "a bug". Can you check you requested the merge on the right branch + describe the bug you're trying to fix (or link to a bug on the tracker)?
Thanks