Merge lp:~camptocamp/account-financial-tools/add-manual-line-and-fees-nbi into lp:~account-core-editors/account-financial-tools/7.0
- add-manual-line-and-fees-nbi
- Merge into 7.0
Status: | Merged |
---|---|
Approved by: | Yannick Vaucher @ Camptocamp |
Approved revision: | 228 |
Merged at revision: | 185 |
Proposed branch: | lp:~camptocamp/account-financial-tools/add-manual-line-and-fees-nbi |
Merge into: | lp:~account-core-editors/account-financial-tools/7.0 |
Diff against target: |
2360 lines (+1612/-145) 43 files modified
account_credit_control/__openerp__.py (+2/-1) account_credit_control/account.py (+5/-36) account_credit_control/company.py (+1/-1) account_credit_control/data.xml (+15/-0) account_credit_control/i18n/de.po (+2/-2) account_credit_control/i18n/en.po (+3/-3) account_credit_control/i18n/es.po (+3/-3) account_credit_control/i18n/fr.po (+1/-1) account_credit_control/invoice.py (+30/-1) account_credit_control/line.py (+51/-24) account_credit_control/line_view.xml (+8/-1) account_credit_control/partner.py (+39/-12) account_credit_control/policy.py (+38/-9) account_credit_control/run.py (+17/-6) account_credit_control/run_view.xml (+2/-1) account_credit_control/scenarios/features/09_credit_control_run_jul.feature (+4/-4) account_credit_control/scenarios/features/11_credit_control_manual_setting.feature (+42/-0) account_credit_control/scenarios/features/steps/account_credit_control.py (+1/-1) account_credit_control/scenarios/features/steps/account_credit_control_changer.py (+76/-0) account_credit_control/wizard/__init__.py (+1/-0) account_credit_control/wizard/credit_control_communication.py (+6/-4) account_credit_control/wizard/credit_control_emailer_view.xml (+17/-7) account_credit_control/wizard/credit_control_marker_view.xml (+24/-9) account_credit_control/wizard/credit_control_policy_changer.py (+178/-0) account_credit_control/wizard/credit_control_policy_changer_view.xml (+65/-0) account_credit_control/wizard/credit_control_printer.py (+23/-7) account_credit_control/wizard/credit_control_printer_view.xml (+23/-10) account_credit_control_dunning_fees/__init__.py (+21/-0) account_credit_control_dunning_fees/__openerp__.py (+71/-0) account_credit_control_dunning_fees/i18n/account_credit_control_dunning_fees.pot (+81/-0) account_credit_control_dunning_fees/i18n/fr.po (+80/-0) account_credit_control_dunning_fees/model/__init__.py (+24/-0) account_credit_control_dunning_fees/model/dunning.py (+120/-0) account_credit_control_dunning_fees/model/line.py (+29/-0) account_credit_control_dunning_fees/model/policy.py (+36/-0) account_credit_control_dunning_fees/model/run.py (+39/-0) account_credit_control_dunning_fees/report/credit_control_summary.html.mako (+246/-0) account_credit_control_dunning_fees/report/report.xml (+12/-0) account_credit_control_dunning_fees/tests/__init__.py (+23/-0) account_credit_control_dunning_fees/tests/test_fees_generation.py (+95/-0) account_credit_control_dunning_fees/view/line_view.xml (+30/-0) account_credit_control_dunning_fees/view/policy_view.xml (+26/-0) async_move_line_importer/model/move_line_importer.py (+2/-2) |
To merge this branch: | bzr merge lp:~camptocamp/account-financial-tools/add-manual-line-and-fees-nbi |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Romain Deheele - Camptocamp (community) | code review | Approve | |
Leonardo Pistone | code review | Approve | |
Review via email: mp+218584@code.launchpad.net |
Commit message
Description of the change
Extend credit control to add new functionnalities:
There is now a wizard that allows to manually force policy level of an invoice.
The wizard can be reach from invoice.
Adds first version of dunning fees addons
- 216. By Nicolas Bessi - Camptocamp
-
[IMP] allows manual credit control changer to generate no follow credit control lines.
This is done in order to keep a trace of all taken action on an invoice - 217. By Nicolas Bessi - Camptocamp
-
[REFACTOR] printer filter to be more polite and improve the way to get ids
- 218. By Nicolas Bessi - Camptocamp
-
[FIX] typo overriden -> overridden
- 219. By Nicolas Bessi - Camptocamp
-
[TYPO]
- 220. By Nicolas Bessi - Camptocamp
-
[FIX] double identic statement
- 221. By Nicolas Bessi - Camptocamp
-
[FIX] english comment
- 222. By Nicolas Bessi - Camptocamp
-
[PEP8]
- 223. By Nicolas Bessi - Camptocamp
-
[TYPO]
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote : | # |
Hello thanks for the review.
I fixed you remarks.
for l145 as I'm copying data, I want to stay polite and do not remove an expected key ba an other piece of code.
Regards
Nicolas
- 224. By Nicolas Bessi - Camptocamp
-
[TYPO] overriden -> overridden
Leonardo Pistone (lepistone) wrote : | # |
Last few remarks to the end of the diff:
- 1407 the line is perhaps unintentional?
- 1299 typo "initialize"
- 2343 typo bypasses.
These are just small doc typos, so I'm approving the MP anyway.
For this kind of small typos, I'd not insist too much, since it will be so much easier to fix those on github, editing and merging from the web interface.
Thanks!
Romain Deheele - Camptocamp (romaindeheele) wrote : | # |
Hello,
Just little things as:
- I see deprecated attribute type on form views (l.869, 906)
- l.2221: s/Euro policy level/Usd policy level
- l.1310, 1311: '==' instead of '='
Otherwise, few little typos:
- l.1709: s/writen/written
- l.1709: s/fields/field
- l.2199: s/Initialaize/
- I would add commas on l.280, 290, 1392
- I would remove double spaces on l.699, 725
thanks for these new features,
Romain
- 225. By Nicolas Bessi - Camptocamp
-
[FIX] deprecated tag in view
- 226. By Nicolas Bessi - Camptocamp
-
[FIX] name of level in tests
- 227. By Nicolas Bessi - Camptocamp
-
[FIX] Typo in domain
- 228. By Nicolas Bessi - Camptocamp
-
[TYPOS]
Romain Deheele - Camptocamp (romaindeheele) wrote : | # |
Thanks for the changes,
Romain
Preview Diff
1 | === modified file 'account_credit_control/__openerp__.py' | |||
2 | --- account_credit_control/__openerp__.py 2014-03-24 08:37:48 +0000 | |||
3 | +++ account_credit_control/__openerp__.py 2014-06-24 12:34:19 +0000 | |||
4 | @@ -19,7 +19,7 @@ | |||
5 | 19 | # | 19 | # |
6 | 20 | ############################################################################## | 20 | ############################################################################## |
7 | 21 | {'name': 'Account Credit Control', | 21 | {'name': 'Account Credit Control', |
9 | 22 | 'version': '0.1.1', | 22 | 'version': '0.2.0', |
10 | 23 | 'author': 'Camptocamp', | 23 | 'author': 'Camptocamp', |
11 | 24 | 'maintainer': 'Camptocamp', | 24 | 'maintainer': 'Camptocamp', |
12 | 25 | 'category': 'Finance', | 25 | 'category': 'Finance', |
13 | @@ -69,6 +69,7 @@ | |||
14 | 69 | "wizard/credit_control_emailer_view.xml", | 69 | "wizard/credit_control_emailer_view.xml", |
15 | 70 | "wizard/credit_control_marker_view.xml", | 70 | "wizard/credit_control_marker_view.xml", |
16 | 71 | "wizard/credit_control_printer_view.xml", | 71 | "wizard/credit_control_printer_view.xml", |
17 | 72 | "wizard/credit_control_policy_changer_view.xml", | ||
18 | 72 | "security/ir.model.access.csv"], | 73 | "security/ir.model.access.csv"], |
19 | 73 | 'demo_xml': ["credit_control_demo.xml"], | 74 | 'demo_xml': ["credit_control_demo.xml"], |
20 | 74 | 'tests': [], | 75 | 'tests': [], |
21 | 75 | 76 | ||
22 | === modified file 'account_credit_control/account.py' | |||
23 | --- account_credit_control/account.py 2013-09-04 12:37:34 +0000 | |||
24 | +++ account_credit_control/account.py 2014-06-24 12:34:19 +0000 | |||
25 | @@ -27,11 +27,11 @@ | |||
26 | 27 | _inherit = "account.account" | 27 | _inherit = "account.account" |
27 | 28 | 28 | ||
28 | 29 | _columns = { | 29 | _columns = { |
34 | 30 | 'credit_control_line_ids': | 30 | 'credit_control_line_ids': fields.one2many( |
35 | 31 | fields.one2many('credit.control.line', | 31 | 'credit.control.line', |
36 | 32 | 'account_id', | 32 | 'account_id', |
37 | 33 | string='Credit Lines', | 33 | string='Credit Lines', |
38 | 34 | readonly=True), | 34 | readonly=True), |
39 | 35 | } | 35 | } |
40 | 36 | 36 | ||
41 | 37 | def copy_data(self, cr, uid, id, default=None, context=None): | 37 | def copy_data(self, cr, uid, id, default=None, context=None): |
42 | @@ -42,34 +42,3 @@ | |||
43 | 42 | default['credit_control_line_ids'] = False | 42 | default['credit_control_line_ids'] = False |
44 | 43 | return super(AccountAccount, self).copy_data( | 43 | return super(AccountAccount, self).copy_data( |
45 | 44 | cr, uid, id, default=default, context=context) | 44 | cr, uid, id, default=default, context=context) |
46 | 45 | |||
47 | 46 | |||
48 | 47 | class AccountInvoice(orm.Model): | ||
49 | 48 | """Add a link to a credit control policy on account.account""" | ||
50 | 49 | |||
51 | 50 | _inherit = "account.invoice" | ||
52 | 51 | _columns = { | ||
53 | 52 | 'credit_policy_id': | ||
54 | 53 | fields.many2one('credit.control.policy', | ||
55 | 54 | 'Credit Control Policy', | ||
56 | 55 | help=("The Credit Control Policy used for this " | ||
57 | 56 | "invoice. If nothing is defined, it will " | ||
58 | 57 | "use the account setting or the partner " | ||
59 | 58 | "setting.") | ||
60 | 59 | ), | ||
61 | 60 | 'credit_control_line_ids': | ||
62 | 61 | fields.one2many('credit.control.line', | ||
63 | 62 | 'invoice_id', | ||
64 | 63 | string='Credit Lines', | ||
65 | 64 | readonly=True), | ||
66 | 65 | } | ||
67 | 66 | |||
68 | 67 | def copy_data(self, cr, uid, id, default=None, context=None): | ||
69 | 68 | if default is None: | ||
70 | 69 | default = {} | ||
71 | 70 | else: | ||
72 | 71 | default = default.copy() | ||
73 | 72 | default = default.copy() | ||
74 | 73 | default['credit_control_line_ids'] = False | ||
75 | 74 | return super(AccountInvoice, self).copy_data( | ||
76 | 75 | cr, uid, id, default=default, context=context) | ||
77 | 76 | 45 | ||
78 | === modified file 'account_credit_control/company.py' | |||
79 | --- account_credit_control/company.py 2013-03-15 14:50:58 +0000 | |||
80 | +++ account_credit_control/company.py 2014-06-24 12:34:19 +0000 | |||
81 | @@ -31,7 +31,7 @@ | |||
82 | 31 | 'credit_policy_id': fields.many2one('credit.control.policy', | 31 | 'credit_policy_id': fields.many2one('credit.control.policy', |
83 | 32 | 'Credit Control Policy', | 32 | 'Credit Control Policy', |
84 | 33 | help=("The Credit Control Policy used on partners" | 33 | help=("The Credit Control Policy used on partners" |
86 | 34 | " by default. This setting can be overriden" | 34 | " by default. This setting can be overridden" |
87 | 35 | " on partners or invoices.")), | 35 | " on partners or invoices.")), |
88 | 36 | } | 36 | } |
89 | 37 | 37 | ||
90 | 38 | 38 | ||
91 | === modified file 'account_credit_control/data.xml' | |||
92 | --- account_credit_control/data.xml 2013-07-12 13:03:20 +0000 | |||
93 | +++ account_credit_control/data.xml 2014-06-24 12:34:19 +0000 | |||
94 | @@ -25,6 +25,21 @@ | |||
95 | 25 | <field name="do_nothing" eval="1"/> | 25 | <field name="do_nothing" eval="1"/> |
96 | 26 | </record> | 26 | </record> |
97 | 27 | 27 | ||
98 | 28 | <!-- no follow policy --> | ||
99 | 29 | <record model="credit.control.policy.level" | ||
100 | 30 | id="no_follow_1"> | ||
101 | 31 | <field name="name">No follow</field> | ||
102 | 32 | <field name="level" eval="1"/> | ||
103 | 33 | <field name="computation_mode">net_days</field> | ||
104 | 34 | <field name="delay_days" eval="0"/> | ||
105 | 35 | <field name="email_template_id" ref="email_template_credit_control_base"/> | ||
106 | 36 | <field name="policy_id" ref="credit_control_no_follow"/> | ||
107 | 37 | <field name="channel">email</field> | ||
108 | 38 | <field name="custom_text">Manual no follow</field> | ||
109 | 39 | |||
110 | 40 | <field name="custom_mail_text">Manual no follow</field> | ||
111 | 41 | </record> | ||
112 | 42 | |||
113 | 28 | <!-- policy 1 --> | 43 | <!-- policy 1 --> |
114 | 29 | <record model="credit.control.policy" | 44 | <record model="credit.control.policy" |
115 | 30 | id="credit_control_3_time"> | 45 | id="credit_control_3_time"> |
116 | 31 | 46 | ||
117 | === modified file 'account_credit_control/i18n/de.po' | |||
118 | --- account_credit_control/i18n/de.po 2013-09-12 14:39:17 +0000 | |||
119 | +++ account_credit_control/i18n/de.po 2014-06-24 12:34:19 +0000 | |||
120 | @@ -984,10 +984,10 @@ | |||
121 | 984 | #: help:res.company,credit_policy_id:0 | 984 | #: help:res.company,credit_policy_id:0 |
122 | 985 | msgid "" | 985 | msgid "" |
123 | 986 | "The Credit Control Policy used on partners by default. This setting can be " | 986 | "The Credit Control Policy used on partners by default. This setting can be " |
125 | 987 | "overriden on partners or invoices." | 987 | "overridden on partners or invoices." |
126 | 988 | msgstr "" | 988 | msgstr "" |
127 | 989 | "The Credit Control Policy used on partners by default. This setting can be " | 989 | "The Credit Control Policy used on partners by default. This setting can be " |
129 | 990 | "overriden on partners or invoices." | 990 | "overridden on partners or invoices." |
130 | 991 | 991 | ||
131 | 992 | #. module: account_credit_control | 992 | #. module: account_credit_control |
132 | 993 | #: field:credit.control.line,policy_level_id:0 | 993 | #: field:credit.control.line,policy_level_id:0 |
133 | 994 | 994 | ||
134 | === modified file 'account_credit_control/i18n/en.po' | |||
135 | --- account_credit_control/i18n/en.po 2013-09-12 14:39:17 +0000 | |||
136 | +++ account_credit_control/i18n/en.po 2014-06-24 12:34:19 +0000 | |||
137 | @@ -984,10 +984,10 @@ | |||
138 | 984 | #: help:res.company,credit_policy_id:0 | 984 | #: help:res.company,credit_policy_id:0 |
139 | 985 | msgid "" | 985 | msgid "" |
140 | 986 | "The Credit Control Policy used on partners by default. This setting can be " | 986 | "The Credit Control Policy used on partners by default. This setting can be " |
142 | 987 | "overriden on partners or invoices." | 987 | "overridden on partners or invoices." |
143 | 988 | msgstr "" | 988 | msgstr "" |
144 | 989 | "The Credit Control Policy used on partners by default. This setting can be " | 989 | "The Credit Control Policy used on partners by default. This setting can be " |
146 | 990 | "overriden on partners or invoices." | 990 | "overridden on partners or invoices." |
147 | 991 | 991 | ||
148 | 992 | #. module: account_credit_control | 992 | #. module: account_credit_control |
149 | 993 | #: field:credit.control.line,policy_level_id:0 | 993 | #: field:credit.control.line,policy_level_id:0 |
150 | @@ -1042,4 +1042,4 @@ | |||
151 | 1042 | #. module: account_credit_control | 1042 | #. module: account_credit_control |
152 | 1043 | #: report:addons/account_credit_control/report/credit_control_summary.html.mako:211 | 1043 | #: report:addons/account_credit_control/report/credit_control_summary.html.mako:211 |
153 | 1044 | msgid "If you have any question, do not hesitate to contact us." | 1044 | msgid "If you have any question, do not hesitate to contact us." |
154 | 1045 | msgstr "If you have any question, do not hesitate to contact us." | ||
155 | 1046 | \ No newline at end of file | 1045 | \ No newline at end of file |
156 | 1046 | msgstr "If you have any question, do not hesitate to contact us." | ||
157 | 1047 | 1047 | ||
158 | === modified file 'account_credit_control/i18n/es.po' | |||
159 | --- account_credit_control/i18n/es.po 2013-09-12 14:39:17 +0000 | |||
160 | +++ account_credit_control/i18n/es.po 2014-06-24 12:34:19 +0000 | |||
161 | @@ -982,10 +982,10 @@ | |||
162 | 982 | #: help:res.company,credit_policy_id:0 | 982 | #: help:res.company,credit_policy_id:0 |
163 | 983 | msgid "" | 983 | msgid "" |
164 | 984 | "The Credit Control Policy used on partners by default. This setting can be " | 984 | "The Credit Control Policy used on partners by default. This setting can be " |
166 | 985 | "overriden on partners or invoices." | 985 | "overridden on partners or invoices." |
167 | 986 | msgstr "" | 986 | msgstr "" |
168 | 987 | "The Credit Control Policy used on partners by default. This setting can be " | 987 | "The Credit Control Policy used on partners by default. This setting can be " |
170 | 988 | "overriden on partners or invoices." | 988 | "overridden on partners or invoices." |
171 | 989 | 989 | ||
172 | 990 | #. module: account_credit_control | 990 | #. module: account_credit_control |
173 | 991 | #: field:credit.control.line,policy_level_id:0 | 991 | #: field:credit.control.line,policy_level_id:0 |
174 | @@ -1040,4 +1040,4 @@ | |||
175 | 1040 | #. module: account_credit_control | 1040 | #. module: account_credit_control |
176 | 1041 | #: report:addons/account_credit_control/report/credit_control_summary.html.mako:211 | 1041 | #: report:addons/account_credit_control/report/credit_control_summary.html.mako:211 |
177 | 1042 | msgid "If you have any question, do not hesitate to contact us." | 1042 | msgid "If you have any question, do not hesitate to contact us." |
178 | 1043 | msgstr "If you have any question, do not hesitate to contact us." | ||
179 | 1044 | \ No newline at end of file | 1043 | \ No newline at end of file |
180 | 1044 | msgstr "If you have any question, do not hesitate to contact us." | ||
181 | 1045 | 1045 | ||
182 | === modified file 'account_credit_control/i18n/fr.po' | |||
183 | --- account_credit_control/i18n/fr.po 2013-09-12 14:39:17 +0000 | |||
184 | +++ account_credit_control/i18n/fr.po 2014-06-24 12:34:19 +0000 | |||
185 | @@ -965,7 +965,7 @@ | |||
186 | 965 | #: help:res.company,credit_policy_id:0 | 965 | #: help:res.company,credit_policy_id:0 |
187 | 966 | msgid "" | 966 | msgid "" |
188 | 967 | "The Credit Control Policy used on partners by default. This setting can be " | 967 | "The Credit Control Policy used on partners by default. This setting can be " |
190 | 968 | "overriden on partners or invoices." | 968 | "overridden on partners or invoices." |
191 | 969 | msgstr "" | 969 | msgstr "" |
192 | 970 | "Politique de relance par défaut du client. (Ce paramétrage peut être " | 970 | "Politique de relance par défaut du client. (Ce paramétrage peut être " |
193 | 971 | "défini plus spécifiquement au niveau de la facture)." | 971 | "défini plus spécifiquement au niveau de la facture)." |
194 | 972 | 972 | ||
195 | === modified file 'account_credit_control/invoice.py' | |||
196 | --- account_credit_control/invoice.py 2013-09-18 07:59:03 +0000 | |||
197 | +++ account_credit_control/invoice.py 2014-06-24 12:34:19 +0000 | |||
198 | @@ -18,7 +18,7 @@ | |||
199 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
200 | 19 | # | 19 | # |
201 | 20 | ############################################################################## | 20 | ############################################################################## |
203 | 21 | from openerp.osv import orm | 21 | from openerp.osv import orm, fields |
204 | 22 | from openerp.tools.translate import _ | 22 | from openerp.tools.translate import _ |
205 | 23 | 23 | ||
206 | 24 | 24 | ||
207 | @@ -26,7 +26,36 @@ | |||
208 | 26 | """Check on cancelling of an invoice""" | 26 | """Check on cancelling of an invoice""" |
209 | 27 | _inherit = 'account.invoice' | 27 | _inherit = 'account.invoice' |
210 | 28 | 28 | ||
211 | 29 | _columns = { | ||
212 | 30 | 'credit_policy_id': | ||
213 | 31 | fields.many2one('credit.control.policy', | ||
214 | 32 | 'Credit Control Policy', | ||
215 | 33 | help=("The Credit Control Policy used for this " | ||
216 | 34 | "invoice. If nothing is defined, it will " | ||
217 | 35 | "use the account setting or the partner " | ||
218 | 36 | "setting."), | ||
219 | 37 | readonly=True, | ||
220 | 38 | ), | ||
221 | 39 | 'credit_control_line_ids': | ||
222 | 40 | fields.one2many('credit.control.line', | ||
223 | 41 | 'invoice_id', | ||
224 | 42 | string='Credit Lines', | ||
225 | 43 | readonly=True), | ||
226 | 44 | } | ||
227 | 45 | |||
228 | 46 | def copy_data(self, cr, uid, id, default=None, context=None): | ||
229 | 47 | """Ensure that credit lines and policy are not copied""" | ||
230 | 48 | if default is None: | ||
231 | 49 | default = {} | ||
232 | 50 | else: | ||
233 | 51 | default = default.copy() | ||
234 | 52 | default['credit_control_line_ids'] = False | ||
235 | 53 | default['credit_policy_id'] = False | ||
236 | 54 | return super(AccountInvoice, self).copy_data( | ||
237 | 55 | cr, uid, id, default=default, context=context) | ||
238 | 56 | |||
239 | 29 | def action_cancel(self, cr, uid, ids, context=None): | 57 | def action_cancel(self, cr, uid, ids, context=None): |
240 | 58 | """Prevent to cancel invoice related to credit line""" | ||
241 | 30 | # We will search if this invoice is linked with credit | 59 | # We will search if this invoice is linked with credit |
242 | 31 | cc_line_obj = self.pool.get('credit.control.line') | 60 | cc_line_obj = self.pool.get('credit.control.line') |
243 | 32 | for invoice_id in ids: | 61 | for invoice_id in ids: |
244 | 33 | 62 | ||
245 | === modified file 'account_credit_control/line.py' | |||
246 | --- account_credit_control/line.py 2013-09-04 12:37:34 +0000 | |||
247 | +++ account_credit_control/line.py 2014-06-24 12:34:19 +0000 | |||
248 | @@ -38,9 +38,11 @@ | |||
249 | 38 | _name = "credit.control.line" | 38 | _name = "credit.control.line" |
250 | 39 | _description = "A credit control line" | 39 | _description = "A credit control line" |
251 | 40 | _rec_name = "id" | 40 | _rec_name = "id" |
253 | 41 | 41 | _order = "date DESC" | |
254 | 42 | _columns = { | 42 | _columns = { |
256 | 43 | 'date': fields.date('Controlling date', required=True), | 43 | 'date': fields.date('Controlling date', |
257 | 44 | required=True, | ||
258 | 45 | select=True), | ||
259 | 44 | # maturity date of related move line we do not use a related field in order to | 46 | # maturity date of related move line we do not use a related field in order to |
260 | 45 | # allow manual changes | 47 | # allow manual changes |
261 | 46 | 'date_due': fields.date('Due date', | 48 | 'date_due': fields.date('Due date', |
262 | @@ -116,6 +118,7 @@ | |||
263 | 116 | string='Level', | 118 | string='Level', |
264 | 117 | store=True, | 119 | store=True, |
265 | 118 | readonly=True), | 120 | readonly=True), |
266 | 121 | 'manually_overridden': fields.boolean('Manually overridden') | ||
267 | 119 | } | 122 | } |
268 | 120 | 123 | ||
269 | 121 | 124 | ||
270 | @@ -141,8 +144,27 @@ | |||
271 | 141 | return data | 144 | return data |
272 | 142 | 145 | ||
273 | 143 | def create_or_update_from_mv_lines(self, cr, uid, ids, lines, | 146 | def create_or_update_from_mv_lines(self, cr, uid, ids, lines, |
276 | 144 | level_id, controlling_date, context=None): | 147 | level_id, controlling_date, |
277 | 145 | """Create or update line based on levels""" | 148 | check_tolerance=True, context=None): |
278 | 149 | """Create or update line based on levels | ||
279 | 150 | |||
280 | 151 | if check_tolerance is true credit line will not be | ||
281 | 152 | created if open amount is too small. | ||
282 | 153 | eg. we do not want to send a letter for 10 cents | ||
283 | 154 | of open amount. | ||
284 | 155 | |||
285 | 156 | :param lines: move.line id list | ||
286 | 157 | :param level_id: credit.control.policy.level id | ||
287 | 158 | :param controlling_date: date string of the credit controlling date. | ||
288 | 159 | Generally it should be the same | ||
289 | 160 | as create date | ||
290 | 161 | :param check_tolerance: boolean if True credit line | ||
291 | 162 | will not be generated if open amount | ||
292 | 163 | is smaller than company defined | ||
293 | 164 | tolerance | ||
294 | 165 | |||
295 | 166 | :returns: list of created credit line ids | ||
296 | 167 | """ | ||
297 | 146 | currency_obj = self.pool.get('res.currency') | 168 | currency_obj = self.pool.get('res.currency') |
298 | 147 | level_obj = self.pool.get('credit.control.policy.level') | 169 | level_obj = self.pool.get('credit.control.policy.level') |
299 | 148 | ml_obj = self.pool.get('account.move.line') | 170 | ml_obj = self.pool.get('account.move.line') |
300 | @@ -164,26 +186,31 @@ | |||
301 | 164 | for line in ml_obj.browse(cr, uid, lines, context): | 186 | for line in ml_obj.browse(cr, uid, lines, context): |
302 | 165 | 187 | ||
303 | 166 | open_amount = line.amount_residual_currency | 188 | open_amount = line.amount_residual_currency |
324 | 167 | 189 | cur_tolerance = tolerance.get(line.currency_id.id, tolerance_base) | |
325 | 168 | if open_amount > tolerance.get(line.currency_id.id, tolerance_base): | 190 | if check_tolerance and open_amount < cur_tolerance: |
326 | 169 | vals = self._prepare_from_move_line( | 191 | continue |
327 | 170 | cr, uid, line, level, controlling_date, open_amount, context=context) | 192 | vals = self._prepare_from_move_line(cr, uid, |
328 | 171 | line_id = self.create(cr, uid, vals, context=context) | 193 | line, |
329 | 172 | line_ids.append(line_id) | 194 | level, |
330 | 173 | 195 | controlling_date, | |
331 | 174 | # when we have lines generated earlier in draft, | 196 | open_amount, |
332 | 175 | # on the same level, it means that we have left | 197 | context=context) |
333 | 176 | # them, so they are to be considered as ignored | 198 | line_id = self.create(cr, uid, vals, context=context) |
334 | 177 | previous_draft_ids = self.search( | 199 | line_ids.append(line_id) |
335 | 178 | cr, uid, | 200 | |
336 | 179 | [('move_line_id', '=', line.id), | 201 | # when we have lines generated earlier in draft, |
337 | 180 | ('level', '=', level.id), | 202 | # on the same level, it means that we have left |
338 | 181 | ('state', '=', 'draft'), | 203 | # them, so they are to be considered as ignored |
339 | 182 | ('id', '!=', line_id)], | 204 | previous_draft_ids = self.search( |
340 | 183 | context=context) | 205 | cr, uid, |
341 | 184 | if previous_draft_ids: | 206 | [('move_line_id', '=', line.id), |
342 | 185 | self.write(cr, uid, previous_draft_ids, | 207 | ('policy_level_id', '=', level.id), |
343 | 186 | {'state': 'ignored'}, context=context) | 208 | ('state', '=', 'draft'), |
344 | 209 | ('id', '!=', line_id)], | ||
345 | 210 | context=context) | ||
346 | 211 | if previous_draft_ids: | ||
347 | 212 | self.write(cr, uid, previous_draft_ids, | ||
348 | 213 | {'state': 'ignored'}, context=context) | ||
349 | 187 | 214 | ||
350 | 188 | return line_ids | 215 | return line_ids |
351 | 189 | 216 | ||
352 | 190 | 217 | ||
353 | === modified file 'account_credit_control/line_view.xml' | |||
354 | --- account_credit_control/line_view.xml 2013-03-18 09:21:33 +0000 | |||
355 | +++ account_credit_control/line_view.xml 2014-06-24 12:34:19 +0000 | |||
356 | @@ -10,6 +10,7 @@ | |||
357 | 10 | <field name="date_due"/> | 10 | <field name="date_due"/> |
358 | 11 | <field name="date_sent"/> | 11 | <field name="date_sent"/> |
359 | 12 | <field name="level"/> | 12 | <field name="level"/> |
360 | 13 | <field name="manually_overridden"/> | ||
361 | 13 | <field name="state"/> | 14 | <field name="state"/> |
362 | 14 | <field name="channel"/> | 15 | <field name="channel"/> |
363 | 15 | <field name="invoice_id"/> | 16 | <field name="invoice_id"/> |
364 | @@ -32,7 +33,7 @@ | |||
365 | 32 | <field name="type">search</field> | 33 | <field name="type">search</field> |
366 | 33 | <field name="arch" type="xml"> | 34 | <field name="arch" type="xml"> |
367 | 34 | <search string="Control Credit Lines"> | 35 | <search string="Control Credit Lines"> |
369 | 35 | <group> | 36 | <group string="Filters"> |
370 | 36 | <filter name="filter_draft" icon="terp-mail-message-new" | 37 | <filter name="filter_draft" icon="terp-mail-message-new" |
371 | 37 | string="Draft" domain="[('state', '=', 'draft')]" | 38 | string="Draft" domain="[('state', '=', 'draft')]" |
372 | 38 | help="Draft lines have to be triaged."/> | 39 | help="Draft lines have to be triaged."/> |
373 | @@ -48,6 +49,9 @@ | |||
374 | 48 | <filter name="filter_error" icon="terp-gtk-stop" string="Error" | 49 | <filter name="filter_error" icon="terp-gtk-stop" string="Error" |
375 | 49 | domain="[('state', 'in', ('error', 'email_error'))]" | 50 | domain="[('state', 'in', ('error', 'email_error'))]" |
376 | 50 | help="An error has occured during the sending of the email."/> | 51 | help="An error has occured during the sending of the email."/> |
377 | 52 | <filter name="filter_manual" icon="terp-gtk-stop" string="Manual change" | ||
378 | 53 | domain="[('manually_overridden', '=', True)]" | ||
379 | 54 | help="The line was deprecated by a manual change of policy on invoice."/> | ||
380 | 51 | <separator orientation="vertical"/> | 55 | <separator orientation="vertical"/> |
381 | 52 | 56 | ||
382 | 53 | <field name="date"/> | 57 | <field name="date"/> |
383 | @@ -89,6 +93,8 @@ | |||
384 | 89 | <separator orientation="vertical"/> | 93 | <separator orientation="vertical"/> |
385 | 90 | <filter domain='[]' context="{'group_by': 'channel'}" | 94 | <filter domain='[]' context="{'group_by': 'channel'}" |
386 | 91 | icon="terp-document-new" string="Channel"/> | 95 | icon="terp-document-new" string="Channel"/> |
387 | 96 | <filter domain='[]' context="{'group_by': 'manually_overridden'}" | ||
388 | 97 | icon="terp-document-new" string="Manual change"/> | ||
389 | 92 | </group> | 98 | </group> |
390 | 93 | </search> | 99 | </search> |
391 | 94 | </field> | 100 | </field> |
392 | @@ -103,6 +109,7 @@ | |||
393 | 103 | <field name="date"/> | 109 | <field name="date"/> |
394 | 104 | <field name="date_due"/> | 110 | <field name="date_due"/> |
395 | 105 | <field name="level"/> | 111 | <field name="level"/> |
396 | 112 | <field name="manually_overridden"/> | ||
397 | 106 | <field name="state"/> | 113 | <field name="state"/> |
398 | 107 | <field name="channel"/> | 114 | <field name="channel"/> |
399 | 108 | <field name="invoice_id"/> | 115 | <field name="invoice_id"/> |
400 | 109 | 116 | ||
401 | === modified file 'account_credit_control/partner.py' | |||
402 | --- account_credit_control/partner.py 2013-09-04 12:29:15 +0000 | |||
403 | +++ account_credit_control/partner.py 2014-06-24 12:34:19 +0000 | |||
404 | @@ -19,6 +19,7 @@ | |||
405 | 19 | # | 19 | # |
406 | 20 | ############################################################################## | 20 | ############################################################################## |
407 | 21 | from openerp.osv import orm, fields | 21 | from openerp.osv import orm, fields |
408 | 22 | from openerp.tools.translate import _ | ||
409 | 22 | 23 | ||
410 | 23 | 24 | ||
411 | 24 | class ResPartner(orm.Model): | 25 | class ResPartner(orm.Model): |
412 | @@ -28,21 +29,47 @@ | |||
413 | 28 | _inherit = "res.partner" | 29 | _inherit = "res.partner" |
414 | 29 | 30 | ||
415 | 30 | _columns = { | 31 | _columns = { |
428 | 31 | 'credit_policy_id': | 32 | 'credit_policy_id': fields.many2one( |
429 | 32 | fields.many2one('credit.control.policy', | 33 | 'credit.control.policy', |
430 | 33 | 'Credit Control Policy', | 34 | 'Credit Control Policy', |
431 | 34 | help=("The Credit Control Policy used for this " | 35 | domain="[('account_ids', 'in', property_account_receivable)]", |
432 | 35 | "partner. This setting can be forced on the " | 36 | help=("The Credit Control Policy used for this " |
433 | 36 | "invoice. If nothing is defined, it will use " | 37 | "partner. This setting can be forced on the " |
434 | 37 | "the company setting.")), | 38 | "invoice. If nothing is defined, it will use " |
435 | 38 | 'credit_control_line_ids': | 39 | "the company setting.") |
436 | 39 | fields.one2many('credit.control.line', | 40 | ), |
437 | 40 | 'invoice_id', | 41 | 'credit_control_line_ids': fields.one2many( |
438 | 41 | string='Credit Control Lines', | 42 | 'credit.control.line', |
439 | 42 | readonly=True) | 43 | 'invoice_id', |
440 | 44 | string='Credit Control Lines', | ||
441 | 45 | readonly=True | ||
442 | 46 | ) | ||
443 | 43 | } | 47 | } |
444 | 44 | 48 | ||
445 | 49 | def _check_credit_policy(self, cr, uid, part_ids, context=None): | ||
446 | 50 | """Ensure that policy on partner are limited to the account policy""" | ||
447 | 51 | if isinstance(part_ids, (int, long)): | ||
448 | 52 | part_ids = [part_ids] | ||
449 | 53 | policy_obj = self.pool['credit.control.policy'] | ||
450 | 54 | for partner in self.browse(cr, uid, part_ids, context): | ||
451 | 55 | if not partner.property_account_receivable or \ | ||
452 | 56 | not partner.credit_policy_id: | ||
453 | 57 | return True | ||
454 | 58 | account = partner.property_account_receivable | ||
455 | 59 | policy_obj.check_policy_against_account( | ||
456 | 60 | cr, uid, | ||
457 | 61 | account.id, | ||
458 | 62 | partner.credit_policy_id.id, | ||
459 | 63 | context=context | ||
460 | 64 | ) | ||
461 | 65 | return True | ||
462 | 66 | |||
463 | 67 | _constraints = [(_check_credit_policy, | ||
464 | 68 | 'The policy must be related to the receivable account', | ||
465 | 69 | ['credit_policy_id'])] | ||
466 | 70 | |||
467 | 45 | def copy_data(self, cr, uid, id, default=None, context=None): | 71 | def copy_data(self, cr, uid, id, default=None, context=None): |
468 | 72 | """Remove credit lines when copying partner""" | ||
469 | 46 | if default is None: | 73 | if default is None: |
470 | 47 | default = {} | 74 | default = {} |
471 | 48 | else: | 75 | else: |
472 | 49 | 76 | ||
473 | === modified file 'account_credit_control/policy.py' | |||
474 | --- account_credit_control/policy.py 2014-03-04 07:52:47 +0000 | |||
475 | +++ account_credit_control/policy.py 2014-06-24 12:34:19 +0000 | |||
476 | @@ -18,11 +18,11 @@ | |||
477 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
478 | 19 | # | 19 | # |
479 | 20 | ############################################################################## | 20 | ############################################################################## |
481 | 21 | from openerp.osv.orm import Model, fields | 21 | from openerp.osv import orm, fields |
482 | 22 | from openerp.tools.translate import _ | 22 | from openerp.tools.translate import _ |
483 | 23 | 23 | ||
484 | 24 | 24 | ||
486 | 25 | class CreditControlPolicy(Model): | 25 | class CreditControlPolicy(orm.Model): |
487 | 26 | """Define a policy of reminder""" | 26 | """Define a policy of reminder""" |
488 | 27 | 27 | ||
489 | 28 | _name = "credit.control.policy" | 28 | _name = "credit.control.policy" |
490 | @@ -42,7 +42,7 @@ | |||
491 | 42 | 'account_ids': fields.many2many('account.account', | 42 | 'account_ids': fields.many2many('account.account', |
492 | 43 | string='Accounts', | 43 | string='Accounts', |
493 | 44 | required=True, | 44 | required=True, |
495 | 45 | domain="[('reconcile', '=', True)]", | 45 | domain="[('type', '=', 'receivable')]", |
496 | 46 | help="This policy will be active only" | 46 | help="This policy will be active only" |
497 | 47 | " for the selected accounts"), | 47 | " for the selected accounts"), |
498 | 48 | 'active': fields.boolean('Active'), | 48 | 'active': fields.boolean('Active'), |
499 | @@ -103,7 +103,10 @@ | |||
500 | 103 | my_obj = self.pool.get(model) | 103 | my_obj = self.pool.get(model) |
501 | 104 | move_l_obj = self.pool.get('account.move.line') | 104 | move_l_obj = self.pool.get('account.move.line') |
502 | 105 | 105 | ||
504 | 106 | default_domain = self._move_lines_domain(cr, uid, policy, controlling_date, context=context) | 106 | default_domain = self._move_lines_domain(cr, uid, |
505 | 107 | policy, | ||
506 | 108 | controlling_date, | ||
507 | 109 | context=context) | ||
508 | 107 | to_add_ids = set() | 110 | to_add_ids = set() |
509 | 108 | to_remove_ids = set() | 111 | to_remove_ids = set() |
510 | 109 | 112 | ||
511 | @@ -198,15 +201,34 @@ | |||
512 | 198 | if isinstance(policy_id, list): | 201 | if isinstance(policy_id, list): |
513 | 199 | policy_id = policy_id[0] | 202 | policy_id = policy_id[0] |
514 | 200 | cr.execute("SELECT move_line_id FROM credit_control_line" | 203 | cr.execute("SELECT move_line_id FROM credit_control_line" |
516 | 201 | " WHERE policy_id != %s and move_line_id in %s", | 204 | " WHERE policy_id != %s and move_line_id in %s" |
517 | 205 | " AND manually_overridden IS false", | ||
518 | 202 | (policy_id, tuple(lines))) | 206 | (policy_id, tuple(lines))) |
519 | 203 | res = cr.fetchall() | 207 | res = cr.fetchall() |
520 | 204 | if res: | 208 | if res: |
521 | 205 | different_lines.update([x[0] for x in res]) | 209 | different_lines.update([x[0] for x in res]) |
522 | 206 | return different_lines | 210 | return different_lines |
523 | 207 | 211 | ||
526 | 208 | 212 | def check_policy_against_account(self, cr, uid, account_id, policy_id, | |
527 | 209 | class CreditControlPolicyLevel(Model): | 213 | context=None): |
528 | 214 | """Ensure that the policy corresponds to account relation""" | ||
529 | 215 | policy = self.browse(cr, uid, policy_id, context=context) | ||
530 | 216 | account = self.pool['account.account'].browse(cr, uid, account_id, | ||
531 | 217 | context=context) | ||
532 | 218 | policies_id = self.search(cr, uid, [], | ||
533 | 219 | context=context) | ||
534 | 220 | policies = self.browse(cr, uid, policies_id, context=context) | ||
535 | 221 | allowed = [x for x in policies | ||
536 | 222 | if account in x.account_ids or x.do_nothing] | ||
537 | 223 | if policy not in allowed: | ||
538 | 224 | allowed_names = u"\n".join(x.name for x in allowed) | ||
539 | 225 | raise orm.except_orm( | ||
540 | 226 | _('You can only use a policy set on account %s') % account.name, | ||
541 | 227 | _("Please choose one of the following policies:\n %s") % allowed_names) | ||
542 | 228 | return True | ||
543 | 229 | |||
544 | 230 | |||
545 | 231 | class CreditControlPolicyLevel(orm.Model): | ||
546 | 210 | """Define a policy level. A level allows to determine if | 232 | """Define a policy level. A level allows to determine if |
547 | 211 | a move line is due and the level of overdue of the line""" | 233 | a move line is due and the level of overdue of the line""" |
548 | 212 | 234 | ||
549 | @@ -319,8 +341,11 @@ | |||
550 | 319 | " FROM credit_control_line\n" | 341 | " FROM credit_control_line\n" |
551 | 320 | " WHERE move_line_id = mv_line.id\n" | 342 | " WHERE move_line_id = mv_line.id\n" |
552 | 321 | # lines from a previous level with a draft or ignored state | 343 | # lines from a previous level with a draft or ignored state |
553 | 344 | # or manually overridden | ||
554 | 322 | # have to be generated again for the previous level | 345 | # have to be generated again for the previous level |
556 | 323 | " AND state not in ('draft', 'ignored'))") | 346 | " AND NOT manually_overridden\n" |
557 | 347 | " AND state NOT IN ('draft', 'ignored'))" | ||
558 | 348 | " AND (mv_line.debit IS NOT NULL AND mv_line.debit != 0.0)\n") | ||
559 | 324 | sql += " AND" | 349 | sql += " AND" |
560 | 325 | sql += self._get_sql_date_boundary_for_computation_mode(cr, uid, level, | 350 | sql += self._get_sql_date_boundary_for_computation_mode(cr, uid, level, |
561 | 326 | controlling_date, context) | 351 | controlling_date, context) |
562 | @@ -346,11 +371,15 @@ | |||
563 | 346 | " WHERE cr_line.id = (SELECT credit_control_line.id FROM credit_control_line\n" | 371 | " WHERE cr_line.id = (SELECT credit_control_line.id FROM credit_control_line\n" |
564 | 347 | " WHERE credit_control_line.move_line_id = mv_line.id\n" | 372 | " WHERE credit_control_line.move_line_id = mv_line.id\n" |
565 | 348 | " AND state != 'ignored'" | 373 | " AND state != 'ignored'" |
566 | 374 | " AND NOT manually_overridden" | ||
567 | 349 | " ORDER BY credit_control_line.level desc limit 1)\n" | 375 | " ORDER BY credit_control_line.level desc limit 1)\n" |
568 | 350 | " AND cr_line.level = %(previous_level)s\n" | 376 | " AND cr_line.level = %(previous_level)s\n" |
569 | 377 | " AND (mv_line.debit IS NOT NULL AND mv_line.debit != 0.0)\n" | ||
570 | 351 | # lines from a previous level with a draft or ignored state | 378 | # lines from a previous level with a draft or ignored state |
571 | 379 | # or manually overridden | ||
572 | 352 | # have to be generated again for the previous level | 380 | # have to be generated again for the previous level |
574 | 353 | " AND cr_line.state not in ('draft', 'ignored')\n" | 381 | " AND NOT manually_overridden\n" |
575 | 382 | " AND cr_line.state NOT IN ('draft', 'ignored')\n" | ||
576 | 354 | " AND mv_line.id in %(line_ids)s\n") | 383 | " AND mv_line.id in %(line_ids)s\n") |
577 | 355 | sql += " AND " | 384 | sql += " AND " |
578 | 356 | sql += self._get_sql_date_boundary_for_computation_mode(cr, uid, level, | 385 | sql += self._get_sql_date_boundary_for_computation_mode(cr, uid, level, |
579 | 357 | 386 | ||
580 | === modified file 'account_credit_control/run.py' | |||
581 | --- account_credit_control/run.py 2013-09-04 12:29:15 +0000 | |||
582 | +++ account_credit_control/run.py 2014-06-24 12:34:19 +0000 | |||
583 | @@ -81,14 +81,24 @@ | |||
584 | 81 | 81 | ||
585 | 82 | def _check_run_date(self, cr, uid, ids, controlling_date, context=None): | 82 | def _check_run_date(self, cr, uid, ids, controlling_date, context=None): |
586 | 83 | """Ensure that there is no credit line in the future using controlling_date""" | 83 | """Ensure that there is no credit line in the future using controlling_date""" |
588 | 84 | line_obj = self.pool.get('credit.control.line') | 84 | run_obj = self.pool['credit.control.run'] |
589 | 85 | runs = run_obj.search(cr, uid, [('date', '>', controlling_date)], | ||
590 | 86 | order='date DESC', limit=1, context=context) | ||
591 | 87 | if runs: | ||
592 | 88 | run = run_obj.browse(cr, uid, runs[0], context=context) | ||
593 | 89 | raise orm.except_orm(_('Error'), | ||
594 | 90 | _('A run has already been executed more ' | ||
595 | 91 | 'recently than %s') % (run.date)) | ||
596 | 92 | |||
597 | 93 | line_obj = self.pool['credit.control.line'] | ||
598 | 85 | lines = line_obj.search(cr, uid, [('date', '>', controlling_date)], | 94 | lines = line_obj.search(cr, uid, [('date', '>', controlling_date)], |
599 | 86 | order='date DESC', limit=1, context=context) | 95 | order='date DESC', limit=1, context=context) |
600 | 87 | if lines: | 96 | if lines: |
601 | 88 | line = line_obj.browse(cr, uid, lines[0], context=context) | 97 | line = line_obj.browse(cr, uid, lines[0], context=context) |
602 | 89 | raise orm.except_orm(_('Error'), | 98 | raise orm.except_orm(_('Error'), |
605 | 90 | _('A run has already been executed more ' | 99 | _('A credit control line more ' |
606 | 91 | 'recently than %s') % (line.date)) | 100 | 'recent than %s exists at %s') % |
607 | 101 | (controlling_date, line.date)) | ||
608 | 92 | return True | 102 | return True |
609 | 93 | 103 | ||
610 | 94 | def _generate_credit_lines(self, cr, uid, run_id, context=None): | 104 | def _generate_credit_lines(self, cr, uid, run_id, context=None): |
611 | @@ -110,10 +120,10 @@ | |||
612 | 110 | _('Please select a policy')) | 120 | _('Please select a policy')) |
613 | 111 | 121 | ||
614 | 112 | report = '' | 122 | report = '' |
615 | 123 | generated_ids = [] | ||
616 | 113 | for policy in policies: | 124 | for policy in policies: |
617 | 114 | if policy.do_nothing: | 125 | if policy.do_nothing: |
618 | 115 | continue | 126 | continue |
619 | 116 | |||
620 | 117 | lines = policy._get_move_lines_to_process(run.date, context=context) | 127 | lines = policy._get_move_lines_to_process(run.date, context=context) |
621 | 118 | manual_lines = policy._lines_different_policy(lines, context=context) | 128 | manual_lines = policy._lines_different_policy(lines, context=context) |
622 | 119 | lines.difference_update(manual_lines) | 129 | lines.difference_update(manual_lines) |
623 | @@ -125,7 +135,7 @@ | |||
624 | 125 | level_lines = level.get_level_lines(run.date, lines, context=context) | 135 | level_lines = level.get_level_lines(run.date, lines, context=context) |
625 | 126 | policy_generated_ids += cr_line_obj.create_or_update_from_mv_lines( | 136 | policy_generated_ids += cr_line_obj.create_or_update_from_mv_lines( |
626 | 127 | cr, uid, [], list(level_lines), level.id, run.date, context=context) | 137 | cr, uid, [], list(level_lines), level.id, run.date, context=context) |
628 | 128 | 138 | generated_ids.extend(policy_generated_ids) | |
629 | 129 | if policy_generated_ids: | 139 | if policy_generated_ids: |
630 | 130 | report += _("Policy \"%s\" has generated %d Credit Control Lines.\n") % \ | 140 | report += _("Policy \"%s\" has generated %d Credit Control Lines.\n") % \ |
631 | 131 | (policy.name, len(policy_generated_ids)) | 141 | (policy.name, len(policy_generated_ids)) |
632 | @@ -138,6 +148,7 @@ | |||
633 | 138 | 'report': report, | 148 | 'report': report, |
634 | 139 | 'manual_ids': [(6, 0, manually_managed_lines)]} | 149 | 'manual_ids': [(6, 0, manually_managed_lines)]} |
635 | 140 | run.write(vals, context=context) | 150 | run.write(vals, context=context) |
636 | 151 | return generated_ids | ||
637 | 141 | 152 | ||
638 | 142 | def generate_credit_lines(self, cr, uid, run_id, context=None): | 153 | def generate_credit_lines(self, cr, uid, run_id, context=None): |
639 | 143 | """Generate credit control lines | 154 | """Generate credit control lines |
640 | @@ -147,7 +158,7 @@ | |||
641 | 147 | """ | 158 | """ |
642 | 148 | try: | 159 | try: |
643 | 149 | cr.execute('SELECT id FROM credit_control_run' | 160 | cr.execute('SELECT id FROM credit_control_run' |
645 | 150 | ' LIMIT 1 FOR UPDATE NOWAIT') | 161 | ' LIMIT 1 FOR UPDATE NOWAIT') |
646 | 151 | except Exception as exc: | 162 | except Exception as exc: |
647 | 152 | # in case of exception openerp will do a rollback for us and free the lock | 163 | # in case of exception openerp will do a rollback for us and free the lock |
648 | 153 | raise orm.except_orm(_('Error'), | 164 | raise orm.except_orm(_('Error'), |
649 | 154 | 165 | ||
650 | === modified file 'account_credit_control/run_view.xml' | |||
651 | --- account_credit_control/run_view.xml 2013-03-18 09:21:33 +0000 | |||
652 | +++ account_credit_control/run_view.xml 2014-06-24 12:34:19 +0000 | |||
653 | @@ -19,7 +19,8 @@ | |||
654 | 19 | <field name="type">form</field> | 19 | <field name="type">form</field> |
655 | 20 | <field name="arch" type="xml"> | 20 | <field name="arch" type="xml"> |
656 | 21 | <form string="Credit control run"> | 21 | <form string="Credit control run"> |
658 | 22 | <field name="date"/> | 22 | <field name="date" |
659 | 23 | attrs="{'readonly': [('state', '!=', 'draft')]}"/> | ||
660 | 23 | <newline/> | 24 | <newline/> |
661 | 24 | <notebook colspan="4"> | 25 | <notebook colspan="4"> |
662 | 25 | <page string="Policies"> | 26 | <page string="Policies"> |
663 | 26 | 27 | ||
664 | === modified file 'account_credit_control/scenarios/features/09_credit_control_run_jul.feature' | |||
665 | --- account_credit_control/scenarios/features/09_credit_control_run_jul.feature 2014-03-03 11:23:20 +0000 | |||
666 | +++ account_credit_control/scenarios/features/09_credit_control_run_jul.feature 2014-06-24 12:34:19 +0000 | |||
667 | @@ -13,10 +13,10 @@ | |||
668 | 13 | Feature: Ensure that email credit line generation first pass is correct | 13 | Feature: Ensure that email credit line generation first pass is correct |
669 | 14 | 14 | ||
670 | 15 | @account_credit_control_mark | 15 | @account_credit_control_mark |
675 | 16 | Scenario: mark lines | 16 | Scenario: mark lines |
676 | 17 | Given there is "draft" credit lines | 17 | Given there is "draft" credit lines |
677 | 18 | And I mark all draft email to state "to_be_sent" | 18 | And I mark all draft email to state "to_be_sent" |
678 | 19 | Then the draft line should be in state "to_be_sent" | 19 | Then the draft line should be in state "to_be_sent" |
679 | 20 | 20 | ||
680 | 21 | @account_credit_control_run_month | 21 | @account_credit_control_run_month |
681 | 22 | Scenario: Create run | 22 | Scenario: Create run |
682 | 23 | 23 | ||
683 | === added file 'account_credit_control/scenarios/features/11_credit_control_manual_setting.feature' | |||
684 | --- account_credit_control/scenarios/features/11_credit_control_manual_setting.feature 1970-01-01 00:00:00 +0000 | |||
685 | +++ account_credit_control/scenarios/features/11_credit_control_manual_setting.feature 2014-06-24 12:34:19 +0000 | |||
686 | @@ -0,0 +1,42 @@ | |||
687 | 1 | ############################################################################### | ||
688 | 2 | # | ||
689 | 3 | # OERPScenario, OpenERP Functional Tests | ||
690 | 4 | # Copyright 2012 Camptocamp SA | ||
691 | 5 | # Author Nicolas Bessi | ||
692 | 6 | ############################################################################## | ||
693 | 7 | |||
694 | 8 | # Features Generic tags (none for all) | ||
695 | 9 | ############################################################################## | ||
696 | 10 | |||
697 | 11 | @account_credit_control @account_credit_control_run @account_credit_control_run_change_level | ||
698 | 12 | |||
699 | 13 | Feature: Ensure that manually changing an invoice level feature works as expected | ||
700 | 14 | |||
701 | 15 | @account_credit_control_change_level | ||
702 | 16 | Scenario: Change level | ||
703 | 17 | Given I change level for invoice "SAJ/2014/0004" to "10 days net" of policy "3 time policy" | ||
704 | 18 | Then wizard selected move lines should be: | ||
705 | 19 | | name | | ||
706 | 20 | | SI_4 | | ||
707 | 21 | When I confirm the level change | ||
708 | 22 | And I should have "3" credit control lines overridden | ||
709 | 23 | And one new credit control line of level "10 days net" related to invoice "SAJ/2014/0004" | ||
710 | 24 | Then I force date of generated credit line to "2013-09-15" | ||
711 | 25 | |||
712 | 26 | @account_credit_control_run_month_sept | ||
713 | 27 | Scenario: Create run | ||
714 | 28 | Given there is "draft" credit lines | ||
715 | 29 | And I mark all draft email to state "to_be_sent" | ||
716 | 30 | Then the draft line should be in state "to_be_sent" | ||
717 | 31 | Given I need a "credit.control.run" with oid: credit_control.manual_change | ||
718 | 32 | And having: | ||
719 | 33 | | name | value | | ||
720 | 34 | | date | 2013-09-30 | | ||
721 | 35 | When I launch the credit run | ||
722 | 36 | Then my credit run should be in state "done" | ||
723 | 37 | |||
724 | 38 | @account_credit_control_manual_next_step | ||
725 | 39 | Scenario: Check manually managed line on run | ||
726 | 40 | Given the invoice "SAJ/2014/0004" with manual changes | ||
727 | 41 | And the invoice has "1" line of level "1" for policy "3 time policy" | ||
728 | 42 | And the invoice has "1" line of level "2" for policy "3 time policy" | ||
729 | 0 | 43 | ||
730 | === modified file 'account_credit_control/scenarios/features/steps/account_credit_control.py' | |||
731 | --- account_credit_control/scenarios/features/steps/account_credit_control.py 2014-03-04 07:52:47 +0000 | |||
732 | +++ account_credit_control/scenarios/features/steps/account_credit_control.py 2014-06-24 12:34:19 +0000 | |||
733 | @@ -142,4 +142,4 @@ | |||
734 | 142 | ('state', 'in', ('draft', 'ignored'))]) | 142 | ('state', 'in', ('draft', 'ignored'))]) |
735 | 143 | assert_equal(len(to_check), int(number), msg="More than %s found" % number) | 143 | assert_equal(len(to_check), int(number), msg="More than %s found" % number) |
736 | 144 | lines = model('credit.control.line').browse(to_check) | 144 | lines = model('credit.control.line').browse(to_check) |
738 | 145 | assert ['ignored', 'draft'] == lines.state | 145 | assert set(['ignored', 'draft']) == set(lines.state) |
739 | 146 | 146 | ||
740 | === added file 'account_credit_control/scenarios/features/steps/account_credit_control_changer.py' | |||
741 | --- account_credit_control/scenarios/features/steps/account_credit_control_changer.py 1970-01-01 00:00:00 +0000 | |||
742 | +++ account_credit_control/scenarios/features/steps/account_credit_control_changer.py 2014-06-24 12:34:19 +0000 | |||
743 | @@ -0,0 +1,76 @@ | |||
744 | 1 | # -*- coding: utf-8 -*- | ||
745 | 2 | @given(u'I change level for invoice "{invoice_name}" to "{level_name}" of policy "{policy_name}"') | ||
746 | 3 | def impl(ctx, invoice_name, level_name, policy_name): | ||
747 | 4 | invoice = model('account.invoice').get([('number', '=', invoice_name)]) | ||
748 | 5 | assert_true(invoice, msg='No invoices found') | ||
749 | 6 | level = model('credit.control.policy.level').get([('name', '=', level_name)]) | ||
750 | 7 | assert_true(level, 'level not found') | ||
751 | 8 | policy = model('credit.control.policy').get([('name', '=', policy_name)]) | ||
752 | 9 | assert_true(policy, 'Policy not found') | ||
753 | 10 | assert_equal(policy.id, level.policy_id.id) | ||
754 | 11 | context = {'active_ids': [invoice.id]} | ||
755 | 12 | data = {'new_policy_id': policy.id, | ||
756 | 13 | 'new_policy_level_id': level.id} | ||
757 | 14 | wizard = model('credit.control.policy.changer').create(data, context=context) | ||
758 | 15 | ctx.wizard = wizard | ||
759 | 16 | |||
760 | 17 | @then(u'wizard selected move lines should be') | ||
761 | 18 | def impl(ctx): | ||
762 | 19 | assert_true(ctx.wizard) | ||
763 | 20 | names = [x.name for x in ctx.wizard.move_line_ids] | ||
764 | 21 | for line in ctx.table: | ||
765 | 22 | assert_in(line['name'], names) | ||
766 | 23 | |||
767 | 24 | @when(u'I confirm the level change') | ||
768 | 25 | def impl(ctx): | ||
769 | 26 | assert_true(ctx.wizard) | ||
770 | 27 | ctx.wizard.set_new_policy() | ||
771 | 28 | |||
772 | 29 | @when(u'I should have "{line_number:d}" credit control lines overridden') | ||
773 | 30 | def impl(ctx, line_number): | ||
774 | 31 | assert_true(ctx.wizard) | ||
775 | 32 | move_ids = [x.id for x in ctx.wizard.move_line_ids] | ||
776 | 33 | overridden = model('credit.control.line').search([('move_line_id', 'in', move_ids), | ||
777 | 34 | ('manually_overridden', '=', True)]) | ||
778 | 35 | # assert len(overridden) == line_number | ||
779 | 36 | |||
780 | 37 | @when(u'one new credit control line of level "{level_name}" related to invoice "{invoice_name}"') | ||
781 | 38 | def impl(ctx, level_name, invoice_name): | ||
782 | 39 | invoice = model('account.invoice').get([('number', '=', invoice_name)]) | ||
783 | 40 | assert_true(invoice, msg='No invoices found') | ||
784 | 41 | level = model('credit.control.policy.level').get([('name', '=', level_name)]) | ||
785 | 42 | assert_true(level, 'level not found') | ||
786 | 43 | assert_true(ctx.wizard) | ||
787 | 44 | move_ids = [x.id for x in ctx.wizard.move_line_ids] | ||
788 | 45 | created_id = model('credit.control.line').search([('move_line_id', 'in', move_ids), | ||
789 | 46 | ('manually_overridden', '=', False)]) | ||
790 | 47 | |||
791 | 48 | assert len(created_id) == 1 | ||
792 | 49 | created = model('credit.control.line').get(created_id[0]) | ||
793 | 50 | ctx.created = created | ||
794 | 51 | assert_equal(created.policy_level_id.id, level.id) | ||
795 | 52 | assert_equal(created.invoice_id.id, invoice.id) | ||
796 | 53 | assert_equal(created.invoice_id.credit_policy_id.id, level.policy_id.id) | ||
797 | 54 | |||
798 | 55 | @then(u'I force date of generated credit line to "{date}"') | ||
799 | 56 | def impl(ctx, date): | ||
800 | 57 | assert_true(ctx.created) | ||
801 | 58 | ctx.created.write({'date': date}) | ||
802 | 59 | |||
803 | 60 | @given(u'the invoice "{invoice_name}" with manual changes') | ||
804 | 61 | def impl(ctx, invoice_name): | ||
805 | 62 | invoice = model('account.invoice').get([('number', '=', invoice_name)]) | ||
806 | 63 | assert_true(invoice, msg='No invoices found') | ||
807 | 64 | man_lines = (x for x in invoice.credit_control_line_ids if x.manually_overridden) | ||
808 | 65 | assert_true(next(man_lines, None), 'No manual change on the invoice') | ||
809 | 66 | ctx.invoice = invoice | ||
810 | 67 | |||
811 | 68 | @given(u'the invoice has "{line_number:d}" line of level "{level:d}" for policy "{policy_name}"') | ||
812 | 69 | def impl(ctx, line_number, level, policy_name): | ||
813 | 70 | assert_true(ctx.invoice) | ||
814 | 71 | policy = model('credit.control.policy').get([('name', '=', policy_name)]) | ||
815 | 72 | assert_true(policy) | ||
816 | 73 | lines = model('credit.control.line').search([('invoice_id', '=', ctx.invoice.id), | ||
817 | 74 | ('level', '=', level), | ||
818 | 75 | ('policy_id', '=', policy.id)]) | ||
819 | 76 | assert_equal(len(lines), line_number) | ||
820 | 0 | 77 | ||
821 | === modified file 'account_credit_control/wizard/__init__.py' | |||
822 | --- account_credit_control/wizard/__init__.py 2012-11-07 12:08:18 +0000 | |||
823 | +++ account_credit_control/wizard/__init__.py 2014-06-24 12:34:19 +0000 | |||
824 | @@ -22,3 +22,4 @@ | |||
825 | 22 | from . import credit_control_marker | 22 | from . import credit_control_marker |
826 | 23 | from . import credit_control_printer | 23 | from . import credit_control_printer |
827 | 24 | from . import credit_control_communication | 24 | from . import credit_control_communication |
828 | 25 | from . import credit_control_policy_changer | ||
829 | 25 | 26 | ||
830 | === modified file 'account_credit_control/wizard/credit_control_communication.py' | |||
831 | --- account_credit_control/wizard/credit_control_communication.py 2013-07-12 10:44:13 +0000 | |||
832 | +++ account_credit_control/wizard/credit_control_communication.py 2014-06-24 12:34:19 +0000 | |||
833 | @@ -80,14 +80,18 @@ | |||
834 | 80 | return cr_l_ids | 80 | return cr_l_ids |
835 | 81 | 81 | ||
836 | 82 | def _generate_comm_from_credit_line_ids(self, cr, uid, line_ids, context=None): | 82 | def _generate_comm_from_credit_line_ids(self, cr, uid, line_ids, context=None): |
837 | 83 | """Aggregate credit control line by partner, level, and currency | ||
838 | 84 | It also generate a communication object per aggregation. | ||
839 | 85 | """ | ||
840 | 83 | if not line_ids: | 86 | if not line_ids: |
841 | 84 | return [] | 87 | return [] |
842 | 85 | comms = [] | 88 | comms = [] |
844 | 86 | sql = ("SELECT distinct partner_id, policy_level_id, credit_control_policy_level.level" | 89 | sql = ("SELECT distinct partner_id, policy_level_id, " |
845 | 90 | " credit_control_line.currency_id, credit_control_policy_level.level" | ||
846 | 87 | " FROM credit_control_line JOIN credit_control_policy_level " | 91 | " FROM credit_control_line JOIN credit_control_policy_level " |
847 | 88 | " ON (credit_control_line.policy_level_id = credit_control_policy_level.id)" | 92 | " ON (credit_control_line.policy_level_id = credit_control_policy_level.id)" |
848 | 89 | " WHERE credit_control_line.id in %s" | 93 | " WHERE credit_control_line.id in %s" |
850 | 90 | " ORDER by credit_control_policy_level.level") | 94 | " ORDER by credit_control_policy_level.level, credit_control_line.currency_id") |
851 | 91 | 95 | ||
852 | 92 | cr.execute(sql, (tuple(line_ids),)) | 96 | cr.execute(sql, (tuple(line_ids),)) |
853 | 93 | res = cr.dictfetchall() | 97 | res = cr.dictfetchall() |
854 | @@ -101,8 +105,6 @@ | |||
855 | 101 | data['partner_id'] = level_assoc['partner_id'] | 105 | data['partner_id'] = level_assoc['partner_id'] |
856 | 102 | data['current_policy_level'] = level_assoc['policy_level_id'] | 106 | data['current_policy_level'] = level_assoc['policy_level_id'] |
857 | 103 | comm_id = self.create(cr, uid, data, context=context) | 107 | comm_id = self.create(cr, uid, data, context=context) |
858 | 104 | |||
859 | 105 | |||
860 | 106 | comms.append(self.browse(cr, uid, comm_id, context=context)) | 108 | comms.append(self.browse(cr, uid, comm_id, context=context)) |
861 | 107 | return comms | 109 | return comms |
862 | 108 | 110 | ||
863 | 109 | 111 | ||
864 | === modified file 'account_credit_control/wizard/credit_control_emailer_view.xml' | |||
865 | --- account_credit_control/wizard/credit_control_emailer_view.xml 2013-03-18 09:21:33 +0000 | |||
866 | +++ account_credit_control/wizard/credit_control_emailer_view.xml 2014-06-24 12:34:19 +0000 | |||
867 | @@ -4,17 +4,27 @@ | |||
868 | 4 | <record id="credit_line_emailer_form" model="ir.ui.view"> | 4 | <record id="credit_line_emailer_form" model="ir.ui.view"> |
869 | 5 | <field name="name">credit.line.emailer.form</field> | 5 | <field name="name">credit.line.emailer.form</field> |
870 | 6 | <field name="model">credit.control.emailer</field> | 6 | <field name="model">credit.control.emailer</field> |
871 | 7 | <field name="type">form</field> | ||
872 | 8 | <field name="arch" type="xml"> | 7 | <field name="arch" type="xml"> |
874 | 9 | <form string="Mailer"> | 8 | <form string="Mailer" version="7.0"> |
875 | 10 | <separator string="Send emails for the selected lines" colspan="4"/> | 9 | <separator string="Send emails for the selected lines" colspan="4"/> |
876 | 11 | <newline/> | 10 | <newline/> |
878 | 12 | <field name="line_ids" colspan="4" nolabel="1" /> | 11 | <notebook> |
879 | 12 | <page string="Lines"> | ||
880 | 13 | <field name="line_ids" colspan="4" nolabel="1" /> | ||
881 | 14 | </page> | ||
882 | 15 | </notebook> | ||
883 | 13 | <newline/> | 16 | <newline/> |
888 | 14 | <group colspan="4"> | 17 | <footer> |
889 | 15 | <button special="cancel" string="Cancel" icon='gtk-cancel'/> | 18 | <button class="oe_highlight" |
890 | 16 | <button name="email_lines" string="Send the emails" type="object" icon="gtk-execute"/> | 19 | name="email_lines" |
891 | 17 | </group> | 20 | string="Send the emails" |
892 | 21 | type="object"/> | ||
893 | 22 | or | ||
894 | 23 | <button | ||
895 | 24 | class="oe_link" | ||
896 | 25 | special="cancel" | ||
897 | 26 | string="Cancel"/> | ||
898 | 27 | </footer> | ||
899 | 18 | </form> | 28 | </form> |
900 | 19 | </field> | 29 | </field> |
901 | 20 | </record> | 30 | </record> |
902 | 21 | 31 | ||
903 | === modified file 'account_credit_control/wizard/credit_control_marker_view.xml' | |||
904 | --- account_credit_control/wizard/credit_control_marker_view.xml 2013-03-18 09:21:33 +0000 | |||
905 | +++ account_credit_control/wizard/credit_control_marker_view.xml 2014-06-24 12:34:19 +0000 | |||
906 | @@ -4,19 +4,34 @@ | |||
907 | 4 | <record id="credit_line_marker_form" model="ir.ui.view"> | 4 | <record id="credit_line_marker_form" model="ir.ui.view"> |
908 | 5 | <field name="name">credit.line.marker.form</field> | 5 | <field name="name">credit.line.marker.form</field> |
909 | 6 | <field name="model">credit.control.marker</field> | 6 | <field name="model">credit.control.marker</field> |
910 | 7 | <field name="type">form</field> | ||
911 | 8 | <field name="arch" type="xml"> | 7 | <field name="arch" type="xml"> |
914 | 9 | <form string="Lines marker"> | 8 | <form string="Lines marker" version="7.0"> |
915 | 10 | <separator string="Change the state of the selected lines." colspan="4"/> | 9 | <separator string="Change the state of the selected lines" colspan="4"/> |
916 | 10 | <newline/> | ||
917 | 11 | <label string="Warning: you will maybe not be able to revert this operation." colspan="4"></label> | 11 | <label string="Warning: you will maybe not be able to revert this operation." colspan="4"></label> |
918 | 12 | <newline/> | 12 | <newline/> |
925 | 13 | <field name="name" colspan="4"/> | 13 | <group> |
926 | 14 | <field name="line_ids" colspan="4" nolabel="1"/> | 14 | <group><field name="name"/></group> |
927 | 15 | <newline/> | 15 | <group></group> |
922 | 16 | <group colspan="4"> | ||
923 | 17 | <button special="cancel" string="Cancel" icon='gtk-cancel'/> | ||
924 | 18 | <button name="mark_lines" string="Change Lines' State" type="object" icon="gtk-execute"/> | ||
928 | 19 | </group> | 16 | </group> |
929 | 17 | <notebook> | ||
930 | 18 | <page string="Lines"> | ||
931 | 19 | <field name="line_ids" colspan="4" nolabel="1"/> | ||
932 | 20 | </page> | ||
933 | 21 | </notebook> | ||
934 | 22 | <newline/> | ||
935 | 23 | <footer> | ||
936 | 24 | <button | ||
937 | 25 | class="oe_highlight" | ||
938 | 26 | name="mark_lines" | ||
939 | 27 | string="Change Lines' State" | ||
940 | 28 | type="object"/> | ||
941 | 29 | or | ||
942 | 30 | <button | ||
943 | 31 | class="oe_link" | ||
944 | 32 | special="cancel" | ||
945 | 33 | string="Cancel"/> | ||
946 | 34 | </footer> | ||
947 | 20 | </form> | 35 | </form> |
948 | 21 | </field> | 36 | </field> |
949 | 22 | </record> | 37 | </record> |
950 | 23 | 38 | ||
951 | === added file 'account_credit_control/wizard/credit_control_policy_changer.py' | |||
952 | --- account_credit_control/wizard/credit_control_policy_changer.py 1970-01-01 00:00:00 +0000 | |||
953 | +++ account_credit_control/wizard/credit_control_policy_changer.py 2014-06-24 12:34:19 +0000 | |||
954 | @@ -0,0 +1,178 @@ | |||
955 | 1 | # -*- coding: utf-8 -*- | ||
956 | 2 | ############################################################################## | ||
957 | 3 | # | ||
958 | 4 | # Author: Nicolas Bessi | ||
959 | 5 | # Copyright 2014 Camptocamp SA | ||
960 | 6 | # | ||
961 | 7 | # This program is free software: you can redistribute it and/or modify | ||
962 | 8 | # it under the terms of the GNU Affero General Public License as | ||
963 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
964 | 10 | # License, or (at your option) any later version. | ||
965 | 11 | # | ||
966 | 12 | # This program is distributed in the hope that it will be useful, | ||
967 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
968 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
969 | 15 | # GNU Affero General Public License for more details. | ||
970 | 16 | # | ||
971 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
972 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
973 | 19 | # | ||
974 | 20 | ############################################################################## | ||
975 | 21 | import logging | ||
976 | 22 | from openerp.tools.translate import _ | ||
977 | 23 | from openerp.osv import orm, fields | ||
978 | 24 | logger = logging.getLogger(__name__) | ||
979 | 25 | |||
980 | 26 | |||
981 | 27 | class credit_control_policy_changer(orm.TransientModel): | ||
982 | 28 | """Wizard that is run from invoices and allows to set manually a policy | ||
983 | 29 | Policy are actually apply to related move lines availabe | ||
984 | 30 | in selection widget | ||
985 | 31 | |||
986 | 32 | """ | ||
987 | 33 | _name = "credit.control.policy.changer" | ||
988 | 34 | _columns = { | ||
989 | 35 | 'new_policy_id': fields.many2one('credit.control.policy', | ||
990 | 36 | 'New Policy to Apply', | ||
991 | 37 | required=True), | ||
992 | 38 | 'new_policy_level_id': fields.many2one('credit.control.policy.level', | ||
993 | 39 | 'New level to apply', | ||
994 | 40 | required=True), | ||
995 | 41 | # Only used to provide dynamic filtering on form | ||
996 | 42 | 'do_nothing': fields.boolean('No follow policy'), | ||
997 | 43 | 'move_line_ids': fields.many2many('account.move.line', | ||
998 | 44 | rel='credit_changer_ml_rel', | ||
999 | 45 | string='Move line to change'), | ||
1000 | 46 | } | ||
1001 | 47 | |||
1002 | 48 | def _get_default_lines(self, cr, uid, context=None): | ||
1003 | 49 | """Get default lines for fields move_line_ids | ||
1004 | 50 | of wizard. Only take lines that are on the same account | ||
1005 | 51 | and move of the invoice and not reconciled | ||
1006 | 52 | |||
1007 | 53 | :return: list of compliant move line ids | ||
1008 | 54 | |||
1009 | 55 | """ | ||
1010 | 56 | if context is None: | ||
1011 | 57 | context = {} | ||
1012 | 58 | active_ids = context.get('active_ids') | ||
1013 | 59 | selected_line_ids = [] | ||
1014 | 60 | inv_model = self.pool['account.invoice'] | ||
1015 | 61 | move_line_model = self.pool['account.move.line'] | ||
1016 | 62 | if not active_ids: | ||
1017 | 63 | return False | ||
1018 | 64 | # raise ValueError('No active_ids passed in context') | ||
1019 | 65 | for invoice in inv_model.browse(cr, uid, active_ids, context=context): | ||
1020 | 66 | if invoice.type in ('in_invoice', 'in_refund', 'out_refund'): | ||
1021 | 67 | raise orm.except_orm(_('User error'), | ||
1022 | 68 | _('Please use wizard on cutomer invoices')) | ||
1023 | 69 | |||
1024 | 70 | domain = [('account_id', '=', invoice.account_id.id), | ||
1025 | 71 | ('move_id', '=', invoice.move_id.id), | ||
1026 | 72 | ('reconcile_id', '=', False)] | ||
1027 | 73 | move_ids = move_line_model.search(cr, uid, domain, context=context) | ||
1028 | 74 | selected_line_ids.extend(move_ids) | ||
1029 | 75 | return selected_line_ids | ||
1030 | 76 | |||
1031 | 77 | _defaults = {'move_line_ids': _get_default_lines} | ||
1032 | 78 | |||
1033 | 79 | def onchange_policy_id(self, cr, uid, ids, new_policy_id, context=None): | ||
1034 | 80 | if not new_policy_id: | ||
1035 | 81 | return {} | ||
1036 | 82 | policy = self.pool['credit.control.policy'].browse(cr, uid, | ||
1037 | 83 | new_policy_id, | ||
1038 | 84 | context=context) | ||
1039 | 85 | return {'value': {'do_nothing': policy.do_nothing}} | ||
1040 | 86 | |||
1041 | 87 | def _mark_as_overridden(self, cr, uid, move_lines, context=None): | ||
1042 | 88 | """Mark `move_lines` related credit control line as overridden | ||
1043 | 89 | This is done by setting manually_overridden fields to True | ||
1044 | 90 | |||
1045 | 91 | :param move_lines: move line to mark as overridden | ||
1046 | 92 | |||
1047 | 93 | :retun: list of credit line ids that where marked as overridden | ||
1048 | 94 | |||
1049 | 95 | """ | ||
1050 | 96 | credit_model = self.pool['credit.control.line'] | ||
1051 | 97 | domain = [('move_line_id', 'in', [x.id for x in move_lines])] | ||
1052 | 98 | credits_ids = credit_model.search(cr, uid, domain, context=context) | ||
1053 | 99 | credit_model.write(cr, uid, | ||
1054 | 100 | credits_ids, | ||
1055 | 101 | {'manually_overridden': True}, | ||
1056 | 102 | context) | ||
1057 | 103 | return credits_ids | ||
1058 | 104 | |||
1059 | 105 | def _set_invoice_policy(self, cr, uid, move_line_ids, policy, | ||
1060 | 106 | context=None): | ||
1061 | 107 | """Force policy on invoice""" | ||
1062 | 108 | invoice_model = self.pool['account.invoice'] | ||
1063 | 109 | invoice_ids = set([x.invoice.id for x in move_line_ids if x.invoice]) | ||
1064 | 110 | invoice_model.write(cr, uid, list(invoice_ids), | ||
1065 | 111 | {'credit_policy_id': policy.id}, | ||
1066 | 112 | context=context) | ||
1067 | 113 | |||
1068 | 114 | def _check_accounts_policies(self, cr, uid, lines, policy, context=None): | ||
1069 | 115 | policy_obj = self.pool['credit.control.policy'] | ||
1070 | 116 | for line in lines: | ||
1071 | 117 | policy_obj.check_policy_against_account( | ||
1072 | 118 | cr, uid, | ||
1073 | 119 | line.account_id.id, | ||
1074 | 120 | policy.id, | ||
1075 | 121 | context=context | ||
1076 | 122 | ) | ||
1077 | 123 | return True | ||
1078 | 124 | |||
1079 | 125 | def set_new_policy(self, cr, uid, wizard_id, context=None): | ||
1080 | 126 | """Set new policy on an invoice. | ||
1081 | 127 | |||
1082 | 128 | This is done by creating a new credit control line | ||
1083 | 129 | related to the move line and the policy setted in | ||
1084 | 130 | the wizard form | ||
1085 | 131 | |||
1086 | 132 | :return: ir.actions.act_windows dict | ||
1087 | 133 | |||
1088 | 134 | """ | ||
1089 | 135 | assert len(wizard_id) == 1, "Only one id expected" | ||
1090 | 136 | wizard_id = wizard_id[0] | ||
1091 | 137 | |||
1092 | 138 | credit_line_model = self.pool['credit.control.line'] | ||
1093 | 139 | ir_model = self.pool['ir.model.data'] | ||
1094 | 140 | ui_act_model = self.pool['ir.actions.act_window'] | ||
1095 | 141 | wizard = self.browse(cr, uid, wizard_id, context=context) | ||
1096 | 142 | controlling_date = fields.date.today() | ||
1097 | 143 | self._check_accounts_policies( | ||
1098 | 144 | cr, | ||
1099 | 145 | uid, | ||
1100 | 146 | wizard.move_line_ids, | ||
1101 | 147 | wizard.new_policy_id) | ||
1102 | 148 | self._mark_as_overridden(cr, | ||
1103 | 149 | uid, | ||
1104 | 150 | wizard.move_line_ids, | ||
1105 | 151 | context=context) | ||
1106 | 152 | # As disscused with business expert | ||
1107 | 153 | # draft lines should be passed to ignored | ||
1108 | 154 | # if same level as the new one | ||
1109 | 155 | # As it is a manual action | ||
1110 | 156 | # We also ignore rounding tolerance | ||
1111 | 157 | generated_ids = None | ||
1112 | 158 | generated_ids = credit_line_model.create_or_update_from_mv_lines( | ||
1113 | 159 | cr, uid, [], | ||
1114 | 160 | [x.id for x in wizard.move_line_ids], | ||
1115 | 161 | wizard.new_policy_level_id.id, | ||
1116 | 162 | controlling_date, | ||
1117 | 163 | check_tolerance=False, | ||
1118 | 164 | context=None | ||
1119 | 165 | ) | ||
1120 | 166 | self._set_invoice_policy(cr, uid, | ||
1121 | 167 | wizard.move_line_ids, | ||
1122 | 168 | wizard.new_policy_id, | ||
1123 | 169 | context=context) | ||
1124 | 170 | if not generated_ids: | ||
1125 | 171 | return {} | ||
1126 | 172 | view_id = ir_model.get_object_reference(cr, uid, | ||
1127 | 173 | "account_credit_control", | ||
1128 | 174 | "credit_control_line_action") | ||
1129 | 175 | assert view_id, 'No view found' | ||
1130 | 176 | action = ui_act_model.read(cr, uid, view_id[1], context=context) | ||
1131 | 177 | action['domain'] = [('id', 'in', generated_ids)] | ||
1132 | 178 | return action | ||
1133 | 0 | 179 | ||
1134 | === added file 'account_credit_control/wizard/credit_control_policy_changer_view.xml' | |||
1135 | --- account_credit_control/wizard/credit_control_policy_changer_view.xml 1970-01-01 00:00:00 +0000 | |||
1136 | +++ account_credit_control/wizard/credit_control_policy_changer_view.xml 2014-06-24 12:34:19 +0000 | |||
1137 | @@ -0,0 +1,65 @@ | |||
1138 | 1 | <?xml version="1.0" encoding="utf-8"?> | ||
1139 | 2 | <openerp> | ||
1140 | 3 | <data> | ||
1141 | 4 | <record id="credit_control_policy_changer_form" model="ir.ui.view"> | ||
1142 | 5 | <field name="name">credit control policy form</field> | ||
1143 | 6 | <field name="model">credit.control.policy.changer</field> | ||
1144 | 7 | <field name="arch" type="xml"> | ||
1145 | 8 | <form version="7.0" string="Set current credit level"> | ||
1146 | 9 | <separator string="Change the overdue level of current invoice" colspan="4"/> | ||
1147 | 10 | <label string="This wizard will let you set the overdue policy and level for selected invoices"/> | ||
1148 | 11 | <newline/> | ||
1149 | 12 | <group> | ||
1150 | 13 | <group> | ||
1151 | 14 | <field name="new_policy_id" | ||
1152 | 15 | on_change="onchange_policy_id(new_policy_id)"/> | ||
1153 | 16 | <field name="do_nothing" | ||
1154 | 17 | invisible="1"/> | ||
1155 | 18 | <field name="new_policy_level_id" | ||
1156 | 19 | domain="[('policy_id', '=', new_policy_id)]"/> | ||
1157 | 20 | </group> | ||
1158 | 21 | <group></group> | ||
1159 | 22 | </group> | ||
1160 | 23 | <notebook colspan="4"> | ||
1161 | 24 | <page string="Move lines to affect"> | ||
1162 | 25 | <field name="move_line_ids"/> | ||
1163 | 26 | </page> | ||
1164 | 27 | </notebook> | ||
1165 | 28 | <footer> | ||
1166 | 29 | <button class="oe_highlight" | ||
1167 | 30 | name="set_new_policy" | ||
1168 | 31 | string="Set new policy" | ||
1169 | 32 | type="object"/> | ||
1170 | 33 | or | ||
1171 | 34 | <button class="oe_link" | ||
1172 | 35 | special="cancel" | ||
1173 | 36 | string="Cancel"/> | ||
1174 | 37 | </footer> | ||
1175 | 38 | </form> | ||
1176 | 39 | |||
1177 | 40 | </field> | ||
1178 | 41 | </record> | ||
1179 | 42 | |||
1180 | 43 | <!-- for button --> | ||
1181 | 44 | <record id="action_wizard_credit_policy_changer" model="ir.actions.act_window"> | ||
1182 | 45 | <field name="name">Change current credit policy</field> | ||
1183 | 46 | <field name="res_model">credit.control.policy.changer</field> | ||
1184 | 47 | <field name="src_model">account.invoice</field> | ||
1185 | 48 | <field name="view_type">form</field> | ||
1186 | 49 | <field name="view_mode">form</field> | ||
1187 | 50 | <field name="view_id" ref="credit_control_policy_changer_form"/> | ||
1188 | 51 | <field name="target">new</field> | ||
1189 | 52 | <field name="help">Allows to manually change credit level</field> | ||
1190 | 53 | </record> | ||
1191 | 54 | |||
1192 | 55 | <!-- for menu --> | ||
1193 | 56 | <act_window name="Change current credit policy" | ||
1194 | 57 | res_model="credit.control.policy.changer" | ||
1195 | 58 | src_model="account.invoice" | ||
1196 | 59 | view_mode="form" | ||
1197 | 60 | target="new" | ||
1198 | 61 | key2="client_action_multi" | ||
1199 | 62 | id="action_wizard_credit_policy_changer_menu_action"/> | ||
1200 | 63 | |||
1201 | 64 | </data> | ||
1202 | 65 | </openerp> | ||
1203 | 0 | 66 | ||
1204 | === modified file 'account_credit_control/wizard/credit_control_printer.py' | |||
1205 | --- account_credit_control/wizard/credit_control_printer.py 2013-06-08 09:34:35 +0000 | |||
1206 | +++ account_credit_control/wizard/credit_control_printer.py 2014-06-24 12:34:19 +0000 | |||
1207 | @@ -23,6 +23,7 @@ | |||
1208 | 23 | from openerp.osv import orm, fields | 23 | from openerp.osv import orm, fields |
1209 | 24 | from openerp.tools.translate import _ | 24 | from openerp.tools.translate import _ |
1210 | 25 | 25 | ||
1211 | 26 | |||
1212 | 26 | class CreditControlPrinter(orm.TransientModel): | 27 | class CreditControlPrinter(orm.TransientModel): |
1213 | 27 | """Print lines""" | 28 | """Print lines""" |
1214 | 28 | 29 | ||
1215 | @@ -34,15 +35,16 @@ | |||
1216 | 34 | if context is None: | 35 | if context is None: |
1217 | 35 | context = {} | 36 | context = {} |
1218 | 36 | res = False | 37 | res = False |
1222 | 37 | if (context.get('active_model') == 'credit.control.line' and | 38 | if context.get('active_model') != 'credit.control.line': |
1223 | 38 | context.get('active_ids')): | 39 | return res |
1224 | 39 | res = context['active_ids'] | 40 | res = context.get('active_ids', False) |
1225 | 40 | return res | 41 | return res |
1226 | 41 | 42 | ||
1227 | 42 | _columns = { | 43 | _columns = { |
1228 | 43 | 'mark_as_sent': fields.boolean('Mark letter lines as sent', | 44 | 'mark_as_sent': fields.boolean('Mark letter lines as sent', |
1229 | 44 | help="Only letter lines will be marked."), | 45 | help="Only letter lines will be marked."), |
1230 | 45 | 'report_file': fields.binary('Generated Report', readonly=True), | 46 | 'report_file': fields.binary('Generated Report', readonly=True), |
1231 | 47 | 'report_name': fields.char('Report name'), | ||
1232 | 46 | 'state': fields.char('state', size=32), | 48 | 'state': fields.char('state', size=32), |
1233 | 47 | 'line_ids': fields.many2many( | 49 | 'line_ids': fields.many2many( |
1234 | 48 | 'credit.control.line', | 50 | 'credit.control.line', |
1235 | @@ -62,6 +64,12 @@ | |||
1236 | 62 | ('channel', '=', 'letter')] | 64 | ('channel', '=', 'letter')] |
1237 | 63 | return line_obj.search(cr, uid, domain, context=context) | 65 | return line_obj.search(cr, uid, domain, context=context) |
1238 | 64 | 66 | ||
1239 | 67 | def _credit_line_predicate(self, cr, uid, line_record, context=None): | ||
1240 | 68 | return True | ||
1241 | 69 | |||
1242 | 70 | def _get_line_ids(self, cr, uid, lines, predicate, context=None): | ||
1243 | 71 | return [l.id for l in lines if predicate(cr, uid, l, context)] | ||
1244 | 72 | |||
1245 | 65 | def print_lines(self, cr, uid, wiz_id, context=None): | 73 | def print_lines(self, cr, uid, wiz_id, context=None): |
1246 | 66 | assert not (isinstance(wiz_id, list) and len(wiz_id) > 1), \ | 74 | assert not (isinstance(wiz_id, list) and len(wiz_id) > 1), \ |
1247 | 67 | "wiz_id: only one id expected" | 75 | "wiz_id: only one id expected" |
1248 | @@ -71,14 +79,22 @@ | |||
1249 | 71 | form = self.browse(cr, uid, wiz_id, context) | 79 | form = self.browse(cr, uid, wiz_id, context) |
1250 | 72 | 80 | ||
1251 | 73 | if not form.line_ids and not form.print_all: | 81 | if not form.line_ids and not form.print_all: |
1255 | 74 | raise orm.except_orm(_('Error'), _('No credit control lines selected.')) | 82 | raise orm.except_orm(_('Error'), |
1256 | 75 | 83 | _('No credit control lines selected.')) | |
1257 | 76 | line_ids = [l.id for l in form.line_ids] | 84 | |
1258 | 85 | line_ids = self._get_line_ids(cr, | ||
1259 | 86 | uid, | ||
1260 | 87 | form.line_ids, | ||
1261 | 88 | self._credit_line_predicate, | ||
1262 | 89 | context=context) | ||
1263 | 90 | |||
1264 | 77 | comms = comm_obj._generate_comm_from_credit_line_ids(cr, uid, line_ids, | 91 | comms = comm_obj._generate_comm_from_credit_line_ids(cr, uid, line_ids, |
1265 | 78 | context=context) | 92 | context=context) |
1266 | 79 | report_file = comm_obj._generate_report(cr, uid, comms, context=context) | 93 | report_file = comm_obj._generate_report(cr, uid, comms, context=context) |
1267 | 80 | 94 | ||
1269 | 81 | form.write({'report_file': base64.b64encode(report_file), 'state': 'done'}) | 95 | form.write({'report_file': base64.b64encode(report_file), |
1270 | 96 | 'report_name': 'credit_control_esr_bvr_%s.pdf' % fields.datetime.now(), | ||
1271 | 97 | 'state': 'done'}) | ||
1272 | 82 | 98 | ||
1273 | 83 | if form.mark_as_sent: | 99 | if form.mark_as_sent: |
1274 | 84 | comm_obj._mark_credit_line_as_sent(cr, uid, comms, context=context) | 100 | comm_obj._mark_credit_line_as_sent(cr, uid, comms, context=context) |
1275 | 85 | 101 | ||
1276 | === modified file 'account_credit_control/wizard/credit_control_printer_view.xml' | |||
1277 | --- account_credit_control/wizard/credit_control_printer_view.xml 2013-03-18 09:21:33 +0000 | |||
1278 | +++ account_credit_control/wizard/credit_control_printer_view.xml 2014-06-24 12:34:19 +0000 | |||
1279 | @@ -6,21 +6,34 @@ | |||
1280 | 6 | <field name="model">credit.control.printer</field> | 6 | <field name="model">credit.control.printer</field> |
1281 | 7 | <field name="type">form</field> | 7 | <field name="type">form</field> |
1282 | 8 | <field name="arch" type="xml"> | 8 | <field name="arch" type="xml"> |
1288 | 9 | <form string="Lines report"> | 9 | <form string="Lines report" version="7.0"> |
1289 | 10 | <separator colspan="4" string="Print the selected lines"/> | 10 | <separator string="Print the selected lines" colspan="4"/> |
1290 | 11 | <newline/> | 11 | <newline/> |
1291 | 12 | <field name="mark_as_sent" colspan="4" attrs="{'invisible': [('state', '=', 'done')]}"/> | 12 | <group> |
1292 | 13 | <newline/> | 13 | <field name="mark_as_sent" |
1293 | 14 | colspan="4" | ||
1294 | 15 | attrs="{'invisible': [('state', '=', 'done')]}"/> | ||
1295 | 16 | </group> | ||
1296 | 17 | <newline/> | ||
1297 | 18 | <notebook> | ||
1298 | 19 | <page string="Lines" attrs="{'invisible': [('state', '=', 'done')]}"> | ||
1299 | 14 | <field name="line_ids" colspan="4" nolabel="1" | 20 | <field name="line_ids" colspan="4" nolabel="1" |
1300 | 15 | attrs="{'invisible': [('state', '=', 'done')]}" /> | 21 | attrs="{'invisible': [('state', '=', 'done')]}" /> |
1302 | 16 | <field name="report_file" colspan="4" attrs="{'invisible': [('state', '!=', 'done')]}"/> | 22 | </page> |
1303 | 23 | </notebook> | ||
1304 | 24 | <field name="report_name" | ||
1305 | 25 | invisible="1"/> | ||
1306 | 26 | <field name="report_file" | ||
1307 | 27 | colspan="4" | ||
1308 | 28 | filename="report_name" | ||
1309 | 29 | attrs="{'invisible': [('state', '!=', 'done')]}"/> | ||
1310 | 17 | <field name="state" invisible="1" /> | 30 | <field name="state" invisible="1" /> |
1311 | 18 | <newline/> | 31 | <newline/> |
1315 | 19 | <group colspan="4"> | 32 | <footer> |
1316 | 20 | <button special="cancel" string="Cancel" icon='gtk-cancel' attrs="{'invisible': [('state', '==', 'done')]}"/> | 33 | <button class="oe_highlight" name="print_lines" string="Print" type="object" attrs="{'invisible': [('state', '=', 'done')]}"/> |
1317 | 21 | <button name="print_lines" string="Print" type="object" icon="gtk-execute" attrs="{'invisible': [('state', '==', 'done')]}"/> | 34 | <button special="cancel" string="Cancel" icon='gtk-cancel' attrs="{'invisible': [('state', '=', 'done')]}"/> |
1318 | 22 | <button special="cancel" string="Close" icon='gtk-close' attrs="{'invisible': [('state', '!=', 'done')]}"/> | 35 | <button special="cancel" string="Close" icon='gtk-close' attrs="{'invisible': [('state', '!=', 'done')]}"/> |
1320 | 23 | </group> | 36 | </footer> |
1321 | 24 | </form> | 37 | </form> |
1322 | 25 | </field> | 38 | </field> |
1323 | 26 | </record> | 39 | </record> |
1324 | 27 | 40 | ||
1325 | === added directory 'account_credit_control_dunning_fees' | |||
1326 | === added file 'account_credit_control_dunning_fees/__init__.py' | |||
1327 | --- account_credit_control_dunning_fees/__init__.py 1970-01-01 00:00:00 +0000 | |||
1328 | +++ account_credit_control_dunning_fees/__init__.py 2014-06-24 12:34:19 +0000 | |||
1329 | @@ -0,0 +1,21 @@ | |||
1330 | 1 | # -*- coding: utf-8 -*- | ||
1331 | 2 | ############################################################################## | ||
1332 | 3 | # | ||
1333 | 4 | # Author: Nicolas Bessi | ||
1334 | 5 | # Copyright 2014 Camptocamp SA | ||
1335 | 6 | # | ||
1336 | 7 | # This program is free software: you can redistribute it and/or modify | ||
1337 | 8 | # it under the terms of the GNU Affero General Public License as | ||
1338 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
1339 | 10 | # License, or (at your option) any later version. | ||
1340 | 11 | # | ||
1341 | 12 | # This program is distributed in the hope that it will be useful, | ||
1342 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1343 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1344 | 15 | # GNU Affero General Public License for more details. | ||
1345 | 16 | # | ||
1346 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
1347 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1348 | 19 | # | ||
1349 | 20 | ############################################################################## | ||
1350 | 21 | from . import model | ||
1351 | 0 | 22 | ||
1352 | === added file 'account_credit_control_dunning_fees/__openerp__.py' | |||
1353 | --- account_credit_control_dunning_fees/__openerp__.py 1970-01-01 00:00:00 +0000 | |||
1354 | +++ account_credit_control_dunning_fees/__openerp__.py 2014-06-24 12:34:19 +0000 | |||
1355 | @@ -0,0 +1,71 @@ | |||
1356 | 1 | # -*- coding: utf-8 -*- | ||
1357 | 2 | ############################################################################## | ||
1358 | 3 | # | ||
1359 | 4 | # Author: Nicolas Bessi | ||
1360 | 5 | # Copyright 2014 Camptocamp SA | ||
1361 | 6 | # | ||
1362 | 7 | # This program is free software: you can redistribute it and/or modify | ||
1363 | 8 | # it under the terms of the GNU Affero General Public License as | ||
1364 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
1365 | 10 | # License, or (at your option) any later version. | ||
1366 | 11 | # | ||
1367 | 12 | # This program is distributed in the hope that it will be useful, | ||
1368 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1369 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1370 | 15 | # GNU Affero General Public License for more details. | ||
1371 | 16 | # | ||
1372 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
1373 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1374 | 19 | # | ||
1375 | 20 | ############################################################################## | ||
1376 | 21 | {'name': 'Credit control dunning fees', | ||
1377 | 22 | 'version': '0.1.0', | ||
1378 | 23 | 'author': 'Camptocamp', | ||
1379 | 24 | 'maintainer': 'Camptocamp', | ||
1380 | 25 | 'category': 'Accounting', | ||
1381 | 26 | 'complexity': 'normal', | ||
1382 | 27 | 'depends': ['account_credit_control'], | ||
1383 | 28 | 'description': """ | ||
1384 | 29 | Dunning Fees for Credit Control | ||
1385 | 30 | =============================== | ||
1386 | 31 | |||
1387 | 32 | This extention of credit control adds the notion of dunning fees | ||
1388 | 33 | on credit control lines. | ||
1389 | 34 | |||
1390 | 35 | Configuration | ||
1391 | 36 | ------------- | ||
1392 | 37 | For release 0.1 only fixed fees are supported. | ||
1393 | 38 | |||
1394 | 39 | You can specifiy a fixed fees amount, a product and a currency | ||
1395 | 40 | on the credit control level form. | ||
1396 | 41 | |||
1397 | 42 | The amount will be used as fees values the currency will determine | ||
1398 | 43 | the currency of the fee. If the credit control line has not the | ||
1399 | 44 | same currency as the fees currency, fees will be converted to | ||
1400 | 45 | the credit control line currency. | ||
1401 | 46 | |||
1402 | 47 | The product is used to compute taxes in reconciliation process. | ||
1403 | 48 | |||
1404 | 49 | Run | ||
1405 | 50 | --- | ||
1406 | 51 | Fees are automatically computed on credit run and saved | ||
1407 | 52 | on the generated credit lines. | ||
1408 | 53 | |||
1409 | 54 | Fees can be manually edited as long credit line is draft | ||
1410 | 55 | |||
1411 | 56 | Credit control Summary report includes a new fees column. | ||
1412 | 57 | ------- | ||
1413 | 58 | Support of fees price list | ||
1414 | 59 | |||
1415 | 60 | """, | ||
1416 | 61 | 'website': 'http://www.camptocamp.com', | ||
1417 | 62 | 'data': ['view/policy_view.xml', | ||
1418 | 63 | 'view/line_view.xml', | ||
1419 | 64 | 'report/report.xml'], | ||
1420 | 65 | 'demo': [], | ||
1421 | 66 | 'test': [], | ||
1422 | 67 | 'installable': True, | ||
1423 | 68 | 'auto_install': False, | ||
1424 | 69 | 'license': 'AGPL-3', | ||
1425 | 70 | 'application': False, | ||
1426 | 71 | } | ||
1427 | 0 | 72 | ||
1428 | === added directory 'account_credit_control_dunning_fees/i18n' | |||
1429 | === added file 'account_credit_control_dunning_fees/i18n/account_credit_control_dunning_fees.pot' | |||
1430 | --- account_credit_control_dunning_fees/i18n/account_credit_control_dunning_fees.pot 1970-01-01 00:00:00 +0000 | |||
1431 | +++ account_credit_control_dunning_fees/i18n/account_credit_control_dunning_fees.pot 2014-06-24 12:34:19 +0000 | |||
1432 | @@ -0,0 +1,81 @@ | |||
1433 | 1 | # Translation of OpenERP Server. | ||
1434 | 2 | # This file contains the translation of the following modules: | ||
1435 | 3 | # * account_credit_control_dunning_fees | ||
1436 | 4 | # | ||
1437 | 5 | msgid "" | ||
1438 | 6 | msgstr "" | ||
1439 | 7 | "Project-Id-Version: OpenERP Server 7.0\n" | ||
1440 | 8 | "Report-Msgid-Bugs-To: \n" | ||
1441 | 9 | "POT-Creation-Date: 2014-05-07 11:44+0000\n" | ||
1442 | 10 | "PO-Revision-Date: 2014-05-07 11:44+0000\n" | ||
1443 | 11 | "Last-Translator: <>\n" | ||
1444 | 12 | "Language-Team: \n" | ||
1445 | 13 | "MIME-Version: 1.0\n" | ||
1446 | 14 | "Content-Type: text/plain; charset=UTF-8\n" | ||
1447 | 15 | "Content-Transfer-Encoding: \n" | ||
1448 | 16 | "Plural-Forms: \n" | ||
1449 | 17 | |||
1450 | 18 | #. module: account_credit_control_dunning_fees | ||
1451 | 19 | #: code:_description:0 | ||
1452 | 20 | #: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_line | ||
1453 | 21 | #, python-format | ||
1454 | 22 | msgid "A credit control line" | ||
1455 | 23 | msgstr "" | ||
1456 | 24 | |||
1457 | 25 | #. module: account_credit_control_dunning_fees | ||
1458 | 26 | #: code:_description:0 | ||
1459 | 27 | #: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_policy_level | ||
1460 | 28 | #, python-format | ||
1461 | 29 | msgid "A credit control policy level" | ||
1462 | 30 | msgstr "" | ||
1463 | 31 | |||
1464 | 32 | #. module: account_credit_control_dunning_fees | ||
1465 | 33 | #: code:_description:0 | ||
1466 | 34 | #: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_run | ||
1467 | 35 | #, python-format | ||
1468 | 36 | msgid "Credit control line generator" | ||
1469 | 37 | msgstr "" | ||
1470 | 38 | |||
1471 | 39 | #. module: account_credit_control_dunning_fees | ||
1472 | 40 | #: field:credit.control.line,dunning_fees_amount:0 | ||
1473 | 41 | #: view:credit.control.policy:0 | ||
1474 | 42 | msgid "Fees" | ||
1475 | 43 | msgstr "" | ||
1476 | 44 | |||
1477 | 45 | #. module: account_credit_control_dunning_fees | ||
1478 | 46 | #: field:credit.control.policy.level,dunning_fixed_amount:0 | ||
1479 | 47 | msgid "Fees Fixed Amount" | ||
1480 | 48 | msgstr "" | ||
1481 | 49 | |||
1482 | 50 | #. module: account_credit_control_dunning_fees | ||
1483 | 51 | #: field:credit.control.policy.level,dunning_product_id:0 | ||
1484 | 52 | msgid "Fees Product" | ||
1485 | 53 | msgstr "" | ||
1486 | 54 | |||
1487 | 55 | #. module: account_credit_control_dunning_fees | ||
1488 | 56 | #: field:credit.control.policy.level,dunning_currency_id:0 | ||
1489 | 57 | msgid "Fees currency" | ||
1490 | 58 | msgstr "" | ||
1491 | 59 | |||
1492 | 60 | #. module: account_credit_control_dunning_fees | ||
1493 | 61 | #: selection:credit.control.policy.level,dunning_fees_type:0 | ||
1494 | 62 | msgid "Fixed" | ||
1495 | 63 | msgstr "" | ||
1496 | 64 | |||
1497 | 65 | #. module: account_credit_control_dunning_fees | ||
1498 | 66 | #: view:credit.control.policy:0 | ||
1499 | 67 | msgid "Mail and reporting" | ||
1500 | 68 | msgstr "" | ||
1501 | 69 | |||
1502 | 70 | #. module: account_credit_control_dunning_fees | ||
1503 | 71 | #: code:_description:0 | ||
1504 | 72 | #: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_dunning_fees_computer | ||
1505 | 73 | #, python-format | ||
1506 | 74 | msgid "credit.control.dunning.fees.computer" | ||
1507 | 75 | msgstr "" | ||
1508 | 76 | |||
1509 | 77 | #. module: account_credit_control_dunning_fees | ||
1510 | 78 | #: field:credit.control.policy.level,dunning_fees_type:0 | ||
1511 | 79 | msgid "unknown" | ||
1512 | 80 | msgstr "" | ||
1513 | 81 | |||
1514 | 0 | 82 | ||
1515 | === added file 'account_credit_control_dunning_fees/i18n/fr.po' | |||
1516 | --- account_credit_control_dunning_fees/i18n/fr.po 1970-01-01 00:00:00 +0000 | |||
1517 | +++ account_credit_control_dunning_fees/i18n/fr.po 2014-06-24 12:34:19 +0000 | |||
1518 | @@ -0,0 +1,80 @@ | |||
1519 | 1 | # Translation of OpenERP Server. | ||
1520 | 2 | # This file contains the translation of the following modules: | ||
1521 | 3 | # * account_credit_control_dunning_fees | ||
1522 | 4 | # | ||
1523 | 5 | msgid "" | ||
1524 | 6 | msgstr "" | ||
1525 | 7 | "Project-Id-Version: OpenERP Server 7.0\n" | ||
1526 | 8 | "Report-Msgid-Bugs-To: \n" | ||
1527 | 9 | "POT-Creation-Date: 2014-04-16 07:11+0000\n" | ||
1528 | 10 | "PO-Revision-Date: 2014-04-16 07:11+0000\n" | ||
1529 | 11 | "Last-Translator: <>\n" | ||
1530 | 12 | "Language-Team: \n" | ||
1531 | 13 | "MIME-Version: 1.0\n" | ||
1532 | 14 | "Content-Type: text/plain; charset=UTF-8\n" | ||
1533 | 15 | "Content-Transfer-Encoding: \n" | ||
1534 | 16 | "Plural-Forms: \n" | ||
1535 | 17 | |||
1536 | 18 | #. module: account_credit_control_dunning_fees | ||
1537 | 19 | #: code:_description:0 | ||
1538 | 20 | #: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_line | ||
1539 | 21 | #, python-format | ||
1540 | 22 | msgid "A credit control line" | ||
1541 | 23 | msgstr "Ligne de relance" | ||
1542 | 24 | |||
1543 | 25 | #. module: account_credit_control_dunning_fees | ||
1544 | 26 | #: code:_description:0 | ||
1545 | 27 | #: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_policy_level | ||
1546 | 28 | #, python-format | ||
1547 | 29 | msgid "A credit control policy level" | ||
1548 | 30 | msgstr "Une politique de relance" | ||
1549 | 31 | |||
1550 | 32 | #. module: account_credit_control_dunning_fees | ||
1551 | 33 | #: code:_description:0 | ||
1552 | 34 | #: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_run | ||
1553 | 35 | #, python-format | ||
1554 | 36 | msgid "Credit control line generator" | ||
1555 | 37 | msgstr "Générateur de relance" | ||
1556 | 38 | |||
1557 | 39 | #. module: account_credit_control_dunning_fees | ||
1558 | 40 | #: field:credit.control.line,dunning_fees_amount:0 | ||
1559 | 41 | #: view:credit.control.policy:0 | ||
1560 | 42 | msgid "Fees" | ||
1561 | 43 | msgstr "Frais de relance" | ||
1562 | 44 | |||
1563 | 45 | #. module: account_credit_control_dunning_fees | ||
1564 | 46 | #: field:credit.control.policy.level,dunning_fixed_amount:0 | ||
1565 | 47 | msgid "Fees Fixed Amount" | ||
1566 | 48 | msgstr "Montant des frais" | ||
1567 | 49 | |||
1568 | 50 | #. module: account_credit_control_dunning_fees | ||
1569 | 51 | #: field:credit.control.policy.level,dunning_product_id:0 | ||
1570 | 52 | msgid "Fees Product" | ||
1571 | 53 | msgstr "Article lié" | ||
1572 | 54 | |||
1573 | 55 | #. module: account_credit_control_dunning_fees | ||
1574 | 56 | #: field:credit.control.policy.level,dunning_currency_id:0 | ||
1575 | 57 | msgid "Fees currency" | ||
1576 | 58 | msgstr "Devises" | ||
1577 | 59 | |||
1578 | 60 | #. module: account_credit_control_dunning_fees | ||
1579 | 61 | #: selection:credit.control.policy.level,dunning_fees_type:0 | ||
1580 | 62 | msgid "Fixed" | ||
1581 | 63 | msgstr "Fixe" | ||
1582 | 64 | |||
1583 | 65 | #. module: account_credit_control_dunning_fees | ||
1584 | 66 | #: view:credit.control.policy:0 | ||
1585 | 67 | msgid "Mail and reporting" | ||
1586 | 68 | msgstr "Lettres et e-mails" | ||
1587 | 69 | |||
1588 | 70 | #. module: account_credit_control_dunning_fees | ||
1589 | 71 | #: code:_description:0 | ||
1590 | 72 | #: model:ir.model,name:account_credit_control_dunning_fees.model_credit_control_dunning_fees_computer | ||
1591 | 73 | #, python-format | ||
1592 | 74 | msgid "credit.control.dunning.fees.computer" | ||
1593 | 75 | msgstr "credit.control.dunning.fees.computer" | ||
1594 | 76 | |||
1595 | 77 | #. module: account_credit_control_dunning_fees | ||
1596 | 78 | #: field:credit.control.policy.level,dunning_fees_type:0 | ||
1597 | 79 | msgid "unknown" | ||
1598 | 80 | msgstr "inconnu" | ||
1599 | 0 | 81 | ||
1600 | === added directory 'account_credit_control_dunning_fees/model' | |||
1601 | === added file 'account_credit_control_dunning_fees/model/__init__.py' | |||
1602 | --- account_credit_control_dunning_fees/model/__init__.py 1970-01-01 00:00:00 +0000 | |||
1603 | +++ account_credit_control_dunning_fees/model/__init__.py 2014-06-24 12:34:19 +0000 | |||
1604 | @@ -0,0 +1,24 @@ | |||
1605 | 1 | # -*- coding: utf-8 -*- | ||
1606 | 2 | ############################################################################## | ||
1607 | 3 | # | ||
1608 | 4 | # Author: Nicolas Bessi | ||
1609 | 5 | # Copyright 2014 Camptocamp SA | ||
1610 | 6 | # | ||
1611 | 7 | # This program is free software: you can redistribute it and/or modify | ||
1612 | 8 | # it under the terms of the GNU Affero General Public License as | ||
1613 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
1614 | 10 | # License, or (at your option) any later version. | ||
1615 | 11 | # | ||
1616 | 12 | # This program is distributed in the hope that it will be useful, | ||
1617 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1618 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1619 | 15 | # GNU Affero General Public License for more details. | ||
1620 | 16 | # | ||
1621 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
1622 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1623 | 19 | # | ||
1624 | 20 | ############################################################################## | ||
1625 | 21 | from . import line | ||
1626 | 22 | from . import policy | ||
1627 | 23 | from . import run | ||
1628 | 24 | from . import dunning | ||
1629 | 0 | 25 | ||
1630 | === added file 'account_credit_control_dunning_fees/model/dunning.py' | |||
1631 | --- account_credit_control_dunning_fees/model/dunning.py 1970-01-01 00:00:00 +0000 | |||
1632 | +++ account_credit_control_dunning_fees/model/dunning.py 2014-06-24 12:34:19 +0000 | |||
1633 | @@ -0,0 +1,120 @@ | |||
1634 | 1 | # -*- coding: utf-8 -*- | ||
1635 | 2 | ############################################################################## | ||
1636 | 3 | # | ||
1637 | 4 | # Author: Nicolas Bessi | ||
1638 | 5 | # Copyright 2014 Camptocamp SA | ||
1639 | 6 | # | ||
1640 | 7 | # This program is free software: you can redistribute it and/or modify | ||
1641 | 8 | # it under the terms of the GNU Affero General Public License as | ||
1642 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
1643 | 10 | # License, or (at your option) any later version. | ||
1644 | 11 | # | ||
1645 | 12 | # This program is distributed in the hope that it will be useful, | ||
1646 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1647 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1648 | 15 | # GNU Affero General Public License for more details. | ||
1649 | 16 | # | ||
1650 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
1651 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1652 | 19 | # | ||
1653 | 20 | ############################################################################## | ||
1654 | 21 | from openerp.osv import orm | ||
1655 | 22 | |||
1656 | 23 | |||
1657 | 24 | class FeesComputer(orm.BaseModel): | ||
1658 | 25 | """Model that compute dunnig fees. | ||
1659 | 26 | |||
1660 | 27 | This class does not need any database storage as | ||
1661 | 28 | it contains pure logic. | ||
1662 | 29 | |||
1663 | 30 | It inherits form ``orm.BaseModel`` to benefit of orm facility | ||
1664 | 31 | |||
1665 | 32 | Similar to AbstractModel but log access and actions | ||
1666 | 33 | """ | ||
1667 | 34 | |||
1668 | 35 | _name = 'credit.control.dunning.fees.computer' | ||
1669 | 36 | _auto = False | ||
1670 | 37 | _log_access = True | ||
1671 | 38 | _register = True | ||
1672 | 39 | _transient = False | ||
1673 | 40 | |||
1674 | 41 | def _get_compute_fun(self, level_fees_type): | ||
1675 | 42 | """Retrieve function of class that should compute the fees based on type | ||
1676 | 43 | |||
1677 | 44 | :param level_fee_type: type exisiting in model `credit.control.policy.level` | ||
1678 | 45 | for field dunning_fees_type | ||
1679 | 46 | |||
1680 | 47 | :returns: a function of class :class:`FeesComputer` with following signature | ||
1681 | 48 | self, cr, uid, credit_line (record), context | ||
1682 | 49 | |||
1683 | 50 | """ | ||
1684 | 51 | if level_fees_type == 'fixed': | ||
1685 | 52 | return self.compute_fixed_fees | ||
1686 | 53 | else: | ||
1687 | 54 | raise NotImplementedError('fees type %s is not supported' % level_fees_type) | ||
1688 | 55 | |||
1689 | 56 | def _compute_fees(self, cr, uid, credit_line_ids, context=None): | ||
1690 | 57 | """Compute fees for `credit_line_ids` parameter | ||
1691 | 58 | |||
1692 | 59 | Fees amount is written on credit line in field dunning_fees_amount | ||
1693 | 60 | |||
1694 | 61 | :param credit_line_ids: list of `credit.control.line` ids | ||
1695 | 62 | |||
1696 | 63 | :returns: `credit_line_ids` list of `credit.control.line` ids | ||
1697 | 64 | |||
1698 | 65 | """ | ||
1699 | 66 | if context is None: | ||
1700 | 67 | context = {} | ||
1701 | 68 | if not credit_line_ids: | ||
1702 | 69 | return credit_line_ids | ||
1703 | 70 | c_model = self.pool['credit.control.line'] | ||
1704 | 71 | credit_lines = c_model.browse(cr, uid, credit_line_ids, context=context) | ||
1705 | 72 | for credit in credit_lines: | ||
1706 | 73 | # if there is no dependence between generated credit lines | ||
1707 | 74 | # this could be threaded | ||
1708 | 75 | self._compute(cr, uid, credit, context=context), | ||
1709 | 76 | return credit_line_ids | ||
1710 | 77 | |||
1711 | 78 | def _compute(self, cr, uid, credit_line, context=None): | ||
1712 | 79 | """Compute fees for a given credit line | ||
1713 | 80 | |||
1714 | 81 | Fees amount is written on credit line in field dunning_fees_amount | ||
1715 | 82 | |||
1716 | 83 | :param credit_line: credit line record | ||
1717 | 84 | |||
1718 | 85 | :returns: `credit_line` record | ||
1719 | 86 | """ | ||
1720 | 87 | fees_type = credit_line.policy_level_id.dunning_fees_type | ||
1721 | 88 | compute = self._get_compute_fun(fees_type) | ||
1722 | 89 | fees = compute(cr, uid, credit_line, context=context) | ||
1723 | 90 | if fees: | ||
1724 | 91 | credit_line.write({'dunning_fees_amount': fees}, | ||
1725 | 92 | context=context) | ||
1726 | 93 | return credit_line | ||
1727 | 94 | |||
1728 | 95 | def compute_fixed_fees(self, cr, uid, credit_line, context=None): | ||
1729 | 96 | """Compute fees amount for fixed fees. | ||
1730 | 97 | Correspond to the fixed dunning fees type | ||
1731 | 98 | |||
1732 | 99 | if currency of the fees is not the same as the currency | ||
1733 | 100 | of the credit line, fees amount is converted to | ||
1734 | 101 | currency of credit line. | ||
1735 | 102 | |||
1736 | 103 | :param credit_line: credit line record | ||
1737 | 104 | |||
1738 | 105 | :return: fees amount float (in credit line currency) | ||
1739 | 106 | |||
1740 | 107 | """ | ||
1741 | 108 | currency_model = self.pool['res.currency'] | ||
1742 | 109 | credit_currency = credit_line.currency_id | ||
1743 | 110 | level = credit_line.policy_level_id | ||
1744 | 111 | fees_amount = level.dunning_fixed_amount | ||
1745 | 112 | if not fees_amount: | ||
1746 | 113 | return 0.0 | ||
1747 | 114 | fees_currency = level.dunning_currency_id | ||
1748 | 115 | if fees_currency == credit_currency: | ||
1749 | 116 | return fees_amount | ||
1750 | 117 | else: | ||
1751 | 118 | return currency_model.compute(cr, uid, fees_currency.id, | ||
1752 | 119 | credit_currency.id, fees_amount, | ||
1753 | 120 | context=context) | ||
1754 | 0 | 121 | ||
1755 | === added file 'account_credit_control_dunning_fees/model/line.py' | |||
1756 | --- account_credit_control_dunning_fees/model/line.py 1970-01-01 00:00:00 +0000 | |||
1757 | +++ account_credit_control_dunning_fees/model/line.py 2014-06-24 12:34:19 +0000 | |||
1758 | @@ -0,0 +1,29 @@ | |||
1759 | 1 | # -*- coding: utf-8 -*- | ||
1760 | 2 | ############################################################################## | ||
1761 | 3 | # | ||
1762 | 4 | # Author: Nicolas Bessi | ||
1763 | 5 | # Copyright 2014 Camptocamp SA | ||
1764 | 6 | # | ||
1765 | 7 | # This program is free software: you can redistribute it and/or modify | ||
1766 | 8 | # it under the terms of the GNU Affero General Public License as | ||
1767 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
1768 | 10 | # License, or (at your option) any later version. | ||
1769 | 11 | # | ||
1770 | 12 | # This program is distributed in the hope that it will be useful, | ||
1771 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1772 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1773 | 15 | # GNU Affero General Public License for more details. | ||
1774 | 16 | # | ||
1775 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
1776 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1777 | 19 | # | ||
1778 | 20 | ############################################################################## | ||
1779 | 21 | from openerp.osv import orm, fields | ||
1780 | 22 | |||
1781 | 23 | |||
1782 | 24 | class credit_control_line(orm.Model): | ||
1783 | 25 | """Add dunning_fees_amount_fees field""" | ||
1784 | 26 | |||
1785 | 27 | _inherit = "credit.control.line" | ||
1786 | 28 | |||
1787 | 29 | _columns = {'dunning_fees_amount': fields.float('Fees')} | ||
1788 | 0 | 30 | ||
1789 | === added file 'account_credit_control_dunning_fees/model/policy.py' | |||
1790 | --- account_credit_control_dunning_fees/model/policy.py 1970-01-01 00:00:00 +0000 | |||
1791 | +++ account_credit_control_dunning_fees/model/policy.py 2014-06-24 12:34:19 +0000 | |||
1792 | @@ -0,0 +1,36 @@ | |||
1793 | 1 | # -*- coding: utf-8 -*- | ||
1794 | 2 | ############################################################################## | ||
1795 | 3 | # | ||
1796 | 4 | # Author: Nicolas Bessi | ||
1797 | 5 | # Copyright 2014 Camptocamp SA | ||
1798 | 6 | # | ||
1799 | 7 | # This program is free software: you can redistribute it and/or modify | ||
1800 | 8 | # it under the terms of the GNU Affero General Public License as | ||
1801 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
1802 | 10 | # License, or (at your option) any later version. | ||
1803 | 11 | # | ||
1804 | 12 | # This program is distributed in the hope that it will be useful, | ||
1805 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1806 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1807 | 15 | # GNU Affero General Public License for more details. | ||
1808 | 16 | # | ||
1809 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
1810 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1811 | 19 | # | ||
1812 | 20 | ############################################################################## | ||
1813 | 21 | from openerp.osv import orm, fields | ||
1814 | 22 | |||
1815 | 23 | |||
1816 | 24 | class credit_control_policy(orm.Model): | ||
1817 | 25 | """ADD dunning fees fields""" | ||
1818 | 26 | |||
1819 | 27 | _inherit = "credit.control.policy.level" | ||
1820 | 28 | _columns = {'dunning_product_id': fields.many2one('product.product', | ||
1821 | 29 | 'Fees Product'), | ||
1822 | 30 | 'dunning_fixed_amount': fields.float('Fees Fixed Amount'), | ||
1823 | 31 | 'dunning_currency_id': fields.many2one('res.currency', | ||
1824 | 32 | 'Fees currency'), | ||
1825 | 33 | # planned type are fixed, percent, compound | ||
1826 | 34 | 'dunning_fees_type': fields.selection([('fixed', 'Fixed')])} | ||
1827 | 35 | |||
1828 | 36 | _defaults = {'dunning_fees_type': 'fixed'} | ||
1829 | 0 | 37 | ||
1830 | === added file 'account_credit_control_dunning_fees/model/run.py' | |||
1831 | --- account_credit_control_dunning_fees/model/run.py 1970-01-01 00:00:00 +0000 | |||
1832 | +++ account_credit_control_dunning_fees/model/run.py 2014-06-24 12:34:19 +0000 | |||
1833 | @@ -0,0 +1,39 @@ | |||
1834 | 1 | # -*- coding: utf-8 -*- | ||
1835 | 2 | ############################################################################## | ||
1836 | 3 | # | ||
1837 | 4 | # Author: Nicolas Bessi | ||
1838 | 5 | # Copyright 2014 Camptocamp SA | ||
1839 | 6 | # | ||
1840 | 7 | # This program is free software: you can redistribute it and/or modify | ||
1841 | 8 | # it under the terms of the GNU Affero General Public License as | ||
1842 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
1843 | 10 | # License, or (at your option) any later version. | ||
1844 | 11 | # | ||
1845 | 12 | # This program is distributed in the hope that it will be useful, | ||
1846 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1847 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1848 | 15 | # GNU Affero General Public License for more details. | ||
1849 | 16 | # | ||
1850 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
1851 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1852 | 19 | # | ||
1853 | 20 | ############################################################################## | ||
1854 | 21 | from openerp.osv import orm, fields | ||
1855 | 22 | |||
1856 | 23 | |||
1857 | 24 | class credit_control_run(orm.Model): | ||
1858 | 25 | """Add computation of fees""" | ||
1859 | 26 | |||
1860 | 27 | _inherit = "credit.control.run" | ||
1861 | 28 | |||
1862 | 29 | def _generate_credit_lines(self, cr, uid, run_id, context=None): | ||
1863 | 30 | """Override method to add fees computation""" | ||
1864 | 31 | credit_line_ids = super(credit_control_run, self)._generate_credit_lines( | ||
1865 | 32 | cr, | ||
1866 | 33 | uid, | ||
1867 | 34 | run_id, | ||
1868 | 35 | context=context | ||
1869 | 36 | ) | ||
1870 | 37 | fees_model = self.pool['credit.control.dunning.fees.computer'] | ||
1871 | 38 | fees_model._compute_fees(cr, uid, credit_line_ids, context=context) | ||
1872 | 39 | return credit_line_ids | ||
1873 | 0 | 40 | ||
1874 | === added directory 'account_credit_control_dunning_fees/report' | |||
1875 | === added file 'account_credit_control_dunning_fees/report/credit_control_summary.html.mako' | |||
1876 | --- account_credit_control_dunning_fees/report/credit_control_summary.html.mako 1970-01-01 00:00:00 +0000 | |||
1877 | +++ account_credit_control_dunning_fees/report/credit_control_summary.html.mako 2014-06-24 12:34:19 +0000 | |||
1878 | @@ -0,0 +1,246 @@ | |||
1879 | 1 | ## -*- coding: utf-8 -*- | ||
1880 | 2 | <html> | ||
1881 | 3 | <head> | ||
1882 | 4 | <style type="text/css"> | ||
1883 | 5 | ${css} | ||
1884 | 6 | body { | ||
1885 | 7 | font-family: helvetica; | ||
1886 | 8 | font-size: 12px; | ||
1887 | 9 | } | ||
1888 | 10 | |||
1889 | 11 | .custom_text { | ||
1890 | 12 | font-family: helvetica; | ||
1891 | 13 | font-size: 12px; | ||
1892 | 14 | } | ||
1893 | 15 | |||
1894 | 16 | table { | ||
1895 | 17 | font-family: helvetica; | ||
1896 | 18 | font-size: 12px; | ||
1897 | 19 | } | ||
1898 | 20 | |||
1899 | 21 | .header { | ||
1900 | 22 | margin-left: 0px; | ||
1901 | 23 | text-align: left; | ||
1902 | 24 | width: 300px; | ||
1903 | 25 | font-size: 12px; | ||
1904 | 26 | } | ||
1905 | 27 | |||
1906 | 28 | .title { | ||
1907 | 29 | font-size: 16px; | ||
1908 | 30 | font-weight: bold; | ||
1909 | 31 | } | ||
1910 | 32 | |||
1911 | 33 | .basic_table{ | ||
1912 | 34 | text-align: center; | ||
1913 | 35 | border: 1px solid lightGrey; | ||
1914 | 36 | border-collapse: collapse; | ||
1915 | 37 | font-family: helvetica; | ||
1916 | 38 | font-size: 12px; | ||
1917 | 39 | } | ||
1918 | 40 | |||
1919 | 41 | .basic_table th { | ||
1920 | 42 | border: 1px solid lightGrey; | ||
1921 | 43 | font-size: 11px; | ||
1922 | 44 | font-weight: bold; | ||
1923 | 45 | |||
1924 | 46 | } | ||
1925 | 47 | |||
1926 | 48 | .basic_table td { | ||
1927 | 49 | border: 1px solid lightGrey; | ||
1928 | 50 | font-size: 12px; | ||
1929 | 51 | } | ||
1930 | 52 | |||
1931 | 53 | .list_table { | ||
1932 | 54 | border-color: black; | ||
1933 | 55 | text-align: center; | ||
1934 | 56 | border-collapse: collapse; | ||
1935 | 57 | } | ||
1936 | 58 | |||
1937 | 59 | .list_table td { | ||
1938 | 60 | border-color: gray; | ||
1939 | 61 | border-top: 1px solid gray; | ||
1940 | 62 | text-align: left; | ||
1941 | 63 | font-size: 12px; | ||
1942 | 64 | padding-right: 3px; | ||
1943 | 65 | padding-left: 3px; | ||
1944 | 66 | padding-top: 3px; | ||
1945 | 67 | padding-bottom:3px; | ||
1946 | 68 | } | ||
1947 | 69 | |||
1948 | 70 | .list_table th { | ||
1949 | 71 | border-bottom: 2px solid black; | ||
1950 | 72 | text-align: left; | ||
1951 | 73 | font-size: 11px; | ||
1952 | 74 | font-weight: bold; | ||
1953 | 75 | padding-right: 3px | ||
1954 | 76 | padding-left: 3px | ||
1955 | 77 | } | ||
1956 | 78 | |||
1957 | 79 | .list_table thead { | ||
1958 | 80 | display: table-header-group; | ||
1959 | 81 | } | ||
1960 | 82 | |||
1961 | 83 | .address table { | ||
1962 | 84 | font-size: 11px; | ||
1963 | 85 | border-collapse: collapse; | ||
1964 | 86 | margin: 0px; | ||
1965 | 87 | padding: 0px; | ||
1966 | 88 | } | ||
1967 | 89 | |||
1968 | 90 | .address .shipping { | ||
1969 | 91 | |||
1970 | 92 | } | ||
1971 | 93 | |||
1972 | 94 | .address .invoice { | ||
1973 | 95 | margin-top: 10px; | ||
1974 | 96 | } | ||
1975 | 97 | |||
1976 | 98 | .address .recipient { | ||
1977 | 99 | font-size: 13px; | ||
1978 | 100 | margin-right: 120px; | ||
1979 | 101 | margin-left: 350px; | ||
1980 | 102 | float: right; | ||
1981 | 103 | } | ||
1982 | 104 | |||
1983 | 105 | |||
1984 | 106 | table .address_title { | ||
1985 | 107 | font-weight: bold; | ||
1986 | 108 | } | ||
1987 | 109 | |||
1988 | 110 | .address td.name { | ||
1989 | 111 | font-weight: bold; | ||
1990 | 112 | } | ||
1991 | 113 | |||
1992 | 114 | td.amount, th.amount { | ||
1993 | 115 | text-align: right; | ||
1994 | 116 | padding-right:2px; | ||
1995 | 117 | } | ||
1996 | 118 | |||
1997 | 119 | h1 { | ||
1998 | 120 | font-size: 16px; | ||
1999 | 121 | font-weight: bold; | ||
2000 | 122 | } | ||
2001 | 123 | |||
2002 | 124 | tr.line .note { | ||
2003 | 125 | border-style: none; | ||
2004 | 126 | font-size: 9px; | ||
2005 | 127 | padding-left: 10px; | ||
2006 | 128 | } | ||
2007 | 129 | |||
2008 | 130 | tr.line { | ||
2009 | 131 | margin-bottom: 10px; | ||
2010 | 132 | } | ||
2011 | 133 | </style> | ||
2012 | 134 | </head> | ||
2013 | 135 | <body> | ||
2014 | 136 | |||
2015 | 137 | %for comm in objects : | ||
2016 | 138 | <% setLang(comm.get_contact_address().lang) %> | ||
2017 | 139 | <div class="address"> | ||
2018 | 140 | <table class="recipient"> | ||
2019 | 141 | <% | ||
2020 | 142 | add = comm.get_contact_address() | ||
2021 | 143 | %> | ||
2022 | 144 | %if comm.partner_id.id == add.id: | ||
2023 | 145 | <tr><td class="name">${comm.partner_id.title and comm.partner_id.title.name or ''} ${comm.partner_id.name }</td></tr> | ||
2024 | 146 | <% address_lines = comm.partner_id.contact_address.split("\n") %> | ||
2025 | 147 | |||
2026 | 148 | %else: | ||
2027 | 149 | <tr><td class="name">${comm.partner_id.name or ''}</td></tr> | ||
2028 | 150 | <tr><td>${add.title and add.title.name or ''} ${add.name}</td></tr> | ||
2029 | 151 | <% address_lines = add.contact_address.split("\n")[1:] %> | ||
2030 | 152 | %endif | ||
2031 | 153 | %for part in address_lines: | ||
2032 | 154 | %if part: | ||
2033 | 155 | <tr><td>${part}</td></tr> | ||
2034 | 156 | %endif | ||
2035 | 157 | %endfor | ||
2036 | 158 | </table> | ||
2037 | 159 | <br/> | ||
2038 | 160 | <br/> | ||
2039 | 161 | <br/> | ||
2040 | 162 | <br/> | ||
2041 | 163 | |||
2042 | 164 | </div> | ||
2043 | 165 | <br/> | ||
2044 | 166 | <br/> | ||
2045 | 167 | <br/> | ||
2046 | 168 | <div> | ||
2047 | 169 | |||
2048 | 170 | <h3 style="clear: both; padding-top: 20px;"> | ||
2049 | 171 | ${_('Reminder')}: ${comm.current_policy_level.name or '' } | ||
2050 | 172 | </h3> | ||
2051 | 173 | |||
2052 | 174 | <p>${_('Dear')},</p> | ||
2053 | 175 | <p class="custom_text" width="95%">${comm.current_policy_level.custom_text.replace('\n', '<br />')}</p> | ||
2054 | 176 | |||
2055 | 177 | <br/> | ||
2056 | 178 | <br/> | ||
2057 | 179 | <p><b>${_('Summary')}<br/></b></p> | ||
2058 | 180 | <table class="basic_table" style="width: 100%;"> | ||
2059 | 181 | <tr> | ||
2060 | 182 | <th width="200">${_('Invoice number')}</th> | ||
2061 | 183 | <th>${_('Invoice date')}</th> | ||
2062 | 184 | <th>${_('Date due')}</th> | ||
2063 | 185 | <th>${_('Invoiced amount')}</th> | ||
2064 | 186 | <th>${_('Open amount')}</th> | ||
2065 | 187 | <th>${_('Fees')}</th> | ||
2066 | 188 | <th>${_('Currency')}</th> | ||
2067 | 189 | |||
2068 | 190 | </tr> | ||
2069 | 191 | %for line in comm.credit_control_line_ids: | ||
2070 | 192 | <tr> | ||
2071 | 193 | %if line.invoice_id: | ||
2072 | 194 | <td width="200">${line.invoice_id.number} | ||
2073 | 195 | %if line.invoice_id.name: | ||
2074 | 196 | <br/> | ||
2075 | 197 | ${line.invoice_id.name} | ||
2076 | 198 | %endif | ||
2077 | 199 | </td> | ||
2078 | 200 | %else: | ||
2079 | 201 | <td width="200">${line.move_line_id.name}</td> | ||
2080 | 202 | %endif | ||
2081 | 203 | <td class="date">${line.date_entry}</td> | ||
2082 | 204 | <td class="date">${line.date_due}</td> | ||
2083 | 205 | <td class="amount">${line.amount_due}</td> | ||
2084 | 206 | <td class="amount">${line.balance_due}</td> | ||
2085 | 207 | <td class="amount">${line.dunning_fees_amount}</td> | ||
2086 | 208 | <td class="amount">${line.currency_id.name or comm.company_id.currency_id.name}</td> | ||
2087 | 209 | </tr> | ||
2088 | 210 | %endfor | ||
2089 | 211 | </table> | ||
2090 | 212 | <br/> | ||
2091 | 213 | <br/> | ||
2092 | 214 | <%doc> | ||
2093 | 215 | <!-- uncomment to have info after summary --> | ||
2094 | 216 | <p>${_('If you have any question, do not hesitate to contact us.')}</p> | ||
2095 | 217 | |||
2096 | 218 | <p>${comm.user_id.name} ${comm.user_id.email and '<%s>'%(comm.user_id.email) or ''}<br/> | ||
2097 | 219 | ${comm.company_id.name}<br/> | ||
2098 | 220 | % if comm.company_id.street: | ||
2099 | 221 | ${comm.company_id.street or ''}<br/> | ||
2100 | 222 | |||
2101 | 223 | % endif | ||
2102 | 224 | |||
2103 | 225 | % if comm.company_id.street2: | ||
2104 | 226 | ${comm.company_id.street2}<br/> | ||
2105 | 227 | % endif | ||
2106 | 228 | % if comm.company_id.city or comm.company_id.zip: | ||
2107 | 229 | ${comm.company_id.zip or ''} ${comm.company_id.city or ''}<br/> | ||
2108 | 230 | % endif | ||
2109 | 231 | % if comm.company_id.country_id: | ||
2110 | 232 | ${comm.company_id.state_id and ('%s, ' % comm.company_id.state_id.name) or ''} ${comm.company_id.country_id.name or ''}<br/> | ||
2111 | 233 | % endif | ||
2112 | 234 | % if comm.company_id.phone: | ||
2113 | 235 | Phone: ${comm.company_id.phone}<br/> | ||
2114 | 236 | % endif | ||
2115 | 237 | % if comm.company_id.website: | ||
2116 | 238 | ${comm.company_id.website or ''}<br/> | ||
2117 | 239 | % endif | ||
2118 | 240 | </%doc> | ||
2119 | 241 | |||
2120 | 242 | <p style="page-break-after:always"></p> | ||
2121 | 243 | %endfor | ||
2122 | 244 | |||
2123 | 245 | </body> | ||
2124 | 246 | </html> | ||
2125 | 0 | 247 | ||
2126 | === added file 'account_credit_control_dunning_fees/report/report.xml' | |||
2127 | --- account_credit_control_dunning_fees/report/report.xml 1970-01-01 00:00:00 +0000 | |||
2128 | +++ account_credit_control_dunning_fees/report/report.xml 2014-06-24 12:34:19 +0000 | |||
2129 | @@ -0,0 +1,12 @@ | |||
2130 | 1 | <openerp> | ||
2131 | 2 | <data> | ||
2132 | 3 | <report auto="False" | ||
2133 | 4 | id="account_credit_control.report_webkit_html" | ||
2134 | 5 | model="credit.control.communication" | ||
2135 | 6 | name="credit_control_summary" | ||
2136 | 7 | file="account_credit_control_dunning_fees/report/credit_control_summary.html.mako" | ||
2137 | 8 | string="Credit Summary" | ||
2138 | 9 | report_type="webkit" | ||
2139 | 10 | webkit_header="report_webkit.ir_header_webkit_basesample0"/> | ||
2140 | 11 | </data> | ||
2141 | 12 | </openerp> | ||
2142 | 0 | 13 | ||
2143 | === added directory 'account_credit_control_dunning_fees/security' | |||
2144 | === added directory 'account_credit_control_dunning_fees/tests' | |||
2145 | === added file 'account_credit_control_dunning_fees/tests/__init__.py' | |||
2146 | --- account_credit_control_dunning_fees/tests/__init__.py 1970-01-01 00:00:00 +0000 | |||
2147 | +++ account_credit_control_dunning_fees/tests/__init__.py 2014-06-24 12:34:19 +0000 | |||
2148 | @@ -0,0 +1,23 @@ | |||
2149 | 1 | # -*- coding: utf-8 -*- | ||
2150 | 2 | ############################################################################## | ||
2151 | 3 | # | ||
2152 | 4 | # Author: Nicolas Bessi | ||
2153 | 5 | # Copyright 2014 Camptocamp SA | ||
2154 | 6 | # | ||
2155 | 7 | # This program is free software: you can redistribute it and/or modify | ||
2156 | 8 | # it under the terms of the GNU Affero General Public License as | ||
2157 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
2158 | 10 | # License, or (at your option) any later version. | ||
2159 | 11 | # | ||
2160 | 12 | # This program is distributed in the hope that it will be useful, | ||
2161 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2162 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2163 | 15 | # GNU Affero General Public License for more details. | ||
2164 | 16 | # | ||
2165 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
2166 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2167 | 19 | # | ||
2168 | 20 | ############################################################################## | ||
2169 | 21 | from . import test_fees_generation | ||
2170 | 22 | |||
2171 | 23 | checks = [test_fees_generation] | ||
2172 | 0 | 24 | ||
2173 | === added file 'account_credit_control_dunning_fees/tests/test_fees_generation.py' | |||
2174 | --- account_credit_control_dunning_fees/tests/test_fees_generation.py 1970-01-01 00:00:00 +0000 | |||
2175 | +++ account_credit_control_dunning_fees/tests/test_fees_generation.py 2014-06-24 12:34:19 +0000 | |||
2176 | @@ -0,0 +1,95 @@ | |||
2177 | 1 | # -*- coding: utf-8 -*- | ||
2178 | 2 | ############################################################################## | ||
2179 | 3 | # | ||
2180 | 4 | # Author: Nicolas Bessi | ||
2181 | 5 | # Copyright 2014 Camptocamp SA | ||
2182 | 6 | # | ||
2183 | 7 | # This program is free software: you can redistribute it and/or modify | ||
2184 | 8 | # it under the terms of the GNU Affero General Public License as | ||
2185 | 9 | # published by the Free Software Foundation, either version 3 of the | ||
2186 | 10 | # License, or (at your option) any later version. | ||
2187 | 11 | # | ||
2188 | 12 | # This program is distributed in the hope that it will be useful, | ||
2189 | 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2190 | 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2191 | 15 | # GNU Affero General Public License for more details. | ||
2192 | 16 | # | ||
2193 | 17 | # You should have received a copy of the GNU Affero General Public License | ||
2194 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2195 | 19 | # | ||
2196 | 20 | ############################################################################## | ||
2197 | 21 | from mock import MagicMock | ||
2198 | 22 | import openerp.tests.common as test_common | ||
2199 | 23 | |||
2200 | 24 | |||
2201 | 25 | class FixedFeesTester(test_common.TransactionCase): | ||
2202 | 26 | |||
2203 | 27 | def setUp(self): | ||
2204 | 28 | """Initialize credit control level mock to test fees computations""" | ||
2205 | 29 | super(FixedFeesTester, self).setUp() | ||
2206 | 30 | self.currency_model = self.registry('res.currency') | ||
2207 | 31 | self.euro = self.currency_model.search(self.cr, self.uid, | ||
2208 | 32 | [('name', '=', 'EUR')]) | ||
2209 | 33 | self.assertTrue(self.euro) | ||
2210 | 34 | self.euro = self.registry('res.currency').browse(self.cr, | ||
2211 | 35 | self.uid, | ||
2212 | 36 | self.euro[0]) | ||
2213 | 37 | |||
2214 | 38 | self.usd = self.currency_model.search(self.cr, self.uid, | ||
2215 | 39 | [('name', '=', 'USD')]) | ||
2216 | 40 | self.assertTrue(self.usd) | ||
2217 | 41 | self.usd = self.registry('res.currency').browse(self.cr, | ||
2218 | 42 | self.uid, | ||
2219 | 43 | self.usd[0]) | ||
2220 | 44 | |||
2221 | 45 | self.euro_level = MagicMock(name='Euro policy level') | ||
2222 | 46 | self.euro_level.dunning_fixed_amount = 5.0 | ||
2223 | 47 | self.euro_level.dunning_currency_id = self.euro | ||
2224 | 48 | self.euro_level.dunning_type = 'fixed' | ||
2225 | 49 | |||
2226 | 50 | self.usd_level = MagicMock(name='USD policy level') | ||
2227 | 51 | self.usd_level.dunning_fixed_amount = 5.0 | ||
2228 | 52 | self.usd_level.dunning_currency_id = self.usd | ||
2229 | 53 | self.usd_level.dunning_type = 'fixed' | ||
2230 | 54 | self.dunning_model = self.registry('credit.control.dunning.fees.computer') | ||
2231 | 55 | |||
2232 | 56 | def test_type_getter(self): | ||
2233 | 57 | """Test that correct compute function is returned for "fixed" type""" | ||
2234 | 58 | c_fun = self.dunning_model._get_compute_fun('fixed') | ||
2235 | 59 | self.assertEqual(c_fun, self.dunning_model.compute_fixed_fees) | ||
2236 | 60 | |||
2237 | 61 | def test_unknow_type(self): | ||
2238 | 62 | """Test that non implemented error is raised if invalide fees type""" | ||
2239 | 63 | with self.assertRaises(NotImplementedError): | ||
2240 | 64 | self.dunning_model._get_compute_fun('bang') | ||
2241 | 65 | |||
2242 | 66 | def test_computation_same_currency(self): | ||
2243 | 67 | """Test that fees are correctly computed with same currency""" | ||
2244 | 68 | credit_line = MagicMock(name='Euro credit line') | ||
2245 | 69 | credit_line.policy_level_id = self.euro_level | ||
2246 | 70 | credit_line.currency_id = self.euro | ||
2247 | 71 | fees = self.dunning_model.compute_fixed_fees(self.cr, self.uid, | ||
2248 | 72 | credit_line, | ||
2249 | 73 | {}) | ||
2250 | 74 | self.assertEqual(fees, self.euro_level.dunning_fixed_amount) | ||
2251 | 75 | |||
2252 | 76 | def test_computation_different_currency(self): | ||
2253 | 77 | """Test that fees are correctly computed with different currency""" | ||
2254 | 78 | credit_line = MagicMock(name='USD credit line') | ||
2255 | 79 | credit_line.policy_level_id = self.euro_level | ||
2256 | 80 | credit_line.currency_id = self.usd | ||
2257 | 81 | fees = self.dunning_model.compute_fixed_fees(self.cr, self.uid, | ||
2258 | 82 | credit_line, | ||
2259 | 83 | {}) | ||
2260 | 84 | self.assertNotEqual(fees, self.euro_level.dunning_fixed_amount) | ||
2261 | 85 | |||
2262 | 86 | def test_no_fees(self): | ||
2263 | 87 | """Test that fees are not generated if no amount defined on level""" | ||
2264 | 88 | credit_line = MagicMock(name='USD credit line') | ||
2265 | 89 | credit_line.policy_level_id = self.euro_level | ||
2266 | 90 | self.euro_level.dunning_fixed_amount = 0.0 | ||
2267 | 91 | credit_line.currency_id = self.usd | ||
2268 | 92 | fees = self.dunning_model.compute_fixed_fees(self.cr, self.uid, | ||
2269 | 93 | credit_line, | ||
2270 | 94 | {}) | ||
2271 | 95 | self.assertEqual(fees, 0.0) | ||
2272 | 0 | 96 | ||
2273 | === added directory 'account_credit_control_dunning_fees/view' | |||
2274 | === added file 'account_credit_control_dunning_fees/view/line_view.xml' | |||
2275 | --- account_credit_control_dunning_fees/view/line_view.xml 1970-01-01 00:00:00 +0000 | |||
2276 | +++ account_credit_control_dunning_fees/view/line_view.xml 2014-06-24 12:34:19 +0000 | |||
2277 | @@ -0,0 +1,30 @@ | |||
2278 | 1 | <?xml version="1.0" encoding="utf-8"?> | ||
2279 | 2 | <openerp> | ||
2280 | 3 | <data> | ||
2281 | 4 | |||
2282 | 5 | <record id="add_fees_on_credit_control_line" model="ir.ui.view"> | ||
2283 | 6 | <field name="name">add fees on credit control line</field> | ||
2284 | 7 | <field name="model">credit.control.line</field> | ||
2285 | 8 | <field name="inherit_id" ref="account_credit_control.credit_control_line_tree" /> | ||
2286 | 9 | <field name="arch" type="xml"> | ||
2287 | 10 | <field name="balance_due" position="after"> | ||
2288 | 11 | <field name="dunning_fees_amount" | ||
2289 | 12 | attrs="{'readonly': [('state', '!=', 'draft')]}"/> | ||
2290 | 13 | </field> | ||
2291 | 14 | </field> | ||
2292 | 15 | </record> | ||
2293 | 16 | |||
2294 | 17 | <record id="add_fees_on_credit_control_line_from" model="ir.ui.view"> | ||
2295 | 18 | <field name="name">add fees on credit control line form</field> | ||
2296 | 19 | <field name="model">credit.control.line</field> | ||
2297 | 20 | <field name="inherit_id" ref="account_credit_control.credit_control_line_form"/> | ||
2298 | 21 | <field name="arch" type="xml"> | ||
2299 | 22 | <field name="balance_due" position="after"> | ||
2300 | 23 | <field name="dunning_fees_amount" | ||
2301 | 24 | attrs="{'readonly': [('state', '!=', 'draft')]}"/> | ||
2302 | 25 | </field> | ||
2303 | 26 | </field> | ||
2304 | 27 | </record> | ||
2305 | 28 | |||
2306 | 29 | </data> | ||
2307 | 30 | </openerp> | ||
2308 | 0 | 31 | ||
2309 | === added file 'account_credit_control_dunning_fees/view/policy_view.xml' | |||
2310 | --- account_credit_control_dunning_fees/view/policy_view.xml 1970-01-01 00:00:00 +0000 | |||
2311 | +++ account_credit_control_dunning_fees/view/policy_view.xml 2014-06-24 12:34:19 +0000 | |||
2312 | @@ -0,0 +1,26 @@ | |||
2313 | 1 | <?xml version="1.0" encoding="utf-8"?> | ||
2314 | 2 | <openerp> | ||
2315 | 3 | <data> | ||
2316 | 4 | <record id="add_dunning_fees_on_policy" model="ir.ui.view"> | ||
2317 | 5 | <field name="name">add dunning fees on policy</field> | ||
2318 | 6 | <field name="model">credit.control.policy</field> | ||
2319 | 7 | <field name="inherit_id" ref="account_credit_control.credit_control_policy_form" /> | ||
2320 | 8 | <field name="arch" type="xml"> | ||
2321 | 9 | <page string="Mail and reporting" position="after"> | ||
2322 | 10 | <page string="Fees"> | ||
2323 | 11 | <group> | ||
2324 | 12 | <group> | ||
2325 | 13 | <field name="dunning_fixed_amount"/> | ||
2326 | 14 | <field name="dunning_product_id" | ||
2327 | 15 | attrs="{'required': [('dunning_fixed_amount', '!=', False)]}"/> | ||
2328 | 16 | <field name="dunning_currency_id" | ||
2329 | 17 | attrs="{'required': [('dunning_fixed_amount', '!=', False)]}"/> | ||
2330 | 18 | </group> | ||
2331 | 19 | </group> | ||
2332 | 20 | </page> | ||
2333 | 21 | </page> | ||
2334 | 22 | </field> | ||
2335 | 23 | </record> | ||
2336 | 24 | |||
2337 | 25 | </data> | ||
2338 | 26 | </openerp> | ||
2339 | 0 | 27 | ||
2340 | === modified file 'async_move_line_importer/model/move_line_importer.py' | |||
2341 | --- async_move_line_importer/model/move_line_importer.py 2013-11-01 10:54:13 +0000 | |||
2342 | +++ async_move_line_importer/model/move_line_importer.py 2014-06-24 12:34:19 +0000 | |||
2343 | @@ -41,7 +41,7 @@ | |||
2344 | 41 | 41 | ||
2345 | 42 | It will parse the saved CSV file using orm.BaseModel.load | 42 | It will parse the saved CSV file using orm.BaseModel.load |
2346 | 43 | in a thread. If you set bypass_orm to True then the load function | 43 | in a thread. If you set bypass_orm to True then the load function |
2348 | 44 | will use a totally overriden create function that is a lot faster | 44 | will use a totally overridden create function that is a lot faster |
2349 | 45 | but that totally bypass the ORM | 45 | but that totally bypass the ORM |
2350 | 46 | 46 | ||
2351 | 47 | """ | 47 | """ |
2352 | @@ -303,7 +303,7 @@ | |||
2353 | 303 | Will generate an success/failure report and generate some | 303 | Will generate an success/failure report and generate some |
2354 | 304 | maile threads. It uses BaseModel.load to lookup CSV. | 304 | maile threads. It uses BaseModel.load to lookup CSV. |
2355 | 305 | If you set bypass_orm to True then the load function | 305 | If you set bypass_orm to True then the load function |
2357 | 306 | will use a totally overriden create function that is a lot faster | 306 | will use a totally overridden create function that is a lot faster |
2358 | 307 | but that totally bypass the ORM | 307 | but that totally bypass the ORM |
2359 | 308 | 308 | ||
2360 | 309 | """ | 309 | """ |
Thanks Nicolas. A few small remarks up to line 1300:
- l138 typo pop('field_ name', None) ) overriden" -> manually_overridden
- l143 seems like you are copying twice
- l145 (non-blocking) i'm not sure if it's better to set a key to false or remove a key from defaults (like in defaults.
- "manually_
- l438 "that policy correspond" -> "that the policy corresponds"
- l445 slightly more readable if "if" goes to the next line
- l1013 line -> lines