Merge lp:~akretion-team/openerp-connector-magento/openerp-connector-magento-catalog into lp:~openerp-connector-core-editors/openerp-connector-magento/7.0

Proposed by Sébastien BEAU - http://www.akretion.com
Status: Rejected
Rejected by: Sébastien BEAU - http://www.akretion.com
Proposed branch: lp:~akretion-team/openerp-connector-magento/openerp-connector-magento-catalog
Merge into: lp:~openerp-connector-core-editors/openerp-connector-magento/7.0
Diff against target: 2313 lines (+2228/-0) (has conflicts)
16 files modified
magentoerpconnect_catalog/__init__.py (+29/-0)
magentoerpconnect_catalog/__openerp__.py (+67/-0)
magentoerpconnect_catalog/connector.py (+26/-0)
magentoerpconnect_catalog/consumer.py (+118/-0)
magentoerpconnect_catalog/magento_model.py (+50/-0)
magentoerpconnect_catalog/magento_model_view.xml (+26/-0)
magentoerpconnect_catalog/product.py (+185/-0)
magentoerpconnect_catalog/product_attribute.py (+527/-0)
magentoerpconnect_catalog/product_attribute_view.xml (+231/-0)
magentoerpconnect_catalog/product_category.py (+239/-0)
magentoerpconnect_catalog/product_image.py (+336/-0)
magentoerpconnect_catalog/product_image_view.xml (+79/-0)
magentoerpconnect_catalog/product_view.xml (+78/-0)
magentoerpconnect_catalog/tests/__init__.py (+29/-0)
magentoerpconnect_catalog/tests/test_attribute_synchronisation.py (+109/-0)
magentoerpconnect_catalog/tests/test_data.py (+99/-0)
Conflict adding file magentoerpconnect_catalog.  Moved existing file to magentoerpconnect_catalog.moved.
To merge this branch: bzr merge lp:~akretion-team/openerp-connector-magento/openerp-connector-magento-catalog
Reviewer Review Type Date Requested Status
OpenERP Connector Core Editors Pending
Review via email: mp+223605@code.launchpad.net

Description of the change

Add product catalog export

To post a comment you must log in.
44. By Sébastien BEAU - http://www.akretion.com

[REF] comment product image view for now, need to be fixed

45. By Sébastien BEAU - http://www.akretion.com

[REF] attribute set export skeletonSetId should be map only at creation

46. By Sébastien BEAU - http://www.akretion.com

[FIX] fix backend view, move attribute_set_tpl_id just after default category

47. By Sébastien BEAU - http://www.akretion.com

[FIX] replace fields by vals (connector 2.2 update)

48. By Sébastien BEAU - http://www.akretion.com

[IMP] add test for attribute set synchronisation

Revision history for this message
Sébastien BEAU - http://www.akretion.com (sebastien.beau) wrote :

This merge have been moved on github https://github.com/OCA/connector-magento/pull/4

Unmerged revisions

48. By Sébastien BEAU - http://www.akretion.com

[IMP] add test for attribute set synchronisation

47. By Sébastien BEAU - http://www.akretion.com

[FIX] replace fields by vals (connector 2.2 update)

46. By Sébastien BEAU - http://www.akretion.com

[FIX] fix backend view, move attribute_set_tpl_id just after default category

45. By Sébastien BEAU - http://www.akretion.com

[REF] attribute set export skeletonSetId should be map only at creation

44. By Sébastien BEAU - http://www.akretion.com

[REF] comment product image view for now, need to be fixed

43. By Chafique DELLI

[ADD]:add module that manages the product variant's price and fix export product attributes and fix export products
(../connector-magentoconnect-catalog rev 736)

42. By Sébastien BEAU - http://www.akretion.com

[IMP] add multi-lang support for exporting product and add a TODO FIXME
(../connector-magentoconnect-catalog rev 735)

41. By Sébastien BEAU - http://www.akretion.com

[FIX] fix export of attrbute option, now support multi-lang, TODO fix the option sequence or add comment to understand the +1
(../connector-magentoconnect-catalog rev 734)

40. By Sébastien BEAU - http://www.akretion.com

[IMP] improve view for attribute set
(../connector-magentoconnect-catalog rev 733)

39. By Sébastien BEAU - http://www.akretion.com

[IMP] add the export of the translation for the category
(../connector-magentoconnect-catalog rev 731)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'magentoerpconnect_catalog'
=== renamed directory 'magentoerpconnect_catalog' => 'magentoerpconnect_catalog.moved'
=== added file 'magentoerpconnect_catalog/__init__.py'
--- magentoerpconnect_catalog/__init__.py 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/__init__.py 2014-07-01 22:23:08 +0000
@@ -0,0 +1,29 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright 2013
5# Author: Guewen Baconnier - Camptocamp SA
6# Augustin Cisterne-Kaasv - Elico-corp
7# David Béal - Akretion
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23import connector
24import consumer
25import magento_model
26import product
27import product_category
28import product_attribute
29import product_image
030
=== added file 'magentoerpconnect_catalog/__openerp__.py'
--- magentoerpconnect_catalog/__openerp__.py 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/__openerp__.py 2014-07-01 22:23:08 +0000
@@ -0,0 +1,67 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Guewen Baconnier
5# Copyright 2013 Camptocamp SA
6# Copyright 2013 Akretion
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23
24{'name': 'Magento Connector - Catalog',
25 'version': '2.0.0',
26 'category': 'Connector',
27 'depends': ['magentoerpconnect',
28 'product_custom_attributes',
29 #'product_links',
30 'product_image',
31 ],
32 'author': 'MagentoERPconnect Core Editors',
33 'license': 'AGPL-3',
34 'website': 'https://launchpad.net/magentoerpconnect',
35 'description': """
36Magento Connector - Catalog
37===========================
38
39Extension for **Magento Connector**, add management of the product's catalog:
40
41Export
42* products
43* categories
44* attributes (only export up to now): attribute set, attributes and attribute options :
45
46 - to be used, you need to manually create an attribute set which match with magento 'Default' attribute set (generally magento_id '4')
47
48* product image: dependency
49
50 - dev branch: lp:~akretion-team/openerp-product-attributes/openerp-product-attributes-image
51 - future production branch: lp:openerp-product-attributes/openerp-product-attributes
52
53TODO:
54* import/export product links
55* import attributes
56""",
57 'images': [],
58 'demo': [],
59 'data': [
60 'magento_model_view.xml',
61 'product_view.xml',
62 'product_attribute_view.xml',
63 'product_image_view.xml',
64 ],
65 'installable': True,
66 'application': False,
67}
0\ No newline at end of file68\ No newline at end of file
169
=== added file 'magentoerpconnect_catalog/connector.py'
--- magentoerpconnect_catalog/connector.py 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/connector.py 2014-07-01 22:23:08 +0000
@@ -0,0 +1,26 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright 2013
5# Author: Guewen Baconnier - Camptocamp SA
6# Augustin Cisterne-Kaasv - Elico-corp
7# David Béal - Akretion
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from openerp.addons.connector.connector import install_in_connector
24
25
26install_in_connector()
027
=== added file 'magentoerpconnect_catalog/consumer.py'
--- magentoerpconnect_catalog/consumer.py 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/consumer.py 2014-07-01 22:23:08 +0000
@@ -0,0 +1,118 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright 2013
5# Author: Guewen Baconnier - Camptocamp SA
6# Augustin Cisterne-Kaasv - Elico-corp
7# David Béal - Akretion
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from openerp.addons.connector.event import (on_record_write,
24 on_record_create,
25 on_record_unlink
26 )
27
28import openerp.addons.magentoerpconnect.consumer as magentoerpconnect
29
30from openerp.addons.connector.connector import Binder
31from openerp.addons.magentoerpconnect.connector import get_environment
32from openerp.addons.magentoerpconnect.unit.delete_synchronizer import (
33 export_delete_record)
34
35
36EXCLUDED_FIELDS_WRITING = {
37 'product.product': ['magento_bind_ids', 'image_ids'],
38 'product.category': ['magento_bind_ids',],
39 'magento.product.category': ['magento_bind_ids',],
40}
41
42def exclude_fields_from_synchro(model_name, fields):
43 if fields and EXCLUDED_FIELDS_WRITING.get(model_name):
44 fields = list(set(fields).difference(EXCLUDED_FIELDS_WRITING))
45 return fields
46
47@on_record_create(model_names=[
48 'magento.product.category',
49 'magento.product.product',
50 'magento.product.attribute',
51 'magento.attribute.set',
52 'magento.attribute.option',
53 'magento.product.image',
54 ])
55@on_record_write(model_names=[
56 'magento.product.category',
57 'magento.product.product',
58 'magento.product.attribute',
59 'magento.attribute.option',
60 'magento.product.image',
61 #'magento.product.storeview',
62 ])
63def delay_export(session, model_name, record_id, vals=None):
64 #fields = exclude_fields_from_synchro(model_name, fields)
65 magentoerpconnect.delay_export(session, model_name,
66 record_id, vals=vals)
67
68
69@on_record_write(model_names=[
70 'product.product',
71 'product.category',
72 ])
73def delay_export_all_bindings(session, model_name, record_id, vals=None):
74 #fields = exclude_fields_from_synchro(model_name, fields)
75 magentoerpconnect.delay_export_all_bindings(session, model_name,
76 record_id, vals=vals)
77
78#
79#@on_record_unlink(model_names=[
80# 'product.category',
81# ])
82#def delay_unlink_all_bindings(session, model_name, record_id):
83# #magentoerpconnect.delay_unlink_all_bindings(session, model_name, record_id)
84# import pdb;pdb.set_trace()
85# magentoerpconnect.delay_unlink(session, model_name, record_id)
86
87
88@on_record_unlink(model_names=[
89 'magento.product.category',
90 'magento.product.product'
91 'magento.product.attribute',
92 'magento.attribute.set',
93 'magento.attribute.option',
94 ])
95def delay_unlink(session, model_name, record_id):
96 magentoerpconnect.delay_unlink(session, model_name, record_id)
97
98
99@on_record_unlink(model_names=['magento.product.image'])
100def delay_image_unlink(session, model_name, record_id):
101 model = session.pool.get('magento.product.image')
102 record = model.browse(session.cr, session.uid,
103 record_id, context=session.context)
104 magento_keys = []
105 env = get_environment(session, 'magento.product.image',
106 record.backend_id.id)
107 binder = env.get_connector_unit(Binder)
108 magento_keys.append(binder.to_backend(record_id))
109 # in addition to magento 'image id' needs 'product id' to remove images
110 # see http://www.magentocommerce.com/api/soap/catalog/...
111 # catalogProductAttributeMedia/catalog_product_attribute_media.remove.html
112 env = get_environment(session, 'magento.product.product',
113 record.backend_id.id)
114 binder = env.get_connector_unit(Binder)
115 magento_keys.append(binder.to_backend(record.openerp_id.product_id.id, wrap=True))
116 if magento_keys:
117 export_delete_record.delay(session, 'magento.product.image',
118 record.backend_id.id, magento_keys)
0119
=== added directory 'magentoerpconnect_catalog/i18n'
=== added file 'magentoerpconnect_catalog/magento_model.py'
--- magentoerpconnect_catalog/magento_model.py 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/magento_model.py 2014-07-01 22:23:08 +0000
@@ -0,0 +1,50 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright 2013
5# Author: Guewen Baconnier - Camptocamp
6# David Béal - Akretion
7# Sébastien Beau - Akretion
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23import logging
24from openerp.osv import orm, fields
25from openerp.addons.connector.session import ConnectorSession
26from openerp.addons.magentoerpconnect.unit.import_synchronizer import import_batch
27
28
29_logger = logging.getLogger(__name__)
30
31
32class magento_backend(orm.Model):
33 _inherit = 'magento.backend'
34
35 def import_attribute_sets(self, cr, uid, ids, context=None):
36 if not hasattr(ids, '__iter__'):
37 ids = [ids]
38 self.check_magento_structure(cr, uid, ids, context=context)
39 session = ConnectorSession(cr, uid, context=context)
40 for backend_id in ids:
41 import_batch.delay(session, 'magento.attribute.set', backend_id)
42 return True
43
44 _columns = {
45 'attribute_set_tpl_id': fields.many2one(
46 'magento.attribute.set',
47 'Attribute set template',
48 help="Attribute set ID basing on which the new attribute set "
49 "will be created."),
50 }
051
=== added file 'magentoerpconnect_catalog/magento_model_view.xml'
--- magentoerpconnect_catalog/magento_model_view.xml 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/magento_model_view.xml 2014-07-01 22:23:08 +0000
@@ -0,0 +1,26 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4
5<record id="view_magento_backend_form" model="ir.ui.view">
6 <field name="model">magento.backend</field>
7 <field name="inherit_id" ref="magentoerpconnect.view_magento_backend_form"/>
8 <field name="arch" type="xml">
9 <xpath expr="//notebook/page[@name='import']/group[5]" position="after">
10 <group>
11 <label string="Import attribute sets"
12 class="oe_inline"/>
13 <button name="import_attribute_sets"
14 type="object"
15 class="oe_highlight"
16 string="Import in background"/>
17 </group>
18 </xpath>
19 <xpath expr="//notebook/page[@name='advanced_configuration']/group/field[@name='default_category_id']" position="after">
20 <field name="attribute_set_tpl_id"/>
21 </xpath>
22 </field>
23</record>
24
25 </data>
26</openerp>
027
=== added file 'magentoerpconnect_catalog/product.py'
--- magentoerpconnect_catalog/product.py 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/product.py 2014-07-01 22:23:08 +0000
@@ -0,0 +1,185 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright 2013
5# Author: Guewen Baconnier - Camptocamp SA
6# Augustin Cisterne-Kaasv - Elico-corp
7# David Béal - Akretion
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from openerp.osv import fields, orm, osv
24from openerp.addons.connector.queue.job import job
25from openerp.addons.connector.unit.mapper import (mapping,
26 changed_by,
27 ExportMapper)
28from openerp.addons.magentoerpconnect.unit.delete_synchronizer import (
29 MagentoDeleteSynchronizer)
30from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
31 MagentoTranslationExporter)
32from openerp.addons.magentoerpconnect.backend import magento
33from openerp.addons.magentoerpconnect.product import ProductProductAdapter
34from openerp.addons.connector.exception import MappingError
35from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
36 export_record
37)
38
39
40@magento
41class ProductProductDeleteSynchronizer(MagentoDeleteSynchronizer):
42 """ Partner deleter for Magento """
43 _model_name = ['magento.product.product']
44
45
46@magento
47class ProductProductExport(MagentoTranslationExporter):
48 _model_name = ['magento.product.product']
49
50 def _export_dependencies(self):
51 """ Export the dependencies for the product"""
52 #TODO add export of category
53 attribute_binder = self.get_binder_for_model('magento.product.attribute')
54 option_binder = self.get_binder_for_model('magento.attribute.option')
55 record = self.binding_record
56 for group in record.attribute_group_ids:
57 for attribute in group.attribute_ids:
58 attribute_ext_id = attribute_binder.to_backend(attribute.attribute_id.id, wrap=True)
59 if attribute_ext_id:
60 options = []
61 if attribute.ttype == 'many2one' and record[attribute.name]:
62 options = [record[attribute.name]]
63 elif attribute.ttype == 'many2many':
64 options = record[attribute.name]
65 for option in options:
66 if not option_binder.to_backend(option.id, wrap=True):
67 ctx = self.session.context.copy()
68 ctx['connector_no_export'] = True
69 binding_id = self.session.pool['magento.attribute.option'].create(
70 self.session.cr, self.session.uid,{
71 'backend_id': self.backend_record.id,
72 'openerp_id': option.id,
73 'name': option.name,
74 }, context=ctx)
75 export_record(self.session, 'magento.attribute.option', binding_id)
76
77
78@magento
79class ProductProductExportMapper(ExportMapper):
80 _model_name = 'magento.product.product'
81
82 #TODO FIXME
83 # direct = [('name', 'name'),
84 # ('description', 'description'),
85 # ('weight', 'weight'),
86 # ('list_price', 'price'),
87 # ('description_sale', 'short_description'),
88 # ('default_code', 'sku'),
89 # ('product_type', 'type'),
90 # ('created_at', 'created_at'),
91 # ('updated_at', 'updated_at'),
92 # ('status', 'status'),
93 # ('visibility', 'visibility'),
94 # ('product_type', 'product_type')
95 # ]
96 @mapping
97 def all(self, record):
98 return {'name': record.name,
99 'description': record.description,
100 'weight': record.weight,
101 'price': record.list_price,
102 'short_description': record.description_sale,
103 'type': record.product_type,
104 'created_at': record.created_at,
105 #'updated_at': record.updated_at,
106 'status': record.status,
107 'visibility': record.visibility,
108 'product_type': record.product_type }
109
110 @mapping
111 def sku(self, record):
112 sku = record.default_code
113 if not sku:
114 raise MappingError("The product attribute default code cannot be empty.")
115 return {'sku': sku}
116
117 @mapping
118 def set(self, record):
119 binder = self.get_binder_for_model('magento.attribute.set')
120 set_id = binder.to_backend(record.attribute_set_id.id, wrap=True)
121 return {'attrset': set_id}
122
123 @mapping
124 def updated_at(self, record):
125 updated_at = record.updated_at
126 if not updated_at:
127 updated_at = '1970-01-01'
128 return {'updated_at': updated_at}
129
130 @mapping
131 def website_ids(self, record):
132 website_ids = []
133 for website_id in record.website_ids:
134 magento_id = website_id.magento_id
135 website_ids.append(magento_id)
136 return {'website_ids': website_ids}
137
138 @mapping
139 def category(self, record):
140 categ_ids = []
141 if record.categ_id:
142 for m_categ in record.categ_id.magento_bind_ids:
143 if m_categ.backend_id.id == self.backend_record.id:
144 categ_ids.append(m_categ.magento_id)
145
146 for categ in record.categ_ids:
147 for m_categ in categ.magento_bind_ids:
148 if m_categ.backend_id.id == self.backend_record.id:
149 categ_ids.append(m_categ.magento_id)
150 return {'categories': categ_ids}
151
152 @mapping
153 def get_product_attribute_option(self, record):
154 result = {}
155 attribute_binder = self.get_binder_for_model('magento.product.attribute')
156 option_binder = self.get_binder_for_model('magento.attribute.option')
157 for group in record.attribute_group_ids:
158 for attribute in group.attribute_ids:
159 magento_attribute = None
160 #TODO maybe adding a get_bind function can be better
161 for bind in attribute.magento_bind_ids:
162 if bind.backend_id.id == self.backend_record.id:
163 magento_attribute = bind
164
165 if not magento_attribute:
166 continue
167
168 if attribute.ttype == 'many2one':
169 option = record[attribute.name]
170 if option:
171 result[magento_attribute.attribute_code] = \
172 option_binder.to_backend(option.id, wrap=True)
173 else:
174 continue
175 elif attribute.ttype == 'many2many':
176 options = record[attribute.name]
177 if options:
178 result[magento_attribute.attribute_code] = \
179 [option_binder.to_backend(option.id, wrap=True) for option in options]
180 else:
181 continue
182 else:
183 #TODO add support of lang
184 result[magento_attribute.attribute_code] = record[attribute.name]
185 return result
0186
=== added file 'magentoerpconnect_catalog/product_attribute.py'
--- magentoerpconnect_catalog/product_attribute.py 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/product_attribute.py 2014-07-01 22:23:08 +0000
@@ -0,0 +1,527 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright 2013
5# Author: Guewen Baconnier - Camptocamp
6# Augustin Cisterne-Kaas - Elico-corp
7# David Béal - Akretion
8# Sébastien Beau - Akretion
9# Chafique Delli - Akretion
10# This program is free software: you can redistribute it and/or modify
11# it under the terms of the GNU Affero General Public License as
12# published by the Free Software Foundation, either version 3 of the
13# License, or (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU Affero General Public License for more details.
19#
20# You should have received a copy of the GNU Affero General Public License
21# along with this program. If not, see <http://www.gnu.org/licenses/>.
22#
23##############################################################################
24
25
26from openerp.osv import fields, orm
27#from openerp.tools.translate import _
28from openerp.osv.osv import except_osv
29from openerp.addons.connector.unit.mapper import (
30 mapping,
31 #changed_by,
32 only_create,
33 ImportMapper,
34 ExportMapper,)
35#from openerp.addons.connector.exception import MappingError
36from openerp.addons.magentoerpconnect.backend import magento
37from openerp.addons.magentoerpconnect.unit.backend_adapter import GenericAdapter
38from openerp.addons.magentoerpconnect.unit.binder import MagentoModelBinder
39from openerp.addons.magentoerpconnect.unit.delete_synchronizer import (
40 MagentoDeleteSynchronizer)
41from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
42 MagentoExporter)
43from openerp.addons.magentoerpconnect.unit.import_synchronizer import (
44 DelayedBatchImport,
45 MagentoImportSynchronizer,)
46from openerp.addons.connector.exception import FailedJobError
47
48
49@magento(replacing=MagentoModelBinder)
50class MagentoAttributeBinder(MagentoModelBinder):
51 _model_name = [
52 'magento.product.attribute',
53 'magento.attribute.option',
54 'magento.attribute.set',
55 ]
56
57
58# Attribute Set
59class AttributeSet(orm.Model):
60 _inherit = 'attribute.set'
61
62 _columns = {
63 'magento_bind_ids': fields.one2many(
64 'magento.attribute.set',
65 'openerp_id',
66 string='Magento Bindings',),
67 }
68
69
70class MagentoAttributeSet(orm.Model):
71 _name = 'magento.attribute.set'
72 _description = "Magento attribute set"
73 _inherit = 'magento.binding'
74 _rec_name = 'attribute_set_name'
75
76 _columns = {
77 'openerp_id': fields.many2one(
78 'attribute.set',
79 string='Attribute set',
80 ondelete='cascade'),
81 'attribute_set_name': fields.char(
82 'Name',
83 size=64,
84 required=True),
85 'sort_order': fields.integer(
86 'Sort order',
87 readonly=True),
88 }
89
90 def name_get(self, cr, uid, ids, context=None):
91 res = []
92 for elm in self.read(cr, uid, ids, ['attribute_set_name'],
93 context=context):
94 res.append((elm['id'], elm['attribute_set_name']))
95 return res
96
97 _sql_constraints = [
98 ('magento_uniq', 'unique(backend_id, openerp_id)',
99 "An 'Attribute set' with the same ID on this Magento backend "
100 "already exists")
101 ]
102
103
104@magento
105class AttributeSetAdapter(GenericAdapter):
106 _model_name = 'magento.attribute.set'
107 _magento_default_model = 'product_attribute_set'
108 _magento_model = 'ol_catalog_product_attributeset'
109
110 def create(self, data):
111 """ Create a record on the external system """
112 return self._call('%s.create' % self._magento_default_model,
113 [data['attribute_set_name'], data['skeletonSetId']])
114
115 def delete(self, id):
116 """ Delete a record on the external system """
117 return self._call('%s.remove' % self._magento_default_model, [str(id)])
118
119 def search(self, filters=None):
120 """ Search records according and returns a list of ids
121 :rtype: list
122 """
123 return self._call('%s.search' % self._magento_model, [])
124
125 def read(self, id, storeview_id=None, attributes=None):
126 """ Returns the information of a record
127 :rtype: dict
128 """
129 return self._call('%s.info' % self._magento_model, [int(id)])
130
131 def update(self, id, attribute_id):
132 """ Add an existing attribute to an attribute set on the external system
133 :rtype: boolean
134 """
135 return self._call('%s.attributeAdd' % self._magento_default_model,
136 [str(attribute_id),str(id)])
137
138
139@magento
140class AttributeSetDelayedBatchImport(DelayedBatchImport):
141 _model_name = ['magento.attribute.set']
142
143
144@magento
145class AttributeSetImport(MagentoImportSynchronizer):
146 _model_name = ['magento.attribute.set']
147
148
149@magento
150class AttributeSetImportMapper(ImportMapper):
151 _model_name = 'magento.attribute.set'
152
153 direct = [
154 ('attribute_set_name', 'attribute_set_name'),
155 ('attribute_set_id', 'magento_id'),
156 ('sort_order', 'sort_order'), ]
157
158 @mapping
159 def backend_id(self, record):
160 return {'backend_id': self.backend_record.id}
161
162
163@magento
164class AttributeSetDeleteSynchronizer(MagentoDeleteSynchronizer):
165 _model_name = ['magento.attribute.set']
166
167
168@magento
169class AttributeSetExport(MagentoExporter):
170 _model_name = ['magento.attribute.set']
171
172
173@magento
174class AttributeSetExportMapper(ExportMapper):
175 _model_name = 'magento.attribute.set'
176
177 direct = [
178 ('attribute_set_name', 'attribute_set_name'),
179 ('sort_order', 'sort_order'),
180 ]
181
182 @only_create
183 @mapping
184 def skeletonSetId(self, record):
185 tmpl_set_id = self.backend_record.attribute_set_tpl_id.id
186 if tmpl_set_id:
187 binder = self.get_binder_for_model('magento.attribute.set')
188 magento_tpl_set_id = binder.to_backend(tmpl_set_id)
189 else:
190 raise FailedJobError((
191 "'Attribute set template' field must be define on "
192 "the backend.\n\n"
193 "Resolution: \n"
194 "- Go to Connectors > Magento > Backends > '%s'\n"
195 "- Fill the field Attribte set Tempalte\n"
196 )% self.backend_record.name)
197 return {'skeletonSetId': magento_tpl_set_id}
198
199
200# Attribute
201class AttributeAttribute(orm.Model):
202 _inherit = 'attribute.attribute'
203
204 def _get_model_product(self, cr, uid, ids, idcontext=None):
205 model, res_id = self.pool['ir.model.data'].get_object_reference(
206 cr, uid, 'product', 'model_product_product')
207 return res_id
208
209 _columns = {
210 'magento_bind_ids': fields.one2many(
211 'magento.product.attribute',
212 'openerp_id',
213 string='Magento Bindings',),
214 }
215
216 _defaults = {
217 'model_id': _get_model_product,
218 }
219
220
221class MagentoProductAttribute(orm.Model):
222 _name = 'magento.product.attribute'
223 _description = "Magento Product Attribute"
224 _inherit = 'magento.binding'
225 _rec_name = 'attribute_code'
226 MAGENTO_HELP = "This field is a technical / configuration field for " \
227 "the attribute on Magento. \nPlease refer to the Magento " \
228 "documentation for details. "
229
230 def copy(self, cr, uid, id, default=None, context=None):
231 if default is None:
232 default = {}
233 default['attribute_code'] = default.get('attribute_code', '') + 'Copy '
234 return super(MagentoProductAttribute, self).copy(
235 cr, uid, id, default, context=context)
236
237 def _frontend_input(self, cr, uid, ids, field_names, arg, context=None):
238 res={}
239 for elm in self.browse(cr, uid, ids):
240 field_type = elm.openerp_id.attribute_type
241 map_type = {
242 'char': 'text',
243 'text': 'textarea',
244 'float': 'price',
245 'datetime': 'date',
246 'binary': 'media_image',
247 }
248 res[elm.id] = map_type.get(field_type, field_type)
249 return res
250
251 _columns = {
252 'openerp_id': fields.many2one(
253 'attribute.attribute',
254 string='Attribute',
255 required=True,
256 ondelete='cascade'),
257 'attribute_code': fields.char(
258 'Code',
259 required=True,
260 size=200,),
261 'scope': fields.selection(
262 [('store', 'store'), ('website', 'website'), ('global', 'global')],
263 'Scope',
264 required=True,
265 help=MAGENTO_HELP),
266 'apply_to': fields.selection([
267 ('simple', 'simple'),
268 ],
269 'Apply to',
270 required=True,
271 help=MAGENTO_HELP),
272 'frontend_input': fields.function(
273 _frontend_input,
274 method=True,
275 string='Frontend input',
276 type='char',
277 store=False,
278 help="This field depends on OpenERP attribute 'type' field "
279 "but used on Magento"),
280 'frontend_label': fields.char(
281 'Label', required=True, size=100, help=MAGENTO_HELP),
282 'position': fields.integer('Position', help=MAGENTO_HELP),
283 'group_id': fields.integer('Group', help=MAGENTO_HELP) ,
284 'default_value': fields.char(
285 'Default Value',
286 size=10,
287 help=MAGENTO_HELP),
288 'note': fields.char(
289 'Note', size=200, help=MAGENTO_HELP),
290 'entity_type_id': fields.integer(
291 'Entity Type', help=MAGENTO_HELP),
292 # boolean fields
293 'is_visible_in_advanced_search': fields.boolean(
294 'Visible in advanced search?', help=MAGENTO_HELP),
295 'is_visible': fields.boolean('Visible?', help=MAGENTO_HELP),
296 'is_visible_on_front': fields.boolean(
297 'Visible (front)?', help=MAGENTO_HELP),
298 'is_html_allowed_on_front': fields.boolean(
299 'Html (front)?', help=MAGENTO_HELP),
300 'is_wysiwyg_enabled': fields.boolean(
301 'Wysiwyg enabled?', help=MAGENTO_HELP),
302 'is_global': fields.boolean('Global?', help=MAGENTO_HELP),
303 'is_unique': fields.boolean('Unique?', help=MAGENTO_HELP),
304 'is_required': fields.boolean('Required?', help=MAGENTO_HELP),
305 'is_filterable': fields.boolean('Filterable?', help=MAGENTO_HELP),
306 'is_comparable': fields.boolean('Comparable?', help=MAGENTO_HELP),
307 'is_searchable': fields.boolean('Searchable ?', help=MAGENTO_HELP),
308 'is_configurable': fields.boolean('Configurable?', help=MAGENTO_HELP),
309 'is_user_defined': fields.boolean('User defined?', help=MAGENTO_HELP),
310 'used_for_sort_by': fields.boolean('Use for sort?', help=MAGENTO_HELP),
311 'is_used_for_price_rules': fields.boolean(
312 'Used for pricing rules?', help=MAGENTO_HELP),
313 'is_used_for_promo_rules': fields.boolean(
314 'Use for promo?', help=MAGENTO_HELP),
315 'used_in_product_listing': fields.boolean(
316 'In product listing?', help=MAGENTO_HELP),
317 }
318
319 _defaults = {
320 'scope': 'global',
321 'apply_to': 'simple',
322 'is_visible': True,
323 'is_visible_on_front': True,
324 'is_visible_in_advanced_search': True,
325 'is_filterable': True,
326 'is_searchable': True,
327 'is_comparable': True,
328 }
329
330 _sql_constraints = [
331 ('magento_uniq', 'unique(attribute_code)',
332 "Attribute with the same code already exists : must be unique"),
333 ('openerp_uniq', 'unique(backend_id, openerp_id)',
334 'An attribute can not be bound to several records on the same backend.'),
335 ]
336
337
338@magento
339class ProductAttributeAdapter(GenericAdapter):
340 _model_name = 'magento.product.attribute'
341 _magento_model = 'product_attribute'
342
343 def delete(self, id):
344 return self._call('%s.remove'% self._magento_model,[int(id)])
345
346
347@magento
348class ProductAttributeDeleteSynchronizer(MagentoDeleteSynchronizer):
349 _model_name = ['magento.product.attribute']
350
351
352@magento
353class ProductAttributeExport(MagentoExporter):
354 _model_name = ['magento.product.attribute']
355
356 def _should_import(self):
357 "Attributes in magento doesn't retrieve infos on dates"
358 return False
359
360 def _after_export(self):
361 """ Run the after export"""
362 sess = self.session
363 attribute_location_obj = sess.pool.get('attribute.location')
364 magento_attribute_obj = sess.pool.get('magento.product.attribute')
365 magento_attribute_set_obj = sess.pool.get('magento.attribute.set')
366 attribute_set_adapter = self.get_connector_unit_for_model(
367 GenericAdapter, 'magento.attribute.set')
368 attribute_id = self.binding_record.openerp_id.id
369 magento_attribute_id = magento_attribute_obj.browse(
370 sess.cr, sess.uid,
371 self.binding_record.id,context=sess.context).magento_id
372 attribute_location_ids = attribute_location_obj.search(
373 sess.cr, sess.uid,
374 [['attribute_id','=',attribute_id]], context=sess.context)
375 for attribute_location in attribute_location_ids:
376 attribute_set_id = attribute_location_obj.browse(
377 sess.cr, sess.uid,
378 attribute_location, context=sess.context).attribute_set_id.id
379 magento_attribute_set_ids = magento_attribute_set_obj.search(
380 sess.cr, sess.uid,
381 [['openerp_id','=',attribute_set_id]],
382 context=sess.context)
383 for magento_attribute_set in magento_attribute_set_ids:
384 magento_attribute_set_id = magento_attribute_set_obj.browse(
385 sess.cr, sess.uid,
386 magento_attribute_set,context=sess.context).magento_id
387 attribute_set_adapter.update(
388 magento_attribute_set_id, magento_attribute_id)
389
390
391
392@magento
393class ProductAttributeExportMapper(ExportMapper):
394 _model_name = 'magento.product.attribute'
395
396 direct = [
397 ('attribute_code', 'attribute_code'), # required
398 ('frontend_input', 'frontend_input'),
399 ('scope', 'scope'),
400 ('is_global', 'is_global'),
401 ('is_filterable', 'is_filterable'),
402 ('is_comparable', 'is_comparable'),
403 ('is_visible', 'is_visible'),
404 ('is_searchable', 'is_searchable'),
405 ('is_user_defined', 'is_user_defined'),
406 ('is_configurable', 'is_configurable'),
407 ('is_visible_on_front', 'is_visible_on_front'),
408 ('is_used_for_price_rules', 'is_used_for_price_rules'),
409 ('is_unique', 'is_unique'),
410 ('is_required', 'is_required'),
411 ('position', 'position'),
412 ('group_id', 'group_id'),
413 ('default_value', 'default_value'),
414 ('is_visible_in_advanced_search', 'is_visible_in_advanced_search'),
415 ('note', 'note'),
416 ('entity_type_id', 'entity_type_id'),
417 ]
418
419 @mapping
420 def frontend_label(self, record):
421 #required
422 return {'frontend_label': [{
423 'store_id': 0,
424 'label': record.frontend_label,
425 }]}
426
427
428# Attribute option
429class AttributeOption(orm.Model):
430 _inherit = 'attribute.option'
431
432 _columns = {
433 'magento_bind_ids': fields.one2many(
434 'magento.attribute.option',
435 'openerp_id',
436 string='Magento Bindings',),
437 }
438
439
440class MagentoAttributeOption(orm.Model):
441 _name = 'magento.attribute.option'
442 _description = ""
443 _inherit = 'magento.binding'
444
445 _columns = {
446 'openerp_id': fields.many2one(
447 'attribute.option',
448 string='Attribute option',
449 required=True,
450 ondelete='cascade'),
451 'name': fields.char(
452 'Name',
453 size=64,
454 required=True),
455 'is_default': fields.boolean('Is default'),
456 }
457
458 _defaults = {
459 'is_default': True,
460 }
461
462 _sql_constraints = [
463 ('magento_uniq', 'unique(backend_id, magento_id)',
464 'An attribute option with the same ID on Magento already exists.'),
465 ('openerp_uniq', 'unique(backend_id, openerp_id)',
466 'An attribute option can not be bound to several records on the same backend.'),
467 ]
468
469
470
471@magento
472class AttributeOptionAdapter(GenericAdapter):
473 _model_name = 'magento.attribute.option'
474 _magento_model = 'oerp_product_attribute'
475
476 def create(self, data):
477 return self._call('%s.addOption'% self._magento_model,
478 [data.pop('attribute'), data])
479
480
481@magento
482class AttributeOptionDeleteSynchronizer(MagentoDeleteSynchronizer):
483 _model_name = ['magento.attribute.option']
484
485
486@magento
487class AttributeOptionExport(MagentoExporter):
488 _model_name = ['magento.attribute.option']
489
490
491@magento
492class AttributeOptionExportMapper(ExportMapper):
493 _model_name = 'magento.attribute.option'
494
495 direct = []
496
497 @mapping
498 def label(self, record):
499 storeview_ids = self.session.search(
500 'magento.storeview',
501 [('backend_id', '=', self.backend_record.id)])
502 storeviews = self.session.browse('magento.storeview', storeview_ids)
503 label = []
504 for storeview in storeviews:
505 name = record.openerp_id.read(['name'], context={
506 'lang': storeview.lang_id.code,
507 })[0]['name']
508 label.append({
509 'store_id': [storeview.magento_id],
510 'value': name
511 })
512 return {'label': label}
513
514 @mapping
515 def attribute(self, record):
516 binder = self.get_binder_for_model('magento.product.attribute')
517 magento_attribute_id = binder.to_backend(record.openerp_id.attribute_id.id, wrap=True)
518 return {'attribute': magento_attribute_id}
519
520 @mapping
521 def order(self, record):
522 #TODO FIXME
523 return {'order': record.openerp_id.sequence + 1 }
524
525 @mapping
526 def is_default(self, record):
527 return {'is_default': int(record.is_default)}
0528
=== added file 'magentoerpconnect_catalog/product_attribute_view.xml'
--- magentoerpconnect_catalog/product_attribute_view.xml 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/product_attribute_view.xml 2014-07-01 22:23:08 +0000
@@ -0,0 +1,231 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<openerp>
3 <data>
4
5<!-- Attribute-->
6<record id="attribute_attribute_form_view" model="ir.ui.view">
7 <field name="model">attribute.attribute</field>
8 <field name="inherit_id"
9 ref="base_custom_attributes.attribute_attribute_form_view"/>
10 <field name="arch" type="xml">
11 <xpath expr="//group" position="after">
12 <group colspan="4">
13 <separator string="Magento attributes"/>
14 <field name="magento_bind_ids" nolabel="1" colspan="6"
15 context="{
16 'hide_openerp_id': True,
17 'default_frontend_label': field_description,
18 'default_attribute_code': name}">
19 <tree name="magento">
20 <field name="attribute_code"/>
21 <field name="backend_id"/>
22 <field name="is_required"/>
23 <field name="default_value" string="Default"/>
24 <field name="scope"/>
25 </tree>
26 </field>
27 </group>
28 </xpath>
29 </field>
30</record>
31
32<record id="attribute_set_form_view" model="ir.ui.view">
33 <field name="model">attribute.set</field>
34 <field name="inherit_id"
35 ref="base_custom_attributes.attribute_set_form_view"/>
36 <field name="arch" type="xml">
37 <form string="Attribute Set" position="inside">
38 <separator string="Magento attribute sets" colspan="6"/>
39 <field name="magento_bind_ids" nolabel="1" colspan="6"
40 context="{'default_attribute_set_name': name}">
41 <tree string="Attribute set" editable="top">
42 <field name="backend_id"/>
43 <field name="attribute_set_name"/>
44 <field name="sort_order"/>
45 <field name="magento_id" readonly="1"/>
46 </tree>
47 </field>
48 </form>
49 </field>
50</record>
51
52
53<menuitem id="menu_magento_product_attribute_main"
54 name="Attributes"
55 parent="magentoerpconnect.menu_magento_root"
56 sequence="40" />
57
58
59
60<!--Magento attribute-->
61<record id="magento_product_attribute_tree_view" model="ir.ui.view">
62 <field name="model">magento.product.attribute</field>
63 <field name="arch" type="xml">
64 <tree string="Attribute">
65 <field name="openerp_id"/>
66 <field name="attribute_code"/>
67 <field name="backend_id"/>
68 </tree>
69 </field>
70</record>
71
72<record id="magento_product_attribute_action" model="ir.actions.act_window">
73 <field name="type">ir.actions.act_window</field>
74 <field name="res_model">magento.product.attribute</field>
75 <field name="view_type">form</field>
76 <field name="name">Magento attribute</field>
77 <field name="view_id" ref="magento_product_attribute_tree_view"/>
78 <field name="help" type="html">
79 <p class="oe_view_nocontent_create">
80 Click to add an attribute.
81 </p>
82 </field>
83</record>
84
85<menuitem id="menu_magento_product_attribute"
86 name="Attributes"
87 action="magento_product_attribute_action"
88 parent="menu_magento_product_attribute_main"
89 sequence="10"/>
90
91
92<record id="magento_product_attribute_form_view" model="ir.ui.view">
93 <field name="model">magento.product.attribute</field>
94 <field name="arch" type="xml">
95 <form string="main" version="7.0">
96 <group name="main" col="4">
97 <field name="frontend_label"/>
98 <field name="attribute_code"
99 attributes="{'readonly': [('magento_id', '!=', False)]}"/>
100 <field name="backend_id" string="Backend"/>
101 <field name="scope"/>
102 <field name="frontend_input"/>
103 <!-- TODO FIXME <field name="openerp_id"
104 invisible="context.get('hide_openerp_id')"/>-->
105 </group>
106 <group name="other" col="4">
107 <field name="default_value"
108 attrs="{'invisible':[('frontend_input', 'in',
109 ['media_image', 'multiselect'])]}"/>
110 <field name="entity_type_id"/>
111 <field name="group_id"/>
112 <field name="apply_to"/>
113 <field name="position"/>
114 <field name="note"/>
115 </group>
116 <separator/>
117 <group name="boolean" col="6"
118 attrs="{'invisible':[
119 ('frontend_input', 'in', ['media_image'])]}">
120 <field name="is_required"/>
121 <field name="is_filterable"/>
122 <field name="is_visible"/>
123 <field name="is_global"/>
124 <field name="is_searchable"/>
125 <field name="is_visible_on_front"/>
126 <field name="is_unique"/>
127 <field name="is_configurable"/>
128 <field name="is_visible_in_advanced_search"/>
129 <field name="is_used_for_price_rules"/>
130 <field name="is_comparable"/>
131 <field name="is_user_defined"/>
132 <field name="is_used_for_promo_rules"/>
133 <field name="used_for_sort_by"/>
134 <field name="is_wysiwyg_enabled"/>
135 <field name="used_in_product_listing"/>
136 <span colspan="2"/>
137 <field name="is_html_allowed_on_front"/>
138 </group>
139 <group name="system" col="4">
140 <field name="sync_date" readonly="1"/>
141 <field name="magento_id" readonly="1"/>
142 </group>
143 </form>
144 </field>
145</record>
146
147
148<!--Magento attribute set-->
149<record id="magento_attribute_set_tree_view" model="ir.ui.view">
150 <field name="model">magento.attribute.set</field>
151 <field name="arch" type="xml">
152 <tree string="Attribute set" editable="top">
153 <field name="backend_id"/>
154 <field name="attribute_set_name"/>
155 <field name="openerp_id"/>
156 <field name="sync_date" readonly="1"/>
157 <field name="sort_order"/>
158 <field name="magento_id" readonly="1"/>
159 </tree>
160 </field>
161</record>
162
163
164<record id="magento_attribute_set_form_view" model="ir.ui.view">
165 <field name="model">magento.attribute.set</field>
166 <field name="arch" type="xml">
167 <form string="main" version="7.0">
168 <group col="4">
169 <field name="backend_id"/>
170 <field name="attribute_set_name"/>
171 <field name="sync_date"/>
172 <field name="openerp_id"/>
173 <field name="sort_order"/>
174 <field name="magento_id"/>
175 </group>
176 </form>
177 </field>
178</record>
179
180
181<record id="magento_attribute_set_action" model="ir.actions.act_window">
182 <field name="type">ir.actions.act_window</field>
183 <field name="res_model">magento.attribute.set</field>
184 <field name="view_type">form</field>
185 <field name="name">Mag. attr. set</field>
186 <!--<field name="view_id" ref="magento_attribute_set_tree_view"/>-->
187 <field name="help" type="html">
188 <p class="oe_view_nocontent_create">
189 Click to add an attribute set.
190 </p>
191 </field>
192</record>
193
194<menuitem id="menu_magento_attribute_set"
195 name="Sets"
196 action="magento_attribute_set_action"
197 parent="menu_magento_product_attribute_main"
198 sequence="5"/>
199
200
201<!--Magento attribute option-->
202<record id="magento_attribute_option_tree_view" model="ir.ui.view">
203 <field name="model">magento.attribute.option</field>
204 <field name="arch" type="xml">
205 <tree string="Attribute option">
206 <field name="openerp_id"/>
207 </tree>
208 </field>
209</record>
210
211<record id="magento_attribute_option_action" model="ir.actions.act_window">
212 <field name="type">ir.actions.act_window</field>
213 <field name="res_model">magento.attribute.option</field>
214 <field name="view_type">form</field>
215 <field name="name">Mag. attr. option</field>
216 <field name="view_id" ref="magento_attribute_option_tree_view"/>
217 <field name="help" type="html">
218 <p class="oe_view_nocontent_create">
219 Click to add an attribute option.
220 </p>
221 </field>
222</record>
223
224<menuitem id="menu_magento_attribute_option"
225 name="Options"
226 action="magento_attribute_option_action"
227 parent="menu_magento_product_attribute_main"
228 sequence="15"/>
229
230 </data>
231</openerp>
0232
=== added file 'magentoerpconnect_catalog/product_category.py'
--- magentoerpconnect_catalog/product_category.py 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/product_category.py 2014-07-01 22:23:08 +0000
@@ -0,0 +1,239 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright 2013
5# Author: Guewen Baconnier - Camptocamp SA
6# Augustin Cisterne-Kaasv - Elico-corp
7# David Béal - Akretion
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from openerp.osv import fields, orm
24from openerp.addons.connector.unit.mapper import (mapping,
25 #changed_by,
26 ExportMapper)
27from openerp.addons.magentoerpconnect.unit.delete_synchronizer import (
28 MagentoDeleteSynchronizer)
29from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
30 MagentoTranslationExporter)
31from openerp.addons.magentoerpconnect.backend import magento
32from openerp.addons.magentoerpconnect import product_category
33
34
35class MagentoProductCategory(orm.Model):
36 _inherit = 'magento.product.category'
37 MAGENTO_HELP = "This field is a technical / configuration field for " \
38 "the category on Magento. \nPlease refer to the Magento " \
39 "documentation for details. "
40
41 def get_custom_design(self, cr, uid, context=None):
42 return [
43 ('base/default', 'base default'),
44 ('default/modern', 'default modern'),
45 ('default/iphone', 'default iphone'),
46 ('default/default', 'default default'),
47 ('default/blank', 'default blank'),
48 ]
49
50 def _get_custom_design(self, cr, uid, context=None):
51 return self.get_custom_design(cr, uid, context=context)
52
53 def get_page_layout(self, cr, uid, context=None):
54 return [
55 ('empty', 'Empty'),
56 ('one_column', '1 colmun'),
57 ('two_columns_left', '2 columns with left bar'),
58 ('two_columns_right', '2 columns with right bar'),
59 ('three_columns', '3 columns'),
60 ]
61
62 def _get_page_layout(self, cr, uid, context=None):
63 return self.get_page_layout(cr, uid, context=context)
64
65 _columns = {
66 #==== General Information ====
67 'thumbnail_like_image': fields.boolean('Thumbnail like main image'),
68 'thumbnail_binary': fields.binary('Thumbnail'),
69 'thumbnail': fields.char(
70 'Thumbnail name',
71 size=100, help=MAGENTO_HELP),
72 'image_binary': fields.binary('Image'),
73 'image': fields.char(
74 'Image name',
75 size=100, help=MAGENTO_HELP),
76 'meta_title': fields.char('Title (Meta)', size=75, help=MAGENTO_HELP),
77 'meta_keywords': fields.text('Meta Keywords', help=MAGENTO_HELP),
78 'meta_description': fields.text('Meta Description', help=MAGENTO_HELP),
79 'url_key': fields.char('URL-key', size=100, readonly="True"),
80 #==== Display Settings ====
81 'display_mode': fields.selection([
82 ('PRODUCTS', 'Products Only'),
83 ('PAGE', 'Static Block Only'),
84 ('PRODUCTS_AND_PAGE', 'Static Block & Products')],
85 'Display Mode', required=True, help=MAGENTO_HELP),
86 'is_anchor': fields.boolean('Anchor?', help=MAGENTO_HELP),
87 'use_default_available_sort_by': fields.boolean(
88 'Default Config For Available Sort By', help=MAGENTO_HELP),
89
90 #TODO use custom attribut for category
91
92 #'available_sort_by': fields.sparse(
93 # type='many2many',
94 # relation='magerp.product_category_attribute_options',
95 # string='Available Product Listing (Sort By)',
96 # serialization_field='magerp_fields',
97 # domain="[('attribute_name', '=', 'sort_by'), ('value', '!=','None')]",
98 # help=MAGENTO_HELP),
99 #filter_price_range landing_page ?????????????
100 'default_sort_by': fields.selection([
101 ('_', 'Config settings'), #?????????????
102 ('position', 'Best Value'),
103 ('name', 'Name'),
104 ('price', 'Price')],
105 'Default sort by', required=True, help=MAGENTO_HELP),
106
107 #==== Custom Design ====
108 'custom_apply_to_products': fields.boolean(
109 'Apply to products', help=MAGENTO_HELP),
110 'custom_design': fields.selection(
111 _get_custom_design,
112 string='Custom design',
113 help=MAGENTO_HELP),
114 'custom_design_from': fields.date(
115 'Active from', help=MAGENTO_HELP),
116 'custom_design_to': fields.date(
117 'Active to', help=MAGENTO_HELP),
118 'custom_layout_update': fields.text(
119 'Layout update', help=MAGENTO_HELP),
120 'page_layout': fields.selection(
121 _get_page_layout,
122 'Page layout', help=MAGENTO_HELP),
123 }
124
125 _defaults = {
126 'thumbnail_like_image': True,
127 'display_mode': 'PRODUCTS',
128 'use_default_available_sort_by': True,
129 'default_sort_by': '_',
130 'is_anchor': True,
131 'include_in_menu': True,
132 }
133
134 _sql_constraints = [
135 ('magento_img_uniq', 'unique(backend_id, image)',
136 "'Image file name' already exists : must be unique"),
137 ('magento_thumb_uniq', 'unique(backend_id, thumbnail)',
138 "'thumbnail name' already exists : must be unique"),
139 ]
140
141
142@magento
143class ProductCategoryDeleteSynchronizer(MagentoDeleteSynchronizer):
144 """ Product category deleter for Magento """
145 _model_name = ['magento.product.category']
146
147
148@magento
149class ProductCategoryExport(MagentoTranslationExporter):
150 _model_name = ['magento.product.category']
151
152 def _export_dependencies(self):
153 """Export parent of the category"""
154 #TODO FIXME
155 return True
156 env = self.environment
157 record = self.binding_record
158 binder = self.get_binder_for_model()
159 if record.magento_parent_id:
160 mag_parent_id = record.magento_parent_id.id
161 if binder.to_backend(mag_parent_id) is None:
162 exporter = env.get_connector_unit(ProductCategoryExporter)
163 exporter.run(mag_parent_id)
164 elif record.openerp_id.parent_id:
165 parent = record.openerp_id.parent_id
166 if binder.to_backend(parent.id, wrap=True) is None:
167 exporter = env.get_connector_unit(ProductCategoryExporter)
168 exporter.run(parent.magento_parent_id.id)
169
170@magento
171class ProductCategoryExportMapper(ExportMapper):
172 _model_name = 'magento.product.category'
173
174 direct = [('description', 'description'),
175 #change that to mapping top level category has no name
176 ('name', 'name'),
177 ('meta_title', 'meta_title'),
178 ('meta_keywords', 'meta_keywords'),
179 ('meta_description', 'meta_description'),
180 ('display_mode', 'display_mode'),
181 ('is_anchor', 'is_anchor'),
182 ('use_default_available_sort_by', 'use_default_available_sort_by'),
183 ('custom_design', 'custom_design'),
184 ('custom_design_from', 'custom_design_from'),
185 ('custom_design_to', 'custom_design_to'),
186 ('custom_layout_update', 'custom_layout_update'),
187 ('page_layout', 'page_layout'),
188 ]
189
190 @mapping
191 def sort(self, record):
192 return {'default_sort_by':'price', 'available_sort_by': 'price'}
193
194 @mapping
195 def parent(self, record):
196 """ Magento root category's Id equals 1 """
197 if not record.magento_parent_id:
198 openerp_parent = record.parent_id
199 binder = self.get_binder_for_model('magento.product.category')
200 parent_id = binder.to_backend(openerp_parent.id, wrap=True)
201 else:
202 parent_id = record.magento_parent_id.magento_id
203 if not parent_id:
204 parent_id = 1
205 return {'parent_id':parent_id}
206
207 @mapping
208 def active(self, record):
209 is_active = record['is_active']
210 if not is_active:
211 is_active = 0
212 return {'is_active':is_active}
213
214 @mapping
215 def menu(self, record):
216 include_in_menu = record['include_in_menu']
217 if not include_in_menu:
218 include_in_menu = 0
219 return {'include_in_menu':include_in_menu}
220
221 @mapping
222 def image(self, record):
223 res = {}
224 if record.image_binary:
225 res.update({'image': record.image,
226 'image_binary': record.image_binary})
227 if record.thumbnail_like_image == True :
228 res.update({'thumbnail': record.image,})
229 elif record.thumbnail:
230 res.update({'thumbnail': record.thumbnail,
231 'thumbnail_binary': record.thumbnail_binary})
232 return res
233
234@magento(replacing=product_category.ProductCategoryImportMapper)
235class ProductCategoryImportMapper(product_category.ProductCategoryImportMapper):
236 _model_name = 'magento.product.category'
237 direct = product_category.ProductCategoryImportMapper.direct + []
238
239 #TODO add mapping for default_sort_by and available_sort_by
0240
=== added file 'magentoerpconnect_catalog/product_image.py'
--- magentoerpconnect_catalog/product_image.py 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/product_image.py 2014-07-01 22:23:08 +0000
@@ -0,0 +1,336 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright 2013
5# Author: Guewen Baconnier - Camptocamp
6# David Béal - Akretion
7# Sébastien Beau - Akretion
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23import mimetypes
24
25from openerp.osv import fields, orm
26#from openerp.tools.translate import _
27#from openerp.osv.osv import except_osv
28from openerp.addons.connector.unit.mapper import (mapping,
29 ExportMapper)
30from openerp.addons.magentoerpconnect.unit.binder import MagentoModelBinder
31from openerp.addons.magentoerpconnect.unit.delete_synchronizer import (
32 MagentoDeleteSynchronizer)
33from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
34 MagentoExporter)
35from openerp.addons.magentoerpconnect.backend import magento
36from openerp.addons.magentoerpconnect.unit.backend_adapter import GenericAdapter
37
38
39MAGENTO_HELP = "This field is a technical / configuration field for " \
40 "the attribute on Magento. \nPlease refer to the Magento " \
41 "documentation for details. "
42
43
44@magento(replacing=MagentoModelBinder)
45class MagentoImageBinder(MagentoModelBinder):
46 _model_name = [
47 'magento.product.image',
48 ]
49
50
51class MagentoProductProduct(orm.Model):
52 _inherit = 'magento.product.product'
53
54 def _get_images(self, cr, uid, ids, field_names, arg, context=None):
55 res={}
56 for prd in self.browse(cr, uid, ids, context=context):
57 img_ids = self.pool['magento.product.image'].search(
58 cr, uid, [
59 ('product_id', '=', prd.openerp_id.id),
60 ('backend_id', '=', prd.backend_id.id), ], context=context)
61 res[prd.id] = img_ids
62 return res
63
64 def copy(self, cr, uid, id, default=None, context=None):
65 #take care about duplicate on one2many and function fields
66 #https://bugs.launchpad.net/openobject-server/+bug/705364
67 if default is None:
68 default = {}
69 default['magento_product_image_ids'] = None
70 return super(MagentoProductProduct, self).copy(cr, uid, id,
71 default=default,
72 context=context)
73 _columns = {
74 'magento_product_image_ids': fields.function(
75 _get_images,
76 type='one2many',
77 relation='magento.product.image',
78 string='Magento product images'),
79 'magento_product_storeview_ids': fields.one2many(
80 'magento.product.storeview',
81 'magento_product_id',
82 string='Magento storeview',),
83 }
84
85 def open_images(self, cr, uid, ids, context=None):
86 view_id = self.pool['ir.model.data'].get_object_reference(
87 cr, uid, 'magentoerpconnect_catalog',
88 'magento_product_img_form_view')[1]
89 return {
90 'name': 'Product images',
91 'view_type': 'form',
92 'view_mode': 'form',
93 'view_id': view_id,
94 'res_model': self._name,
95 'context': context,
96 'type': 'ir.actions.act_window',
97 'res_id': ids and ids[0] or False,
98 }
99
100
101class ProductImage(orm.Model):
102 _inherit = 'product.image'
103
104 _columns = {
105 'magento_bind_ids': fields.one2many(
106 'magento.product.image',
107 'openerp_id',
108 string='Magento bindings',),
109 }
110
111
112class MagentoProductImage(orm.Model):
113 _name = 'magento.product.image'
114 _description = "Magento product image"
115 _inherit = 'magento.binding'
116 _inherits = {'product.image': 'openerp_id'}
117
118 _columns = {
119 'openerp_id': fields.many2one(
120 'product.image',
121 required=True,
122 ondelete="cascade",
123 string='Image'),
124 }
125
126 def _get_backend(self, cr, uid, context=None):
127 backend_id = False
128 backend_m = self.pool['magento.backend']
129 back_ids = backend_m.search(cr, uid, [], context=context)
130 if back_ids:
131 backend_id = backend_m.browse(
132 cr, uid, back_ids, context=context)[0].id
133 return backend_id
134
135 _defaults = {
136 'backend_id': _get_backend,
137 }
138
139 _sql_constraints = [
140 ('magento_uniq', 'unique(backend_id, magento_id)',
141 "An image with the same ID on Magento already exists")
142 ]
143
144@magento
145class ProductImageDeleteSynchronizer(MagentoDeleteSynchronizer):
146 _model_name = ['magento.product.image']
147
148
149@magento
150class ProductImageExport(MagentoExporter):
151 _model_name = ['magento.product.image']
152
153 def _should_import(self):
154 "Images in magento doesn't retrieve infos on dates"
155 return False
156
157
158@magento
159class ProductImageExportMapper(ExportMapper):
160 _model_name = 'magento.product.image'
161
162 direct = [
163 ('label', 'label'),
164 ('sequence', 'position'),
165 ]
166
167 @mapping
168 def product(self, record):
169 binder = self.get_binder_for_model('magento.product.product')
170 external_product_id = binder.to_backend(
171 record.openerp_id.product_id.id, True)
172 return {'product': str(external_product_id)}
173
174 @mapping
175 def identifierType(self, record):
176 return {'identifierType': 'ID'}
177
178 @mapping
179 def types(self, record):
180 return {'types': ['image', 'small_image', 'thumbnail']}
181 # return {'types':
182 # [x for x in ['image', 'small_image', 'thumbnail'] if record[x]]
183 # }
184
185 @mapping
186 def file(self, record):
187 return {'file': {
188 'mime': mimetypes.guess_type(record.name + record.extension)[0],
189 'name': record.label,
190 'content': self.session.pool['image.image'].get_image(
191 self.session.cr, self.session.uid,
192 record.openerp_id.image_id.id,
193 context=self.session.context),
194 }
195 }
196
197
198@magento
199class ProductImageAdapter(GenericAdapter):
200 _model_name = 'magento.product.image'
201 _magento_model = 'catalog_product_attribute_media'
202
203 def create(self, data, storeview_id=None):
204 #import pdb;pdb.set_trace()
205 print data
206 return self._call('%s.create' % self._magento_model,
207 [data.pop('product'), data, storeview_id])
208
209 def write(self, id, data):
210 """ Update records on the external system
211 changes with GenericAdapter : prevent 'int(id)' """
212 return self._call('%s.update' % self._magento_model,
213 [data.pop('product'), id, data])
214
215 def delete(self, id):
216 """ Delete a record on the external system """
217 image_id, external_product_id = id
218 return self._call('%s.remove' % self._magento_model,
219 [external_product_id, image_id])
220
221
222class MagentoProductStoreview(orm.Model):
223 _name = 'magento.product.storeview'
224 _description = "Magento product storeview"
225 _inherits = {'magento.product.product': 'magento_product_id'}
226
227 _columns = {
228 'magento_product_id' : fields.many2one(
229 'magento.product.product',
230 required=True,
231 ondelete="cascade",
232 string='Image'),
233 'storeview_id': fields.many2one(
234 'magento.storeview',
235 required=True,
236 string='Storeview'),
237 'image': fields.many2one(
238 'magento.product.image',
239 'Base image',
240 help=MAGENTO_HELP),
241 'small_image': fields.many2one(
242 'magento.product.image',
243 'Small image',
244 help=MAGENTO_HELP),
245 'thumbnail': fields.many2one(
246 'magento.product.image',
247 'Thumbnail',
248 domain="[('backend_id', '=', 'backend_id')]",
249 help=MAGENTO_HELP),
250 'exclude_ids': fields.many2many(
251 'magento.product.image', 'product_id',
252 string='Exclude',
253 help=MAGENTO_HELP),
254 }
255
256
257@magento
258class ProductStoreviewExport(MagentoExporter):
259 _model_name = ['magento.product.storeview']
260
261# TODO
262# def _export_dependencies(self):
263
264 def _should_import(self):
265 "Images in magento doesn't retrieve infos on dates"
266 return False
267 #
268 #def _run(self, fields=None):
269 # """ Flow of the synchronization, implemented in inherited classes"""
270 # assert self.binding_id
271 # assert self.binding_record
272 #
273 #
274 # if not self.magento_id:
275 # fields = None # should be created with all the fields
276 #
277 # if self._has_to_skip():
278 # return
279 #
280 # export the missing linked resources
281 # self._export_dependencies()
282 #
283 # self._map_data(fields=fields)
284 #
285 # if self.magento_id:
286 # record = self.mapper.data
287 # if not record:
288 # return _('Nothing to export.')
289 # special check on data before export
290 # self._validate_data(record)
291 # self._update(record)
292 # else:
293 # record = self.mapper.data_for_create
294 # if not record:
295 # return _('Nothing to export.')
296 # special check on data before export
297 # self._validate_data(record)
298 # self.magento_id = self._create(record)
299 # return _('Record exported with ID %s on Magento.') % self.magento_id
300
301
302@magento
303class ProductStoreviewExportMapper(ExportMapper):
304 _model_name = 'magento.product.storeview'
305
306 direct = [
307 ('label', 'label'),
308 ('sequence', 'position'), ]
309
310 @mapping
311 def product(self, record):
312 return {'product': ''}
313
314
315#
316#@magento
317#class ProductStoreviewAdapter(GenericAdapter):
318# _model_name = 'magento.product.storeview'
319#
320# def update_image(self, product_id, data, storeview_id=None):
321# #data = {'small', image_id, 'medium':image_id,...}
322#
323# return self._call('catalog_product_attribute_media.update',
324# [product_id, image_id, data, storeview_id])
325#
326
327
328
329#
330#@job
331#def export_record(session, model_name, binding_id, fields=None):
332# """ Export a record on Magento """
333# record = session.browse(model_name, binding_id)
334# env = get_environment(session, model_name, record.backend_id.id)
335# exporter = env.get_connector_unit(MagentoExporter)
336# return exporter.run(binding_id, fields=fields)
0337
=== added file 'magentoerpconnect_catalog/product_image_view.xml'
--- magentoerpconnect_catalog/product_image_view.xml 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/product_image_view.xml 2014-07-01 22:23:08 +0000
@@ -0,0 +1,79 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<openerp>
3 <data>
4
5 <!--
6<record id="view_product_image_form" model="ir.ui.view">
7 <field name="model">product.image</field>
8 <field name="inherit_id"
9 ref="product_image.view_product_image_form" />
10 <field name="arch" type="xml" >
11 <xpath expr="//group[@name='link']" position="after">
12 <field name="product_id" invisible="1"/>
13 <group name="magento">
14 <field name="magento_bind_ids" nolabel="1">
15 <tree name="magento_img_storeview"
16 editable="bottom">
17 <field name="backend_id" string="Backend"/>
18 </tree>
19 </field>
20 </group>
21 </xpath>
22 </field>
23</record>
24
25<record id="magento_product_img_form_view" model="ir.ui.view">
26 <field name="model">magento.product.product</field>
27 <field name="priority">30</field>
28 <field name="arch" type="xml">
29 <form version="7.0" string="_">
30 <separator string="Magento images"/>
31 <field name="backend_id" invisible="True"/>
32 <field name="openerp_id" invisible="True"/>
33 <field name="magento_product_image_ids">
34 <tree editable="bottom">
35 <field name="product_id"/>
36 <field name="label"/>
37 <field name="sequence"/>
38 <field name="name"/>
39 <field name="extension" string="ext."/>
40 <field name="magento_id"/>
41 <field name="file" widget="image"/>
42 </tree>
43 </field>
44 <separator string="Magento storeviews"/>
45 <field name="magento_product_storeview_ids">
46 <tree editable="bottom">
47 <field name="image"
48 domain="[('backend_id', '=', parent.backend_id), ('product_id', '=', parent.openerp_id)]"/>
49 <field name="small_image"
50 domain="[('backend_id', '=', parent.backend_id), ('product_id', '=', parent.openerp_id)]"/>
51 <field name="thumbnail"
52 domain="[('backend_id', '=', parent.backend_id), ('product_id', '=', parent.openerp_id)]"/>
53 <field name="storeview_id"
54 domain="[('backend_id', '=', parent.backend_id)]"/>
55 <field name="exclude_ids"
56 widget="many2many_tags"
57 domain="[('backend_id', '=', parent.backend_id), ('product_id', '=', parent.openerp_id)]"/>
58 </tree>
59 </field>
60 </form>
61 </field>
62</record>
63
64<record id="product_normal_form_view" model="ir.ui.view">
65 <field name="model">product.product</field>
66 <field name="inherit_id"
67 ref="magentoerpconnect.product_normal_form_view"/>
68 <field name="arch" type="xml">
69 <xpath expr="//field[@name='magento_bind_ids']/tree/field[@name='backend_id']"
70 position="before">
71 <button string="Images management" type="object"
72 name="open_images" icon="stock_gantt"/>
73 </xpath>
74 </field>
75</record>
76
77-->
78 </data>
79</openerp>
080
=== added file 'magentoerpconnect_catalog/product_view.xml'
--- magentoerpconnect_catalog/product_view.xml 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/product_view.xml 2014-07-01 22:23:08 +0000
@@ -0,0 +1,78 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<openerp>
3 <data>
4
5<record id="view_magento_product_category_form" model="ir.ui.view">
6 <field name="name">magento.product.category.form</field>
7 <field name="model">magento.product.category</field>
8 <field name="inherit_id" ref="magentoerpconnect.view_magento_product_category_form" />
9 <field name="arch" type="xml" >
10 <xpath expr="/form/group[1]" position="replace">
11 <group col="4">
12 <field name="backend_id" colspan="2"/>
13 <field name="magento_id" readonly="1" colspan="2"/>
14 </group>
15 </xpath>
16 <xpath expr="/form" position="inside">
17 <group string="General informations" col="4">
18 <group colspan="2">
19 <field name="is_active"/>
20 <field name="include_in_menu"/>
21 <field name="magento_parent_id"/>
22 </group>
23 <group colspan="2">
24 <label for="magento_child_ids" class="oe_inline"/>
25 <field name="magento_child_ids" colspan="2" nolabel="1"/>
26 </group>
27 <field name="description" colspan="4"/>
28 <group colspan="2">
29 <field name="image"/>
30 <field name="meta_title"/>
31 <field name="meta_description"/>
32 <field name="meta_keywords"/>
33 <field name="thumbnail_like_image"/>
34 <group name="thumbnail_grp" colspan="2"
35 attrs="{'invisible': [('thumbnail_like_image', '=', True)]}">
36
37 <field name="thumbnail"/>
38 <field name="thumbnail_binary" widget="image"
39 filename="thumbnail" nolabel="1"/>
40 </group>
41 </group>
42 <group colspan="2">
43 <field name="image_binary" widget="image"
44 filename="image" nolabel="1"/>
45 </group>
46 </group>
47 <group string="Display settings" col="4">
48 <field name="display_mode"/>
49 <field name="is_anchor"/>
50 <field name="use_default_available_sort_by"/>
51 </group>
52 <group string="Custom design" col="4">
53 <field name="custom_design"/>
54 <field name="custom_design_from"/>
55 <field name="custom_apply_to_products"/>
56 <field name="custom_design_to"/>
57 <field name="page_layout"/><br/><br/>
58 <field name="custom_layout_update" colspan="4"/>
59 </group>
60 </xpath>
61 </field>
62</record>
63
64
65<record id="product_product_form_view_set_button" model="ir.ui.view">
66 <field name="model">product.product</field>
67 <field name="inherit_id"
68 ref="product_custom_attributes.product_product_form_view_set_button"/>
69 <field name="arch" type="xml">
70 <field name="attribute_set_id" position="attributes">
71 <attribute name="attrs">{'required': [('magento_bind_ids','!=',[])]}</attribute>
72 </field>
73 </field>
74</record>
75
76
77 </data>
78</openerp>
0\ No newline at end of file79\ No newline at end of file
180
=== added directory 'magentoerpconnect_catalog/tests'
=== added file 'magentoerpconnect_catalog/tests/__init__.py'
--- magentoerpconnect_catalog/tests/__init__.py 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/tests/__init__.py 2014-07-01 22:23:08 +0000
@@ -0,0 +1,29 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Guewen Baconnier
5# Copyright 2012 Camptocamp SA
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 <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22import test_attribute_synchronisation
23
24fast_suite = [
25]
26
27checks = [
28 test_attribute_synchronisation,
29]
030
=== added file 'magentoerpconnect_catalog/tests/test_attribute_synchronisation.py'
--- magentoerpconnect_catalog/tests/test_attribute_synchronisation.py 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/tests/test_attribute_synchronisation.py 2014-07-01 22:23:08 +0000
@@ -0,0 +1,109 @@
1# -*- coding: utf-8 -*-
2###############################################################################
3#
4# Module for OpenERP
5# Copyright (C) 2014 Akretion (http://www.akretion.com).
6# @author Sébastien BEAU <sebastien.beau@akretion.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21###############################################################################
22
23from openerp.addons.magentoerpconnect.tests.test_synchronization import (
24 SetUpMagentoSynchronized)
25from openerp.addons.magentoerpconnect.unit.import_synchronizer import (
26 import_record)
27from openerp.addons.magentoerpconnect.tests.common import (
28 mock_api,
29 mock_urlopen_image)
30from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
31 export_record)
32from .test_data import magento_attribute_responses
33
34
35class TestImportAttribute(SetUpMagentoSynchronized):
36 """ Test the import from a Magento Mock.
37
38 The data returned by Magento are those created for the
39 demo version of Magento on a standard 1.7 version.
40 """
41
42 def test_10_import_attribute_set(self):
43 """ Import the default attribute set"""
44 with mock_api(magento_attribute_responses):
45 import_record(self.session, 'magento.attribute.set',
46 self.backend_id, '9')
47
48 mag_attr_obj = self.registry('magento.attribute.set')
49 cr, uid = self.cr, self.uid
50 mag_attr_set_ids = mag_attr_obj.search(cr, uid, [
51 ('magento_id', '=', '9'),
52 ('backend_id', '=', self.backend_id),
53 ])
54 self.assertEqual(len(mag_attr_set_ids), 1)
55 mag_attr_set = mag_attr_obj.browse(cr, uid, mag_attr_set_ids[0])
56 self.assertEqual(mag_attr_set.attribute_set_name, 'Default')
57
58
59class TestExportAttribute(SetUpMagentoSynchronized):
60 """ Test the export from a Magento Mock.
61
62 The data returned by Magento are those created for the
63 demo version of Magento on a standard 1.7 version.
64 """
65 def setUp(self):
66 super(TestExportAttribute, self).setUp()
67 with mock_api(magento_attribute_responses):
68 import_record(self.session, 'magento.attribute.set',
69 self.backend_id, '9')
70
71 mag_attr_model = self.registry('magento.attribute.set')
72 cr, uid = self.cr, self.uid
73 mag_attr_set_ids = mag_attr_model.search(cr, uid, [
74 ('magento_id', '=', '9'),
75 ('backend_id', '=', self.backend_id),
76 ])
77 self.registry('magento.backend').write(cr, uid, self.backend_id, {
78 'attribute_set_tpl_id': mag_attr_set_ids[0]
79 })
80
81 def test_20_export_attribute_set(self):
82 """ Test export of attribute set"""
83 response = {
84 'product_attribute_set.create': 69,
85 }
86 cr = self.cr
87 uid = self.uid
88 with mock_api(response, key_func=lambda m, a: m) as calls_done:
89 mag_attr_set_model = self.registry('magento.attribute.set')
90 attr_set_model = self.registry('attribute.set')
91
92 attr_set_id = attr_set_model.create(cr, uid, {
93 'name': 'Test Export Attribute',
94 }, {'force_model': 'product.template'})
95 mag_attr_set_id = mag_attr_set_model.create(cr, uid, {
96 'attribute_set_name': 'Test Export Attribute',
97 'openerp_id': attr_set_id,
98 'backend_id': self.backend_id,
99 })
100
101 export_record(self.session, 'magento.attribute.set',
102 mag_attr_set_id)
103
104 self.assertEqual(len(calls_done), 1)
105
106 method, (data, skeleton_id) = calls_done[0]
107 print data
108 self.assertEqual(method, 'product_attribute_set.create')
109 self.assertEqual(skeleton_id, '9')
0110
=== added file 'magentoerpconnect_catalog/tests/test_data.py'
--- magentoerpconnect_catalog/tests/test_data.py 1970-01-01 00:00:00 +0000
+++ magentoerpconnect_catalog/tests/test_data.py 2014-07-01 22:23:08 +0000
@@ -0,0 +1,99 @@
1# -*- coding: utf-8 -*-
2###############################################################################
3#
4# Module for OpenERP
5# Copyright (C) 2014 Akretion (http://www.akretion.com).
6# @author Sébastien BEAU <sebastien.beau@akretion.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21###############################################################################
22
23
24magento_attribute_responses = \
25{('ol_catalog_product_attributeset.info', (9,)): {'attribute_set_id': '9',
26 'attribute_set_name': 'Default',
27 'entity_type_id': '10',
28 'sort_order': '16'},
29 ('ol_catalog_product_attributeset.info', (38,)): {'attribute_set_id': '38',
30 'attribute_set_name': 'Cell Phones',
31 'entity_type_id': '10',
32 'sort_order': '0'},
33 ('ol_catalog_product_attributeset.info', (39,)): {'attribute_set_id': '39',
34 'attribute_set_name': 'Computer',
35 'entity_type_id': '10',
36 'sort_order': '0'},
37 ('ol_catalog_product_attributeset.info', (40,)): {'attribute_set_id': '40',
38 'attribute_set_name': 'Shoes',
39 'entity_type_id': '10',
40 'sort_order': '0'},
41 ('ol_catalog_product_attributeset.info', (41,)): {'attribute_set_id': '41',
42 'attribute_set_name': 'Shirts T',
43 'entity_type_id': '10',
44 'sort_order': '0'},
45 ('ol_catalog_product_attributeset.info', (42,)): {'attribute_set_id': '42',
46 'attribute_set_name': 'Furniture',
47 'entity_type_id': '10',
48 'sort_order': '0'},
49 ('ol_catalog_product_attributeset.info', (44,)): {'attribute_set_id': '44',
50 'attribute_set_name': 'Cameras',
51 'entity_type_id': '10',
52 'sort_order': '0'},
53 ('ol_catalog_product_attributeset.info', (45,)): {'attribute_set_id': '45',
54 'attribute_set_name': 'Shirts Other',
55 'entity_type_id': '10',
56 'sort_order': '0'},
57 ('ol_catalog_product_attributeset.info', (46,)): {'attribute_set_id': '46',
58 'attribute_set_name': 'Shirts (General)',
59 'entity_type_id': '10',
60 'sort_order': '0'},
61 ('ol_catalog_product_attributeset.info', (58,)): {'attribute_set_id': '58',
62 'attribute_set_name': 'RAM',
63 'entity_type_id': '10',
64 'sort_order': '0'},
65 ('ol_catalog_product_attributeset.info', (59,)): {'attribute_set_id': '59',
66 'attribute_set_name': 'Warranties',
67 'entity_type_id': '10',
68 'sort_order': '0'},
69 ('ol_catalog_product_attributeset.info', (60,)): {'attribute_set_id': '60',
70 'attribute_set_name': 'CPU',
71 'entity_type_id': '10',
72 'sort_order': '0'},
73 ('ol_catalog_product_attributeset.info', (61,)): {'attribute_set_id': '61',
74 'attribute_set_name': 'Monitors',
75 'entity_type_id': '10',
76 'sort_order': '0'},
77 ('ol_catalog_product_attributeset.info', (62,)): {'attribute_set_id': '62',
78 'attribute_set_name': 'Hard Drive',
79 'entity_type_id': '10',
80 'sort_order': '0'},
81 ('ol_catalog_product_attributeset.info', (63,)): {'attribute_set_id': '63',
82 'attribute_set_name': 't-shirt-open',
83 'entity_type_id': '10',
84 'sort_order': '0'},
85 ('ol_catalog_product_attributeset.search', ()): ['44',
86 '38',
87 '39',
88 '60',
89 '9',
90 '42',
91 '62',
92 '61',
93 '58',
94 '46',
95 '45',
96 '41',
97 '40',
98 '63',
99 '59']}