634 |
635 | This program is free software: you can redistribute it and/or modify
636 | it under the terms of the GNU Affero General Public License as published
637 | by the Free Software Foundation, either version 3 of the License, or
638 | (at your option) any later version.
639 |
640 | This program is distributed in the hope that it will be useful,
641 | but WITHOUT ANY WARRANTY; without even the implied warranty of
642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643 | GNU Affero General Public License for more details.
644 |
645 | You should have received a copy of the GNU Affero General Public License
646 | along with this program. If not, see .
647 |
648 | Also add information on how to contact you by electronic and paper mail.
649 |
650 | If your software can interact with users remotely through a computer
651 | network, you should also make sure that it provides a way for users to
652 | get its source. For example, if your program is a web application, its
653 | interface could display a "Source" link that leads users to an archive
654 | of the code. There are many ways you could offer source, and different
655 | solutions will be better for different programs; see section 13 for the
656 | specific requirements.
657 |
658 | You should also get your employer (if you work as a programmer) or school,
659 | if any, to sign a "copyright disclaimer" for the program, if necessary.
660 | For more information on this, and how to apply and follow the GNU AGPL, see
661 | .
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | all: addons
2 |
3 | design/etl.xmi: design/etl.zargo
4 | -echo "REBUILD etl.xmi from etl.zargo. I cant do it"
5 |
6 | addons: etl
7 |
8 | etl: design/etl.uml
9 | xmi2odoo -r -i $< -t addons -v 2 -V 8.0
10 |
11 | clean:
12 | sleep 1
13 | touch design/etl.uml
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/ingadhoc/odoo-etl)
2 | [](https://coveralls.io/r/ingadhoc/odoo-etl?branch=8.0)
3 |
4 | odoo-etl (DEPRECEATED)
5 |
6 | IMPORTANT: This project is deprecteade and anymore supported by adhoc
7 |
8 | Odoo data manipulation, like an small ETL (Extract, Transform and Load) for odoo databases.
9 |
10 | The main idea of the project is to give functional users the availability to move data from one odoo database to another odoo database. The design is quite simple, it use native odoo methods (primarily load and export_data).
11 |
12 | The aim of this project is different from odoo migration or OpenUpgrade, it allows to start from a clean database, merging different odoo databases into a single multicompany db, etc.
13 |
14 | This project was developed by a non developer so for sure you are gonna find lot of ugly statements and ideas.
15 |
16 | It was developed using xmi2oerp tool, thanks Cristian Sebastian Rocha for that great work!
17 |
18 | You can see an ugly example video in the following links, in this example we are going to show how to move data from a v6.1 database with demo data to a trunk database without demo data. Links:
19 | * https://www.youtube.com/watch?v=HZQQaNQ9k7U
20 | * https://www.youtube.com/watch?v=VmScwCM3whg
21 | * https://www.youtube.com/watch?v=PS2ShlY1gLI
22 |
23 | Any feedback is welcome, if someone likes the idea, please don't hesitate to contact us so we can work together.
24 |
25 | You can find some kind of tutorial on: https://docs.google.com/document/d/1HWERCUp9rMHqEibT7B_mfu9jePV-FBkYbo--OB0jXqA
26 |
27 |
28 | ## Installation
29 |
30 | ### Dependencies
31 |
32 | sudo pip install -r requirements.txt
33 |
34 | If you don't have Pip, find it here: http://pypi.python.org/pypi/pip
35 |
36 | ## Contributing
37 | We follow some guidelines and advice than [Odoo Argentina](https://github.com/ingadhoc/odoo-argentina/wiki). In summary:
38 |
39 | 1. Fork it!
40 | 2. Create your feature branch: `git checkout -b my-new-feature`
41 | 3. Commit your changes: `git commit -am 'Add some feature'`
42 | 4. Push to the branch: `git push origin my-new-feature`
43 | 5. Submit a pull request :D
44 |
45 | ## Credits
46 |
47 |
48 |
49 | **Adhoc SA** - www.adhoc.com.ar
50 |
51 | ## License
52 |
53 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
54 |
55 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
56 |
57 | You should have received a copy of the GNU Affero General Public License along with this program. If not, see http://www.gnu.org/licenses/.
58 |
--------------------------------------------------------------------------------
/etl/README:
--------------------------------------------------------------------------------
1 | #
2 | # odoo ETL
3 | # Copyright (C) 2015 Ingenieria ADHOC
4 | # No email
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU Affero General Public License as
8 | # published by the Free Software Foundation, either version 3 of the
9 | # License, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU Affero General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Affero General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 |
21 | etl
22 |
23 | odoo ETL
24 |
--------------------------------------------------------------------------------
/etl/__init__.py:
--------------------------------------------------------------------------------
1 | import value_mapping_field
2 | import external_model
3 | import external_model_record
4 | import field_mapping
5 | import field
6 | import manager
7 | import value_mapping_field_value
8 | import action
9 | import value_mapping_field_detail
10 | import wizard
11 | import report
12 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
13 |
--------------------------------------------------------------------------------
/etl/__openerp__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | ##############################################################################
3 | #
4 | # Copyright (C) 2015 ADHOC SA (http://www.adhoc.com.ar)
5 | # All Rights Reserved.
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU Affero General Public License as
9 | # published by the Free Software Foundation, either version 3 of the
10 | # License, or (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU Affero General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU Affero General Public License
18 | # along with this program. If not, see .
19 | #
20 | ##############################################################################
21 | {
22 | 'active': False,
23 | 'author': u'ADHOC SA',
24 | 'category': u'base.module_category_knowledge_management',
25 | 'data': [
26 | u'security/etl_group.xml',
27 | u'view/etl_menuitem.xml',
28 | u'view/value_mapping_field_view.xml',
29 | u'view/external_model_view.xml',
30 | u'view/external_model_record_view.xml',
31 | u'view/field_mapping_view.xml',
32 | u'view/field_view.xml',
33 | u'view/action_view.xml',
34 | u'view/manager_view.xml',
35 | u'view/value_mapping_field_value_view.xml',
36 | u'view/value_mapping_field_detail_view.xml',
37 | u'data/value_mapping_field_properties.xml',
38 | u'data/external_model_properties.xml',
39 | u'data/external_model_record_properties.xml',
40 | u'data/field_mapping_properties.xml',
41 | u'data/field_properties.xml',
42 | u'data/manager_properties.xml',
43 | u'data/value_mapping_field_value_properties.xml',
44 | u'data/action_properties.xml',
45 | u'data/value_mapping_field_detail_properties.xml',
46 | u'data/value_mapping_field_track.xml',
47 | u'data/external_model_track.xml',
48 | u'data/external_model_record_track.xml',
49 | u'data/field_mapping_track.xml',
50 | u'data/field_track.xml',
51 | u'data/manager_track.xml',
52 | u'data/value_mapping_field_value_track.xml',
53 | u'data/action_track.xml',
54 | u'data/value_mapping_field_detail_track.xml',
55 | 'security/ir.model.access.csv',
56 | ],
57 | 'depends': ['base'],
58 | 'description': """
59 | odoo ETL
60 | ========
61 | Usefull Notes:
62 | --------------
63 | * It is recommendend to delete all external identifiers on source database for model "res_partner" because when creating a user, odoo simulates partner creation and raise a unique constraint (excepto admin user)
64 | * Also could be recommendend to delete external identifiers related to product and product_temlate (excepto to service product)
65 | * Advisable to configure xmlrpc users to timezone cero to avoid errors
66 | """,
67 | 'installable': True,
68 | 'application': True,
69 | 'license': 'AGPL-3',
70 | 'name': u'odoo ETL',
71 | 'test': [],
72 | 'version': u'1.1',
73 | 'website': 'www.adhoc.com.ar'}
74 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
75 |
--------------------------------------------------------------------------------
/etl/action.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | ##############################################################################
3 | # For copyright and license notices, see __openerp__.py file in module root
4 | # directory
5 | ##############################################################################
6 | from openerp import models, fields, api, SUPERUSER_ID
7 | import sys
8 | import pytz
9 | from ast import literal_eval
10 | from datetime import datetime
11 | from dateutil import relativedelta
12 | from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
13 | import logging
14 | _logger = logging.getLogger(__name__)
15 |
16 |
17 | class action(models.Model):
18 | """"""
19 |
20 | _name = 'etl.action'
21 | _description = 'action'
22 |
23 | _order = "sequence"
24 |
25 | blocked = fields.Boolean(
26 | string='Blocked',
27 | copy=False,
28 | )
29 | sequence = fields.Integer(
30 | string='Sequence'
31 | )
32 | state = fields.Selection(
33 | [(u'to_analyze', 'to_analyze'), (u'enabled', 'enabled'), (u'disabled', 'disabled'), (u'no_records', 'no_records')],
34 | string='State',
35 | required=True
36 | )
37 | name = fields.Char(
38 | string='Name',
39 | required=True
40 | )
41 | source_domain = fields.Char(
42 | string='Source Domain',
43 | required=True,
44 | default='[]'
45 | )
46 | log = fields.Text(
47 | string='Log'
48 | )
49 | note = fields.Html(
50 | string='Notes'
51 | )
52 | repeating_action = fields.Boolean(
53 | string='Repeating Action?',
54 | store=True,
55 | compute='_get_repeating_action',
56 | )
57 | source_id_exp = fields.Char(
58 | string='source_id_exp',
59 | required=True,
60 | default='id'
61 | )
62 | target_id_type = fields.Selection(
63 | [(u'source_id', 'source_id'), (u'builded_id', 'builded_id')],
64 | string='Target ID Type',
65 | required=True,
66 | related='manager_id.target_id_type'
67 | )
68 | from_rec_id = fields.Integer(
69 | string='From Record'
70 | )
71 | to_rec_id = fields.Integer(
72 | string='To Record'
73 | )
74 | target_id_prefix = fields.Char(
75 | string='target_id_prefix',
76 | compute='_get_action_prefix'
77 | )
78 | manager_id = fields.Many2one(
79 | 'etl.manager',
80 | ondelete='cascade',
81 | string='Manager',
82 | required=True
83 | )
84 | field_mapping_ids = fields.One2many(
85 | 'etl.field_mapping',
86 | 'action_id',
87 | string='Fields Mapping',
88 | copy=False,
89 | )
90 | source_model_id = fields.Many2one(
91 | 'etl.external_model',
92 | string='Source Model',
93 | required=True,
94 | ondelete='cascade',
95 | )
96 | target_model_id = fields.Many2one(
97 | 'etl.external_model',
98 | string='Target Model',
99 | ondelete='cascade',
100 | )
101 | source_records = fields.Integer(
102 | related='source_model_id.records',
103 | readonly=True,
104 | string='Source Records',
105 | )
106 | target_records = fields.Integer(
107 | related='target_model_id.records',
108 | readonly=True,
109 | string='Target Records',
110 | )
111 |
112 | _constraints = [
113 | ]
114 |
115 | @api.one
116 | @api.depends(
117 | 'source_model_id.model','target_id_type'
118 | )
119 | def _get_action_prefix(self):
120 | value = False
121 | if self.target_id_type == 'builded_id':
122 | value = self.manager_id.name + '_' + self.source_model_id.model.replace('.','_')
123 | self.target_id_prefix = value
124 |
125 | @api.one
126 | @api.depends(
127 | 'field_mapping_ids.state'
128 | )
129 | def _get_repeating_action(self):
130 | repeating_action = False
131 | repeating_field_mapps = self.field_mapping_ids.search([
132 | ('state', '=', 'on_repeating'),
133 | ('action_id', '=', self.id),
134 | ])
135 | if repeating_field_mapps:
136 | repeating_action = True
137 | self.repeating_action = repeating_action
138 |
139 | @api.multi
140 | def action_block(self):
141 | return self.write({'blocked': True})
142 |
143 | @api.one
144 | def match_fields(self):
145 | ''' Match fields'''
146 | _logger.info("Matching fields on action %s" % self.name)
147 | migrator_field = self.env['etl.field']
148 | field_mapping = self.env['etl.field_mapping']
149 |
150 | # Get disabled and to analize words and fields
151 | field_disable_default = []
152 | field_analyze_default = []
153 | field_disable_words = []
154 | if self.manager_id.field_disable_default:
155 | field_disable_default = literal_eval(
156 | self.manager_id.field_disable_default)
157 | if self.manager_id.field_analyze_default:
158 | field_analyze_default = literal_eval(
159 | self.manager_id.field_analyze_default)
160 | if self.manager_id.field_disable_words:
161 | field_disable_words = literal_eval(
162 | self.manager_id.field_disable_words)
163 |
164 | # get source fields thar are not functions ore one2many
165 | # Function in False or in '_fnct_read' (aparentemente _fnct_read es para campos related y los queremos mapear)
166 | source_domain = [
167 | ('model_id.id', '=', self.source_model_id.id),
168 | ('ttype', 'not in', ['one2many']),
169 | '|', ('function', 'in', [False, '_fnct_read']),
170 | ('required', '=', 'True')]
171 | source_fields = migrator_field.search(source_domain)
172 |
173 | mapping_data = []
174 | action_has_active_field = False
175 | for field in source_fields:
176 | # If nothing asserts, choose expresion
177 | mapping_type = 'expression'
178 |
179 | # build source_field with or not /id
180 | source_field_name = field.name
181 | if field.ttype in ['many2one', 'many2many']:
182 | source_field_name += '/id'
183 |
184 | # look for a target field
185 | target_domain = [
186 | ('model_id.id', '=', self.target_model_id.id),
187 | ('name', '=', field.name)]
188 | target_fields = migrator_field.search(target_domain)
189 |
190 | # check the state
191 | state = 'enabled'
192 | if field.name in field_analyze_default or not target_fields:
193 | state = 'to_analyze'
194 | if field.name in field_disable_default:
195 | state = 'disabled'
196 | else:
197 | for field_disable_word in field_disable_words:
198 | if field.name.find(field_disable_word) == 0:
199 | state = 'disabled'
200 |
201 | # check if is active field
202 | if field.name == 'active':
203 | action_has_active_field = True
204 |
205 | # depending on the target field properties, set some other values
206 | target_field = ''
207 | target_field_name = False
208 | if target_fields:
209 | mapping_type = 'field'
210 | target_field = target_fields[0]
211 |
212 | target_field_name = target_field.name
213 | if target_field.ttype in ['many2one', 'many2many']:
214 | target_field_name += '/id'
215 | if target_field.ttype == 'many2many':
216 | relation = target_field.relation
217 | previus_actions = self.search([
218 | ('manager_id', '=', self.manager_id.id),
219 | ('sequence', '<', self.sequence),
220 | ('target_model_id.model', '=', relation)])
221 | if not previus_actions:
222 | state = 'other_class'
223 | elif field.ttype == 'datetime' and target_field.ttype == 'date' or field.ttype == 'date' and target_field.ttype == 'datetime':
224 | mapping_type = 'date_adapt'
225 | elif field.ttype == 'reference':
226 | mapping_type = 'reference'
227 |
228 | # Check if there is any value mapping for current field
229 | value_mapping_field = False
230 | value_mappings = self.env['etl.value_mapping_field'].search([
231 | ('source_model_id.model', '=', field.relation),
232 | ('manager_id', '=', self.manager_id.id)])
233 | if value_mappings:
234 | mapping_type = 'value_mapping'
235 | value_mapping_field = value_mappings[0]
236 |
237 | # If field name = 'state' then we upload it on a repeating action so we are sure we can upload all the related data
238 | if field.name == 'state':
239 | state = 'on_repeating'
240 | vals = [
241 | 'field_mapping_' + str(self.id) + '_' + str(field.id),
242 | state,
243 | field.id,
244 | source_field_name,
245 | mapping_type,
246 | target_field and target_field.id or False,
247 | target_field_name,
248 | self.id,
249 | value_mapping_field and value_mapping_field.id or False]
250 |
251 | # See if mappings have already a blocked mapping created
252 | blocked_fields = field_mapping.search([
253 | ('blocked', '=', True),
254 | ('action_id', '=', self.id)])
255 | blocked_field_ext_ids = blocked_fields.export_data(
256 | ['id'])['datas']
257 | if [vals[0]] in blocked_field_ext_ids:
258 | continue
259 | mapping_data.append(vals)
260 |
261 | # load mapping
262 | mapping_fields = [
263 | 'id',
264 | 'state',
265 | 'source_field_id/.id',
266 | 'source_field',
267 | 'type',
268 | 'target_field_id/.id',
269 | 'target_field',
270 | 'action_id/.id',
271 | 'value_mapping_field_id/.id']
272 | _logger.info("Loading mapping fields for action %s" % self.name)
273 | import_result = field_mapping.load(mapping_fields, mapping_data)
274 | vals = {'log': import_result}
275 |
276 | if action_has_active_field and self.source_domain == '[]':
277 | vals['source_domain'] = "['|',('active','=',False),('active','=',True)]"
278 | # write log and domain if active field exist
279 | self.write(vals)
280 | # TODO, si algo anda lento o mal hay que borrar esto. No puedo hacer el check m2o depends ants de tenerlas ordenadas
281 | # return self.check_m2o_depends(cr, uid, ids, context=context)
282 | # return True
283 |
284 | @api.one
285 | def check_m2o_depends(self):
286 | ''' Check if there are fields that should be load in a repeating action
287 | If there is at least one mapping field with repeating,
288 | make the action repeating '''
289 | data = []
290 |
291 | # Look for enabled or to analize future actions of this manager and
292 | # this action
293 | future_actions = self.search([
294 | ('manager_id', '=', self.manager_id.id),
295 | ('sequence', '>=', self.sequence),
296 | ('state', 'in', ['enabled', 'to_analyze'])])
297 | future_models = []
298 | for future_action in future_actions:
299 | future_models.append(future_action.source_model_id.model)
300 |
301 | # Look for active fields of this action
302 | field_mapping_domain = [
303 | ('blocked', '!=', True),
304 | ('action_id', '=', self.id),
305 | ('source_field_id.ttype', '=', 'many2one'),
306 | ('state', 'in', ['enabled', 'to_analyze', 'on_repeating']),
307 | ('type', '=', 'field')]
308 | field_mappings = self.env['etl.field_mapping'].search(
309 | field_mapping_domain)
310 |
311 | # If there are mappings with future depends make them 'on_repeating'
312 | for mapping in field_mappings:
313 | dependency = mapping.source_field_id.relation
314 | if dependency in future_models:
315 | state = 'on_repeating'
316 | vals = [
317 | 'field_mapping_%s_%s' % (
318 | str(self.id),
319 | str(mapping.source_field_id.id)),
320 | state]
321 | data.append(vals)
322 | fields = ['id', 'state']
323 |
324 | # if there is any repeating mapping field, then make action
325 | # 'repeating action'
326 | import_result = self.env['etl.field_mapping'].load(fields, data)
327 | vals = {
328 | 'log': import_result,
329 | }
330 | self.write(vals)
331 |
332 | @api.one
333 | def updata_records_number(
334 | self, source_connection=False, target_connection=False):
335 | if not source_connection or not target_connection:
336 | (source_connection, target_connection) = self.manager_id.open_connections()
337 | self.source_model_id.get_records(source_connection)
338 | self.target_model_id.get_records(target_connection)
339 |
340 | @api.multi
341 | def run_repeated_action(
342 | self, source_connection=False, target_connection=False,
343 | repeated_action=True):
344 | return self.run_action(repeated_action=True)
345 |
346 | @api.multi
347 | def read_source_model(
348 | self, source_connection=False, target_connection=False,
349 | repeated_action=False, context=None):
350 | readed_model = []
351 | for action in self:
352 | if action.source_model_id.id in readed_model:
353 | continue
354 | _logger.info('Reading model %s' % action.source_model_id.model)
355 | if not source_connection:
356 | (source_connection, target_connection) = action.manager_id.open_connections()
357 | source_model_obj = source_connection.model(action.source_model_id.model)
358 | domain = []
359 | active_field = action.env['etl.field'].search([
360 | ('model_id', '=', action.source_model_id.id),
361 | ('name', '=', 'active'),
362 | ], limit=1)
363 | if active_field:
364 | domain = [('active', 'in', [True, False])]
365 | source_model_ids = source_model_obj.search(domain)
366 | source_model_obj.export_data(source_model_ids, ['id'])
367 | readed_model.append(action.source_model_id.id)
368 |
369 | @api.one
370 | def run_action(
371 | self, source_connection=False, target_connection=False,
372 | repeated_action=False):
373 | _logger.info('Actions to run: %i' % len(self.ids))
374 | action_obj = self.env['etl.action']
375 | model_obj = self.env['etl.external_model']
376 | field_mapping_obj = self.env['etl.field_mapping']
377 | value_mapping_field_detail_obj = self.env['etl.value_mapping_field_detail']
378 | value_mapping_field_obj = self.env['etl.value_mapping_field']
379 | if not source_connection or not target_connection:
380 | (source_connection, target_connection) = self.manager_id.open_connections()
381 | # add language to connections context
382 | source_connection.context = {'lang': self.manager_id.source_lang}
383 | target_connection.context = {'lang': self.manager_id.target_lang}
384 | _logger.info('Running action external_model_id.type %s' % self.name)
385 |
386 | domain = literal_eval(self.source_domain)
387 | if self.from_rec_id > 0:
388 | domain.append(('id', '>=', self.from_rec_id))
389 | if self.to_rec_id > 0:
390 | domain.append(('id', '<=', self.to_rec_id))
391 |
392 | source_model_obj = source_connection.model(self.source_model_id.model)
393 | target_model_obj = target_connection.model(self.target_model_id.model)
394 |
395 | source_model_ids = source_model_obj.search(domain)
396 | _logger.info('Records to import %i' % len(source_model_ids))
397 |
398 | _logger.info('Building source data...')
399 | # Empezamos con los campos que definimos como id
400 | source_fields = ['.id', self.source_id_exp]
401 | target_fields = ['id']
402 |
403 | if repeated_action:
404 | state = 'on_repeating'
405 | else:
406 | state = 'enabled'
407 |
408 | # source fields = enabled (or repeating) and type field
409 | source_fields.extend([x.source_field for x in self.field_mapping_ids if x.state==state and x.type == 'field' and x.source_field_id.ttype != 'many2many' and x.source_field_id.ttype != 'many2one'])
410 | #print source_fields
411 | # target fields = enabled and field then expression then migrated_id
412 | target_fields.extend([x.target_field for x in self.field_mapping_ids if x.state==state and x.type == 'field' and x.source_field_id.ttype != 'many2many' and x.source_field_id.ttype != 'many2one'])
413 | target_fields.extend([x.target_field for x in self.field_mapping_ids if x.state==state and x.type == 'field' and x.source_field_id.ttype == 'many2one'])
414 | target_fields.extend([x.target_field for x in self.field_mapping_ids if x.state==state and x.type == 'field' and x.source_field_id.ttype == 'many2many'])
415 | target_fields.extend([x.target_field for x in self.field_mapping_ids if x.state==state and x.type == 'value_mapping'])
416 | target_fields.extend([x.target_field for x in self.field_mapping_ids if x.state==state and x.type == 'date_adapt'])
417 | target_fields.extend([x.target_field for x in self.field_mapping_ids if x.state==state and x.type == 'expression'])
418 | target_fields.extend([x.target_field for x in self.field_mapping_ids if x.state==state and x.type == 'migrated_id'])
419 | target_fields.extend([x.target_field for x in self.field_mapping_ids if x.state==state and x.type == 'reference'])
420 |
421 | # Read and append source values of type 'field' and type not m2m
422 | _logger.info('Building none m2m field mapping...')
423 | source_model_data = source_model_obj.export_data(
424 | source_model_ids, source_fields)['datas']
425 |
426 | _logger.info('Building m2o field mapping...')
427 | # Read and append source values of type 'field' and type m2m
428 | source_fields_m2o = [x.id for x in self.field_mapping_ids if x.state==state and x.type == 'field' and x.source_field_id.ttype == 'many2one']
429 | for field_id in source_fields_m2o:
430 | field = field_mapping_obj.browse(field_id)
431 | field_model = field.source_field_id.relation
432 | model_id = model_obj.search([('model','=',field_model),('type','ilike','source')])
433 | field_action = False
434 | if model_id:
435 | field_action = action_obj.search([('source_model_id','=',model_id[0].id)])
436 | if field_action:
437 | field_action = field_action[0]
438 | for source_data_record in source_model_data:
439 | source_data_m2o = source_model_obj.export_data([int(source_data_record[0])], ['.id', field.source_field, field.source_field.replace('/','.')])['datas']
440 | new_field_value = False
441 | if field_action.target_id_type == 'source_id' and source_data_m2o[0][1]:
442 | new_field_value = source_data_m2o[0][1]
443 | elif field_action.target_id_type == 'builded_id' and source_data_m2o[0][2]:
444 | new_field_value = '%s_%s' % (field_action.target_id_prefix, str(source_data_m2o[0][2]))
445 | source_data_record.append(new_field_value)
446 |
447 | _logger.info('Building m2m field mapping...')
448 | # Read and append source values of type 'field' and type m2m
449 | source_fields_m2m = [x.id for x in self.field_mapping_ids if x.state==state and x.type == 'field' and x.source_field_id.ttype == 'many2many']
450 | for field_id in source_fields_m2m:
451 | field = field_mapping_obj.browse(field_id)
452 | field_model = field.source_field_id.relation
453 | model_id = model_obj.search([('model','=',field_model),('type','ilike','source')])
454 | field_action = False
455 | if model_id:
456 | field_action = action_obj.search([('source_model_id','=',model_id[0].id)])
457 | if field_action:
458 | field_action = field_action[0]
459 | model_data_obj = source_connection.model('ir.model.data')
460 | for source_data_record in source_model_data:
461 | source_data_m2m = source_model_obj.export_data([int(source_data_record[0])], ['.id', field.source_field])['datas']
462 | new_field_value = False
463 | for readed_record in source_data_m2m:
464 | if readed_record[1]:
465 | for value in readed_record[1].split(','):
466 | value_id = model_data_obj.search([('model','ilike',field.source_field_id.relation),('name','ilike',value.split('.')[-1])])
467 | if value_id:
468 | value_id = model_data_obj.export_data([value_id[0]], ['.id', 'res_id'])['datas']
469 | value_id = value_id[0][1]
470 | if field_action.target_id_type == 'source_id' and value:
471 | new_field_value = value
472 | elif field_action.target_id_type == 'builded_id' and value_id:
473 | if new_field_value:
474 | new_field_value = new_field_value + ',' + '%s_%s' % (field_action.target_id_prefix, str(value_id))
475 | else:
476 | new_field_value = '%s_%s' % (field_action.target_id_prefix, str(value_id))
477 | source_data_record.append(new_field_value)
478 |
479 | _logger.info('Building value mapping mapping...')
480 | # Read and append source values of type 'value_mapping'
481 | source_fields_value_mapping = [x.source_field for x in self.field_mapping_ids if x.state==state and x.type == 'value_mapping']
482 | #print 'source_fields_value_mapping', source_fields_value_mapping
483 | source_data_value_mapping = source_model_obj.export_data(source_model_ids, source_fields_value_mapping)['datas']
484 | #print 'source_data_value_mapping', source_data_value_mapping
485 | source_value_mapping_id = [x.value_mapping_field_id.id for x in self.field_mapping_ids if x.state==state and x.type == 'value_mapping']
486 | #print 'source_value_mapping_id', source_value_mapping_id
487 | for readed_record, source_data_record in zip(source_data_value_mapping, source_model_data):
488 | target_record = []
489 | for field_value, value_mapping_id in zip(readed_record, source_value_mapping_id):
490 | new_field_value = False
491 | value_mapping = value_mapping_field_obj.browse(
492 | value_mapping_id)
493 | # TODO mejorar esta cosa horrible, no hace falta guardar en dos clases separadas, deberia usar una sola para selection y para id
494 | if value_mapping.type == 'id':
495 | new_field = value_mapping_field_detail_obj.search([
496 | ('source_external_model_record_id.ext_id', '=', field_value),
497 | ('value_mapping_field_id', '=', value_mapping_id)],
498 | limit=1)
499 | # if new_fields:
500 | new_field_value = new_field.target_external_model_record_id.ext_id
501 | elif value_mapping.type == 'selection':
502 | new_field = value_mapping_field_detail_obj.search([
503 | ('source_value_id.ext_id', '=', field_value),
504 | ('value_mapping_field_id', '=', value_mapping_id)],
505 | limit=1)
506 | new_field_value = new_field.target_value_id.ext_id
507 | # Convertimos a false todos aquellos mapeos al que no se les asigno pareja
508 | # Si el modelo permite valores false va a andar bien, si no va a dar el error y debera mapearse
509 | if new_field_value is None:
510 | new_field_value = False
511 | target_record.append(new_field_value)
512 | source_data_record.extend(target_record)
513 |
514 | _logger.info('Building date adapt...')
515 | # Read and append source values of type 'date_adapt'
516 | source_fields_date_adapt = [x.source_field for x in self.field_mapping_ids if x.state==state and x.type == 'date_adapt']
517 | source_data_date_adapt = source_model_obj.export_data(source_model_ids, source_fields_date_adapt)['datas']
518 | source_mapping_date_adapt = [x for x in self.field_mapping_ids if x.state==state and x.type == 'date_adapt']
519 | for readed_record, source_data_record in zip(source_data_date_adapt, source_model_data):
520 | target_record = []
521 | for field_value, source_mapping in zip(readed_record, source_mapping_date_adapt):
522 | if source_mapping.source_field_id.ttype == 'datetime' and field_value:
523 | if source_mapping.target_field_id.ttype == 'date':
524 | # TODO, no estoy seguro si esta forma de truncarlo funciona bien
525 | field_value = field_value[:10]
526 | if source_mapping.source_field_id.ttype == 'date' and field_value:
527 | if source_mapping.target_field_id.ttype == 'datetime':
528 | field_value = self.date_to_datetime(field_value)
529 | target_record.append(field_value)
530 | source_data_record.extend(target_record)
531 |
532 | _logger.info('Building expressions...')
533 | field_mapping_expression_ids = [x.id for x in self.field_mapping_ids if x.state==state and x.type == 'expression']
534 | if field_mapping_expression_ids:
535 | for rec in source_model_data:
536 | rec_id = rec[0]
537 | expression_results = field_mapping_obj.browse(
538 | field_mapping_expression_ids).run_expressions(
539 | int(rec_id),
540 | source_connection,
541 | target_connection)
542 | rec.extend(expression_results)
543 |
544 | _logger.info('Building migrated ids...')
545 | field_mapping_migrated_id_ids = [x.id for x in self.field_mapping_ids if x.state==state and x.type == 'migrated_id']
546 | if field_mapping_migrated_id_ids:
547 | for rec in source_model_data:
548 | rec_id = rec[0]
549 | migrated_id_results = field_mapping_obj.browse(
550 | field_mapping_migrated_id_ids).get_migrated_id(
551 | int(rec_id),
552 | source_connection,
553 | target_connection)
554 | rec.extend(migrated_id_results)
555 |
556 | _logger.info('Building reference fields...')
557 | field_mapping_reference_ids = [x.id for x in self.field_mapping_ids if x.state==state and x.type == 'reference']
558 | if field_mapping_reference_ids:
559 | for rec in source_model_data:
560 | rec_id = rec[0]
561 | reference_results = field_mapping_obj.browse(
562 | field_mapping_reference_ids).get_reference(
563 | int(rec_id), source_connection, target_connection)
564 | _logger.info('Reference_results: %s' % reference_results)
565 | rec.extend(reference_results)
566 |
567 | _logger.info('Removing auxliaria .id')
568 | target_model_data = []
569 | #print source_model_data
570 | #print ''
571 | for record in source_model_data:
572 | if self.target_id_type == 'source_id':
573 | target_model_data.append(record[1:])
574 | elif self.target_id_type == 'builded_id':
575 | target_model_data.append(['%s_%s' % (
576 | self.target_id_prefix, str(record[0]))] + record[2:])
577 |
578 | try:
579 | _logger.info('Loadding Data...')
580 | import_result = target_model_obj.load(
581 | target_fields, target_model_data)
582 | vals = {'log': import_result}
583 | except:
584 | error = sys.exc_info()
585 | print error
586 | vals = {'log': error}
587 |
588 | self.write(vals)
589 | self.target_model_id.get_records(target_connection)
590 |
591 | @api.multi
592 | def order_actions(self, exceptions=None):
593 | _logger.info('Lines to order %i' % len(self.ids))
594 | if exceptions is None:
595 | exceptions = []
596 | # field_mapping_obj = self.pool.get('etl.field_mapping')
597 | ordered_actions = []
598 | ordered_ids = []
599 |
600 | # We exclude de exceptions
601 | unordered_ids = self.search([
602 | ('id', 'in', self.ids),
603 | ('source_model_id.model', 'not in', exceptions)]).ids
604 | _logger.info('Request IDS: %s' % str(self.ids))
605 | _logger.info('Request IDS without exceptions: %s' % str(unordered_ids))
606 |
607 | actions_to_order = [
608 | x.source_model_id.model for x in self.browse(unordered_ids)]
609 | _logger.info('Actions_to_order %s' % actions_to_order)
610 | count = 0
611 | count_max = len(self) * 2
612 | while unordered_ids and (count < count_max):
613 | count += 1
614 | rec = self.browse(unordered_ids[0])
615 | action_clean_dependecies = []
616 | many2one_mappings = self.env['etl.field_mapping'].search([
617 | ('action_id', '=', rec.id),
618 | ('source_field_id.ttype', '=', 'many2one'),
619 | ('state', 'in', ['to_analyze', 'enabled', 'on_repeating'])])
620 | for mapping in many2one_mappings:
621 | if (mapping.source_field_id.relation not in action_clean_dependecies) and (mapping.source_field_id.relation in actions_to_order):
622 | if not(mapping.source_field_id.relation == rec.source_model_id.model):
623 | action_clean_dependecies.append(mapping.source_field_id.relation)
624 | # else:
625 | # TODO usar este dato para algo! para macar la clase por ejemplo
626 | _logger.info('Model: %s, depenencias: %s' % (
627 | rec.source_model_id.model, action_clean_dependecies))
628 | dependecies_ok = True
629 | for action_dependecy in action_clean_dependecies:
630 | if (action_dependecy not in ordered_actions) and (action_dependecy not in exceptions):
631 | dependecies_ok = False
632 | break
633 | unordered_ids.remove(rec.id)
634 | if dependecies_ok:
635 | _logger.info('Dependency ok!')
636 | ordered_ids.append(rec.id)
637 | ordered_actions.append(rec.source_model_id.model)
638 | else:
639 | _logger.info('Break, dependency false!')
640 | unordered_ids.append(rec.id)
641 |
642 | _logger.info('Unordered Models: %s' % str(unordered_ids))
643 | _logger.info('New Order: %s' % str(ordered_actions))
644 |
645 | # Add sequence to exception actions
646 | sequence = 0
647 | for exception in exceptions:
648 | exception_action_ids = self.search([
649 | ('id', 'in', self.ids),
650 | ('source_model_id.model', '=', exception)])
651 | sequence += 10
652 | vals = {
653 | 'sequence': sequence,
654 | }
655 | exception_action_ids.write(vals)
656 |
657 | # Add sequence to ordered actions
658 | sequence = 500
659 | for ordered_action in self.browse(ordered_ids):
660 | sequence += 10
661 | vals = {
662 | 'sequence': sequence,
663 | }
664 | ordered_action.write(vals)
665 | return [unordered_ids, ordered_ids]
666 |
667 | @api.model
668 | def date_to_datetime(self, userdate):
669 | """ Convert date values expressed in user's timezone to
670 | server-side UTC timestamp, assuming a default arbitrary
671 | time of 12:00 AM - because a time is needed.
672 |
673 | :param str userdate: date string in in user time zone
674 | :return: UTC datetime string for server-side use
675 | """
676 | # TODO: move to fields.datetime in server after 7.0
677 | user_date = datetime.strptime(userdate, DEFAULT_SERVER_DATE_FORMAT)
678 | context = self._context
679 | if context and context.get('tz'):
680 | tz_name = context['tz']
681 | else:
682 | tz_name = self.env['res.users'].browse(SUPERUSER_ID).tz
683 | print tz_name
684 | #tz_name = tz_name[0]
685 | if tz_name:
686 | utc = pytz.timezone('UTC')
687 | context_tz = pytz.timezone(tz_name)
688 | #user_datetime = user_date + relativedelta(hours=12.0)
689 | local_timestamp = context_tz.localize(user_date, is_dst=False)
690 | user_datetime = local_timestamp.astimezone(utc)
691 | return user_datetime.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
692 | return user_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
693 |
694 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
695 |
--------------------------------------------------------------------------------
/etl/data/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ingadhoc/odoo-etl/d5f54db11c5f916da79e23c52037ea36a12640a4/etl/data/README
--------------------------------------------------------------------------------
/etl/data/action_properties.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/etl/data/action_track.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
--------------------------------------------------------------------------------
/etl/data/external_model_properties.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/etl/data/external_model_record_properties.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/etl/data/external_model_record_track.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
--------------------------------------------------------------------------------
/etl/data/external_model_track.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
--------------------------------------------------------------------------------
/etl/data/field_mapping_properties.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/etl/data/field_mapping_track.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
--------------------------------------------------------------------------------
/etl/data/field_properties.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/etl/data/field_track.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
--------------------------------------------------------------------------------
/etl/data/manager_properties.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/etl/data/manager_track.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
--------------------------------------------------------------------------------
/etl/data/value_mapping_field_detail_properties.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/etl/data/value_mapping_field_detail_track.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
--------------------------------------------------------------------------------
/etl/data/value_mapping_field_properties.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/etl/data/value_mapping_field_track.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
--------------------------------------------------------------------------------
/etl/data/value_mapping_field_value_properties.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/etl/data/value_mapping_field_value_track.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
--------------------------------------------------------------------------------
/etl/external_model.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | ##############################################################################
3 | # For copyright and license notices, see __openerp__.py file in module root
4 | # directory
5 | ##############################################################################
6 | from openerp import models, fields, api, _
7 | from openerp.exceptions import Warning
8 | from ast import literal_eval
9 | import logging
10 | _logger = logging.getLogger(__name__)
11 |
12 |
13 | class external_model(models.Model):
14 | """"""
15 |
16 | _name = 'etl.external_model'
17 | _description = 'external_model'
18 |
19 | _order = "sequence"
20 |
21 | sequence = fields.Integer(
22 | string='Sequence',
23 | readonly=True
24 | )
25 | type = fields.Selection(
26 | [(u'source', u'Source'), (u'target', u'Target')],
27 | string='Type',
28 | readonly=True,
29 | required=True
30 | )
31 | name = fields.Char(
32 | string='Name',
33 | readonly=True,
34 | required=True
35 | )
36 | model = fields.Char(
37 | string='Model',
38 | readonly=True,
39 | required=True
40 | )
41 | order = fields.Integer(
42 | string='Order',
43 | readonly=True
44 | )
45 | records = fields.Integer(
46 | string='Records',
47 | readonly=True
48 | )
49 | fields_to_read = fields.Char(
50 | string='Fields to read',
51 | default=['name']
52 | )
53 | field_ids = fields.One2many(
54 | 'etl.field',
55 | 'model_id',
56 | string='Fields',
57 | readonly=True
58 | )
59 | source_action_ids = fields.One2many(
60 | 'etl.action',
61 | 'source_model_id',
62 | string='source_action_ids'
63 | )
64 | target_action_ids = fields.One2many(
65 | 'etl.action',
66 | 'target_model_id',
67 | string='target_action_ids'
68 | )
69 | manager_id = fields.Many2one(
70 | 'etl.manager',
71 | ondelete='cascade',
72 | string='Manager',
73 | readonly=True,
74 | required=True
75 | )
76 | external_model_record_ids = fields.One2many(
77 | 'etl.external_model_record',
78 | 'external_model_id',
79 | string='external_model_record_ids'
80 | )
81 |
82 | _constraints = [
83 | ]
84 |
85 | def _name_search(self, cr, uid, name='', args=None, operator='ilike', context=None, limit=100, name_get_uid=None):
86 | if args is None:
87 | args = []
88 | domain = args + ['|', ('model', operator, name), ('name', operator, name)]
89 | return self.name_get(cr, name_get_uid or uid,
90 | super(external_model, self).search(cr, uid, domain, limit=limit, context=context),
91 | context=context)
92 |
93 | @api.one
94 | def read_records(self):
95 | '''Function that reads external id and name field from an external
96 | model and save them in migrator database'''
97 | (source_connection, target_connection) = self.manager_id.open_connections()
98 | if self.type == 'source':
99 | connection = source_connection
100 | else:
101 | connection = target_connection
102 |
103 | fields_to_read = []
104 | if self.fields_to_read:
105 | fields_to_read = literal_eval(self.fields_to_read)
106 |
107 | record_fields = ['.id', 'id']
108 | record_fields.extend(fields_to_read)
109 |
110 | external_model_obj = connection.model(self.model)
111 | external_model_record_ids = external_model_obj.search([])
112 | external_model_record_data = external_model_obj.export_data(
113 | external_model_record_ids, record_fields)['datas']
114 |
115 | new_external_model_record_data = []
116 | for record in external_model_record_data:
117 | # take out item o and init new_record with our own ext id
118 | new_record = [
119 | 'model%i_record_%s' % (self.id, record.pop(0))]
120 | # append readed external id 'id' to new record
121 | new_record.append(record.pop(0))
122 | # buid name wit readed fields
123 | name = ''
124 | # record = record.decode("utf-8")
125 | name = '; '.join([x for x in record if x])
126 | new_record.append(name)
127 | # append model id
128 | new_record.append(self.id)
129 | new_external_model_record_data.append(new_record)
130 | external_model_record_fields = [
131 | 'id',
132 | 'ext_id',
133 | 'name',
134 | 'external_model_id/.id']
135 | # load records
136 | self.env['etl.external_model_record'].load(
137 | external_model_record_fields, new_external_model_record_data)
138 |
139 | @api.multi
140 | def read_fields_button(self):
141 | return self.read_fields(False)
142 |
143 | @api.multi
144 | def read_fields(self, connection=False):
145 | ''' Get fields for external models'''
146 | field_fields = [
147 | 'id',
148 | 'model_id/.id',
149 | 'field_description',
150 | 'name',
151 | 'relation',
152 | 'required',
153 | 'ttype',
154 | 'function']
155 | model_field_data = []
156 | for model in self:
157 | _logger.info('Reading fields %s database, model: %s' % (
158 | model.type, model.name))
159 | if not connection:
160 | (source_connection, target_connection) = model.manager_id.open_connections()
161 | if model.type == 'source':
162 | connection = source_connection
163 | elif model.type == 'target':
164 | connection = target_connection
165 | else:
166 | raise Warning(_('Error getting connection'))
167 | external_model_obj = connection.model(model.model)
168 | try:
169 | external_model_fields = external_model_obj.fields_get()
170 | except:
171 | continue
172 | else:
173 | for field in external_model_fields:
174 | field_dic = external_model_fields[field]
175 | name = field
176 | string = field_dic.get('string' or False)
177 | function = field_dic.get('function' or False)
178 | ttype = field_dic.get('type' or False)
179 | relation = field_dic.get('relation' or False)
180 | required = field_dic.get('required' or False)
181 |
182 | field_data = [
183 | 'field_model_%s_%s' % (str(model.id), name),
184 | model.id,
185 | string,
186 | name,
187 | relation,
188 | required,
189 | ttype,
190 | function
191 | ]
192 | model_field_data.append(field_data)
193 | _logger.info('Writing fields data...')
194 | self.env['etl.field'].load(field_fields, model_field_data)
195 |
196 | @api.one
197 | def get_records(self, connection):
198 | try:
199 | model_obj = connection.model(self.model)
200 | model_ids = model_obj.search([])
201 | vals = {'records': len(model_ids)}
202 | _logger.info('%i records on model %s' % (
203 | len(model_ids), self.name))
204 | self.write(vals)
205 | except:
206 | _logger.error('Error getting records')
207 |
208 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
209 |
--------------------------------------------------------------------------------
/etl/external_model_record.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | ##############################################################################
3 | # For copyright and license notices, see __openerp__.py file in module root
4 | # directory
5 | ##############################################################################
6 | from openerp import models, fields, api, _
7 | from openerp.exceptions import Warning
8 |
9 |
10 | class external_model_record(models.Model):
11 | """"""
12 |
13 | _name = 'etl.external_model_record'
14 | _description = 'external_model_record'
15 |
16 | ext_id = fields.Char(
17 | string='Value To be Mapped',
18 | required=True
19 | )
20 | name = fields.Char(
21 | string='Help Name',
22 | required=True
23 | )
24 | external_model_id = fields.Many2one(
25 | 'etl.external_model',
26 | ondelete='cascade',
27 | string='external_model_id',
28 | required=True
29 | )
30 |
31 | _constraints = [
32 | ]
33 |
34 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
35 |
--------------------------------------------------------------------------------
/etl/field.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | ##############################################################################
3 | # For copyright and license notices, see __openerp__.py file in module root
4 | # directory
5 | ##############################################################################
6 | from openerp import models, fields, api, _
7 | from openerp.exceptions import Warning
8 |
9 |
10 | class field(models.Model):
11 | """"""
12 |
13 | _name = 'etl.field'
14 | _description = 'field'
15 |
16 | name = fields.Char(
17 | string='Name',
18 | required=True
19 | )
20 | field_description = fields.Char(
21 | string='Field Description',
22 | required=True
23 | )
24 | relation = fields.Char(
25 | string='Relation'
26 | )
27 | relation_field = fields.Char(
28 | string='Relation Field'
29 | )
30 | ttype = fields.Char(
31 | string='Type',
32 | required=True
33 | )
34 | required = fields.Char(
35 | string='Required'
36 | )
37 | function = fields.Char(
38 | string='Function'
39 | )
40 | model_id = fields.Many2one(
41 | 'etl.external_model',
42 | ondelete='cascade',
43 | string='Model'
44 | )
45 | type = fields.Selection(
46 | related='model_id.type',
47 | string='Type',
48 | readonly=True,
49 | )
50 |
51 | _constraints = [
52 | ]
53 |
54 | def _name_search(self, cr, uid, name='', args=None, operator='ilike', context=None, limit=100, name_get_uid=None):
55 | if args is None:
56 | args = []
57 | domain = args + ['|', ('field_description', operator, name), ('name', operator, name)]
58 | return self.name_get(cr, name_get_uid or uid,
59 | super(field, self).search(cr, uid, domain, limit=limit, context=context),
60 | context=context)
61 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
62 |
--------------------------------------------------------------------------------
/etl/field_mapping.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | ##############################################################################
3 | # For copyright and license notices, see __openerp__.py file in module root
4 | # directory
5 | ##############################################################################
6 | from openerp import models, fields, api, _
7 | from openerp.exceptions import Warning
8 | import time
9 | from openerp.tools.safe_eval import safe_eval as eval
10 | import logging
11 | _logger = logging.getLogger(__name__)
12 |
13 |
14 | class field_mapping(models.Model):
15 | """"""
16 |
17 | _name = 'etl.field_mapping'
18 | _description = 'field_mapping'
19 |
20 | blocked = fields.Boolean(
21 | string='Blocked',
22 | default=False
23 | )
24 | state = fields.Selection(
25 | [(u'on_repeating', 'on_repeating'), (u'to_analyze', 'to_analyze'), (u'enabled', 'enabled'), (u'disabled', 'disabled'), (u'other_class', 'other_class')],
26 | string='State',
27 | required=True
28 | )
29 | type = fields.Selection(
30 | [(u'field', 'field'), (u'expression', 'expression'), (u'migrated_id', u'Migrated ID'), (u'value_mapping', u'Value Mapping'), (u'date_adapt', u'Date Adapt'), (u'reference', 'reference')],
31 | string='Source Type',
32 | default='field'
33 | )
34 | source_field_id = fields.Many2one(
35 | 'etl.field',
36 | string='Source Field'
37 | )
38 | source_field = fields.Char(
39 | string='Source Exp.'
40 | )
41 | target_field_id = fields.Many2one(
42 | 'etl.field',
43 | string='Target Field'
44 | )
45 | target_field = fields.Char(
46 | string='Target Exp.'
47 | )
48 | expression = fields.Text(
49 | string='Expression',
50 | default="context['result']= False"
51 | )
52 | value_mapping_field_id = fields.Many2one(
53 | 'etl.value_mapping_field',
54 | string='Value Mapping Field'
55 | )
56 | model_field_id = fields.Many2one(
57 | 'etl.field',
58 | string='Model Field'
59 | )
60 | model_field = fields.Char(
61 | string='Model Field Exp.'
62 | )
63 | note = fields.Html(
64 | string='Notes'
65 | )
66 | action_id = fields.Many2one(
67 | 'etl.action',
68 | ondelete='cascade',
69 | string='Action',
70 | required=True
71 | )
72 | target_model_id = fields.Many2one(
73 | related='action_id.target_model_id',
74 | relation='etl.external_model',
75 | string='Target Model',
76 | )
77 | source_model_id = fields.Many2one(
78 | related='action_id.source_model_id',
79 | relation='etl.external_model',
80 | string='Source Model',
81 | )
82 | source_field_ttype = fields.Char(
83 | related='source_field_id.ttype',
84 | readonly=True,
85 | string='Source Type'
86 | )
87 | target_field_ttype = fields.Char(
88 | related='target_field_id.ttype',
89 | readonly=True,
90 | string='Target Type'
91 | )
92 | manager_id = fields.Many2one(
93 | related='action_id.manager_id',
94 | relation='etl.manager',
95 | readonly=True,
96 | string='Manager'
97 | )
98 |
99 | _constraints = [
100 | ]
101 |
102 | @api.onchange('source_field_id')
103 | def onchange_source_field(self):
104 | source_field = False
105 | if self.source_field_id:
106 | source_field = self.source_field_id.name
107 | if self.source_field_id.ttype in (
108 | 'many2one', 'many2many', 'one2many'):
109 | source_field += '/id'
110 | self.source_field = source_field
111 |
112 | @api.onchange('target_field_id')
113 | def onchange_target_field(self):
114 | target_field = False
115 | if self.target_field_id:
116 | target_field = self.target_field_id.name
117 | if self.target_field_id.ttype in (
118 | 'many2one', 'many2many', 'one2many'):
119 | target_field += '/id'
120 | self.target_field = target_field
121 |
122 | @api.multi
123 | def action_block(self):
124 | return self.write({'blocked': True})
125 |
126 | @api.multi
127 | def get_migrated_id(
128 | self, rec_id, source_connection=False, target_connection=False):
129 | '''Get migrated id for field ids and one rec_id (from source database)
130 | For example, for field mapping ids'''
131 | result = []
132 |
133 | for field_mapping in self:
134 | if not source_connection or not target_connection:
135 | (source_connection, target_connection) = field_mapping.action_id.manager_id.open_connections()
136 | source_model_obj = source_connection.model(
137 | field_mapping.action_id.source_model_id.model)
138 | target_ir_model_data_obj = target_connection.model('ir.model.data')
139 | source_fields = [
140 | 'id',
141 | field_mapping.source_field_id.name,
142 | field_mapping.model_field]
143 | _logger.info('Source_fields: %s' % source_fields)
144 | source_model_data = source_model_obj.export_data(
145 | [rec_id], source_fields)['datas']
146 | _logger.info('Source_model_data: %s' % source_model_data)
147 | target_id = False
148 | if source_model_data:
149 | source_id = source_model_data[0][1]
150 | try:
151 | source_resource_obj = source_connection.model(
152 | source_model_data[0][2])
153 | except:
154 | target_id = False
155 | else:
156 | source_reference = source_resource_obj.export_data(
157 | [int(source_id)], ['id'])['datas']
158 | if source_reference[0]:
159 | source_reference_splited = source_reference[0][0].split(
160 | '.', 1)
161 | print 'source_reference_splited', source_reference_splited
162 | if len(source_reference_splited) == 1:
163 | module = False
164 | external_ref = source_reference_splited[0]
165 | else:
166 | module = source_reference_splited[0]
167 | external_ref = source_reference_splited[1]
168 | try:
169 | # cambiamos a esta manera fea porque el metodo de abajo no andaba
170 | target_ids = target_ir_model_data_obj.search([(
171 | 'module', '=', module), ('name', '=', external_ref)])
172 | target_ids = target_ir_model_data_obj.read(target_ids, ['res_id'])
173 | if target_ids:
174 | target_id = target_ids[0].get('res_id', False)
175 | # target_id = target_ir_model_data_obj.get_object_reference(
176 | # module, external_ref)[1]
177 | except:
178 | target_id = False
179 | result.append(target_id)
180 | return result
181 |
182 | @api.multi
183 | def get_reference(
184 | self, rec_id, source_connection=False, target_connection=False):
185 | '''Get reference for field ids and one rec_id (from source database)
186 | For example, for field mapping ids'''
187 |
188 | result = []
189 | for field_mapping in self:
190 | if not source_connection or not target_connection:
191 | (source_connection, target_connection) = field_mapping.action_id.manager_id.open_connections()
192 | source_model_obj = source_connection.model(
193 | field_mapping.action_id.source_model_id.model)
194 | target_ir_model_data_obj = target_connection.model('ir.model.data')
195 | source_fields = [field_mapping.source_field_id.name]
196 | source_model_data = source_model_obj.read(
197 | [rec_id], source_fields)[0]
198 | target_id = False
199 | if source_model_data:
200 | source_reference = source_model_data[
201 | field_mapping.source_field_id.name]
202 | if source_reference:
203 | model, res_id = source_reference.split(',', 1)
204 | try:
205 | source_resource_obj = source_connection.model(model)
206 | except:
207 | target_id = False
208 | else:
209 | source_ext_id = source_resource_obj.export_data(
210 | [res_id], ['id'])['datas']
211 | if source_ext_id[0]:
212 | source_ext_id_splited = source_ext_id[0][0].split(
213 | '.', 1)
214 | if len(source_ext_id_splited) == 1:
215 | module = False
216 | external_ref = source_ext_id_splited[0]
217 | else:
218 | module = source_ext_id_splited[0]
219 | external_ref = source_ext_id_splited[1]
220 | try:
221 | target_id = target_ir_model_data_obj.get_object_reference(
222 | module, external_ref)[1]
223 | except:
224 | # Agregamos este nuevo try porque algunas veces module no es false si no que es como una cadena vacia
225 | try:
226 | target_id = target_ir_model_data_obj.get_object_reference(
227 | '', external_ref)[1]
228 | except:
229 | target_id = False
230 | target_reference = False
231 | if target_id:
232 | target_reference = model + ',' + str(target_id)
233 | result.append(target_reference)
234 | return result
235 |
236 | @api.multi
237 | def run_expressions(
238 | self, rec_id, source_connection=False, target_connection=False):
239 | result = []
240 |
241 | for field_mapping in self:
242 | expression_result = False
243 | if not source_connection or not target_connection:
244 | (source_connection, target_connection) = field_mapping.action_id.manager_id.open_connections()
245 | source_model_obj = source_connection.model(
246 | field_mapping.action_id.source_model_id.model)
247 | target_model_obj = target_connection.model(
248 | field_mapping.action_id.target_model_id.model)
249 |
250 | obj_pool = source_model_obj
251 | cxt = {
252 | 'self': obj_pool, #to be replaced by target_obj
253 | 'source_obj': source_model_obj,
254 | 'source_connection': source_connection,
255 | 'target_obj': target_model_obj,
256 | 'target_connection': target_connection,
257 | 'rec_id': rec_id,
258 | 'pool': self.pool,
259 | 'time': time,
260 | 'cr': self._cr,
261 | # copy context to prevent side-effects of eval
262 | 'context': dict(self._context),
263 | 'uid': self.env.user.id,
264 | 'user': self.env.user,
265 | }
266 | if not field_mapping.expression:
267 | raise Warning(_(
268 | 'Warning. Type expression choosen buy not expression set'))
269 | # nocopy allows to return 'action'
270 | eval(field_mapping.expression.strip(), cxt, mode="exec")
271 | if 'result' in cxt['context']:
272 | expression_result = cxt['context'].get('result')
273 | result.append(expression_result)
274 | return result
275 |
276 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
277 |
--------------------------------------------------------------------------------
/etl/i18n/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ingadhoc/odoo-etl/d5f54db11c5f916da79e23c52037ea36a12640a4/etl/i18n/README
--------------------------------------------------------------------------------
/etl/i18n/pt.po:
--------------------------------------------------------------------------------
1 | # Translation of Odoo Server.
2 | # This file contains the translation of the following modules:
3 | # * etl
4 | #
5 | msgid ""
6 | msgstr ""
7 | "Project-Id-Version: Odoo Server 8.0-20150618\n"
8 | "Report-Msgid-Bugs-To: \n"
9 | "POT-Creation-Date: 2015-07-21 13:33+0000\n"
10 | "PO-Revision-Date: 2015-07-21 13:33+0000\n"
11 | "Last-Translator: <>\n"
12 | "Language-Team: \n"
13 | "MIME-Version: 1.0\n"
14 | "Content-Type: text/plain; charset=UTF-8\n"
15 | "Content-Transfer-Encoding: \n"
16 | "Plural-Forms: \n"
17 |
18 | #. module: etl
19 | #: model:ir.actions.act_window,help:etl.action_etl_action_actions
20 | msgid " Click to create a Actions.
\n"
21 | " "
22 | msgstr " Clique para criar Ações.
\n"
23 | " "
24 |
25 | #. module: etl
26 | #: model:ir.actions.act_window,help:etl.action_etl_field_external_fields
27 | msgid " Click to create a External Fields.
\n"
28 | " "
29 | msgstr " Clique para criar Campos Externos.
\n"
30 | " "
31 |
32 | #. module: etl
33 | #: model:ir.actions.act_window,help:etl.action_etl_external_model_external_models
34 | msgid " Click to create a External Models.
\n"
35 | " "
36 | msgstr " Clique para criar Modelos Externos.
\n"
37 | " "
38 |
39 | #. module: etl
40 | #: model:ir.actions.act_window,help:etl.action_etl_field_mapping_fields_mapping
41 | msgid " Click to create a Fields Mapping.
\n"
42 | " "
43 | msgstr " Clique para criar um Mapeamento de Campos.
\n"
44 | " "
45 |
46 | #. module: etl
47 | #: model:ir.actions.act_window,help:etl.action_etl_manager_manager
48 | msgid " Click to create a Manager.
\n"
49 | " "
50 | msgstr " Clique para criar um Gestor.
\n"
51 | " "
52 |
53 | #. module: etl
54 | #: model:ir.actions.act_window,help:etl.action_etl_value_mapping_field_value_mapping_fields
55 | msgid " Click to create a Value Mapping Fields.
\n"
56 | " "
57 | msgstr " Clique para criar um Mapeamento de Valores dos Campos.
\n"
58 | " "
59 |
60 | #. module: etl
61 | #: model:ir.actions.act_window,help:etl.action_etl_value_mapping_field_detail_values_mapping
62 | msgid " Click to create a Values Mapping.
\n"
63 | " "
64 | msgstr " Clique para criar um Mapeamento de Valores.
\n"
65 | " "
66 |
67 | #. module: etl
68 | #: view:etl.field_mapping:etl.view_etl_field_mapping_filter
69 | #: field:etl.field_mapping,action_id:0
70 | msgid "Action"
71 | msgstr "Ação"
72 |
73 | #. module: etl
74 | #: view:etl.manager:etl.view_etl_manager_form
75 | #: field:etl.manager,action_ids:0
76 | #: model:ir.actions.act_window,name:etl.action_etl_action_actions
77 | #: model:ir.ui.menu,name:etl.menu_actions
78 | msgid "Actions"
79 | msgstr "Ações"
80 |
81 | #. module: etl
82 | #: view:etl.action:etl.view_etl_action_form
83 | #: view:etl.field_mapping:etl.view_etl_field_mapping_form
84 | msgid "Block"
85 | msgstr "Bloquear"
86 |
87 | #. module: etl
88 | #: view:etl.action:etl.view_etl_action_filter
89 | #: field:etl.action,blocked:0
90 | #: view:etl.field_mapping:etl.view_etl_field_mapping_filter
91 | #: field:etl.field_mapping,blocked:0
92 | msgid "Blocked"
93 | msgstr "Bloqueado"
94 |
95 | #. module: etl
96 | #: selection:etl.value_mapping_field,type:0
97 | msgid "Char (not implemented yet)"
98 | msgstr "Char (ainda não está implementado)"
99 |
100 | #. module: etl
101 | #: view:etl.action:etl.view_etl_action_form
102 | msgid "Check Depends"
103 | msgstr "Verificar Dependências"
104 |
105 | #. module: etl
106 | #: field:etl.action,create_uid:0
107 | #: field:etl.external_model,create_uid:0
108 | #: field:etl.external_model_record,create_uid:0
109 | #: field:etl.field,create_uid:0
110 | #: field:etl.field_mapping,create_uid:0
111 | #: field:etl.manager,create_uid:0
112 | #: field:etl.value_mapping_field,create_uid:0
113 | #: field:etl.value_mapping_field_detail,create_uid:0
114 | #: field:etl.value_mapping_field_value,create_uid:0
115 | msgid "Created by"
116 | msgstr "Criado por"
117 |
118 | #. module: etl
119 | #: field:etl.action,create_date:0
120 | #: field:etl.external_model,create_date:0
121 | #: field:etl.external_model_record,create_date:0
122 | #: field:etl.field,create_date:0
123 | #: field:etl.field_mapping,create_date:0
124 | #: field:etl.manager,create_date:0
125 | #: field:etl.value_mapping_field,create_date:0
126 | #: field:etl.value_mapping_field_detail,create_date:0
127 | #: field:etl.value_mapping_field_value,create_date:0
128 | msgid "Created on"
129 | msgstr "Criado em"
130 |
131 | #. module: etl
132 | #: model:ir.ui.menu,name:etl.menu_data
133 | msgid "Data"
134 | msgstr "Data"
135 |
136 | #. module: etl
137 | #: selection:etl.field_mapping,type:0
138 | msgid "Date Adapt"
139 | msgstr "Adaptar Data"
140 |
141 | #. module: etl
142 | #: view:etl.manager:etl.view_etl_manager_form
143 | msgid "Delete Workflows"
144 | msgstr "Apagar Workflows"
145 |
146 | #. module: etl
147 | #: field:etl.value_mapping_field,value_mapping_field_detail_ids:0
148 | msgid "Details"
149 | msgstr "Detalhes"
150 |
151 | #. module: etl
152 | #: model:ir.ui.menu,name:etl.menu_etl
153 | msgid "ETL"
154 | msgstr "ETL"
155 |
156 | #. module: etl
157 | #: code:addons\etl\external_model.py:162
158 | #, python-format
159 | msgid "Error getting connection"
160 | msgstr "Erro ao obter conexão"
161 |
162 | #. module: etl
163 | #: view:etl.manager:etl.view_etl_manager_form
164 | msgid "Exceptions"
165 | msgstr "Exceções"
166 |
167 | #. module: etl
168 | #: view:etl.field_mapping:etl.view_etl_field_mapping_filter
169 | #: field:etl.field_mapping,expression:0
170 | msgid "Expression"
171 | msgstr "Expressão"
172 |
173 | #. module: etl
174 | #: model:ir.actions.act_window,name:etl.action_etl_field_external_fields
175 | #: model:ir.ui.menu,name:etl.menu_external_fields
176 | msgid "External Fields"
177 | msgstr "Campos Externos"
178 |
179 | #. module: etl
180 | #: view:etl.manager:etl.view_etl_manager_form
181 | #: field:etl.manager,external_model_ids:0
182 | #: model:ir.actions.act_window,name:etl.action_etl_external_model_external_models
183 | #: model:ir.ui.menu,name:etl.menu_external_models
184 | msgid "External Models"
185 | msgstr "Modelos Externos"
186 |
187 | #. module: etl
188 | #: view:etl.field:etl.view_etl_field_filter
189 | #: field:etl.field,field_description:0
190 | msgid "Field Description"
191 | msgstr "Descrição do Campo"
192 |
193 | #. module: etl
194 | #: view:etl.action:etl.view_etl_action_form
195 | msgid "Field Mapping"
196 | msgstr "Mapeamento de Campo"
197 |
198 | #. module: etl
199 | #: view:etl.value_mapping_field:etl.view_etl_value_mapping_field_filter
200 | #: field:etl.value_mapping_field,name:0
201 | msgid "Field Name"
202 | msgstr "Nome do Campo"
203 |
204 | #. module: etl
205 | #: view:etl.external_model:etl.view_etl_external_model_form
206 | #: field:etl.external_model,field_ids:0
207 | msgid "Fields"
208 | msgstr "Campos"
209 |
210 | #. module: etl
211 | #: field:etl.manager,field_analyze_default:0
212 | msgid "Fields Analize by Default"
213 | msgstr "Campos Analizados por Defeito"
214 |
215 | #. module: etl
216 | #: field:etl.manager,field_disable_default:0
217 | msgid "Fields Disable by Default"
218 | msgstr "Campos Desativados por Defeito"
219 |
220 | #. module: etl
221 | #: field:etl.manager,field_disable_words:0
222 | msgid "Fields Disable by Default Words"
223 | msgstr "Campos Desativados por Palavras Padrão"
224 |
225 | #. module: etl
226 | #: view:etl.action:etl.view_etl_action_form
227 | #: field:etl.action,field_mapping_ids:0
228 | #: model:ir.actions.act_window,name:etl.action_etl_field_mapping_fields_mapping
229 | #: model:ir.ui.menu,name:etl.menu_fields_mapping
230 | msgid "Fields Mapping"
231 | msgstr "Mapeamento de Campos"
232 |
233 | #. module: etl
234 | #: field:etl.external_model,fields_to_read:0
235 | msgid "Fields to read"
236 | msgstr "Campos para ler"
237 |
238 | #. module: etl
239 | #: field:etl.action,from_rec_id:0
240 | msgid "From Record"
241 | msgstr "De Registo"
242 |
243 | #. module: etl
244 | #: view:etl.field:etl.view_etl_field_filter
245 | #: field:etl.field,function:0
246 | msgid "Function"
247 | msgstr "Função"
248 |
249 | #. module: etl
250 | #: view:etl.manager:etl.view_etl_manager_form
251 | msgid "Get Records Number"
252 | msgstr "Obter número de registos"
253 |
254 | #. module: etl
255 | #: view:etl.action:etl.view_etl_action_filter
256 | #: view:etl.external_model:etl.view_etl_external_model_filter
257 | #: view:etl.external_model_record:etl.view_etl_external_model_record_filter
258 | #: view:etl.field:etl.view_etl_field_filter
259 | #: view:etl.field_mapping:etl.view_etl_field_mapping_filter
260 | #: view:etl.manager:etl.view_etl_manager_filter
261 | #: view:etl.value_mapping_field:etl.view_etl_value_mapping_field_filter
262 | #: view:etl.value_mapping_field_detail:etl.view_etl_value_mapping_field_detail_filter
263 | #: view:etl.value_mapping_field_value:etl.view_etl_value_mapping_field_value_filter
264 | msgid "Group By"
265 | msgstr "Agrupar por"
266 |
267 | #. module: etl
268 | #: view:etl.external_model_record:etl.view_etl_external_model_record_filter
269 | #: field:etl.external_model_record,name:0
270 | #: view:etl.value_mapping_field_value:etl.view_etl_value_mapping_field_value_filter
271 | #: field:etl.value_mapping_field_value,name:0
272 | msgid "Help Name"
273 | msgstr "Nome de ajuda"
274 |
275 | #. module: etl
276 | #: field:etl.action,id:0
277 | #: field:etl.external_model,id:0
278 | #: field:etl.external_model_record,id:0
279 | #: field:etl.field,id:0
280 | #: field:etl.field_mapping,id:0
281 | #: field:etl.manager,id:0
282 | #: field:etl.value_mapping_field,id:0
283 | #: field:etl.value_mapping_field_detail,id:0
284 | #: field:etl.value_mapping_field_value,id:0
285 | msgid "ID"
286 | msgstr "ID"
287 |
288 | #. module: etl
289 | #: selection:etl.value_mapping_field,type:0
290 | msgid "Id"
291 | msgstr "ID"
292 |
293 | #. module: etl
294 | #: view:etl.manager:etl.view_etl_manager_form
295 | msgid "Install Modules"
296 | msgstr "Instalar Módulos"
297 |
298 | #. module: etl
299 | #: view:etl.value_mapping_field_value:etl.view_etl_value_mapping_field_value_filter
300 | #: field:etl.value_mapping_field_value,ext_id:0
301 | msgid "Key"
302 | msgstr "Chave"
303 |
304 | #. module: etl
305 | #: help:etl.manager,source_lang:0
306 | msgid "Language used on source database translatable fields"
307 | msgstr "Linguagem utilizada nos campos traduzíveis do banco de dados de origem"
308 |
309 | #. module: etl
310 | #: help:etl.manager,target_lang:0
311 | msgid "Language used on target database translatable fields"
312 | msgstr "Linguagem utilizada nos campos traduzíveis do banco de dados de destino"
313 |
314 | #. module: etl
315 | #: field:etl.action,write_uid:0
316 | #: field:etl.external_model,write_uid:0
317 | #: field:etl.external_model_record,write_uid:0
318 | #: field:etl.field,write_uid:0
319 | #: field:etl.field_mapping,write_uid:0
320 | #: field:etl.manager,write_uid:0
321 | #: field:etl.value_mapping_field,write_uid:0
322 | #: field:etl.value_mapping_field_detail,write_uid:0
323 | #: field:etl.value_mapping_field_value,write_uid:0
324 | msgid "Last Updated by"
325 | msgstr "Última atualização por"
326 |
327 | #. module: etl
328 | #: field:etl.action,write_date:0
329 | #: field:etl.external_model,write_date:0
330 | #: field:etl.external_model_record,write_date:0
331 | #: field:etl.field,write_date:0
332 | #: field:etl.field_mapping,write_date:0
333 | #: field:etl.manager,write_date:0
334 | #: field:etl.value_mapping_field,write_date:0
335 | #: field:etl.value_mapping_field_detail,write_date:0
336 | #: field:etl.value_mapping_field_value,write_date:0
337 | msgid "Last Updated on"
338 | msgstr "Última atualização em"
339 |
340 | #. module: etl
341 | #: view:etl.action:etl.view_etl_action_form
342 | #: field:etl.action,log:0
343 | #: view:etl.manager:etl.view_etl_manager_form
344 | #: field:etl.manager,log:0
345 | msgid "Log"
346 | msgstr "Log"
347 |
348 | #. module: etl
349 | #: view:etl.action:etl.view_etl_action_filter
350 | #: field:etl.action,manager_id:0
351 | #: view:etl.external_model:etl.view_etl_external_model_filter
352 | #: field:etl.external_model,manager_id:0
353 | #: view:etl.manager:etl.view_etl_manager_form
354 | #: model:ir.actions.act_window,name:etl.action_etl_manager_manager
355 | #: model:ir.ui.menu,name:etl.menu_manager
356 | #: model:res.groups,name:etl.group_manager
357 | msgid "Manager"
358 | msgstr "Gestor"
359 |
360 | #. module: etl
361 | #: view:etl.value_mapping_field:etl.view_etl_value_mapping_field_form
362 | msgid "Map Records"
363 | msgstr "Mapear Registos"
364 |
365 | #. module: etl
366 | #: field:etl.value_mapping_field,value_mapping_field_value_ids:0
367 | msgid "Mapping Values"
368 | msgstr "Valores de Mapeamento"
369 |
370 | #. module: etl
371 | #: view:etl.action:etl.view_etl_action_form
372 | msgid "Match Fields"
373 | msgstr "Corresponder Campos"
374 |
375 | #. module: etl
376 | #: view:etl.manager:etl.view_etl_manager_form
377 | msgid "Match Models"
378 | msgstr "Corresponder Modelos"
379 |
380 | #. module: etl
381 | #: view:etl.manager:etl.view_etl_manager_form
382 | msgid "Match and Order"
383 | msgstr "Corresponder e Ordenar"
384 |
385 | #. module: etl
386 | #: selection:etl.field_mapping,type:0
387 | msgid "Migrated ID"
388 | msgstr "ID Migrado"
389 |
390 | #. module: etl
391 | #: view:etl.external_model:etl.view_etl_external_model_filter
392 | #: field:etl.external_model,model:0
393 | #: field:etl.field,model_id:0
394 | msgid "Model"
395 | msgstr "Modelo"
396 |
397 | #. module: etl
398 | #: field:etl.manager,model_exception_words:0
399 | msgid "Model Exception Words"
400 | msgstr "Modelo Palavras de Excepção"
401 |
402 | #. module: etl
403 | #: field:etl.field_mapping,model_field_id:0
404 | msgid "Model Field"
405 | msgstr "Campo Modelo"
406 |
407 | #. module: etl
408 | #: field:etl.field_mapping,model_field:0
409 | msgid "Model Field Exp."
410 | msgstr "Modelo Expressão de Campo"
411 |
412 | #. module: etl
413 | #: view:etl.action:etl.view_etl_action_form
414 | msgid "Models"
415 | msgstr "Modelos"
416 |
417 | #. module: etl
418 | #: field:etl.manager,model_analyze_default:0
419 | msgid "Models Analyze by Default"
420 | msgstr "Modelos Analizados por Defeito"
421 |
422 | #. module: etl
423 | #: field:etl.manager,model_disable_default:0
424 | msgid "Models Disabled by Default"
425 | msgstr "Modelos Desativados por Defeito"
426 |
427 | #. module: etl
428 | #: field:etl.manager,workflow_models:0
429 | msgid "Models to delete Workflows"
430 | msgstr "Modelos para apagar Workflows"
431 |
432 | #. module: etl
433 | #: field:etl.manager,modules_to_install:0
434 | msgid "Modules To Install"
435 | msgstr "Módulos para Instalar"
436 |
437 | #. module: etl
438 | #: view:etl.action:etl.view_etl_action_filter
439 | #: field:etl.action,name:0
440 | #: view:etl.external_model:etl.view_etl_external_model_filter
441 | #: field:etl.external_model,name:0
442 | #: view:etl.field:etl.view_etl_field_filter
443 | #: field:etl.field,name:0
444 | #: view:etl.manager:etl.view_etl_manager_filter
445 | #: field:etl.manager,name:0
446 | msgid "Name"
447 | msgstr "Nome"
448 |
449 | #. module: etl
450 | #: view:etl.action:etl.view_etl_action_filter
451 | msgid "Not Grey"
452 | msgstr "Ativadas"
453 |
454 | #. module: etl
455 | #: view:etl.action:etl.view_etl_action_form
456 | #: field:etl.action,note:0
457 | #: field:etl.field_mapping,note:0
458 | #: field:etl.manager,note:0
459 | msgid "Notes"
460 | msgstr "Notas"
461 |
462 | #. module: etl
463 | #: view:etl.external_model:etl.view_etl_external_model_filter
464 | #: field:etl.external_model,order:0
465 | msgid "Order"
466 | msgstr "Ordenar"
467 |
468 | #. module: etl
469 | #: view:etl.manager:etl.view_etl_manager_form
470 | msgid "Order Actions"
471 | msgstr "Ordenar Ações"
472 |
473 | #. module: etl
474 | #: view:etl.manager:etl.view_etl_manager_form
475 | msgid "Read Active Source Models"
476 | msgstr "Ler Modelos de Origem Ativos"
477 |
478 | #. module: etl
479 | #: view:etl.external_model:etl.view_etl_external_model_form
480 | msgid "Read Fields"
481 | msgstr "Ler Campos"
482 |
483 | #. module: etl
484 | #: view:etl.manager:etl.view_etl_manager_form
485 | msgid "Read Models"
486 | msgstr "Ler Modelos"
487 |
488 | #. module: etl
489 | #: view:etl.external_model:etl.view_etl_external_model_form
490 | msgid "Read Records"
491 | msgstr "Ler Registos"
492 |
493 | #. module: etl
494 | #: view:etl.manager:etl.view_etl_manager_form
495 | msgid "Read and get Records"
496 | msgstr "Ler e obter Registos"
497 |
498 | #. module: etl
499 | #: view:etl.external_model:etl.view_etl_external_model_filter
500 | #: view:etl.external_model:etl.view_etl_external_model_form
501 | #: field:etl.external_model,records:0
502 | msgid "Records"
503 | msgstr "Registos"
504 |
505 | #. module: etl
506 | #: view:etl.field:etl.view_etl_field_filter
507 | #: field:etl.field,relation:0
508 | msgid "Relation"
509 | msgstr "Relação"
510 |
511 | #. module: etl
512 | #: view:etl.field:etl.view_etl_field_filter
513 | #: field:etl.field,relation_field:0
514 | msgid "Relation Field"
515 | msgstr "Campo de Relação"
516 |
517 | #. module: etl
518 | #: field:etl.action,repeating_action:0
519 | msgid "Repeating Action?"
520 | msgstr "Ação de Repetição?"
521 |
522 | #. module: etl
523 | #: field:etl.manager,repeating_models:0
524 | msgid "Repeating Models"
525 | msgstr "Modelos de Repetição"
526 |
527 | #. module: etl
528 | #: view:etl.field:etl.view_etl_field_filter
529 | #: field:etl.field,required:0
530 | msgid "Required"
531 | msgstr "Obrigatório"
532 |
533 | #. module: etl
534 | #: view:etl.action:etl.view_etl_action_form
535 | msgid "Run Action"
536 | msgstr "Correr Ação"
537 |
538 | #. module: etl
539 | #: view:etl.manager:etl.view_etl_manager_form
540 | msgid "Run Actions"
541 | msgstr "Correr Ações"
542 |
543 | #. module: etl
544 | #: view:etl.field_mapping:etl.view_etl_field_mapping_form
545 | msgid "Run Expressions"
546 | msgstr "Correr Expressões"
547 |
548 | #. module: etl
549 | #: view:etl.action:etl.view_etl_action_form
550 | msgid "Run Repeated Action"
551 | msgstr "Correr Ação Repetida"
552 |
553 | #. module: etl
554 | #: view:etl.manager:etl.view_etl_manager_form
555 | msgid "Run Repeating Actions"
556 | msgstr "Correr Ações Repetidas"
557 |
558 | #. module: etl
559 | #: selection:etl.value_mapping_field,type:0
560 | msgid "Selection"
561 | msgstr "Seleção"
562 |
563 | #. module: etl
564 | #: view:etl.action:etl.view_etl_action_filter
565 | #: field:etl.action,sequence:0
566 | #: view:etl.external_model:etl.view_etl_external_model_filter
567 | #: field:etl.external_model,sequence:0
568 | msgid "Sequence"
569 | msgstr "Sequência"
570 |
571 | #. module: etl
572 | #: selection:etl.external_model,type:0
573 | msgid "Source"
574 | msgstr "Origem"
575 |
576 | #. module: etl
577 | #: view:etl.manager:etl.view_etl_manager_filter
578 | #: field:etl.manager,source_database:0
579 | msgid "Source Database"
580 | msgstr "Base de Dados Origem"
581 |
582 | #. module: etl
583 | #: view:etl.action:etl.view_etl_action_filter
584 | #: field:etl.action,source_domain:0
585 | msgid "Source Domain"
586 | msgstr "Domínio Origem"
587 |
588 | #. module: etl
589 | #: view:etl.field_mapping:etl.view_etl_field_mapping_filter
590 | #: field:etl.field_mapping,source_field:0
591 | msgid "Source Exp."
592 | msgstr "Expressão Origem"
593 |
594 | #. module: etl
595 | #: field:etl.value_mapping_field_detail,source_external_model_record_id:0
596 | msgid "Source External Model Record"
597 | msgstr "Registo de Modelo Externo Origem"
598 |
599 | #. module: etl
600 | #: view:etl.field_mapping:etl.view_etl_field_mapping_filter
601 | #: field:etl.field_mapping,source_field_id:0
602 | msgid "Source Field"
603 | msgstr "Campo Origem"
604 |
605 | #. module: etl
606 | #: view:etl.manager:etl.view_etl_manager_filter
607 | #: field:etl.manager,source_hostname:0
608 | msgid "Source Hostname"
609 | msgstr "Hostname Origem"
610 |
611 | #. module: etl
612 | #: field:etl.value_mapping_field_detail,source_id:0
613 | msgid "Source ID"
614 | msgstr "ID Origem"
615 |
616 | #. module: etl
617 | #: field:etl.manager,source_lang:0
618 | msgid "Source Language"
619 | msgstr "Linguagem Origem"
620 |
621 | #. module: etl
622 | #: field:etl.manager,source_login:0
623 | msgid "Source Login"
624 | msgstr "Login Origem"
625 |
626 | #. module: etl
627 | #: view:etl.action:etl.view_etl_action_filter
628 | #: field:etl.action,source_model_id:0
629 | #: field:etl.value_mapping_field,source_model_id:0
630 | msgid "Source Model"
631 | msgstr "Modelo Origem"
632 |
633 | #. module: etl
634 | #: field:etl.manager,source_password:0
635 | msgid "Source Password"
636 | msgstr "Password Origem"
637 |
638 | #. module: etl
639 | #: field:etl.manager,source_port:0
640 | msgid "Source Port"
641 | msgstr "Porta Origem"
642 |
643 | #. module: etl
644 | #: view:etl.field_mapping:etl.view_etl_field_mapping_filter
645 | #: field:etl.field_mapping,type:0
646 | msgid "Source Type"
647 | msgstr "Tipo Origem"
648 |
649 | #. module: etl
650 | #: view:etl.value_mapping_field_detail:etl.view_etl_value_mapping_field_detail_filter
651 | #: field:etl.value_mapping_field_detail,source_value:0
652 | #: field:etl.value_mapping_field_detail,source_value_id:0
653 | msgid "Source Value"
654 | msgstr "Valor Origem"
655 |
656 | #. module: etl
657 | #: view:etl.value_mapping_field_detail:etl.view_etl_value_mapping_field_detail_filter
658 | msgid "Source..."
659 | msgstr "Origem..."
660 |
661 | #. module: etl
662 | #: view:etl.action:etl.view_etl_action_filter
663 | #: field:etl.action,state:0
664 | #: view:etl.field_mapping:etl.view_etl_field_mapping_filter
665 | #: field:etl.field_mapping,state:0
666 | msgid "State"
667 | msgstr "Estado"
668 |
669 | #. module: etl
670 | #: selection:etl.external_model,type:0
671 | msgid "Target"
672 | msgstr "Destino"
673 |
674 | #. module: etl
675 | #: view:etl.manager:etl.view_etl_manager_filter
676 | #: field:etl.manager,target_database:0
677 | msgid "Target Database"
678 | msgstr "Base de Dados Destino"
679 |
680 | #. module: etl
681 | #: view:etl.field_mapping:etl.view_etl_field_mapping_filter
682 | #: field:etl.field_mapping,target_field:0
683 | msgid "Target Exp."
684 | msgstr "Expressão Destino"
685 |
686 | #. module: etl
687 | #: field:etl.value_mapping_field_detail,target_external_model_record_id:0
688 | msgid "Target External Model Record"
689 | msgstr "Registo de Modelo Externo Destino"
690 |
691 | #. module: etl
692 | #: view:etl.field_mapping:etl.view_etl_field_mapping_filter
693 | #: field:etl.field_mapping,target_field_id:0
694 | msgid "Target Field"
695 | msgstr "Campo Destino"
696 |
697 | #. module: etl
698 | #: view:etl.manager:etl.view_etl_manager_filter
699 | #: field:etl.manager,target_hostname:0
700 | msgid "Target Hostname"
701 | msgstr "Hostname Destino"
702 |
703 | #. module: etl
704 | #: field:etl.value_mapping_field_detail,target_id:0
705 | msgid "Target ID"
706 | msgstr "ID Destino"
707 |
708 | #. module: etl
709 | #: field:etl.action,target_id_type:0
710 | msgid "Target ID Type"
711 | msgstr "ID Tipo Destino"
712 |
713 | #. module: etl
714 | #: field:etl.manager,target_lang:0
715 | msgid "Target Language"
716 | msgstr "Linguagem Destino"
717 |
718 | #. module: etl
719 | #: field:etl.manager,target_login:0
720 | msgid "Target Login"
721 | msgstr "Login Destino"
722 |
723 | #. module: etl
724 | #: view:etl.action:etl.view_etl_action_filter
725 | #: field:etl.action,target_model_id:0
726 | #: field:etl.value_mapping_field,target_model_id:0
727 | msgid "Target Model"
728 | msgstr "Modelo Destino"
729 |
730 | #. module: etl
731 | #: field:etl.manager,target_password:0
732 | msgid "Target Password"
733 | msgstr "Password Destino"
734 |
735 | #. module: etl
736 | #: field:etl.manager,target_port:0
737 | msgid "Target Port"
738 | msgstr "Porta Destino"
739 |
740 | #. module: etl
741 | #: view:etl.value_mapping_field_detail:etl.view_etl_value_mapping_field_detail_filter
742 | #: field:etl.value_mapping_field_detail,target_value:0
743 | #: field:etl.value_mapping_field_detail,target_value_id:0
744 | msgid "Target Value"
745 | msgstr "Valor Destino"
746 |
747 | #. module: etl
748 | #: view:etl.value_mapping_field_detail:etl.view_etl_value_mapping_field_detail_filter
749 | msgid "To Map"
750 | msgstr "Para mapear"
751 |
752 | #. module: etl
753 | #: field:etl.action,to_rec_id:0
754 | msgid "To Record"
755 | msgstr "Para Registo"
756 |
757 | #. module: etl
758 | #: view:etl.external_model:etl.view_etl_external_model_filter
759 | #: field:etl.external_model,type:0
760 | #: view:etl.field:etl.view_etl_field_filter
761 | #: field:etl.field,ttype:0
762 | #: view:etl.value_mapping_field:etl.view_etl_value_mapping_field_filter
763 | #: field:etl.value_mapping_field,type:0
764 | msgid "Type"
765 | msgstr "Tipo"
766 |
767 | #. module: etl
768 | #: code:addons\etl\manager.py:164
769 | #: code:addons\etl\manager.py:174
770 | #, python-format
771 | msgid "Unable to Connect to Database. 'Error: %s'"
772 | msgstr "Não é possível conectar à base de dados. 'Erro: %s'"
773 |
774 | #. module: etl
775 | #: view:etl.action:etl.view_etl_action_form
776 | msgid "Update Records Number"
777 | msgstr "Atualizar número de registos"
778 |
779 | #. module: etl
780 | #: model:res.groups,name:etl.group_user
781 | msgid "User"
782 | msgstr "Utilizador"
783 |
784 | #. module: etl
785 | #: selection:etl.field_mapping,type:0
786 | msgid "Value Mapping"
787 | msgstr "Mapeamento de Valor"
788 |
789 | #. module: etl
790 | #: field:etl.field_mapping,value_mapping_field_id:0
791 | msgid "Value Mapping Field"
792 | msgstr "Mapeamento de Valor do Campo"
793 |
794 | #. module: etl
795 | #: view:etl.manager:etl.view_etl_manager_form
796 | #: field:etl.manager,value_mapping_field_ids:0
797 | #: model:ir.actions.act_window,name:etl.action_etl_value_mapping_field_value_mapping_fields
798 | #: model:ir.ui.menu,name:etl.menu_value_mapping_fields
799 | msgid "Value Mapping Fields"
800 | msgstr "Mapeamento de Valores dos Campos"
801 |
802 | #. module: etl
803 | #: view:etl.external_model_record:etl.view_etl_external_model_record_filter
804 | #: field:etl.external_model_record,ext_id:0
805 | msgid "Value To be Mapped"
806 | msgstr "Valores a Mapear"
807 |
808 | #. module: etl
809 | #: model:ir.actions.act_window,name:etl.action_etl_value_mapping_field_detail_values_mapping
810 | #: model:ir.ui.menu,name:etl.menu_values_mapping
811 | msgid "Values Mapping"
812 | msgstr "Mapeamento de Valores"
813 |
814 | #. module: etl
815 | #: code:addons\etl\field_mapping.py:256
816 | #, python-format
817 | msgid "Warning. Type expression choosen buy not expression set"
818 | msgstr "Atenção. Tipo de expressão escolhida mas não definida"
819 |
820 | #. module: etl
821 | #: view:etl.action:etl.view_etl_action_filter
822 | #: view:etl.action:etl.view_etl_action_form
823 | #: view:etl.action:etl.view_etl_action_tree
824 | #: model:ir.model,name:etl.model_etl_action
825 | msgid "action"
826 | msgstr "Ação"
827 |
828 | #. module: etl
829 | #: selection:etl.action,target_id_type:0
830 | msgid "builded_id"
831 | msgstr "builded_id"
832 |
833 | #. module: etl
834 | #: selection:etl.action,state:0
835 | #: selection:etl.field_mapping,state:0
836 | msgid "disabled"
837 | msgstr "Desativado"
838 |
839 | #. module: etl
840 | #: selection:etl.action,state:0
841 | #: selection:etl.field_mapping,state:0
842 | msgid "enabled"
843 | msgstr "Ativado"
844 |
845 | #. module: etl
846 | #: selection:etl.field_mapping,type:0
847 | msgid "expression"
848 | msgstr "Expressão"
849 |
850 | #. module: etl
851 | #: view:etl.external_model:etl.view_etl_external_model_filter
852 | #: view:etl.external_model:etl.view_etl_external_model_form
853 | #: view:etl.external_model:etl.view_etl_external_model_tree
854 | #: model:ir.model,name:etl.model_etl_external_model
855 | msgid "external_model"
856 | msgstr "Modelo Externo"
857 |
858 | #. module: etl
859 | #: field:etl.external_model_record,external_model_id:0
860 | msgid "external_model_id"
861 | msgstr "Modelo Externo"
862 |
863 | #. module: etl
864 | #: view:etl.external_model_record:etl.view_etl_external_model_record_filter
865 | #: view:etl.external_model_record:etl.view_etl_external_model_record_form
866 | #: view:etl.external_model_record:etl.view_etl_external_model_record_tree
867 | #: model:ir.model,name:etl.model_etl_external_model_record
868 | msgid "external_model_record"
869 | msgstr "Registo de Modelo Externo"
870 |
871 | #. module: etl
872 | #: field:etl.external_model,external_model_record_ids:0
873 | msgid "external_model_record_ids"
874 | msgstr "Modelo Externo"
875 |
876 | #. module: etl
877 | #: view:etl.field:etl.view_etl_field_filter
878 | #: view:etl.field:etl.view_etl_field_form
879 | #: view:etl.field:etl.view_etl_field_tree
880 | #: selection:etl.field_mapping,type:0
881 | #: model:ir.model,name:etl.model_etl_field
882 | msgid "field"
883 | msgstr "Campo"
884 |
885 | #. module: etl
886 | #: view:etl.field_mapping:etl.view_etl_field_mapping_filter
887 | #: view:etl.field_mapping:etl.view_etl_field_mapping_form
888 | #: view:etl.field_mapping:etl.view_etl_field_mapping_tree
889 | #: model:ir.model,name:etl.model_etl_field_mapping
890 | msgid "field_mapping"
891 | msgstr "Mapeamento de Campo"
892 |
893 | #. module: etl
894 | #: field:etl.value_mapping_field,log:0
895 | msgid "log"
896 | msgstr "Log"
897 |
898 | #. module: etl
899 | #: view:etl.manager:etl.view_etl_manager_filter
900 | #: view:etl.manager:etl.view_etl_manager_form
901 | #: view:etl.manager:etl.view_etl_manager_tree
902 | #: model:ir.model,name:etl.model_etl_manager
903 | msgid "manager"
904 | msgstr "Gestor"
905 |
906 | #. module: etl
907 | #: view:etl.value_mapping_field:etl.view_etl_value_mapping_field_filter
908 | #: field:etl.value_mapping_field,manager_id:0
909 | msgid "manager_id"
910 | msgstr "Gestor"
911 |
912 | #. module: etl
913 | #: selection:etl.action,state:0
914 | msgid "no_records"
915 | msgstr "Sem registos"
916 |
917 | #. module: etl
918 | #: view:etl.manager:etl.view_etl_manager_form
919 | msgid "notes"
920 | msgstr "Notas"
921 |
922 | #. module: etl
923 | #: model:ir.module.category,description:etl.module_category_etl
924 | #: model:ir.module.category,name:etl.module_category_etl
925 | msgid "odoo ETL"
926 | msgstr "Odoo ETL"
927 |
928 | #. module: etl
929 | #: selection:etl.field_mapping,state:0
930 | msgid "on_repeating"
931 | msgstr "A repetir"
932 |
933 | #. module: etl
934 | #: selection:etl.field_mapping,state:0
935 | msgid "other_class"
936 | msgstr "Outra classe"
937 |
938 | #. module: etl
939 | #: selection:etl.field_mapping,type:0
940 | msgid "reference"
941 | msgstr "Referência"
942 |
943 | #. module: etl
944 | #: field:etl.external_model,source_action_ids:0
945 | msgid "source_action_ids"
946 | msgstr "Ação Origem"
947 |
948 | #. module: etl
949 | #: selection:etl.action,target_id_type:0
950 | msgid "source_id"
951 | msgstr "Origem"
952 |
953 | #. module: etl
954 | #: field:etl.action,source_id_exp:0
955 | msgid "source_id_exp"
956 | msgstr "Expressão Origem"
957 |
958 | #. module: etl
959 | #: field:etl.external_model,target_action_ids:0
960 | msgid "target_action_ids"
961 | msgstr "Ação Destino""
962 |
963 | #. module: etl
964 | #: field:etl.action,target_id_prefix:0
965 | msgid "target_id_prefix"
966 | msgstr "Prefixo Destino"
967 |
968 | #. module: etl
969 | #: selection:etl.action,state:0
970 | #: selection:etl.field_mapping,state:0
971 | msgid "to_analyze"
972 | msgstr "A analisar"
973 |
974 | #. module: etl
975 | #: view:etl.value_mapping_field:etl.view_etl_value_mapping_field_filter
976 | #: view:etl.value_mapping_field:etl.view_etl_value_mapping_field_form
977 | #: view:etl.value_mapping_field:etl.view_etl_value_mapping_field_tree
978 | #: model:ir.model,name:etl.model_etl_value_mapping_field
979 | msgid "value_mapping_field"
980 | msgstr "Mapeamento de Valor do Campo"
981 |
982 | #. module: etl
983 | #: view:etl.value_mapping_field_detail:etl.view_etl_value_mapping_field_detail_filter
984 | #: view:etl.value_mapping_field_detail:etl.view_etl_value_mapping_field_detail_form
985 | #: view:etl.value_mapping_field_detail:etl.view_etl_value_mapping_field_detail_tree
986 | #: model:ir.model,name:etl.model_etl_value_mapping_field_detail
987 | msgid "value_mapping_field_detail"
988 | msgstr "Mapeamento de Valor de Detalhe do Campo"
989 |
990 | #. module: etl
991 | #: view:etl.value_mapping_field_detail:etl.view_etl_value_mapping_field_detail_filter
992 | #: field:etl.value_mapping_field_detail,value_mapping_field_id:0
993 | #: field:etl.value_mapping_field_value,value_mapping_field_id:0
994 | msgid "value_mapping_field_id"
995 | msgstr "Mapeamento de Valor do Campo"
996 |
997 | #. module: etl
998 | #: view:etl.value_mapping_field_value:etl.view_etl_value_mapping_field_value_filter
999 | #: view:etl.value_mapping_field_value:etl.view_etl_value_mapping_field_value_form
1000 | #: view:etl.value_mapping_field_value:etl.view_etl_value_mapping_field_value_tree
1001 | #: model:ir.model,name:etl.model_etl_value_mapping_field_value
1002 | msgid "value_mapping_field_value"
1003 | msgstr "Valor de Mapeamento de Valor do Campo"
1004 |
1005 |
--------------------------------------------------------------------------------
/etl/images/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ingadhoc/odoo-etl/d5f54db11c5f916da79e23c52037ea36a12640a4/etl/images/README
--------------------------------------------------------------------------------
/etl/manager.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | ##############################################################################
3 | # For copyright and license notices, see __openerp__.py file in module root
4 | # directory
5 | ##############################################################################
6 | from openerp import models, fields, api, _
7 | from openerp.exceptions import Warning
8 | from erppeek import Client
9 | from ast import literal_eval
10 | import logging
11 | _logger = logging.getLogger(__name__)
12 |
13 |
14 | class manager(models.Model):
15 | """"""
16 |
17 | _name = 'etl.manager'
18 | _description = 'manager'
19 |
20 | name = fields.Char(
21 | string='Name',
22 | required=True
23 | )
24 | source_hostname = fields.Char(
25 | string='Source Hostname',
26 | required=True,
27 | default='http://localhost',
28 | )
29 | source_port = fields.Integer(
30 | string='Source Port',
31 | required=True
32 | )
33 | source_database = fields.Char(
34 | string='Source Database',
35 | required=True
36 | )
37 | source_login = fields.Char(
38 | string='Source Login',
39 | required=True
40 | )
41 | source_password = fields.Char(
42 | string='Source Password',
43 | required=True
44 | )
45 | target_hostname = fields.Char(
46 | string='Target Hostname',
47 | required=True,
48 | default='http://localhost',
49 | )
50 | target_port = fields.Integer(
51 | string='Target Port',
52 | required=True
53 | )
54 | target_database = fields.Char(
55 | string='Target Database',
56 | required=True
57 | )
58 | target_login = fields.Char(
59 | string='Target Login',
60 | required=True
61 | )
62 | target_password = fields.Char(
63 | string='Target Password',
64 | required=True
65 | )
66 | log = fields.Text(
67 | string='Log'
68 | )
69 | model_disable_default = fields.Text(
70 | string='Models Disabled by Default',
71 | # TODO move this default to another model
72 | default="['ir.model','ir.model.fields','ir.model.access','ir.model.data','ir.sequence.type','ir.sequence','ir.ui.menu','ir.ui.view.custom','ir.ui.view','ir.ui.view_sc','ir.default','ir.actions.actions','ir.actions.act_window','ir.actions.act_window.view','ir.actions.wizard','ir.actions.url','ir.server.object.lines','ir.actions.server','ir.actions.act_window_close','ir.actions.todo.category','ir.actions.todo','ir.actions.client','ir.values','ir.translation','ir.exports','ir.exports.line','workflow','workflow.activity','workflow.transition','workflow.instance','workflow.workitem','workflow.triggers','ir.rule','ir.module.category','ir.module.module','ir.module.module.dependency','res.widget','res.widget.user','publisher_warranty.contract','ir.module.record','board.board','board.board.line','decimal.precision','process.process','process.node','process.condition','process.transition','process.transition.action','email_template.preview','account.tax.template','account.account.template','account.tax.code.template','account.chart.template','account.fiscal.position.template','account.fiscal.position.tax.template','account.fiscal.position.account.template','temp.range','mrp.property.group','mrp.property','account.invoice.ar.installer','pos.config.journal','oo.config','mass.object','mass.editing.wizard','support.support_contract','support.email','account_analytic_analysis.summary.user','account_analytic_analysis.summary.month','res.groups','mail.alias']"
73 | )
74 | field_disable_default = fields.Text(
75 | string='Fields Disable by Default',
76 | # TODO move this default to another model
77 | default="['lang','printed_vat','context_lang','context_department_id','groups_id','alias_defaults','alias_id','alias_model_id','create_date','calendar_last_notif_ack',]",
78 | )
79 | model_exception_words = fields.Char(
80 | string='Model Exception Words',
81 | # TODO move this default to another model
82 | default="['report','ir.logging','ir.qweb']",
83 | )
84 | model_analyze_default = fields.Text(
85 | string='Models Analyze by Default',
86 | # TODO move this default to another model
87 | default="['ir.attachment','ir.cron','ir.filters','ir.config_parameter','ir.mail_server','res.country','res.country.state','res.lang','res.currency','res.currency.rate.type','res.currency.rate','multi_company.default','res.company','res.users','res.request','res.request.link','res.request.history','res.log','ir.property','mail.message','mail.thread','product.uom.categ','product.uom','product.ul','product.price.type','product.pricelist.type','base.action.rule','email.template','fetchmail.server','edi.document','account.tax','account.account','account.journal.view','account.journal.column','account.fiscalyear','account.period','account.journal.period','account.analytic.journal','account.fiscal.position','account.fiscal.position.tax','account.fiscal.position.account','account.sequence.fiscalyear','procurement.order','sale.shop','document.storage','document.directory','document.directory.dctx','document.directory.content.type','document.directory.content','account.voucher',]",
88 | )
89 | note = fields.Html(
90 | string='Notes'
91 | )
92 | field_analyze_default = fields.Text(
93 | string='Fields Analize by Default',
94 | # TODO move this default to another model
95 | default="['reconcile_partial_id','reconcile_id']",
96 | )
97 | repeating_models = fields.Text(
98 | string='Repeating Models',
99 | # TODO move this default to another model
100 | default="['res.partner','res.company','res.users','account.fiscalyear','product.template','product.product','purchase.order','sale.order','hr.employee','project.task','procurement.order']",
101 | )
102 | field_disable_words = fields.Text(
103 | string='Fields Disable by Default Words',
104 | # TODO move this default to another model
105 | default="['in_group','sel_groups_','rml_header','rml_foot',]",
106 | )
107 | modules_to_install = fields.Text(
108 | string='Modules To Install',
109 | default=[]
110 | )
111 | workflow_models = fields.Char(
112 | string='Models to delete Workflows',
113 | required=True,
114 | default='[]'
115 | )
116 | action_ids = fields.One2many(
117 | 'etl.action',
118 | 'manager_id',
119 | string='Actions',
120 | domain=[('state', 'in', ['to_analyze', 'enabled'])],
121 | copy=False,
122 | )
123 | external_model_ids = fields.One2many(
124 | 'etl.external_model',
125 | 'manager_id',
126 | string='External Models',
127 | readonly=True,
128 | copy=False,
129 | )
130 | value_mapping_field_ids = fields.One2many(
131 | 'etl.value_mapping_field',
132 | 'manager_id',
133 | string='Value Mapping Fields',
134 | copy=False,
135 | )
136 | source_lang = fields.Char(
137 | 'Source Language',
138 | required=True,
139 | default='en_US',
140 | # TODO improove this and load all translations for tranlatable fields
141 | help='Language used on source database translatable fields'
142 | )
143 | target_lang = fields.Char(
144 | 'Target Language',
145 | required=True,
146 | default='en_US',
147 | # TODO improove this and load all translations for tranlatable fields
148 | help='Language used on target database translatable fields'
149 | )
150 | target_id_type = fields.Selection(
151 | [(u'source_id', 'Source ID'), (u'builded_id', 'Builded ID')],
152 | string='Target ID Type',
153 | required=True,
154 | default='builded_id',
155 | help="Selection on how the Records target ID's will be build:\n\t"
156 | " - Source ID - will keep the source ID (external_id)\n\t"
157 | " - Builded ID - every external ID will be build as concatenation of Manager Name + _ + Source Model"
158 | )
159 |
160 | _constraints = [
161 | ]
162 |
163 | @api.multi
164 | def open_connections(self):
165 | '''
166 | '''
167 | self.ensure_one()
168 | try:
169 | _logger.info('Getting source connection')
170 | source_connection = Client(
171 | '%s:%i' % (self.source_hostname, self.source_port),
172 | db=self.source_database,
173 | user=self.source_login,
174 | password=self.source_password)
175 | except Exception, e:
176 | raise Warning(
177 | _("Unable to Connect to Database. 'Error: %s'") % e)
178 | try:
179 | _logger.info('Getting target connection')
180 | target_connection = Client(
181 | '%s:%i' % (self.target_hostname, self.target_port),
182 | db=self.target_database,
183 | user=self.target_login,
184 | password=self.target_password)
185 | except Exception, e:
186 | raise Warning(
187 | _("Unable to Connect to Database. 'Error: %s'") % e)
188 | return [source_connection, target_connection]
189 |
190 | @api.one
191 | def read_active_source_models(self):
192 | '''
193 | '''
194 | (source_connection, target_connection) = self.open_connections()
195 | actions = self.env['etl.action'].search(
196 | [('manager_id', '=', self.id), ('state', '=', 'enabled')],
197 | order='sequence')
198 | actions.read_source_model(source_connection, target_connection)
199 |
200 | @api.one
201 | def delete_workflows(self):
202 | (source_connection, target_connection) = self.open_connections()
203 | target_wf_instance_obj = target_connection.model("workflow.instance")
204 | res_types = literal_eval(self.workflow_models)
205 | target_wf_instance_ids = target_wf_instance_obj.search(
206 | [('res_type', 'in', res_types)])
207 | target_wf_instance_obj.unlink(target_wf_instance_ids)
208 |
209 | @api.one
210 | def install_modules(self):
211 | (source_connection, target_connection) = self.open_connections()
212 | target_module_obj = target_connection.model("ir.module.module")
213 | modules = literal_eval(self.modules_to_install)
214 | domain = [('name', 'in', modules)]
215 | target_module_ids = target_module_obj.search(domain)
216 | target_module_obj.button_immediate_install(target_module_ids)
217 |
218 | @api.one
219 | def run_actions(self):
220 | '''Run all actions (none repeating)'''
221 | (source_connection, target_connection) = self.open_connections()
222 | actions = self.env['etl.action'].search(
223 | [('manager_id', '=', self.id), ('state', '=', 'enabled')],
224 | order='sequence')
225 | actions.run_action(source_connection, target_connection)
226 |
227 | @api.one
228 | def run_repeated_actions(self):
229 | '''Run all repeating actions'''
230 | (source_connection, target_connection) = self.open_connections()
231 | actions = self.env['etl.action'].search([
232 | ('manager_id', '=', self.id),
233 | ('repeating_action', '=', True),
234 | ('state', '=', 'enabled')],
235 | order='sequence')
236 | actions.run_repeated_action(source_connection, target_connection)
237 |
238 | @api.one
239 | def match_models_and_order_actions(self):
240 | '''Match models and order the actions'''
241 | self.match_models()
242 | self.order_actions()
243 | return True
244 |
245 | @api.one
246 | def match_models(self):
247 | '''Match models'''
248 | _logger.info('Matching models for manager %s' % self.name)
249 | # read all source models
250 | source_domain = [('manager_id', '=', self.id), ('type', '=', 'source')]
251 | source_models = self.env['etl.external_model'].search(source_domain)
252 |
253 | # get disable and to analyze models
254 | data = []
255 | model_disable_default = []
256 | model_analyze_default = []
257 | if self.model_disable_default:
258 | model_disable_default = literal_eval(self.model_disable_default)
259 | if self.model_analyze_default:
260 | model_analyze_default = literal_eval(self.model_analyze_default)
261 |
262 | # get blocked external ids models
263 | blocked_models = self.env['etl.action'].search(
264 | [('blocked', '=', True), ('manager_id', '=', self.id)])
265 | blocked_model_ext_ids = blocked_models.export_data(['id'])['datas']
266 |
267 | # for each source model look for a target model and give state
268 | for model in source_models:
269 | target_domain = [
270 | ('manager_id', '=', self.id),
271 | ('type', '=', 'target'), ('model', '=', model.model)]
272 | target_model = self.env['etl.external_model'].search(
273 | target_domain, limit=1)
274 |
275 | # give right state to model mapping
276 | state = 'enabled'
277 | if model.model in model_disable_default:
278 | state = 'disabled'
279 | elif model.model in model_analyze_default or not target_model:
280 | state = 'to_analyze'
281 | if model.records == 0:
282 | state = 'no_records'
283 |
284 | # get vals for action mapping and create and id
285 | vals = [
286 | 'model_mapping_' + str(self.id) + '_' + str(model.id),
287 | state,
288 | model.name + ' (' + model.model + ')',
289 | model.order,
290 | model.id,
291 | target_model and target_model.id or False,
292 | self.id
293 | ]
294 |
295 | # look if this id should be blocked
296 | if [vals[0]] in blocked_model_ext_ids:
297 | continue
298 |
299 | # append if not to data
300 | data.append(vals)
301 |
302 | # write actions with data an fields, give result to log
303 | action_fields = [
304 | 'id', 'state', 'name', 'sequence', 'source_model_id/.id',
305 | 'target_model_id/.id', 'manager_id/.id'
306 | ]
307 | _logger.info('Loading actions match for manager %s' % self.name)
308 | import_result = self.env['etl.action'].load(action_fields, data)
309 |
310 | # write log on manager
311 | self.log = import_result
312 |
313 | # call for match fields
314 | _logger.info('Matching fields for models %s of manager %s' % (
315 | import_result['ids'], self.name))
316 | self.env['etl.action'].browse(import_result['ids']).match_fields()
317 |
318 | @api.one
319 | def order_actions(self):
320 | '''Order actions for ids managers'''
321 | # Get enabled actions
322 | actions = self.env['etl.action'].search([
323 | ('manager_id', '=', self.id),
324 | ('state', 'in', ['to_analyze', 'enabled'])])
325 |
326 | # If repeating_mdodels defined on the manager, take them as exceptions
327 | exceptions = []
328 | if self.repeating_models:
329 | repeating_models = self.repeating_models
330 | exceptions = literal_eval(repeating_models)
331 |
332 | # Get unordered and ordered ids from action model
333 | (unordered_ids, ordered_ids) = actions.order_actions(exceptions)
334 |
335 | # get unordered and ordered actions names to write in log. Write log
336 | ordered_actions = []
337 | unordered_actions = []
338 | for ordered_action in self.env['etl.action'].browse(ordered_ids):
339 | ordered_actions.append(ordered_action.source_model_id.model)
340 | for unordered_action in self.env['etl.action'].browse(unordered_ids):
341 | unordered_actions.append(unordered_action.source_model_id.model)
342 | self.log = 'Ordered actions: %s\n\nUnordered actions: %s' % (
343 | str(ordered_actions), str(unordered_actions))
344 |
345 | # check actions depends if no unordered_ids
346 | if not unordered_ids:
347 | actions.check_m2o_depends()
348 |
349 | @api.one
350 | def read_and_get(self):
351 | '''Read source and target models and get records number'''
352 | (source_connection, target_connection) = self.open_connections()
353 | self.read_models()
354 | self.get_records()
355 |
356 | @api.one
357 | def get_records(self):
358 | '''Get number of records for source and target models'''
359 | (source_connection, target_connection) = self.open_connections()
360 | source_models = self.env['etl.external_model'].search(
361 | [('type', '=', 'source'), ('manager_id', '=', self.id)])
362 | target_models = self.env['etl.external_model'].search(
363 | [('type', '=', 'target'), ('manager_id', '=', self.id)])
364 | source_models.get_records(source_connection)
365 | target_models.get_records(target_connection)
366 |
367 | @api.one
368 | def read_models(self):
369 | '''Get models and fields of source and target database'''
370 | # external_model_obj = self.pool['etl.external_model']
371 | (source_connection, target_connection) = self.open_connections()
372 | self.read_model(source_connection, 'source')[self.id]
373 | self.read_model(target_connection, 'target')[self.id]
374 | source_external_models = self.env['etl.external_model'].search([
375 | ('manager_id', '=', self.id), ('type', '=', 'source')])
376 | target_external_models = self.env['etl.external_model'].search([
377 | ('manager_id', '=', self.id), ('type', '=', 'target')])
378 | source_external_models.read_fields(source_connection)
379 | target_external_models.read_fields(target_connection)
380 |
381 | @api.multi
382 | def read_model(self, connection, relation_type):
383 | ''' Get models for one manger and one type (source or target)'''
384 | res = {}
385 | for manager in self:
386 | external_model_obj = connection.model("ir.model")
387 |
388 | # osv_memory = False for not catching transients models
389 | domain = [('osv_memory', '=', False)]
390 |
391 | # catch de models excpections worlds and append to search domain
392 | words_exception = manager.model_exception_words
393 | if words_exception:
394 | words_exception = literal_eval(words_exception)
395 | for exception in words_exception:
396 | domain.append(('model', 'not like', exception))
397 |
398 | # get external model ids
399 | external_model_ids = external_model_obj.search(domain)
400 |
401 | # read id, model and name of external models
402 | external_model_fields = ['.id', 'model', 'name']
403 | export_data = external_model_obj.export_data(
404 | external_model_ids, external_model_fields)
405 |
406 | # We fix .id to id because we are going to use it
407 | external_model_fields[0] = 'id'
408 |
409 | # We add the type, manager and sequence to external fields and data
410 | external_model_fields.extend(
411 | ['type', 'manager_id/.id', 'sequence'])
412 | external_model_data = []
413 | for record in export_data['datas']:
414 | # we extend each record with type, manager and a sequence
415 | record.extend([relation_type, manager.id, int(record[0]) * 10])
416 | # replace the .id with our own external identifier
417 | record[0] = 'man_%s_%s_%s' % (
418 | str(manager.id),
419 | relation_type,
420 | str(record[1]).replace('.', '_')
421 | )
422 | external_model_data.append(record)
423 |
424 | # Load external_model_data to external models model
425 | rec_ids = self.env['etl.external_model'].load(
426 | external_model_fields, external_model_data)
427 | res[manager.id] = rec_ids
428 | return res
429 |
430 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
431 |
--------------------------------------------------------------------------------
/etl/report/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ingadhoc/odoo-etl/d5f54db11c5f916da79e23c52037ea36a12640a4/etl/report/README
--------------------------------------------------------------------------------
/etl/report/__init__.py:
--------------------------------------------------------------------------------
1 | #
2 | # odoo ETL
3 | # Copyright (C) 2015 Ingenieria ADHOC
4 | # No email
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU Affero General Public License as
8 | # published by the Free Software Foundation, either version 3 of the
9 | # License, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU Affero General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Affero General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 |
21 |
22 |
23 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
24 |
--------------------------------------------------------------------------------
/etl/security/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ingadhoc/odoo-etl/d5f54db11c5f916da79e23c52037ea36a12640a4/etl/security/README
--------------------------------------------------------------------------------
/etl/security/etl_group.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | odoo ETL
6 | odoo ETL
7 | 1
8 |
9 |
10 |
11 | User
12 |
13 |
14 |
15 |
16 | Manager
17 |
18 |
19 |
20 |
21 |
22 |
23 |
25 |
--------------------------------------------------------------------------------
/etl/security/ir.model.access.csv:
--------------------------------------------------------------------------------
1 | "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
2 | "access_etl_manager_manager","etl_manager.manager","model_etl_manager","group_manager",1,1,1,1
3 | "access_etl_manager_user","etl_manager.user","model_etl_manager","group_user",1,1,1,1
4 | "access_etl_action_manager","etl_action.manager","model_etl_action","group_manager",1,1,1,1
5 | "access_etl_action_user","etl_action.user","model_etl_action","group_user",1,1,1,1
6 | "access_etl_field_mapping_manager","etl_field_mapping.manager","model_etl_field_mapping","group_manager",1,1,1,1
7 | "access_etl_field_mapping_user","etl_field_mapping.user","model_etl_field_mapping","group_user",1,1,1,1
8 | "access_etl_external_model_manager","etl_external_model.manager","model_etl_external_model","group_manager",1,1,1,1
9 | "access_etl_external_model_user","etl_external_model.user","model_etl_external_model","group_user",1,1,1,1
10 | "access_etl_field_manager","etl_field.manager","model_etl_field","group_manager",1,1,1,1
11 | "access_etl_field_user","etl_field.user","model_etl_field","group_user",1,1,1,1
12 | "access_etl_value_mapping_field_manager","etl_value_mapping_field.manager","model_etl_value_mapping_field","group_manager",1,1,1,1
13 | "access_etl_value_mapping_field_user","etl_value_mapping_field.user","model_etl_value_mapping_field","group_user",1,1,1,1
14 | "access_etl_value_mapping_field_detail_manager","etl_value_mapping_field_detail.manager","model_etl_value_mapping_field_detail","group_manager",1,1,1,1
15 | "access_etl_value_mapping_field_detail_user","etl_value_mapping_field_detail.user","model_etl_value_mapping_field_detail","group_user",1,1,1,1
16 | "access_etl_external_model_record_manager","etl_external_model_record.manager","model_etl_external_model_record","group_manager",1,1,1,1
17 | "access_etl_external_model_record_user","etl_external_model_record.user","model_etl_external_model_record","group_user",1,1,1,1
18 | "access_etl_value_mapping_field_value_manager","etl_value_mapping_field_value.manager","model_etl_value_mapping_field_value","group_manager",1,1,1,1
19 | "access_etl_value_mapping_field_value_user","etl_value_mapping_field_value.user","model_etl_value_mapping_field_value","group_user",1,1,1,1
20 |
--------------------------------------------------------------------------------
/etl/static/description/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ingadhoc/odoo-etl/d5f54db11c5f916da79e23c52037ea36a12640a4/etl/static/description/icon.png
--------------------------------------------------------------------------------
/etl/test/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ingadhoc/odoo-etl/d5f54db11c5f916da79e23c52037ea36a12640a4/etl/test/README
--------------------------------------------------------------------------------
/etl/value_mapping_field.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | ##############################################################################
3 | # For copyright and license notices, see __openerp__.py file in module root
4 | # directory
5 | ##############################################################################
6 | from openerp import models, fields, api, _
7 | from openerp.exceptions import Warning
8 |
9 |
10 | class value_mapping_field(models.Model):
11 | """"""
12 |
13 | _name = 'etl.value_mapping_field'
14 | _description = 'value_mapping_field'
15 |
16 | name = fields.Char(
17 | string='Field Name',
18 | required=True
19 | )
20 | type = fields.Selection(
21 | [(u'id', u'Id'), (u'char', u'Char (not implemented yet)'), (u'selection', u'Selection')],
22 | string='Type',
23 | required=True
24 | )
25 | source_model_id = fields.Many2one(
26 | 'etl.external_model',
27 | string='Source Model'
28 | )
29 | target_model_id = fields.Many2one(
30 | 'etl.external_model',
31 | string='Target Model'
32 | )
33 | log = fields.Text(
34 | string='log'
35 | )
36 | value_mapping_field_detail_ids = fields.One2many(
37 | 'etl.value_mapping_field_detail',
38 | 'value_mapping_field_id',
39 | string='Details'
40 | )
41 | value_mapping_field_value_ids = fields.One2many(
42 | 'etl.value_mapping_field_value',
43 | 'value_mapping_field_id',
44 | string='Mapping Values'
45 | )
46 | manager_id = fields.Many2one(
47 | 'etl.manager',
48 | ondelete='cascade',
49 | string='manager_id',
50 | required=True
51 | )
52 |
53 | _constraints = [
54 | ]
55 |
56 | @api.one
57 | def map_record(self):
58 | value_mapping_data = []
59 | for source_record in self.source_model_id.external_model_record_ids:
60 | domain = [
61 | ('external_model_id', '=', self.target_model_id.id),
62 | ('name', 'ilike', source_record.name)]
63 | target_record = self.env[
64 | 'etl.external_model_record'].search(domain, limit=1)
65 | value_mapping_data.append([
66 | 'value_mapping_' + str(source_record.id),
67 | source_record.id,
68 | target_record and target_record.id or False,
69 | self.id,
70 | ])
71 |
72 | value_mapping_fields = [
73 | 'id',
74 | 'source_external_model_record_id/.id',
75 | 'target_external_model_record_id/.id',
76 | 'value_mapping_field_id/.id']
77 | import_result = self.env['etl.value_mapping_field_detail'].load(
78 | value_mapping_fields, value_mapping_data)
79 |
80 | # write log and domain if active field exist
81 | self.log = import_result
82 |
83 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
84 |
--------------------------------------------------------------------------------
/etl/value_mapping_field_detail.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | ##############################################################################
3 | # For copyright and license notices, see __openerp__.py file in module root
4 | # directory
5 | ##############################################################################
6 | from openerp import models, fields, api, _
7 | from openerp.exceptions import Warning
8 |
9 |
10 | class value_mapping_field_detail(models.Model):
11 | """"""
12 |
13 | _name = 'etl.value_mapping_field_detail'
14 | _description = 'value_mapping_field_detail'
15 |
16 | source_id = fields.Char(
17 | string='Source ID'
18 | )
19 | source_value = fields.Char(
20 | string='Source Value'
21 | )
22 | target_id = fields.Char(
23 | string='Target ID'
24 | )
25 | target_value = fields.Char(
26 | string='Target Value'
27 | )
28 | source_external_model_record_id = fields.Many2one(
29 | 'etl.external_model_record',
30 | string='Source External Model Record'
31 | )
32 | target_external_model_record_id = fields.Many2one(
33 | 'etl.external_model_record',
34 | string='Target External Model Record'
35 | )
36 | source_value_id = fields.Many2one(
37 | 'etl.value_mapping_field_value',
38 | string='Source Value'
39 | )
40 | target_value_id = fields.Many2one(
41 | 'etl.value_mapping_field_value',
42 | string='Target Value'
43 | )
44 | value_mapping_field_id = fields.Many2one(
45 | 'etl.value_mapping_field',
46 | ondelete='cascade',
47 | string='value_mapping_field_id',
48 | required=True
49 | )
50 | source_name = fields.Char(
51 | related='source_external_model_record_id.name',
52 | string='Source Name',
53 | readonly=True,
54 | )
55 | source_model_id = fields.Many2one(
56 | related='value_mapping_field_id.source_model_id',
57 | relation='etl.external_model',
58 | string='Source Model',
59 | readonly=True,
60 | )
61 | target_model_id = fields.Many2one(
62 | related='value_mapping_field_id.target_model_id',
63 | relation='etl.external_model',
64 | string='Target Model',
65 | readonly=True,
66 | )
67 |
68 | _constraints = [
69 | ]
70 |
71 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
72 |
--------------------------------------------------------------------------------
/etl/value_mapping_field_value.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | ##############################################################################
3 | # For copyright and license notices, see __openerp__.py file in module root
4 | # directory
5 | ##############################################################################
6 | from openerp import models, fields, api, _
7 | from openerp.exceptions import Warning
8 |
9 |
10 | class value_mapping_field_value(models.Model):
11 | """"""
12 |
13 | _name = 'etl.value_mapping_field_value'
14 | _description = 'value_mapping_field_value'
15 |
16 | ext_id = fields.Char(
17 | string='Key',
18 | required=True
19 | )
20 | name = fields.Char(
21 | string='Help Name',
22 | required=True
23 | )
24 | value_mapping_field_id = fields.Many2one(
25 | 'etl.value_mapping_field',
26 | ondelete='cascade',
27 | string='value_mapping_field_id',
28 | required=True
29 | )
30 |
31 | _constraints = [
32 | ]
33 |
34 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
35 |
--------------------------------------------------------------------------------
/etl/view/action_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | etl.action.select
7 | etl.action
8 |
9 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | etl.action.form
36 | etl.action
37 |
38 |
99 |
100 |
101 |
102 |
103 |
104 | etl.action.tree
105 | etl.action
106 |
107 |
110 |
112 |
115 |
117 |
119 |
121 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | Actions
131 | etl.action
132 | form
133 | tree,form
134 |
135 |
136 | {'search_default_not_grey':1}
137 |
138 | Click to create a Actions.
139 |
140 |
141 |
142 |
149 |
150 |
151 |
153 |
--------------------------------------------------------------------------------
/etl/view/etl_menuitem.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
17 |
18 |
19 |
20 |
22 |
--------------------------------------------------------------------------------
/etl/view/external_model_record_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | etl.external_model_record.select
7 | etl.external_model_record
8 |
9 |
10 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | etl.external_model_record.form
23 | etl.external_model_record
24 |
25 |
40 |
41 |
42 |
43 |
44 |
45 | etl.external_model_record.tree
46 | etl.external_model_record
47 |
48 |
50 |
52 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
62 |
--------------------------------------------------------------------------------
/etl/view/external_model_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | etl.external_model.select
7 | etl.external_model
8 |
9 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | etl.external_model.form
33 | etl.external_model
34 |
35 |
75 |
76 |
77 |
78 |
79 |
80 | etl.external_model.tree
81 | etl.external_model
82 |
83 |
85 |
87 |
89 |
91 |
93 |
95 |
97 |
98 |
99 |
100 |
101 |
102 |
103 | External Models
104 | etl.external_model
105 | form
106 | tree,form
107 |
108 |
109 |
110 | Click to create a External Models.
111 |
112 |
113 |
114 |
121 |
122 |
123 |
125 |
--------------------------------------------------------------------------------
/etl/view/field_mapping_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | etl.field_mapping.select
7 | etl.field_mapping
8 |
9 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | etl.field_mapping.form
37 | etl.field_mapping
38 |
39 |
91 |
92 |
93 |
94 |
95 |
96 | etl.field_mapping.tree
97 | etl.field_mapping
98 |
99 |
102 |
104 |
106 |
108 |
110 |
111 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | Fields Mapping
121 | etl.field_mapping
122 | form
123 | tree,form
124 |
125 |
126 |
127 | Click to create a Fields Mapping.
128 |
129 |
130 |
131 |
138 |
139 |
140 |
141 |
143 |
--------------------------------------------------------------------------------
/etl/view/field_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | etl.field.select
7 | etl.field
8 |
9 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | etl.field.form
33 | etl.field
34 |
35 |
62 |
63 |
64 |
65 |
66 |
67 | etl.field.tree
68 | etl.field
69 |
70 |
72 |
74 |
76 |
78 |
80 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | External Fields
89 | etl.field
90 | form
91 | tree,form
92 |
93 |
94 |
95 | Click to create a External Fields.
96 |
97 |
98 |
99 |
106 |
107 |
108 |
110 |
--------------------------------------------------------------------------------
/etl/view/manager_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | etl.manager.select
7 | etl.manager
8 |
9 |
10 |
12 |
14 |
16 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | etl.manager.form
29 | etl.manager
30 |
31 |
131 |
132 |
133 |
134 |
135 |
136 | etl.manager.tree
137 | etl.manager
138 |
139 |
141 |
143 |
145 |
147 |
149 |
151 |
152 |
153 |
154 |
155 |
156 | Manager
157 | etl.manager
158 | form
159 | tree,form
160 |
161 |
162 |
163 | Click to create a Manager.
164 |
165 |
166 |
167 |
174 |
175 |
176 |
177 |
179 |
--------------------------------------------------------------------------------
/etl/view/value_mapping_field_detail_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | etl.value_mapping_field_detail.select
7 | etl.value_mapping_field_detail
8 |
9 |
10 |
12 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | etl.value_mapping_field_detail.form
27 | etl.value_mapping_field_detail
28 |
29 |
53 |
54 |
55 |
56 |
57 |
58 | etl.value_mapping_field_detail.tree
59 | etl.value_mapping_field_detail
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | Values Mapping
74 | etl.value_mapping_field_detail
75 | form
76 | tree,form
77 |
78 |
79 | {'search_default_to_map':1}
80 |
81 | Click to create a Values Mapping.
82 |
83 |
84 |
85 |
92 |
93 |
94 |
96 |
--------------------------------------------------------------------------------
/etl/view/value_mapping_field_value_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | etl.value_mapping_field_value.select
7 | etl.value_mapping_field_value
8 |
9 |
10 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | etl.value_mapping_field_value.form
23 | etl.value_mapping_field_value
24 |
25 |
40 |
41 |
42 |
43 |
44 |
45 | etl.value_mapping_field_value.tree
46 | etl.value_mapping_field_value
47 |
48 |
50 |
52 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
62 |
--------------------------------------------------------------------------------
/etl/view/value_mapping_field_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | etl.value_mapping_field.select
7 | etl.value_mapping_field
8 |
9 |
10 |
12 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | etl.value_mapping_field.form
25 | etl.value_mapping_field
26 |
27 |
59 |
60 |
61 |
62 |
63 |
64 | etl.value_mapping_field.tree
65 | etl.value_mapping_field
66 |
67 |
69 |
71 |
73 |
75 |
76 |
77 |
78 |
79 |
80 | Value Mapping Fields
81 | etl.value_mapping_field
82 | form
83 | tree,form
84 |
85 |
86 |
87 | Click to create a Value Mapping Fields.
88 |
89 |
90 |
91 |
98 |
99 |
100 |
101 |
103 |
--------------------------------------------------------------------------------
/etl/wizard/README:
--------------------------------------------------------------------------------
1 | #
2 | # odoo ETL
3 | # Copyright (C) 2015 Ingenieria ADHOC
4 | # No email
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU Affero General Public License as
8 | # published by the Free Software Foundation, either version 3 of the
9 | # License, or (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU Affero General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Affero General Public License
17 | # along with this program. If not, see .
18 | #
19 |
20 |
21 | Wizard directory.
22 |
--------------------------------------------------------------------------------
/etl/wizard/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
3 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | erppeek
--------------------------------------------------------------------------------