Merge lp:~atin81/account-financial-tools/account-financial-tools into lp:~account-core-editors/account-financial-tools/6.1
- account-financial-tools
- Merge into 6.1
Proposed by
Agustín
Status: | Merged |
---|---|
Approved by: | Yannick Vaucher @ Camptocamp |
Approved revision: | 105 |
Merged at revision: | 107 |
Proposed branch: | lp:~atin81/account-financial-tools/account-financial-tools |
Merge into: | lp:~account-core-editors/account-financial-tools/6.1 |
Diff against target: |
1110 lines (+349/-293) 5 files modified
currency_rate_update/__init__.py (+30/-26) currency_rate_update/__openerp__.py (+46/-41) currency_rate_update/company.py (+66/-68) currency_rate_update/currency_rate_update.py (+204/-155) currency_rate_update/currency_rate_update.xml (+3/-3) |
To merge this branch: | bzr merge lp:~atin81/account-financial-tools/account-financial-tools |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Yannick Vaucher @ Camptocamp | code review, no tests | Approve | |
Omar (Pexego) | code review | Approve | |
Guewen Baconnier @ Camptocamp | code review | Approve | |
Nicolas Bessi - Camptocamp (community) | code review, no tests | Needs Fixing | |
Moisés López - http://www.vauxoo.com | Pending | ||
Review via email: mp+183064@code.launchpad.net |
Commit message
I have corrected the comments you done, please review it and let me know if there is anything else needed for merge it.
Description of the change
Implemented feature for auto update currency exchange using Banxico information for USD & MXN
To post a comment you must log in.
Revision history for this message
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote : | # |
review:
Needs Fixing
(code review, no tests)
- 105. By Agustin Cruz <email address hidden>
-
Corrected Nicolas comments
Revision history for this message
Moisés López - http://www.vauxoo.com (moylop260) wrote : | # |
Hello @Nicolas,
FYI FIX commited
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
Notes on this module:
- the license is still GPL, should be moved to AGPL.
- A cleaning should be done (propagation of context is missing, weird constructions or idioms).
That's not the matter of this MP though, so I approve.
Thanks.
review:
Approve
(code review)
Revision history for this message
Omar (Pexego) (omar7r) wrote : | # |
LGTM
review:
Approve
(code review)
Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote : | # |
Ola
+1 about Guewen comment
So I approve this MP for the feature addition for 'banco de mexico'
Cheers
review:
Approve
(code review, no tests)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'currency_rate_update/__init__.py' (properties changed: +x to -x) | |||
2 | --- currency_rate_update/__init__.py 2011-08-12 12:35:23 +0000 | |||
3 | +++ currency_rate_update/__init__.py 2013-09-17 18:13:12 +0000 | |||
4 | @@ -1,33 +1,37 @@ | |||
5 | 1 | ############################################################################## | 1 | ############################################################################## |
6 | 2 | # | 2 | # |
32 | 3 | # Copyright (c) 2008 Camtocamp SA | 3 | # Copyright (c) 2008 Camtocamp SA |
33 | 4 | # @author JB Aubort, Nicolas Bessi, Joel Grand-Guillaume | 4 | # @author JB Aubort, Nicolas Bessi, Joel Grand-Guillaume |
34 | 5 | # European Central Bank and Polish National Bank invented by Grzegorz Grzelak | 5 | # European Central Bank and Polish National Bank invented by Grzegorz Grzelak |
35 | 6 | # $Id: $ | 6 | # Banxico implemented by Agustin Cruz openpyme.mx |
36 | 7 | # | 7 | # $Id: $ |
37 | 8 | # WARNING: This program as such is intended to be used by professional | 8 | # |
38 | 9 | # programmers who take the whole responsability of assessing all potential | 9 | # WARNING: This program as such is intended to be used by professional |
39 | 10 | # consequences resulting from its eventual inadequacies and bugs | 10 | # programmers who take the whole responsability of assessing all potential |
40 | 11 | # End users who are looking for a ready-to-use solution with commercial | 11 | # consequences resulting from its eventual inadequacies and bugs |
41 | 12 | # garantees and support are strongly adviced to contract a Free Software | 12 | # End users who are looking for a ready-to-use solution with commercial |
42 | 13 | # Service Company | 13 | # garantees and support are strongly adviced to contract a Free Software |
43 | 14 | # | 14 | # Service Company |
44 | 15 | # This program is Free Software; you can redistribute it and/or | 15 | # |
45 | 16 | # modify it under the terms of the GNU General Public License | 16 | # This program is Free Software; you can redistribute it and/or |
46 | 17 | # as published by the Free Software Foundation; either version 2 | 17 | # modify it under the terms of the GNU General Public License |
47 | 18 | # of the License, or (at your option) any later version. | 18 | # as published by the Free Software Foundation; either version 2 |
48 | 19 | # | 19 | # of the License, or (at your option) any later version. |
49 | 20 | # This program is distributed in the hope that it will be useful, | 20 | # |
50 | 21 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 21 | # This program is free software: you can redistribute it and/or modify |
51 | 22 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 22 | # it under the terms of the GNU Affero General Public License as |
52 | 23 | # GNU General Public License for more details. | 23 | # published by the Free Software Foundation, either version 3 of the |
53 | 24 | # | 24 | # License, or (at your option) any later version. |
54 | 25 | # You should have received a copy of the GNU General Public License | 25 | # |
55 | 26 | # along with this program; if not, write to the Free Software | 26 | # This program is distributed in the hope that it will be useful, |
56 | 27 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 27 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
57 | 28 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
58 | 29 | # GNU Affero General Public License for more details. | ||
59 | 30 | # | ||
60 | 31 | # You should have received a copy of the GNU Affero General Public License | ||
61 | 32 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
62 | 28 | # | 33 | # |
63 | 29 | ############################################################################## | 34 | ############################################################################## |
64 | 30 | |||
65 | 31 | import currency_rate_update | 35 | import currency_rate_update |
66 | 32 | import company | 36 | import company |
67 | 33 | import wizard | 37 | import wizard |
68 | 34 | 38 | ||
69 | === modified file 'currency_rate_update/__openerp__.py' (properties changed: +x to -x) | |||
70 | --- currency_rate_update/__openerp__.py 2012-07-31 14:29:55 +0000 | |||
71 | +++ currency_rate_update/__openerp__.py 2013-09-17 18:13:12 +0000 | |||
72 | @@ -1,30 +1,35 @@ | |||
73 | 1 | ############################################################################## | 1 | ############################################################################## |
74 | 2 | # | 2 | # |
100 | 3 | # Copyright (c) 2008 Camtocamp SA | 3 | # Copyright (c) 2008 Camtocamp SA |
101 | 4 | # @author JB Aubort, Nicolas Bessi, Joel Grand-Guillaume | 4 | # @author JB Aubort, Nicolas Bessi, Joel Grand-Guillaume |
102 | 5 | # European Central Bank and Polish National Bank invented by Grzegorz Grzelak | 5 | # European Central Bank and Polish National Bank invented by Grzegorz Grzelak |
103 | 6 | # $Id: $ | 6 | # Banxico implemented by Agustin Cruz openpyme.mx |
104 | 7 | # | 7 | # $Id: $ |
105 | 8 | # WARNING: This program as such is intended to be used by professional | 8 | # |
106 | 9 | # programmers who take the whole responsability of assessing all potential | 9 | # WARNING: This program as such is intended to be used by professional |
107 | 10 | # consequences resulting from its eventual inadequacies and bugs | 10 | # programmers who take the whole responsability of assessing all potential |
108 | 11 | # End users who are looking for a ready-to-use solution with commercial | 11 | # consequences resulting from its eventual inadequacies and bugs |
109 | 12 | # garantees and support are strongly adviced to contract a Free Software | 12 | # End users who are looking for a ready-to-use solution with commercial |
110 | 13 | # Service Company | 13 | # garantees and support are strongly adviced to contract a Free Software |
111 | 14 | # | 14 | # Service Company |
112 | 15 | # This program is Free Software; you can redistribute it and/or | 15 | # |
113 | 16 | # modify it under the terms of the GNU General Public License | 16 | # This program is Free Software; you can redistribute it and/or |
114 | 17 | # as published by the Free Software Foundation; either version 2 | 17 | # modify it under the terms of the GNU General Public License |
115 | 18 | # of the License, or (at your option) any later version. | 18 | # as published by the Free Software Foundation; either version 2 |
116 | 19 | # | 19 | # of the License, or (at your option) any later version. |
117 | 20 | # This program is distributed in the hope that it will be useful, | 20 | # |
118 | 21 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 21 | # This program is free software: you can redistribute it and/or modify |
119 | 22 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 22 | # it under the terms of the GNU Affero General Public License as |
120 | 23 | # GNU General Public License for more details. | 23 | # published by the Free Software Foundation, either version 3 of the |
121 | 24 | # | 24 | # License, or (at your option) any later version. |
122 | 25 | # You should have received a copy of the GNU General Public License | 25 | # |
123 | 26 | # along with this program; if not, write to the Free Software | 26 | # This program is distributed in the hope that it will be useful, |
124 | 27 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 27 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
125 | 28 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
126 | 29 | # GNU Affero General Public License for more details. | ||
127 | 30 | # | ||
128 | 31 | # You should have received a copy of the GNU Affero General Public License | ||
129 | 32 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
130 | 28 | # | 33 | # |
131 | 29 | ############################################################################## | 34 | ############################################################################## |
132 | 30 | { | 35 | { |
133 | @@ -33,9 +38,8 @@ | |||
134 | 33 | "author" : "Camptocamp", | 38 | "author" : "Camptocamp", |
135 | 34 | "website" : "http://camptocamp.com", | 39 | "website" : "http://camptocamp.com", |
136 | 35 | "category" : "Financial Management/Configuration", | 40 | "category" : "Financial Management/Configuration", |
140 | 36 | "description": """Import exchange rates from the Internet. | 41 | "description": """ |
141 | 37 | 42 | Import exchange rates from three different sources on the internet : | |
139 | 38 | The module is able to use 4 different sources: | ||
142 | 39 | 43 | ||
143 | 40 | 1. Admin.ch | 44 | 1. Admin.ch |
144 | 41 | Updated daily, source in CHF. | 45 | Updated daily, source in CHF. |
145 | @@ -51,36 +55,37 @@ | |||
146 | 51 | 55 | ||
147 | 52 | 4. Polish National Bank (Narodowy Bank Polski) (contribution by Grzegorz Grzelak) | 56 | 4. Polish National Bank (Narodowy Bank Polski) (contribution by Grzegorz Grzelak) |
148 | 53 | Takes official rates from www.nbp.pl. Adds rate table symbol in log. | 57 | Takes official rates from www.nbp.pl. Adds rate table symbol in log. |
151 | 54 | You should check when rates should apply to bookkeeping. If next day you should | 58 | You should check when rates should apply to bookkeeping. If next day you should |
152 | 55 | change the update hour in schedule settings because in OpenERP they apply from | 59 | change the update hour in schedule settings because in OpenERP they apply from |
153 | 56 | date of update (date - no hours). | 60 | date of update (date - no hours). |
154 | 61 | |||
155 | 62 | 5. Banxico for USD & MXN (created by Agustín Cruz) | ||
156 | 63 | Updated daily | ||
157 | 57 | 64 | ||
158 | 58 | In the roadmap : Google Finance. | 65 | In the roadmap : Google Finance. |
159 | 59 | Updated daily from Citibank N.A., source in EUR. Information may be delayed. | 66 | Updated daily from Citibank N.A., source in EUR. Information may be delayed. |
160 | 60 | This is parsed from an HTML page, so it may be broken at anytime. | 67 | This is parsed from an HTML page, so it may be broken at anytime. |
161 | 61 | 68 | ||
163 | 62 | The update can be set under the company form. | 69 | The update can be set under de company form. |
164 | 63 | You can set for each services which currency you want to update. | 70 | You can set for each services which currency you want to update. |
166 | 64 | The logs of the update are visible under the service note. | 71 | The log of the update are visible under the service note. |
167 | 65 | You can active or deactivate the update. | 72 | You can active or deactivate the update. |
168 | 66 | The module uses internal ir_cron feature from OpenERP, so the job is launched once | 73 | The module uses internal ir_cron feature from OpenERP, so the job is launched once |
169 | 67 | the server starts if the 'first execute date' is before the current day. | 74 | the server starts if the 'first execute date' is before the current day. |
173 | 68 | The module supports multi-company currency in two ways: | 75 | The module supports multi-company currency in two way : |
174 | 69 | 76 | the currencies are shared, you can set currency update only on one | |
172 | 70 | * the currencies are shared, you can set currency update only on one | ||
175 | 71 | company | 77 | company |
177 | 72 | * the currency are separated, you can set currency on every company | 78 | the currency are separated, you can set currency on every company |
178 | 73 | separately | 79 | separately |
181 | 74 | 80 | A function field let you know your currency configuration. | |
180 | 75 | A function field lets you know your currency configuration. | ||
182 | 76 | 81 | ||
183 | 77 | If in multi-company mode, the base currency will be the first company's currency | 82 | If in multi-company mode, the base currency will be the first company's currency |
184 | 78 | found in database. | 83 | found in database. |
185 | 79 | 84 | ||
187 | 80 | Thanks to main contributors: Grzegorz Grzelak, Alexis de Lattre | 85 | |
188 | 86 | Special thanks and contribs to other Main contributor: Grzegorz Grzelak, Alexis de Lattre | ||
189 | 81 | """, | 87 | """, |
192 | 82 | "depends" : ["base", | 88 | "depends" : ["base", "account"], |
191 | 83 | "account"], #Added to ensure account security groups are present | ||
193 | 84 | "init_xml" : ["security/security.xml"], | 89 | "init_xml" : ["security/security.xml"], |
194 | 85 | "update_xml" : [ | 90 | "update_xml" : [ |
195 | 86 | "currency_rate_update.xml", | 91 | "currency_rate_update.xml", |
196 | 87 | 92 | ||
197 | === modified file 'currency_rate_update/company.py' | |||
198 | --- currency_rate_update/company.py 2012-02-03 13:53:02 +0000 | |||
199 | +++ currency_rate_update/company.py 2013-09-17 18:13:12 +0000 | |||
200 | @@ -1,50 +1,48 @@ | |||
201 | 1 | # -*- encoding: utf-8 -*- | 1 | # -*- encoding: utf-8 -*- |
202 | 2 | # company.py | 2 | # company.py |
203 | 3 | # c2c_currency_update | 3 | # c2c_currency_update |
205 | 4 | # @author Nicolas Bessi | 4 | # @author Nicolas Bessi |
206 | 5 | # Copyright (c) 2009 CamptoCamp. All rights reserved. | 5 | # Copyright (c) 2009 CamptoCamp. All rights reserved. |
229 | 6 | ############################################################################## | 6 | # |
230 | 7 | # | 7 | # WARNING: This program as such is intended to be used by professional |
231 | 8 | # WARNING: This program as such is intended to be used by professional | 8 | # programmers who take the whole responsability of assessing all potential |
232 | 9 | # programmers who take the whole responsability of assessing all potential | 9 | # consequences resulting from its eventual inadequacies and bugs |
233 | 10 | # consequences resulting from its eventual inadequacies and bugs | 10 | # End users who are looking for a ready-to-use solution with commercial |
234 | 11 | # End users who are looking for a ready-to-use solution with commercial | 11 | # garantees and support are strongly adviced to contract a Free Software |
235 | 12 | # garantees and support are strongly adviced to contract a Free Software | 12 | # Service Company |
236 | 13 | # Service Company | 13 | # |
237 | 14 | # | 14 | # This program is free software: you can redistribute it and/or modify |
238 | 15 | # This program is Free Software; you can redistribute it and/or | 15 | # it under the terms of the GNU Affero General Public License as |
239 | 16 | # modify it under the terms of the GNU General Public License | 16 | # published by the Free Software Foundation, either version 3 of the |
240 | 17 | # as published by the Free Software Foundation; either version 2 | 17 | # License, or (at your option) any later version. |
241 | 18 | # of the License, or (at your option) any later version. | 18 | # |
242 | 19 | # | 19 | # This program is distributed in the hope that it will be useful, |
243 | 20 | # This program is distributed in the hope that it will be useful, | 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
244 | 21 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
245 | 22 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 22 | # GNU Affero General Public License for more details. |
246 | 23 | # GNU General Public License for more details. | 23 | # |
247 | 24 | # | 24 | # You should have received a copy of the GNU Affero General Public License |
248 | 25 | # You should have received a copy of the GNU General Public License | 25 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
227 | 26 | # along with this program; if not, write to the Free Software | ||
228 | 27 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
249 | 28 | # | 26 | # |
250 | 29 | ############################################################################## | 27 | ############################################################################## |
251 | 30 | 28 | ||
252 | 31 | import netsvc | 29 | import netsvc |
253 | 32 | from osv import fields, osv | 30 | from osv import fields, osv |
254 | 33 | class res_company(osv.osv): | 31 | class res_company(osv.osv): |
257 | 34 | """override company to add currency update""" | 32 | """Override company to add currency update""" |
258 | 35 | 33 | ||
259 | 36 | def _multi_curr_enable(self, cr, uid, ids, field_name, arg, context={}): | 34 | def _multi_curr_enable(self, cr, uid, ids, field_name, arg, context={}): |
260 | 37 | "check if multi company currency is enabled" | 35 | "check if multi company currency is enabled" |
261 | 38 | result = {} | 36 | result = {} |
263 | 39 | if self.pool.get('ir.model.fields').search(cr, uid, [('name', '=', 'company_id'), ('model', '=', 'res.currency')])==[]: | 37 | if self.pool.get('ir.model.fields').search(cr, uid, [('name', '=', 'company_id'), ('model', '=', 'res.currency')]) == []: |
264 | 40 | enable = 0 | 38 | enable = 0 |
265 | 41 | else: | 39 | else: |
266 | 42 | enable = 1 | 40 | enable = 1 |
267 | 43 | for id in ids: | 41 | for id in ids: |
268 | 44 | result[id] = enable | 42 | result[id] = enable |
269 | 45 | return result | 43 | return result |
272 | 46 | 44 | ||
273 | 47 | 45 | ||
274 | 48 | def button_refresh_currency(self, cr, uid, ids, context=None): | 46 | def button_refresh_currency(self, cr, uid, ids, context=None): |
275 | 49 | """Refrech the currency !!for all the company | 47 | """Refrech the currency !!for all the company |
276 | 50 | now""" | 48 | now""" |
277 | @@ -54,8 +52,8 @@ | |||
278 | 54 | except Exception, e: | 52 | except Exception, e: |
279 | 55 | return False | 53 | return False |
280 | 56 | return True | 54 | return True |
283 | 57 | 55 | ||
284 | 58 | 56 | ||
285 | 59 | def on_change_auto_currency_up(self, cr, uid, id, value): | 57 | def on_change_auto_currency_up(self, cr, uid, id, value): |
286 | 60 | """handle the activation of the currecny update on compagnies. | 58 | """handle the activation of the currecny update on compagnies. |
287 | 61 | There are two ways of implementing multi_company currency, | 59 | There are two ways of implementing multi_company currency, |
288 | @@ -65,24 +63,24 @@ | |||
289 | 65 | object running. | 63 | object running. |
290 | 66 | If yours currency are not share you will be able to activate the | 64 | If yours currency are not share you will be able to activate the |
291 | 67 | auto update on each separated company""" | 65 | auto update on each separated company""" |
293 | 68 | 66 | ||
294 | 69 | if len(id) : | 67 | if len(id) : |
295 | 70 | id = id[0] | 68 | id = id[0] |
296 | 71 | else : | 69 | else : |
297 | 72 | return {} | 70 | return {} |
298 | 73 | enable = self.browse(cr, uid, id).multi_company_currency_enable | 71 | enable = self.browse(cr, uid, id).multi_company_currency_enable |
300 | 74 | compagnies = self.search(cr, uid, []) | 72 | compagnies = self.search(cr, uid, []) |
301 | 75 | activate_cron = 'f' | 73 | activate_cron = 'f' |
302 | 76 | if not value : | 74 | if not value : |
303 | 77 | # this statement is here beacaus we do no want to save in case of error | 75 | # this statement is here beacaus we do no want to save in case of error |
305 | 78 | self.write(cr, uid, id,{'auto_currency_up':value}) | 76 | self.write(cr, uid, id, {'auto_currency_up':value}) |
306 | 79 | for comp in compagnies : | 77 | for comp in compagnies : |
308 | 80 | if self.browse(cr, uid, comp).auto_currency_up: | 78 | if self.browse(cr, uid, comp).auto_currency_up: |
309 | 81 | activate_cron = 't' | 79 | activate_cron = 't' |
310 | 82 | break | 80 | break |
311 | 83 | self.pool.get('currency.rate.update').save_cron( | 81 | self.pool.get('currency.rate.update').save_cron( |
314 | 84 | cr, | 82 | cr, |
315 | 85 | uid, | 83 | uid, |
316 | 86 | {'active':activate_cron} | 84 | {'active':activate_cron} |
317 | 87 | ) | 85 | ) |
318 | 88 | return {} | 86 | return {} |
319 | @@ -90,75 +88,75 @@ | |||
320 | 90 | for comp in compagnies : | 88 | for comp in compagnies : |
321 | 91 | if comp != id and not enable: | 89 | if comp != id and not enable: |
322 | 92 | if self.browse(cr, uid, comp).multi_company_currency_enable: | 90 | if self.browse(cr, uid, comp).multi_company_currency_enable: |
325 | 93 | #we ensure taht we did not have write a true value | 91 | # we ensure taht we did not have write a true value |
326 | 94 | self.write(cr, uid, id,{'auto_currency_up':False}) | 92 | self.write(cr, uid, id, {'auto_currency_up':False}) |
327 | 95 | return { | 93 | return { |
329 | 96 | 'value':{ | 94 | 'value':{ |
330 | 97 | 'auto_currency_up':False | 95 | 'auto_currency_up':False |
331 | 98 | }, | 96 | }, |
333 | 99 | 97 | ||
334 | 100 | 'warning':{ | 98 | 'warning':{ |
335 | 101 | 'title':"Warning", | 99 | 'title':"Warning", |
338 | 102 | 'message': 'Yon can not activate auto currency '+\ | 100 | 'message': 'Yon can not activate auto currency ' + \ |
339 | 103 | 'update on more thant one company with this '+ | 101 | 'update on more thant one company with this ' + |
340 | 104 | 'multi company configuration' | 102 | 'multi company configuration' |
341 | 105 | } | 103 | } |
342 | 106 | } | 104 | } |
344 | 107 | self.write(cr, uid, id,{'auto_currency_up':value}) | 105 | self.write(cr, uid, id, {'auto_currency_up':value}) |
345 | 108 | for comp in compagnies : | 106 | for comp in compagnies : |
347 | 109 | if self.browse(cr, uid, comp).auto_currency_up: | 107 | if self.browse(cr, uid, comp).auto_currency_up: |
348 | 110 | activate_cron = 't' | 108 | activate_cron = 't' |
349 | 111 | self.pool.get('currency.rate.update').save_cron( | 109 | self.pool.get('currency.rate.update').save_cron( |
352 | 112 | cr, | 110 | cr, |
353 | 113 | uid, | 111 | uid, |
354 | 114 | {'active':activate_cron} | 112 | {'active':activate_cron} |
355 | 115 | ) | 113 | ) |
356 | 116 | break | 114 | break |
357 | 117 | return {} | 115 | return {} |
360 | 118 | 116 | ||
361 | 119 | 117 | ||
362 | 120 | def on_change_intervall(self, cr, uid, id, interval) : | 118 | def on_change_intervall(self, cr, uid, id, interval) : |
365 | 121 | ###Function that will update the cron | 119 | # ##Function that will update the cron |
366 | 122 | ###freqeuence | 120 | # ##freqeuence |
367 | 123 | self.pool.get('currency.rate.update').save_cron( | 121 | self.pool.get('currency.rate.update').save_cron( |
370 | 124 | cr, | 122 | cr, |
371 | 125 | uid, | 123 | uid, |
372 | 126 | {'interval_type':interval} | 124 | {'interval_type':interval} |
373 | 127 | ) | 125 | ) |
375 | 128 | compagnies = self.search(cr, uid, []) | 126 | compagnies = self.search(cr, uid, []) |
376 | 129 | for comp in compagnies : | 127 | for comp in compagnies : |
378 | 130 | self.write(cr, uid, comp,{'interval_type':interval}) | 128 | self.write(cr, uid, comp, {'interval_type':interval}) |
379 | 131 | return {} | 129 | return {} |
381 | 132 | 130 | ||
382 | 133 | _inherit = "res.company" | 131 | _inherit = "res.company" |
383 | 134 | _columns = { | 132 | _columns = { |
385 | 135 | ### activate the currency update | 133 | # ## activate the currency update |
386 | 136 | 'auto_currency_up': fields.boolean('Automatical update of the currency this company'), | 134 | 'auto_currency_up': fields.boolean('Automatical update of the currency this company'), |
387 | 137 | 'services_to_use' : fields.one2many( | 135 | 'services_to_use' : fields.one2many( |
389 | 138 | 'currency.rate.update.service', | 136 | 'currency.rate.update.service', |
390 | 139 | 'company_id', | 137 | 'company_id', |
392 | 140 | 'Currency update services' | 138 | 'Currency update services' |
393 | 141 | ), | 139 | ), |
395 | 142 | ###predifine cron frequence | 140 | # ##predifine cron frequence |
396 | 143 | 'interval_type': fields.selection( | 141 | 'interval_type': fields.selection( |
397 | 144 | [ | 142 | [ |
400 | 145 | ('days','Day(s)'), | 143 | ('days', 'Day(s)'), |
401 | 146 | ('weeks', 'Week(s)'), | 144 | ('weeks', 'Week(s)'), |
402 | 147 | ('months', 'Month(s)') | 145 | ('months', 'Month(s)') |
403 | 148 | ], | 146 | ], |
404 | 149 | 'Currency update frequence', | 147 | 'Currency update frequence', |
405 | 150 | help="""changing this value will | 148 | help="""changing this value will |
406 | 151 | also affect other compagnies""" | 149 | also affect other compagnies""" |
407 | 152 | ), | 150 | ), |
410 | 153 | ###function field that allows to know the | 151 | # ##function field that allows to know the |
411 | 154 | ###mutli company currency implementation | 152 | # ##mutli company currency implementation |
412 | 155 | 'multi_company_currency_enable' : fields.function( | 153 | 'multi_company_currency_enable' : fields.function( |
416 | 156 | _multi_curr_enable, | 154 | _multi_curr_enable, |
417 | 157 | method=True, | 155 | method=True, |
418 | 158 | type='boolean', | 156 | type='boolean', |
419 | 159 | string="Multi company currency", | 157 | string="Multi company currency", |
421 | 160 | help='if this case is not check you can'+\ | 158 | help='if this case is not check you can' + \ |
422 | 161 | ' not set currency is active on two company' | 159 | ' not set currency is active on two company' |
423 | 162 | ), | 160 | ), |
425 | 163 | } | 161 | } |
426 | 164 | res_company() | 162 | res_company() |
427 | 165 | 163 | ||
428 | === modified file 'currency_rate_update/company_view.xml' (properties changed: +x to -x) | |||
429 | === modified file 'currency_rate_update/currency_rate_update.py' (properties changed: +x to -x) | |||
430 | --- currency_rate_update/currency_rate_update.py 2012-04-23 12:19:50 +0000 | |||
431 | +++ currency_rate_update/currency_rate_update.py 2013-09-17 18:13:12 +0000 | |||
432 | @@ -2,8 +2,8 @@ | |||
433 | 2 | ############################################################################## | 2 | ############################################################################## |
434 | 3 | # | 3 | # |
435 | 4 | # Copyright (c) 2009 Camptocamp SA | 4 | # Copyright (c) 2009 Camptocamp SA |
438 | 5 | # @author Nicolas Bessi | 5 | # @author Nicolas Bessi |
439 | 6 | # @source JBA and AWST inpiration | 6 | # @source JBA and AWST inpiration |
440 | 7 | # @contributor Grzegorz Grzelak (grzegorz.grzelak@birdglobe.com), Joel Grand-Guillaume | 7 | # @contributor Grzegorz Grzelak (grzegorz.grzelak@birdglobe.com), Joel Grand-Guillaume |
441 | 8 | # Copyright (c) 2010 Alexis de Lattre (alexis@via.ecp.fr) | 8 | # Copyright (c) 2010 Alexis de Lattre (alexis@via.ecp.fr) |
442 | 9 | # - ported XML-based webservices (Admin.ch, ECB, PL NBP) to new XML lib | 9 | # - ported XML-based webservices (Admin.ch, ECB, PL NBP) to new XML lib |
443 | @@ -54,20 +54,19 @@ | |||
444 | 54 | _name = "currency.rate.update.service" | 54 | _name = "currency.rate.update.service" |
445 | 55 | _description = "Currency Rate Update" | 55 | _description = "Currency Rate Update" |
446 | 56 | _columns = { | 56 | _columns = { |
449 | 57 | ##list of webservicies the value sould be a class name | 57 | # #list of webservicies the value sould be a class name |
450 | 58 | 'service' : fields.selection( | 58 | 'service' : fields.selection( |
451 | 59 | [ | 59 | [ |
458 | 60 | ('Admin_ch_getter','Admin.ch'), | 60 | ('Admin_ch_getter', 'Admin.ch'), |
459 | 61 | ('ECB_getter','European Central Bank'), | 61 | ('ECB_getter', 'European Central Bank'), |
460 | 62 | #('NYFB_getter','Federal Reserve Bank of NY'), | 62 | ('Yahoo_getter', 'Yahoo Finance '), |
461 | 63 | #('Google_getter','Google Finance'), | 63 | ('PL_NBP_getter', 'Narodowy Bank Polski'), # Added for polish rates |
462 | 64 | ('Yahoo_getter','Yahoo Finance '), | 64 | ('Banxico_getter', 'Banco de México'), # Added for mexican rates |
457 | 65 | ('PL_NBP_getter','Narodowy Bank Polski'), # Added for polish rates | ||
463 | 66 | ], | 65 | ], |
464 | 67 | "Webservice to use", | 66 | "Webservice to use", |
466 | 68 | required = True | 67 | required=True |
467 | 69 | ), | 68 | ), |
469 | 70 | ##list of currency to update | 69 | # #list of currency to update |
470 | 71 | 'currency_to_update' : fields.many2many( | 70 | 'currency_to_update' : fields.many2many( |
471 | 72 | 'res.currency', | 71 | 'res.currency', |
472 | 73 | 'res_curreny_auto_udate_rel', | 72 | 'res_curreny_auto_udate_rel', |
473 | @@ -75,12 +74,12 @@ | |||
474 | 75 | 'currency_id', | 74 | 'currency_id', |
475 | 76 | 'currency to update with this service', | 75 | 'currency to update with this service', |
476 | 77 | ), | 76 | ), |
478 | 78 | #back ref | 77 | # back ref |
479 | 79 | 'company_id' : fields.many2one( | 78 | 'company_id' : fields.many2one( |
480 | 80 | 'res.company', | 79 | 'res.company', |
481 | 81 | 'linked company', | 80 | 'linked company', |
482 | 82 | ), | 81 | ), |
484 | 83 | ##note fileds that will be used as a logger | 82 | # #note fileds that will be used as a logger |
485 | 84 | 'note':fields.text('update notice'), | 83 | 'note':fields.text('update notice'), |
486 | 85 | 'max_delta_days': fields.integer('Max delta days', required=True, help="If the time delta between the rate date given by the webservice and the current date exeeds this value, then the currency rate is not updated in OpenERP."), | 84 | 'max_delta_days': fields.integer('Max delta days', required=True, help="If the time delta between the rate date given by the webservice and the current date exeeds this value, then the currency rate is not updated in OpenERP."), |
487 | 86 | } | 85 | } |
488 | @@ -89,8 +88,8 @@ | |||
489 | 89 | } | 88 | } |
490 | 90 | _sql_constraints = [ | 89 | _sql_constraints = [ |
491 | 91 | ( | 90 | ( |
494 | 92 | 'curr_service_unique', | 91 | 'curr_service_unique', |
495 | 93 | 'unique (service, company_id)', | 92 | 'unique (service, company_id)', |
496 | 94 | _('You can use a service one time per company !') | 93 | _('You can use a service one time per company !') |
497 | 95 | ) | 94 | ) |
498 | 96 | ] | 95 | ] |
499 | @@ -114,63 +113,63 @@ | |||
500 | 114 | update currencies based on a web url""" | 113 | update currencies based on a web url""" |
501 | 115 | _name = "currency.rate.update" | 114 | _name = "currency.rate.update" |
502 | 116 | _description = "Currency Rate Update" | 115 | _description = "Currency Rate Update" |
504 | 117 | ##dict that represent a cron object | 116 | # #dict that represent a cron object |
505 | 118 | cron = { | 117 | cron = { |
506 | 119 | 'active' : False, | 118 | 'active' : False, |
507 | 120 | 'priority' : 1, | 119 | 'priority' : 1, |
508 | 121 | 'interval_number' : 1, | 120 | 'interval_number' : 1, |
509 | 122 | 'interval_type' : 'weeks', | 121 | 'interval_type' : 'weeks', |
512 | 123 | 'nextcall' : time.strftime("%Y-%m-%d %H:%M:%S", (datetime.today() + timedelta(days=1)).timetuple() ), #tomorrow same time | 122 | 'nextcall' : time.strftime("%Y-%m-%d %H:%M:%S", (datetime.today() + timedelta(days=1)).timetuple()), # tomorrow same time |
513 | 124 | 'numbercall' : -1, | 123 | 'numbercall' :-1, |
514 | 125 | 'doall' : True, | 124 | 'doall' : True, |
515 | 126 | 'model' : 'currency.rate.update', | 125 | 'model' : 'currency.rate.update', |
516 | 127 | 'function' : 'run_currency_update', | 126 | 'function' : 'run_currency_update', |
518 | 128 | 'args' : '()', | 127 | 'args' : '()', |
519 | 129 | } | 128 | } |
522 | 130 | 129 | ||
523 | 131 | logger = netsvc.Logger() | 130 | logger = logging.getLogger(__name__) |
524 | 132 | LOG_NAME = 'cron-rates' | 131 | LOG_NAME = 'cron-rates' |
526 | 133 | MOD_NAME = 'c2c_currency_rate_update: ' | 132 | MOD_NAME = 'currency_rate_update: ' |
527 | 134 | def get_cron_id(self, cr, uid, context): | 133 | def get_cron_id(self, cr, uid, context): |
528 | 135 | """return the updater cron's id. Create one if the cron does not exists """ | 134 | """return the updater cron's id. Create one if the cron does not exists """ |
530 | 136 | 135 | ||
531 | 137 | cron_id = 0 | 136 | cron_id = 0 |
532 | 138 | cron_obj = self.pool.get('ir.cron') | 137 | cron_obj = self.pool.get('ir.cron') |
535 | 139 | try: | 138 | try: |
536 | 140 | #find the cron that send messages | 139 | # find the cron that send messages |
537 | 141 | cron_id = cron_obj.search( | 140 | cron_id = cron_obj.search( |
540 | 142 | cr, | 141 | cr, |
541 | 143 | uid, | 142 | uid, |
542 | 144 | [ | 143 | [ |
544 | 145 | ('function', 'ilike', self.cron['function']), | 144 | ('function', 'ilike', self.cron['function']), |
545 | 146 | ('model', 'ilike', self.cron['model']) | 145 | ('model', 'ilike', self.cron['model']) |
547 | 147 | ], | 146 | ], |
548 | 148 | context={ | 147 | context={ |
549 | 149 | 'active_test': False | 148 | 'active_test': False |
551 | 150 | } | 149 | } |
552 | 151 | ) | 150 | ) |
553 | 152 | cron_id = int(cron_id[0]) | 151 | cron_id = int(cron_id[0]) |
555 | 153 | except Exception,e : | 152 | except Exception, e : |
556 | 154 | self.logger.notifyChannel( | 153 | self.logger.notifyChannel( |
559 | 155 | self.LOG_NAME, | 154 | self.LOG_NAME, |
560 | 156 | netsvc.LOG_INFO, | 155 | netsvc.LOG_INFO, |
561 | 157 | 'warning cron not found one will be created' | 156 | 'warning cron not found one will be created' |
562 | 158 | ) | 157 | ) |
566 | 159 | pass # ignore if the cron is missing cause we are going to create it in db | 158 | pass # ignore if the cron is missing cause we are going to create it in db |
567 | 160 | 159 | ||
568 | 161 | #the cron does not exists | 160 | # the cron does not exists |
569 | 162 | if not cron_id : | 161 | if not cron_id : |
571 | 163 | #translate | 162 | # translate |
572 | 164 | self.cron['name'] = _('Currency Rate Update') | 163 | self.cron['name'] = _('Currency Rate Update') |
573 | 165 | cron_id = cron_obj.create(cr, uid, self.cron, context) | 164 | cron_id = cron_obj.create(cr, uid, self.cron, context) |
575 | 166 | 165 | ||
576 | 167 | return cron_id | 166 | return cron_id |
578 | 168 | 167 | ||
579 | 169 | def save_cron(self, cr, uid, datas, context={}): | 168 | def save_cron(self, cr, uid, datas, context={}): |
580 | 170 | """save the cron config data should be a dict""" | 169 | """save the cron config data should be a dict""" |
584 | 171 | #modify the cron | 170 | # modify the cron |
585 | 172 | cron_id = self.get_cron_id(cr, uid, context) | 171 | cron_id = self.get_cron_id(cr, uid, context) |
586 | 173 | result = self.pool.get('ir.cron').write(cr, uid, [cron_id], datas) | 172 | result = self.pool.get('ir.cron').write(cr, uid, [cron_id], datas) |
587 | 174 | 173 | ||
588 | 175 | def run_currency_update(self, cr, uid): | 174 | def run_currency_update(self, cr, uid): |
589 | 176 | "update currency at the given frequence" | 175 | "update currency at the given frequence" |
590 | @@ -179,24 +178,24 @@ | |||
591 | 179 | rate_obj = self.pool.get('res.currency.rate') | 178 | rate_obj = self.pool.get('res.currency.rate') |
592 | 180 | companies = self.pool.get('res.company').search(cr, uid, []) | 179 | companies = self.pool.get('res.company').search(cr, uid, []) |
593 | 181 | for comp in self.pool.get('res.company').browse(cr, uid, companies): | 180 | for comp in self.pool.get('res.company').browse(cr, uid, companies): |
596 | 182 | ##the multi company currency can beset or no so we handle | 181 | # #the multi company currency can beset or no so we handle |
597 | 183 | ##the two case | 182 | # #the two case |
598 | 184 | if not comp.auto_currency_up : | 183 | if not comp.auto_currency_up : |
599 | 185 | continue | 184 | continue |
601 | 186 | #we initialise the multi compnay search filter or not serach filter | 185 | # we initialise the multi compnay search filter or not serach filter |
602 | 187 | search_filter = [] | 186 | search_filter = [] |
603 | 188 | if comp.multi_company_currency_enable : | 187 | if comp.multi_company_currency_enable : |
606 | 189 | search_filter = [('company_id','=',comp.id)] | 188 | search_filter = [('company_id', '=', comp.id)] |
607 | 190 | #we fetch the main currency. The main rate should be set at 1.00 | 189 | # we fetch the main currency. The main rate should be set at 1.00 |
608 | 191 | main_curr = comp.currency_id.name | 190 | main_curr = comp.currency_id.name |
609 | 192 | for service in comp.services_to_use : | 191 | for service in comp.services_to_use : |
611 | 193 | print "comp.services_to_use =", comp.services_to_use | 192 | logger.debug("comp.services_to_use = %s" % (comp.services_to_use)) |
612 | 194 | note = service.note or '' | 193 | note = service.note or '' |
613 | 195 | try : | 194 | try : |
616 | 196 | ## we initalize the class that will handle the request | 195 | # # we initalize the class that will handle the request |
617 | 197 | ## and return a dict of rate | 196 | # # and return a dict of rate |
618 | 198 | getter = factory.register(service.service) | 197 | getter = factory.register(service.service) |
620 | 199 | print "getter =", getter | 198 | logger.debug("getter = %s" % (type(getter))) |
621 | 200 | curr_to_fetch = map(lambda x : x.name, service.currency_to_update) | 199 | curr_to_fetch = map(lambda x : x.name, service.currency_to_update) |
622 | 201 | res, log_info = getter.get_updated_currency(curr_to_fetch, main_curr, service.max_delta_days) | 200 | res, log_info = getter.get_updated_currency(curr_to_fetch, main_curr, service.max_delta_days) |
623 | 202 | rate_name = time.strftime('%Y-%m-%d') | 201 | rate_name = time.strftime('%Y-%m-%d') |
624 | @@ -215,27 +214,27 @@ | |||
625 | 215 | 'rate':res[curr.name], | 214 | 'rate':res[curr.name], |
626 | 216 | 'name': rate_name | 215 | 'name': rate_name |
627 | 217 | } | 216 | } |
629 | 218 | rate_obj.create( | 217 | rate_obj.create( |
630 | 219 | cr, | 218 | cr, |
631 | 220 | uid, | 219 | uid, |
632 | 221 | vals, | 220 | vals, |
633 | 222 | ) | 221 | ) |
635 | 223 | 222 | ||
636 | 224 | note = note + "\n%s currency updated. "\ | 223 | note = note + "\n%s currency updated. "\ |
638 | 225 | %(datetime.strftime(datetime.today(), '%Y-%m-%d %H:%M:%S')) | 224 | % (datetime.strftime(datetime.today(), '%Y-%m-%d %H:%M:%S')) |
639 | 226 | note = note + (log_info or '') | 225 | note = note + (log_info or '') |
640 | 227 | service.write({'note':note}) | 226 | service.write({'note':note}) |
641 | 228 | except Exception, e: | 227 | except Exception, e: |
642 | 229 | error_msg = note + "\n%s ERROR : %s"\ | 228 | error_msg = note + "\n%s ERROR : %s"\ |
644 | 230 | %(datetime.strftime(datetime.today(), '%Y-%m-%d %H:%M:%S'), str(e)) | 229 | % (datetime.strftime(datetime.today(), '%Y-%m-%d %H:%M:%S'), str(e)) |
645 | 231 | self.logger.notifyChannel(self.LOG_NAME, netsvc.LOG_INFO, str(e)) | 230 | self.logger.notifyChannel(self.LOG_NAME, netsvc.LOG_INFO, str(e)) |
646 | 232 | service.write({'note':error_msg}) | 231 | service.write({'note':error_msg}) |
649 | 233 | 232 | ||
650 | 234 | 233 | ||
651 | 235 | Currency_rate_update() | 234 | Currency_rate_update() |
652 | 236 | 235 | ||
655 | 237 | ### Error Definition as specified in python 2.6 PEP | 236 | # ## Error Definition as specified in python 2.6 PEP |
656 | 238 | class AbstractClassError(Exception): | 237 | class AbstractClassError(Exception): |
657 | 239 | def __str__(self): | 238 | def __str__(self): |
658 | 240 | return 'Abstract Class' | 239 | return 'Abstract Class' |
659 | 241 | def __repr__(self): | 240 | def __repr__(self): |
660 | @@ -247,25 +246,25 @@ | |||
661 | 247 | def __repr__(self): | 246 | def __repr__(self): |
662 | 248 | return 'Abstract Method' | 247 | return 'Abstract Method' |
663 | 249 | 248 | ||
665 | 250 | class UnknowClassError(Exception): | 249 | class UnknowClassError(Exception): |
666 | 251 | def __str__(self): | 250 | def __str__(self): |
667 | 252 | return 'Unknown Class' | 251 | return 'Unknown Class' |
668 | 253 | def __repr__(self): | 252 | def __repr__(self): |
669 | 254 | return 'Unknown Class' | 253 | return 'Unknown Class' |
671 | 255 | class UnsuportedCurrencyError(Exception): | 254 | class UnsuportedCurrencyError(Exception): |
672 | 256 | def __init__(self, value): | 255 | def __init__(self, value): |
673 | 257 | self.curr = value | 256 | self.curr = value |
674 | 258 | def __str__(self): | 257 | def __str__(self): |
676 | 259 | return 'Unsupported currency '+self.curr | 258 | return 'Unsupported currency ' + self.curr |
677 | 260 | def __repr__(self): | 259 | def __repr__(self): |
681 | 261 | return 'Unsupported currency '+self.curr | 260 | return 'Unsupported currency ' + self.curr |
682 | 262 | 261 | ||
683 | 263 | ### end of error definition | 262 | # ## end of error definition |
684 | 264 | class Currency_getter_factory(): | 263 | class Currency_getter_factory(): |
685 | 265 | """Factory pattern class that will return | 264 | """Factory pattern class that will return |
686 | 266 | a currency getter class base on the name passed | 265 | a currency getter class base on the name passed |
687 | 267 | to the register method""" | 266 | to the register method""" |
689 | 268 | def register(self, class_name): | 267 | def register(self, class_name): |
690 | 269 | allowed = [ | 268 | allowed = [ |
691 | 270 | 'Admin_ch_getter', | 269 | 'Admin_ch_getter', |
692 | 271 | 'PL_NBP_getter', | 270 | 'PL_NBP_getter', |
693 | @@ -273,66 +272,67 @@ | |||
694 | 273 | 'NYFB_getter', | 272 | 'NYFB_getter', |
695 | 274 | 'Google_getter', | 273 | 'Google_getter', |
696 | 275 | 'Yahoo_getter', | 274 | 'Yahoo_getter', |
697 | 275 | 'Banxico_getter' | ||
698 | 276 | ] | 276 | ] |
699 | 277 | if class_name in allowed: | 277 | if class_name in allowed: |
700 | 278 | class_def = eval(class_name) | 278 | class_def = eval(class_name) |
701 | 279 | return class_def() | 279 | return class_def() |
702 | 280 | else : | 280 | else : |
703 | 281 | raise UnknowClassError | 281 | raise UnknowClassError |
705 | 282 | 282 | ||
706 | 283 | 283 | ||
707 | 284 | class Curreny_getter_interface(object) : | 284 | class Curreny_getter_interface(object) : |
708 | 285 | "Abstract class of currency getter" | 285 | "Abstract class of currency getter" |
711 | 286 | 286 | ||
712 | 287 | #remove in order to have a dryer code | 287 | # remove in order to have a dryer code |
713 | 288 | # def __init__(self): | 288 | # def __init__(self): |
716 | 289 | # raise AbstractClassError | 289 | # raise AbstractClassError |
717 | 290 | 290 | ||
718 | 291 | log_info = " " | 291 | log_info = " " |
720 | 292 | 292 | ||
721 | 293 | supported_currency_array = \ | 293 | supported_currency_array = \ |
722 | 294 | ['AFN', 'ALL', 'DZD', 'USD', 'USD', 'USD', 'EUR', 'AOA', 'XCD', 'XCD', 'ARS', | 294 | ['AFN', 'ALL', 'DZD', 'USD', 'USD', 'USD', 'EUR', 'AOA', 'XCD', 'XCD', 'ARS', |
749 | 295 | 'AMD', 'AWG', 'AUD', 'EUR', 'AZN', 'EUR', 'BSD', 'BHD', 'EUR', 'BDT', 'BBD', | 295 | 'AMD', 'AWG', 'AUD', 'EUR', 'AZN', 'EUR', 'BSD', 'BHD', 'EUR', 'BDT', 'BBD', |
750 | 296 | 'XCD', 'BYR', 'EUR', 'BZD', 'XOF', 'BMD', 'BTN', 'INR', 'BOB', 'ANG', 'BAM', | 296 | 'XCD', 'BYR', 'EUR', 'BZD', 'XOF', 'BMD', 'BTN', 'INR', 'BOB', 'ANG', 'BAM', |
751 | 297 | 'BWP', 'NOK', 'BRL', 'GBP', 'USD', 'USD', 'BND', 'BGN', 'XOF', 'MMK', 'BIF', | 297 | 'BWP', 'NOK', 'BRL', 'GBP', 'USD', 'USD', 'BND', 'BGN', 'XOF', 'MMK', 'BIF', |
752 | 298 | 'XOF', 'USD', 'KHR', 'XAF', 'CAD', 'EUR', 'CVE', 'KYD', 'XAF', 'XAF', 'CLP', | 298 | 'XOF', 'USD', 'KHR', 'XAF', 'CAD', 'EUR', 'CVE', 'KYD', 'XAF', 'XAF', 'CLP', |
753 | 299 | 'CNY', 'AUD', 'AUD', 'COP', 'XAF', 'KMF', 'XPF', 'XAF', 'CDF', 'NZD', 'CRC', | 299 | 'CNY', 'AUD', 'AUD', 'COP', 'XAF', 'KMF', 'XPF', 'XAF', 'CDF', 'NZD', 'CRC', |
754 | 300 | 'HRK', 'CUP', 'ANG', 'EUR', 'CYP', 'CZK', 'DKK', 'DJF', 'XCD', 'DOP', 'EUR', | 300 | 'HRK', 'CUP', 'ANG', 'EUR', 'CYP', 'CZK', 'DKK', 'DJF', 'XCD', 'DOP', 'EUR', |
755 | 301 | 'XCD', 'IDR', 'USD', 'EGP', 'EUR', 'SVC', 'USD', 'GBP', 'XAF', 'ETB', 'ERN', | 301 | 'XCD', 'IDR', 'USD', 'EGP', 'EUR', 'SVC', 'USD', 'GBP', 'XAF', 'ETB', 'ERN', |
756 | 302 | 'EEK', 'ETB', 'EUR', 'FKP', 'DKK', 'FJD', 'EUR', 'EUR', 'EUR', 'XPF', 'XPF', | 302 | 'EEK', 'ETB', 'EUR', 'FKP', 'DKK', 'FJD', 'EUR', 'EUR', 'EUR', 'XPF', 'XPF', |
757 | 303 | 'EUR', 'XPF', 'XAF', 'GMD', 'GEL', 'EUR', 'GHS', 'GIP', 'XAU', 'GBP', 'EUR', | 303 | 'EUR', 'XPF', 'XAF', 'GMD', 'GEL', 'EUR', 'GHS', 'GIP', 'XAU', 'GBP', 'EUR', |
758 | 304 | 'DKK', 'XCD', 'XCD', 'EUR', 'USD', 'GTQ', 'GGP', 'GNF', 'XOF', 'GYD', 'HTG', | 304 | 'DKK', 'XCD', 'XCD', 'EUR', 'USD', 'GTQ', 'GGP', 'GNF', 'XOF', 'GYD', 'HTG', |
759 | 305 | 'USD', 'AUD', 'BAM', 'EUR', 'EUR', 'HNL', 'HKD', 'HUF', 'ISK', 'INR', 'IDR', | 305 | 'USD', 'AUD', 'BAM', 'EUR', 'EUR', 'HNL', 'HKD', 'HUF', 'ISK', 'INR', 'IDR', |
760 | 306 | 'XDR', 'IRR', 'IQD', 'EUR', 'IMP', 'ILS', 'EUR', 'JMD', 'NOK', 'JPY', 'JEP', | 306 | 'XDR', 'IRR', 'IQD', 'EUR', 'IMP', 'ILS', 'EUR', 'JMD', 'NOK', 'JPY', 'JEP', |
761 | 307 | 'JOD', 'KZT', 'AUD', 'KES', 'AUD', 'KPW', 'KRW', 'KWD', 'KGS', 'LAK', 'LVL', | 307 | 'JOD', 'KZT', 'AUD', 'KES', 'AUD', 'KPW', 'KRW', 'KWD', 'KGS', 'LAK', 'LVL', |
762 | 308 | 'LBP', 'LSL', 'ZAR', 'LRD', 'LYD', 'CHF', 'LTL', 'EUR', 'MOP', 'MKD', 'MGA', | 308 | 'LBP', 'LSL', 'ZAR', 'LRD', 'LYD', 'CHF', 'LTL', 'EUR', 'MOP', 'MKD', 'MGA', |
763 | 309 | 'EUR', 'MWK', 'MYR', 'MVR', 'XOF', 'EUR', 'MTL', 'FKP', 'USD', 'USD', 'EUR', | 309 | 'EUR', 'MWK', 'MYR', 'MVR', 'XOF', 'EUR', 'MTL', 'FKP', 'USD', 'USD', 'EUR', |
764 | 310 | 'MRO', 'MUR', 'EUR', 'AUD', 'MXN', 'USD', 'USD', 'EUR', 'MDL', 'EUR', 'MNT', | 310 | 'MRO', 'MUR', 'EUR', 'AUD', 'MXN', 'USD', 'USD', 'EUR', 'MDL', 'EUR', 'MNT', |
765 | 311 | 'EUR', 'XCD', 'MAD', 'MZN', 'MMK', 'NAD', 'ZAR', 'AUD', 'NPR', 'ANG', 'EUR', | 311 | 'EUR', 'XCD', 'MAD', 'MZN', 'MMK', 'NAD', 'ZAR', 'AUD', 'NPR', 'ANG', 'EUR', |
766 | 312 | 'XCD', 'XPF', 'NZD', 'NIO', 'XOF', 'NGN', 'NZD', 'AUD', 'USD', 'NOK', 'OMR', | 312 | 'XCD', 'XPF', 'NZD', 'NIO', 'XOF', 'NGN', 'NZD', 'AUD', 'USD', 'NOK', 'OMR', |
767 | 313 | 'PKR', 'USD', 'XPD', 'PAB', 'USD', 'PGK', 'PYG', 'PEN', 'PHP', 'NZD', 'XPT', | 313 | 'PKR', 'USD', 'XPD', 'PAB', 'USD', 'PGK', 'PYG', 'PEN', 'PHP', 'NZD', 'XPT', |
768 | 314 | 'PLN', 'EUR', 'STD', 'USD', 'QAR', 'EUR', 'RON', 'RUB', 'RWF', 'STD', 'ANG', | 314 | 'PLN', 'EUR', 'STD', 'USD', 'QAR', 'EUR', 'RON', 'RUB', 'RWF', 'STD', 'ANG', |
769 | 315 | 'MAD', 'XCD', 'SHP', 'XCD', 'XCD', 'EUR', 'XCD', 'EUR', 'USD', 'WST', 'EUR', | 315 | 'MAD', 'XCD', 'SHP', 'XCD', 'XCD', 'EUR', 'XCD', 'EUR', 'USD', 'WST', 'EUR', |
770 | 316 | 'SAR', 'SPL', 'XOF', 'RSD', 'SCR', 'SLL', 'XAG', 'SGD', 'ANG', 'ANG', 'EUR', | 316 | 'SAR', 'SPL', 'XOF', 'RSD', 'SCR', 'SLL', 'XAG', 'SGD', 'ANG', 'ANG', 'EUR', |
771 | 317 | 'EUR', 'SBD', 'SOS', 'ZAR', 'GBP', 'GBP', 'EUR', 'XDR', 'LKR', 'SDG', 'SRD', | 317 | 'EUR', 'SBD', 'SOS', 'ZAR', 'GBP', 'GBP', 'EUR', 'XDR', 'LKR', 'SDG', 'SRD', |
772 | 318 | 'NOK', 'SZL', 'SEK', 'CHF', 'SYP', 'TWD', 'RUB', 'TJS', 'TZS', 'THB', 'IDR', | 318 | 'NOK', 'SZL', 'SEK', 'CHF', 'SYP', 'TWD', 'RUB', 'TJS', 'TZS', 'THB', 'IDR', |
773 | 319 | 'TTD', 'XOF', 'NZD', 'TOP', 'TTD', 'TND', 'TRY', 'TMM', 'USD', 'TVD', 'UGX', | 319 | 'TTD', 'XOF', 'NZD', 'TOP', 'TTD', 'TND', 'TRY', 'TMM', 'USD', 'TVD', 'UGX', |
774 | 320 | 'UAH', 'AED', 'GBP', 'USD', 'USD', 'UYU', 'USD', 'UZS', 'VUV', 'EUR', 'VEB', | 320 | 'UAH', 'AED', 'GBP', 'USD', 'USD', 'UYU', 'USD', 'UZS', 'VUV', 'EUR', 'VEB', |
775 | 321 | 'VEF', 'VND', 'USD', 'USD', 'USD', 'XPF', 'MAD', 'YER', 'ZMK', 'ZWD'] | 321 | 'VEF', 'VND', 'USD', 'USD', 'USD', 'XPF', 'MAD', 'YER', 'ZMK', 'ZWD'] |
776 | 322 | 322 | ||
778 | 323 | ##updated currency this arry will contain the final result | 323 | # #updated currency this arry will contain the final result |
779 | 324 | updated_currency = {} | 324 | updated_currency = {} |
781 | 325 | 325 | ||
782 | 326 | def get_updated_currency(self, currency_array, main_currency, max_delta_days) : | 326 | def get_updated_currency(self, currency_array, main_currency, max_delta_days) : |
783 | 327 | """Interface method that will retrieve the currency | 327 | """Interface method that will retrieve the currency |
784 | 328 | This function has to be reinplemented in child""" | 328 | This function has to be reinplemented in child""" |
785 | 329 | raise AbstractMethodError | 329 | raise AbstractMethodError |
787 | 330 | 330 | ||
788 | 331 | def validate_cur(self, currency) : | 331 | def validate_cur(self, currency) : |
789 | 332 | """Validate if the currency to update is supported""" | 332 | """Validate if the currency to update is supported""" |
790 | 333 | if currency not in self.supported_currency_array : | 333 | if currency not in self.supported_currency_array : |
793 | 334 | raise UnsuportedCurrencyError(currency) | 334 | raise UnsuportedCurrencyError(currency) |
794 | 335 | 335 | ||
795 | 336 | def get_url(self, url): | 336 | def get_url(self, url): |
796 | 337 | """Return a string of a get url query""" | 337 | """Return a string of a get url query""" |
797 | 338 | try: | 338 | try: |
798 | @@ -342,42 +342,43 @@ | |||
799 | 342 | objfile.close() | 342 | objfile.close() |
800 | 343 | return rawfile | 343 | return rawfile |
801 | 344 | except ImportError: | 344 | except ImportError: |
803 | 345 | raise osv.except_osv('Error !', self.MOD_NAME+'Unable to import urllib !') | 345 | raise osv.except_osv('Error !', self.MOD_NAME + 'Unable to import urllib !') |
804 | 346 | except IOError: | 346 | except IOError: |
806 | 347 | raise osv.except_osv('Error !', self.MOD_NAME+'Web Service does not exist !') | 347 | raise osv.except_osv('Error !', self.MOD_NAME + 'Web Service does not exist !') |
807 | 348 | 348 | ||
808 | 349 | def check_rate_date(self, rate_date, max_delta_days): | 349 | def check_rate_date(self, rate_date, max_delta_days): |
809 | 350 | """Check date constrains. WARN : rate_date must be of datetime type""" | 350 | """Check date constrains. WARN : rate_date must be of datetime type""" |
810 | 351 | days_delta = (datetime.today() - rate_date).days | 351 | days_delta = (datetime.today() - rate_date).days |
811 | 352 | if days_delta > max_delta_days: | 352 | if days_delta > max_delta_days: |
813 | 353 | raise Exception('The rate date from ECB (%s) is %d days away from today, which is over the limit (%d days). Rate not updated in OpenERP.'%(rate_date, days_delta, max_delta_days)) | 353 | raise Exception('The rate date from (%s) is %d days away from today, which is over the limit (%d days). Rate not updated in OpenERP.' % (rate_date, days_delta, max_delta_days)) |
814 | 354 | # We always have a warning when rate_date <> today | 354 | # We always have a warning when rate_date <> today |
815 | 355 | rate_date_str = datetime.strftime(rate_date, '%Y-%m-%d') | 355 | rate_date_str = datetime.strftime(rate_date, '%Y-%m-%d') |
816 | 356 | if rate_date_str != datetime.strftime(datetime.today(), '%Y-%m-%d'): | 356 | if rate_date_str != datetime.strftime(datetime.today(), '%Y-%m-%d'): |
817 | 357 | self.log_info = "WARNING : the rate date from ECB (%s) is not today's date" % rate_date_str | 357 | self.log_info = "WARNING : the rate date from ECB (%s) is not today's date" % rate_date_str |
822 | 358 | netsvc.Logger().notifyChannel("rate_update", netsvc.LOG_WARNING, "the rate date from ECB (%s) is not today's date" % rate_date_str) | 358 | logger = logging.getLogger(__name__) |
823 | 359 | 359 | logger.warning("the rate date from ECB (%s) is not today's date" % rate_date_str) | |
824 | 360 | 360 | ||
825 | 361 | #Yahoo ################################################################################### | 361 | |
826 | 362 | #Yahoo ################################################################################### | ||
827 | 362 | class Yahoo_getter(Curreny_getter_interface) : | 363 | class Yahoo_getter(Curreny_getter_interface) : |
828 | 363 | """Implementation of Currency_getter_factory interface | 364 | """Implementation of Currency_getter_factory interface |
829 | 364 | for Yahoo finance service""" | 365 | for Yahoo finance service""" |
831 | 365 | 366 | ||
832 | 366 | def get_updated_currency(self, currency_array, main_currency, max_delta_days): | 367 | def get_updated_currency(self, currency_array, main_currency, max_delta_days): |
833 | 367 | """implementation of abstract method of Curreny_getter_interface""" | 368 | """implementation of abstract method of Curreny_getter_interface""" |
834 | 368 | self.validate_cur(main_currency) | 369 | self.validate_cur(main_currency) |
836 | 369 | url='http://download.finance.yahoo.com/d/quotes.txt?s="%s"=X&f=sl1c1abg' | 370 | url = 'http://download.finance.yahoo.com/d/quotes.txt?s="%s"=X&f=sl1c1abg' |
837 | 370 | if main_currency in currency_array : | 371 | if main_currency in currency_array : |
838 | 371 | currency_array.remove(main_currency) | 372 | currency_array.remove(main_currency) |
839 | 372 | for curr in currency_array : | 373 | for curr in currency_array : |
840 | 373 | self.validate_cur(curr) | 374 | self.validate_cur(curr) |
842 | 374 | res = self.get_url(url%(main_currency+curr)) | 375 | res = self.get_url(url % (main_currency + curr)) |
843 | 375 | val = res.split(',')[1] | 376 | val = res.split(',')[1] |
844 | 376 | if val : | 377 | if val : |
845 | 377 | self.updated_currency[curr] = val | 378 | self.updated_currency[curr] = val |
846 | 378 | else : | 379 | else : |
849 | 379 | raise Exception('Could not update the %s'%(curr)) | 380 | raise Exception('Could not update the %s' % (curr)) |
850 | 380 | 381 | ||
851 | 381 | return self.updated_currency, self.log_info # empty string added by polish changes | 382 | return self.updated_currency, self.log_info # empty string added by polish changes |
852 | 382 | ##Admin CH ############################################################################ | 383 | ##Admin CH ############################################################################ |
853 | 383 | class Admin_ch_getter(Curreny_getter_interface) : | 384 | class Admin_ch_getter(Curreny_getter_interface) : |
854 | @@ -388,35 +389,35 @@ | |||
855 | 388 | """ Parse a dom node to retrieve- | 389 | """ Parse a dom node to retrieve- |
856 | 389 | currencies data""" | 390 | currencies data""" |
857 | 390 | res = {} | 391 | res = {} |
860 | 391 | xpath_rate_currency = "/def:wechselkurse/def:devise[@code='%s']/def:kurs/text()"%(curr.lower()) | 392 | xpath_rate_currency = "/def:wechselkurse/def:devise[@code='%s']/def:kurs/text()" % (curr.lower()) |
861 | 392 | xpath_rate_ref = "/def:wechselkurse/def:devise[@code='%s']/def:waehrung/text()"%(curr.lower()) | 393 | xpath_rate_ref = "/def:wechselkurse/def:devise[@code='%s']/def:waehrung/text()" % (curr.lower()) |
862 | 393 | res['rate_currency'] = float(dom.xpath(xpath_rate_currency, namespaces=ns)[0]) | 394 | res['rate_currency'] = float(dom.xpath(xpath_rate_currency, namespaces=ns)[0]) |
863 | 394 | res['rate_ref'] = float((dom.xpath(xpath_rate_ref, namespaces=ns)[0]).split(' ')[0]) | 395 | res['rate_ref'] = float((dom.xpath(xpath_rate_ref, namespaces=ns)[0]).split(' ')[0]) |
864 | 395 | return res | 396 | return res |
865 | 396 | 397 | ||
866 | 397 | def get_updated_currency(self, currency_array, main_currency, max_delta_days): | 398 | def get_updated_currency(self, currency_array, main_currency, max_delta_days): |
867 | 398 | """implementation of abstract method of Curreny_getter_interface""" | 399 | """implementation of abstract method of Curreny_getter_interface""" |
870 | 399 | url='http://www.afd.admin.ch/publicdb/newdb/mwst_kurse/wechselkurse.php' | 400 | url = 'http://www.afd.admin.ch/publicdb/newdb/mwst_kurse/wechselkurse.php' |
871 | 400 | #we do not want to update the main currency | 401 | # we do not want to update the main currency |
872 | 401 | if main_currency in currency_array : | 402 | if main_currency in currency_array : |
873 | 402 | currency_array.remove(main_currency) | 403 | currency_array.remove(main_currency) |
874 | 403 | # Move to new XML lib cf Launchpad bug #645263 | 404 | # Move to new XML lib cf Launchpad bug #645263 |
875 | 404 | from lxml import etree | 405 | from lxml import etree |
878 | 405 | logger = netsvc.Logger() | 406 | logger = logging.getLogger(__name__) |
879 | 406 | logger.notifyChannel("rate_update", netsvc.LOG_DEBUG, "Admin.ch currency rate service : connecting...") | 407 | logger.debug("Admin.ch currency rate service : connecting...") |
880 | 407 | rawfile = self.get_url(url) | 408 | rawfile = self.get_url(url) |
881 | 408 | dom = etree.fromstring(rawfile) | 409 | dom = etree.fromstring(rawfile) |
883 | 409 | logger.notifyChannel("rate_update", netsvc.LOG_DEBUG, "Admin.ch sent a valid XML file") | 410 | logger.debug("Admin.ch sent a valid XML file") |
884 | 410 | adminch_ns = {'def': 'http://www.afd.admin.ch/publicdb/newdb/mwst_kurse'} | 411 | adminch_ns = {'def': 'http://www.afd.admin.ch/publicdb/newdb/mwst_kurse'} |
885 | 411 | rate_date = dom.xpath('/def:wechselkurse/def:datum/text()', namespaces=adminch_ns)[0] | 412 | rate_date = dom.xpath('/def:wechselkurse/def:datum/text()', namespaces=adminch_ns)[0] |
886 | 412 | rate_date_datetime = datetime.strptime(rate_date, '%Y-%m-%d') | 413 | rate_date_datetime = datetime.strptime(rate_date, '%Y-%m-%d') |
887 | 413 | self.check_rate_date(rate_date_datetime, max_delta_days) | 414 | self.check_rate_date(rate_date_datetime, max_delta_days) |
889 | 414 | #we dynamically update supported currencies | 415 | # we dynamically update supported currencies |
890 | 415 | self.supported_currency_array = dom.xpath("/def:wechselkurse/def:devise/@code", namespaces=adminch_ns) | 416 | self.supported_currency_array = dom.xpath("/def:wechselkurse/def:devise/@code", namespaces=adminch_ns) |
891 | 416 | self.supported_currency_array = [x.upper() for x in self.supported_currency_array] | 417 | self.supported_currency_array = [x.upper() for x in self.supported_currency_array] |
892 | 417 | self.supported_currency_array.append('CHF') | 418 | self.supported_currency_array.append('CHF') |
893 | 418 | 419 | ||
895 | 419 | logger.notifyChannel("rate_update", netsvc.LOG_DEBUG, "Supported currencies = " + str(self.supported_currency_array)) | 420 | logger.debug("Supported currencies = %s" % str(self.supported_currency_array)) |
896 | 420 | self.validate_cur(main_currency) | 421 | self.validate_cur(main_currency) |
897 | 421 | if main_currency != 'CHF': | 422 | if main_currency != 'CHF': |
898 | 422 | main_curr_data = self.rate_retrieve(dom, adminch_ns, main_currency) | 423 | main_curr_data = self.rate_retrieve(dom, adminch_ns, main_currency) |
899 | @@ -434,7 +435,7 @@ | |||
900 | 434 | else : | 435 | else : |
901 | 435 | rate = main_rate * curr_data['rate_ref'] / curr_data['rate_currency'] | 436 | rate = main_rate * curr_data['rate_ref'] / curr_data['rate_currency'] |
902 | 436 | self.updated_currency[curr] = rate | 437 | self.updated_currency[curr] = rate |
904 | 437 | logger.notifyChannel("rate_update", netsvc.LOG_DEBUG, "Rate retrieved : 1 " + main_currency + ' = ' + str(rate) + ' ' + curr) | 438 | logger.debug("Rate retrieved : 1 " + main_currency + ' = ' + str(rate) + ' ' + curr) |
905 | 438 | return self.updated_currency, self.log_info | 439 | return self.updated_currency, self.log_info |
906 | 439 | 440 | ||
907 | 440 | ## ECB getter ############################################################################ | 441 | ## ECB getter ############################################################################ |
908 | @@ -447,36 +448,36 @@ | |||
909 | 447 | """ Parse a dom node to retrieve- | 448 | """ Parse a dom node to retrieve- |
910 | 448 | currencies data""" | 449 | currencies data""" |
911 | 449 | res = {} | 450 | res = {} |
913 | 450 | xpath_curr_rate = "/gesmes:Envelope/def:Cube/def:Cube/def:Cube[@currency='%s']/@rate"%(curr.upper()) | 451 | xpath_curr_rate = "/gesmes:Envelope/def:Cube/def:Cube/def:Cube[@currency='%s']/@rate" % (curr.upper()) |
914 | 451 | res['rate_currency'] = float(dom.xpath(xpath_curr_rate, namespaces=ns)[0]) | 452 | res['rate_currency'] = float(dom.xpath(xpath_curr_rate, namespaces=ns)[0]) |
915 | 452 | return res | 453 | return res |
916 | 453 | 454 | ||
917 | 454 | def get_updated_currency(self, currency_array, main_currency, max_delta_days): | 455 | def get_updated_currency(self, currency_array, main_currency, max_delta_days): |
918 | 455 | """implementation of abstract method of Curreny_getter_interface""" | 456 | """implementation of abstract method of Curreny_getter_interface""" |
920 | 456 | url='http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml' | 457 | url = 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml' |
921 | 457 | # Important : as explained on the ECB web site, the currencies are | 458 | # Important : as explained on the ECB web site, the currencies are |
922 | 458 | # at the beginning of the afternoon ; so, until 3 p.m. Paris time | 459 | # at the beginning of the afternoon ; so, until 3 p.m. Paris time |
923 | 459 | # the currency rates are the ones of trading day N-1 | 460 | # the currency rates are the ones of trading day N-1 |
924 | 460 | # see http://www.ecb.europa.eu/stats/exchange/eurofxref/html/index.en.html | 461 | # see http://www.ecb.europa.eu/stats/exchange/eurofxref/html/index.en.html |
925 | 461 | 462 | ||
927 | 462 | #we do not want to update the main currency | 463 | # we do not want to update the main currency |
928 | 463 | if main_currency in currency_array : | 464 | if main_currency in currency_array : |
929 | 464 | currency_array.remove(main_currency) | 465 | currency_array.remove(main_currency) |
930 | 465 | # Move to new XML lib cf Launchpad bug #645263 | 466 | # Move to new XML lib cf Launchpad bug #645263 |
931 | 466 | from lxml import etree | 467 | from lxml import etree |
934 | 467 | logger = netsvc.Logger() | 468 | logger = logging.getLogger(__name__) |
935 | 468 | logger.notifyChannel("rate_update", netsvc.LOG_DEBUG, "ECB currency rate service : connecting...") | 469 | logger.debug("ECB currency rate service : connecting...") |
936 | 469 | rawfile = self.get_url(url) | 470 | rawfile = self.get_url(url) |
937 | 470 | dom = etree.fromstring(rawfile) | 471 | dom = etree.fromstring(rawfile) |
939 | 471 | logger.notifyChannel("rate_update", netsvc.LOG_DEBUG, "ECB sent a valid XML file") | 472 | logger.debug("ECB sent a valid XML file") |
940 | 472 | ecb_ns = {'gesmes': 'http://www.gesmes.org/xml/2002-08-01', 'def': 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref'} | 473 | ecb_ns = {'gesmes': 'http://www.gesmes.org/xml/2002-08-01', 'def': 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref'} |
941 | 473 | rate_date = dom.xpath('/gesmes:Envelope/def:Cube/def:Cube/@time', namespaces=ecb_ns)[0] | 474 | rate_date = dom.xpath('/gesmes:Envelope/def:Cube/def:Cube/@time', namespaces=ecb_ns)[0] |
942 | 474 | rate_date_datetime = datetime.strptime(rate_date, '%Y-%m-%d') | 475 | rate_date_datetime = datetime.strptime(rate_date, '%Y-%m-%d') |
943 | 475 | self.check_rate_date(rate_date_datetime, max_delta_days) | 476 | self.check_rate_date(rate_date_datetime, max_delta_days) |
945 | 476 | #we dynamically update supported currencies | 477 | # we dynamically update supported currencies |
946 | 477 | self.supported_currency_array = dom.xpath("/gesmes:Envelope/def:Cube/def:Cube/def:Cube/@currency", namespaces=ecb_ns) | 478 | self.supported_currency_array = dom.xpath("/gesmes:Envelope/def:Cube/def:Cube/def:Cube/@currency", namespaces=ecb_ns) |
947 | 478 | self.supported_currency_array.append('EUR') | 479 | self.supported_currency_array.append('EUR') |
949 | 479 | logger.notifyChannel("rate_update", netsvc.LOG_DEBUG, "Supported currencies = " + str(self.supported_currency_array)) | 480 | logger.debug("Supported currencies = %s" % str(self.supported_currency_array)) |
950 | 480 | self.validate_cur(main_currency) | 481 | self.validate_cur(main_currency) |
951 | 481 | if main_currency != 'EUR': | 482 | if main_currency != 'EUR': |
952 | 482 | main_curr_data = self.rate_retrieve(dom, ecb_ns, main_currency) | 483 | main_curr_data = self.rate_retrieve(dom, ecb_ns, main_currency) |
953 | @@ -491,11 +492,11 @@ | |||
954 | 491 | else: | 492 | else: |
955 | 492 | rate = curr_data['rate_currency'] / main_curr_data['rate_currency'] | 493 | rate = curr_data['rate_currency'] / main_curr_data['rate_currency'] |
956 | 493 | self.updated_currency[curr] = rate | 494 | self.updated_currency[curr] = rate |
958 | 494 | logger.notifyChannel("rate_update", netsvc.LOG_DEBUG, "Rate retrieved : 1 " + main_currency + ' = ' + str(rate) + ' ' + curr) | 495 | logger.debug("Rate retrieved : 1 " + main_currency + ' = ' + str(rate) + ' ' + curr) |
959 | 495 | return self.updated_currency, self.log_info | 496 | return self.updated_currency, self.log_info |
960 | 496 | 497 | ||
961 | 497 | ##PL NBP ############################################################################ | 498 | ##PL NBP ############################################################################ |
963 | 498 | class PL_NBP_getter(Curreny_getter_interface) : # class added according to polish needs = based on class Admin_ch_getter | 499 | class PL_NBP_getter(Curreny_getter_interface) : # class added according to polish needs = based on class Admin_ch_getter |
964 | 499 | """Implementation of Currency_getter_factory interface | 500 | """Implementation of Currency_getter_factory interface |
965 | 500 | for PL NBP service""" | 501 | for PL NBP service""" |
966 | 501 | 502 | ||
967 | @@ -503,39 +504,33 @@ | |||
968 | 503 | """ Parse a dom node to retrieve | 504 | """ Parse a dom node to retrieve |
969 | 504 | currencies data""" | 505 | currencies data""" |
970 | 505 | res = {} | 506 | res = {} |
974 | 506 | xpath_rate_currency = "/tabela_kursow/pozycja[kod_waluty='%s']/kurs_sredni/text()"%(curr.upper()) | 507 | xpath_rate_currency = "/tabela_kursow/pozycja[kod_waluty='%s']/kurs_sredni/text()" % (curr.upper()) |
975 | 507 | xpath_rate_ref = "/tabela_kursow/pozycja[kod_waluty='%s']/przelicznik/text()"%(curr.upper()) | 508 | xpath_rate_ref = "/tabela_kursow/pozycja[kod_waluty='%s']/przelicznik/text()" % (curr.upper()) |
976 | 508 | res['rate_currency'] = float(dom.xpath(xpath_rate_currency, namespaces=ns)[0].replace(',','.')) | 509 | res['rate_currency'] = float(dom.xpath(xpath_rate_currency, namespaces=ns)[0].replace(',', '.')) |
977 | 509 | res['rate_ref'] = float(dom.xpath(xpath_rate_ref, namespaces=ns)[0]) | 510 | res['rate_ref'] = float(dom.xpath(xpath_rate_ref, namespaces=ns)[0]) |
978 | 510 | return res | 511 | return res |
979 | 511 | 512 | ||
980 | 512 | def get_updated_currency(self, currency_array, main_currency, max_delta_days): | 513 | def get_updated_currency(self, currency_array, main_currency, max_delta_days): |
981 | 513 | """implementation of abstract method of Curreny_getter_interface""" | 514 | """implementation of abstract method of Curreny_getter_interface""" |
984 | 514 | url='http://www.nbp.pl/kursy/xml/LastA.xml' # LastA.xml is always the most recent one | 515 | url = 'http://www.nbp.pl/kursy/xml/LastA.xml' # LastA.xml is always the most recent one |
985 | 515 | #we do not want to update the main currency | 516 | # we do not want to update the main currency |
986 | 516 | if main_currency in currency_array : | 517 | if main_currency in currency_array : |
987 | 517 | currency_array.remove(main_currency) | 518 | currency_array.remove(main_currency) |
988 | 518 | # Move to new XML lib cf Launchpad bug #645263 | 519 | # Move to new XML lib cf Launchpad bug #645263 |
989 | 519 | from lxml import etree | 520 | from lxml import etree |
992 | 520 | logger = netsvc.Logger() | 521 | logger = logging.getLogger(__name__) |
993 | 521 | logger.notifyChannel("rate_update", netsvc.LOG_DEBUG, "NBP.pl currency rate service : connecting...") | 522 | logger.debug("NBP.pl currency rate service : connecting...") |
994 | 522 | rawfile = self.get_url(url) | 523 | rawfile = self.get_url(url) |
1004 | 523 | dom = etree.fromstring(rawfile) # If rawfile is not XML, it crashes here | 524 | dom = etree.fromstring(rawfile) # If rawfile is not XML, it crashes here |
1005 | 524 | ns = {} # Cool, there are no namespaces ! | 525 | ns = {} # Cool, there are no namespaces ! |
1006 | 525 | logger.notifyChannel("rate_update", netsvc.LOG_DEBUG, "NBP.pl sent a valid XML file") | 526 | logger.debug("NBP.pl sent a valid XML file") |
998 | 526 | #node = xpath.Evaluate("/tabela_kursow", dom) # BEGIN Polish - rates table name | ||
999 | 527 | #if isinstance(node, list) : | ||
1000 | 528 | # node = node[0] | ||
1001 | 529 | #self.log_info = node.getElementsByTagName('numer_tabeli')[0].childNodes[0].data | ||
1002 | 530 | #self.log_info = self.log_info + " " + node.getElementsByTagName('data_publikacji')[0].childNodes[0].data # END Polish - rates table name | ||
1003 | 531 | |||
1007 | 532 | rate_date = dom.xpath('/tabela_kursow/data_publikacji/text()', namespaces=ns)[0] | 527 | rate_date = dom.xpath('/tabela_kursow/data_publikacji/text()', namespaces=ns)[0] |
1008 | 533 | rate_date_datetime = datetime.strptime(rate_date, '%Y-%m-%d') | 528 | rate_date_datetime = datetime.strptime(rate_date, '%Y-%m-%d') |
1009 | 534 | self.check_rate_date(rate_date_datetime, max_delta_days) | 529 | self.check_rate_date(rate_date_datetime, max_delta_days) |
1011 | 535 | #we dynamically update supported currencies | 530 | # we dynamically update supported currencies |
1012 | 536 | self.supported_currency_array = dom.xpath('/tabela_kursow/pozycja/kod_waluty/text()', namespaces=ns) | 531 | self.supported_currency_array = dom.xpath('/tabela_kursow/pozycja/kod_waluty/text()', namespaces=ns) |
1013 | 537 | self.supported_currency_array.append('PLN') | 532 | self.supported_currency_array.append('PLN') |
1015 | 538 | logger.notifyChannel("rate_update", netsvc.LOG_DEBUG, "Supported currencies = " + str(self.supported_currency_array)) | 533 | logger.debug("Supported currencies = %s" % str(self.supported_currency_array)) |
1016 | 539 | self.validate_cur(main_currency) | 534 | self.validate_cur(main_currency) |
1017 | 540 | if main_currency != 'PLN': | 535 | if main_currency != 'PLN': |
1018 | 541 | main_curr_data = self.rate_retrieve(dom, ns, main_currency) | 536 | main_curr_data = self.rate_retrieve(dom, ns, main_currency) |
1019 | @@ -553,5 +548,59 @@ | |||
1020 | 553 | else: | 548 | else: |
1021 | 554 | rate = main_rate * curr_data['rate_ref'] / curr_data['rate_currency'] | 549 | rate = main_rate * curr_data['rate_ref'] / curr_data['rate_currency'] |
1022 | 555 | self.updated_currency[curr] = rate | 550 | self.updated_currency[curr] = rate |
1024 | 556 | logger.notifyChannel("rate_update", netsvc.LOG_DEBUG, "Rate retrieved : 1 " + main_currency + ' = ' + str(rate) + ' ' + curr) | 551 | logger.debug("Rate retrieved : 1 " + main_currency + ' = ' + str(rate) + ' ' + curr) |
1025 | 552 | return self.updated_currency, self.log_info | ||
1026 | 553 | |||
1027 | 554 | ##Banco de México ############################################################################ | ||
1028 | 555 | class Banxico_getter(Curreny_getter_interface) : # class added for Mexico rates | ||
1029 | 556 | """Implementation of Currency_getter_factory interface | ||
1030 | 557 | for Banco de México service""" | ||
1031 | 558 | |||
1032 | 559 | def rate_retrieve(self): | ||
1033 | 560 | """ Get currency exchange from Banxico.xml and proccess it | ||
1034 | 561 | TODO: Get correct data from xml instead of process string | ||
1035 | 562 | """ | ||
1036 | 563 | url = 'http://www.banxico.org.mx/rsscb/rss?BMXC_canal=pagos&BMXC_idioma=es' | ||
1037 | 564 | |||
1038 | 565 | from xml.dom.minidom import parse | ||
1039 | 566 | from StringIO import StringIO | ||
1040 | 567 | |||
1041 | 568 | logger = logging.getLogger(__name__) | ||
1042 | 569 | logger.debug("Banxico currency rate service : connecting...") | ||
1043 | 570 | rawfile = self.get_url(url) | ||
1044 | 571 | |||
1045 | 572 | dom = parse(StringIO(rawfile)) | ||
1046 | 573 | logger.debug("Banxico sent a valid XML file") | ||
1047 | 574 | |||
1048 | 575 | value = dom.getElementsByTagName('cb:value')[0] | ||
1049 | 576 | rate = value.firstChild.nodeValue | ||
1050 | 577 | |||
1051 | 578 | return float(rate) | ||
1052 | 579 | |||
1053 | 580 | |||
1054 | 581 | def get_updated_currency(self, currency_array, main_currency, max_delta_days=1): | ||
1055 | 582 | """implementation of abstract method of Curreny_getter_interface""" | ||
1056 | 583 | logger = logging.getLogger(__name__) | ||
1057 | 584 | # we do not want to update the main currency | ||
1058 | 585 | if main_currency in currency_array : | ||
1059 | 586 | currency_array.remove(main_currency) | ||
1060 | 587 | |||
1061 | 588 | # Suported currencies | ||
1062 | 589 | suported = ['MXN', 'USD'] | ||
1063 | 590 | for curr in currency_array : | ||
1064 | 591 | if curr in suported: | ||
1065 | 592 | # Get currency data | ||
1066 | 593 | main_rate = self.rate_retrieve() | ||
1067 | 594 | if main_currency == 'MXN': | ||
1068 | 595 | rate = 1 / main_rate | ||
1069 | 596 | else: | ||
1070 | 597 | rate = main_rate | ||
1071 | 598 | else: | ||
1072 | 599 | """ No other currency supported | ||
1073 | 600 | """ | ||
1074 | 601 | continue | ||
1075 | 602 | |||
1076 | 603 | self.updated_currency[curr] = rate | ||
1077 | 604 | logger.debug("Rate retrieved : " + main_currency + ' = ' + str(rate) + ' ' + curr) | ||
1078 | 605 | |||
1079 | 557 | return self.updated_currency, self.log_info | 606 | return self.updated_currency, self.log_info |
1080 | 558 | 607 | ||
1081 | === modified file 'currency_rate_update/currency_rate_update.xml' (properties changed: +x to -x) | |||
1082 | --- currency_rate_update/currency_rate_update.xml 2011-08-12 12:35:23 +0000 | |||
1083 | +++ currency_rate_update/currency_rate_update.xml 2013-09-17 18:13:12 +0000 | |||
1084 | @@ -9,7 +9,7 @@ | |||
1085 | 9 | <tree string="Rates"> | 9 | <tree string="Rates"> |
1086 | 10 | <field name="service"/> | 10 | <field name="service"/> |
1087 | 11 | <field name="currency_to_update"/> | 11 | <field name="currency_to_update"/> |
1089 | 12 | <field name="company_id"/> | 12 | <field name="company_id" groups="base.group_multi_company"/> |
1090 | 13 | 13 | ||
1091 | 14 | </tree> | 14 | </tree> |
1092 | 15 | </field> | 15 | </field> |
1093 | @@ -22,7 +22,7 @@ | |||
1094 | 22 | <field name="arch" type="xml"> | 22 | <field name="arch" type="xml"> |
1095 | 23 | <form string="Rate"> | 23 | <form string="Rate"> |
1096 | 24 | <field name="service"/> | 24 | <field name="service"/> |
1098 | 25 | <field name="company_id"/> | 25 | <field name="company_id" groups="base.group_multi_company"/> |
1099 | 26 | <field name="max_delta_days"/> | 26 | <field name="max_delta_days"/> |
1100 | 27 | <separator string="Currencies to update with this service" colspan="4"/> | 27 | <separator string="Currencies to update with this service" colspan="4"/> |
1101 | 28 | <field name="currency_to_update" colspan="4" nolabel="1"/> | 28 | <field name="currency_to_update" colspan="4" nolabel="1"/> |
1102 | @@ -33,4 +33,4 @@ | |||
1103 | 33 | </record> | 33 | </record> |
1104 | 34 | 34 | ||
1105 | 35 | </data> | 35 | </data> |
1107 | 36 | </openerp> | 36 | </openerp> |
1108 | 37 | \ No newline at end of file | 37 | \ No newline at end of file |
1109 | 38 | 38 | ||
1110 | === modified file 'currency_rate_update/security/security.xml' (properties changed: +x to -x) |
Hello,
Thanks for your proposal
res_company class renaming is not a good thing it my break monkey patch or existing imports.
class does not need to be instanciated.
Line 427
Your change is faulty some it can induce false positive, to be reverted please.
netsvc.Logger is Deprecated please use logging module "logger.debug".
Regards
Nicolas