Merge lp:~ajite/openerp-connector/7.0-magentoerpconnect-fix-000002 into lp:~openerp-connector-core-editors/openerp-connector-magento/7.0
- 7.0-magentoerpconnect-fix-000002
- Merge into 7.0
Status: | Work in progress |
---|---|
Proposed branch: | lp:~ajite/openerp-connector/7.0-magentoerpconnect-fix-000002 |
Merge into: | lp:~openerp-connector-core-editors/openerp-connector-magento/7.0 |
Diff against target: |
576 lines (+391/-3) 15 files modified
magentoerpconnect/__init__.py (+1/-0) magentoerpconnect/magento_model.py (+10/-0) magentoerpconnect/magento_model_view.xml (+7/-0) magentoerpconnect/product.py (+39/-1) magentoerpconnect/product_attribute_set.py (+94/-0) magentoerpconnect/product_category.py (+7/-0) magentoerpconnect/product_view.xml (+22/-0) magentoerpconnect/unit/binder.py (+1/-0) magentoerpconnect_catalog/__init__.py (+5/-0) magentoerpconnect_catalog/__openerp__.py (+2/-2) magentoerpconnect_catalog/connector.py (+12/-0) magentoerpconnect_catalog/consumer.py (+25/-0) magentoerpconnect_catalog/product.py (+95/-0) magentoerpconnect_catalog/product_category.py (+55/-0) magentoerpconnect_catalog/product_view.xml (+16/-0) |
To merge this branch: | bzr merge lp:~ajite/openerp-connector/7.0-magentoerpconnect-fix-000002 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenERP Connector Core Editors | Pending | ||
Review via email: mp+180730@code.launchpad.net |
Commit message
Description of the change
The changes that I have made are experimental.
At the moment, some of the previous unit tests are not working because you need to import product attribute sets before importing products.
It is quite stable on my local environment but it still obviously needs improvements.
To try the changes that I have made please use the following branch of the OpenLabs Magento add-on:
bzr branch lp:~ajite/openerp-connector/magento-model-oerp7.x-experimental
It adds 2 API methods in the Product attribute set API (search and info).
Added the export of products and categories.
Added the import of product attribute sets (We need to have them to export export products).
Added a new backend advanced option (Export record On save)
Added attributes in both magento.
Please import the product attribute sets before importing products
You need to have a product code and a product description for the product export function to succeed.
We can create and edit a category then export it to a given backend but we can't move the category to another parent category after the creation. In fact the magento setParentId() will not change the parent id. We need to implement the magento category API move method to make it work.
- 906. By Augustin Cisterne-Kaas <email address hidden>
-
[ADD] Export categories and products. Import of product set attributes.
Augustin Cisterne-Kaas - www.elico-corp.com (ajite) wrote : | # |
Hi Guewen,
Thank you for your feedback.
> Hi Augustin,
>
> Thanks for the MP.
> I read through the diff and that seems already nice, you very well understood
> the mechanisms and how the synchronizations are supposed to work and that
> makes me happy.
>
> I'll need to take more time to do a proper review, but I'm already reassured
> that you go in the right direction so I am quite comfortable if let you
> continue in this direction.
>
I am glad that I am heading in the right direction.
> There is just one thing I want to comment on, about the choice to push the
> records on save.
> Basically in your diff:
>
> push_on_save = record.
> if push_on_save:
>
> This option is to remove, any created or modified record must always me
> exported to Magento, that's the design we choose. So we don't need anymore the
> methods to export the products or categories like in l.411,498.
>
Don't you think that the "push on save" function might be useful for people in a marketing team who are working on a product description and want to save the changes as a draft before sending the final description to a backend ? I think that not having that option might lead to more mistakes from the end-users.
> Another thing about the monkey patching in l.522: this is a bad idea, because
> OpenERP may import the python code of uninstalled modules (it wouldn't have
> bad effects in this case, remark). There is other techniques [0][1] for
> replacing ConnectorUnit classes, but in that case I would just redefine the
> create method in the main 'magentoerpconnect' module.
>
>
> [0] https:/
> connector/
> [1] https:/
> connector/
I forgot to remove the monkey patch line 622. Hopefully you saw it ;)!
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
On 08/19/2013 09:13 AM, Augustin Cisterne-Kaas (www.elico-
>
>> There is just one thing I want to comment on, about the choice to push the
>> records on save.
>> Basically in your diff:
>>
>> push_on_save = record.
>> if push_on_save:
>>
>> This option is to remove, any created or modified record must always me
>> exported to Magento, that's the design we choose. So we don't need anymore the
>> methods to export the products or categories like in l.411,498.
>>
>
> Don't you think that the "push on save" function might be useful for people in a marketing team who are working on a product description and want to save the changes as a draft before sending the final description to a backend ? I think that not having that option might lead to more mistakes from the end-users.
>
You are right, that could be a nice option, I would be more in favor of
a single field on the 'magento.
'magento.
skipped while it is not True. I don't like the global option.
Although, for records which are already exported, we'll miss the sync of
the changes (in both cases, "push on save" global option or "ready"
field) if the option is deactivated and we don't push them manually and
that could be a problem.
Anyhow, I need a bit more reflexion on that, but my feeling is that for
such cases, we should never deactivate the exports and just use the
"visibility" or "active" field of Magento.
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
On 08/19/2013 09:51 AM, Guewen Baconnier @ Camptocamp wrote:
> Anyhow, I need a bit more reflexion on that, but my feeling is that for
> such cases, we should never deactivate the exports and just use the
> "visibility" or "active" field of Magento.
>
That would also prevent many issues with cross-linking between records,
e.g. export a child category but parent category's not yet exported, or
export a product linked (cross-sell, up-sell, ...) to a product not yet
exported.
--
Guewen Baconnier
Business Solutions Software Developer
Camptocamp SA
PSE A, CH-1015 Lausanne
Phone: +41 21 619 10 39
Office: +41 21 619 10 10
http://
- 907. By Augustin Cisterne-Kaas <email address hidden>
-
Removed Global "Push On Save" button
Augustin Cisterne-Kaas - www.elico-corp.com (ajite) wrote : | # |
> On 08/19/2013 09:51 AM, Guewen Baconnier @ Camptocamp wrote:
> > Anyhow, I need a bit more reflexion on that, but my feeling is that for
> > such cases, we should never deactivate the exports and just use the
> > "visibility" or "active" field of Magento.
> >
> That would also prevent many issues with cross-linking between records,
> e.g. export a child category but parent category's not yet exported, or
> export a product linked (cross-sell, up-sell, ...) to a product not yet
> exported.
>
>
> --
> Guewen Baconnier
> Business Solutions Software Developer
>
> Camptocamp SA
> PSE A, CH-1015 Lausanne
> Phone: +41 21 619 10 39
> Office: +41 21 619 10 10
> http://
You are absolutely right.
I have removed the global "push on save" option. I will try to think about something else.
Augustin Cisterne-Kaas - www.elico-corp.com (ajite) wrote : | # |
I have improved the way data were sent. I have added some required attributes in 'magento.
I was able to push 2500 products with custom attribute sets and custom attributes without any problem. I have created another module to handle the custom attributes that were needed for my case.
The write and unlink functions are both working well.
I am not happy with my import product category mapper. How can I improve it ? I have tried to use a binder but that did not work well... Is there anyway to avoid the O(n*m) loop ?
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
On 08/22/2013 12:08 PM, Augustin Cisterne-Kaas (www.elico-
> I have improved the way data were sent. I have added some required attributes in 'magento.
>
> I was able to push 2500 products with custom attribute sets and custom attributes without any problem. I have created another module to handle the custom attributes that were needed for my case.
>
> The write and unlink functions are both working well.
>
Nice news! I'll have a look.
> I am not happy with my import product category mapper. How can I improve it ? I have tried to use a binder but that did not work well... Is there anyway to avoid the O(n*m) loop ?
>
Just to be sure, you speak about ProductProductE
right?
I don't think we can avoid the O(n*m) loop, at least using the ORM, we
could maybe do it with SQL but with a penalty in clarity.
However, we can simplify the function by iterating over a single list
(record.categ_id + record.categ_ids)
Untested:
@mapping
def category(self, record):
all_categs = [record.categ_id] + record.categ_ids
self.backend_
return {'categories': mag_categ_ids}
Augustin Cisterne-Kaas - www.elico-corp.com (ajite) wrote : | # |
> > I am not happy with my import product category mapper. How can I improve it
> ? I have tried to use a binder but that did not work well... Is there anyway
> to avoid the O(n*m) loop ?
> >
> Just to be sure, you speak about ProductProductE
> right?
> I don't think we can avoid the O(n*m) loop, at least using the ORM, we
> could maybe do it with SQL but with a penalty in clarity.
> However, we can simplify the function by iterating over a single list
> (record.categ_id + record.categ_ids)
>
> Untested:
>
> @mapping
> def category(self, record):
> all_categs = [record.categ_id] + record.categ_ids
> mag_categ_ids = [m_categ.magento_id for categ in all_categs
> for m_categ in categ.magento_
> if m_categ.
> self.backend_
> return {'categories': mag_categ_ids}
Yes. The syntax looks much better like that even though it is still O(n*m). I will update it as soon as I possible.
I think that it's better to avoid the SQL request.
Unmerged revisions
- 910. By Augustin Cisterne-Kaas <email address hidden>
-
[FIX] Removed debug message
- 909. By Augustin Cisterne-Kaas <email address hidden>
-
[FIX] Improved push of products
- 908. By Augustin Cisterne-Kaas <email address hidden>
-
[ADD] Added the unlink method.
- 907. By Augustin Cisterne-Kaas <email address hidden>
-
Removed Global "Push On Save" button
- 906. By Augustin Cisterne-Kaas <email address hidden>
-
[ADD] Export categories and products. Import of product set attributes.
- 905. By Augustin Cisterne-Kaas <email address hidden>
-
[ADD] Export categories and products. Import of product set attributes.
Preview Diff
1 | === modified file 'magentoerpconnect/__init__.py' |
2 | --- magentoerpconnect/__init__.py 2013-05-02 12:30:40 +0000 |
3 | +++ magentoerpconnect/__init__.py 2013-08-22 07:24:16 +0000 |
4 | @@ -6,6 +6,7 @@ |
5 | import magento_model |
6 | import product |
7 | import product_category |
8 | +import product_attribute_set |
9 | import partner |
10 | import partner_category |
11 | import invoice |
12 | |
13 | === modified file 'magentoerpconnect/magento_model.py' |
14 | --- magentoerpconnect/magento_model.py 2013-08-15 08:01:46 +0000 |
15 | +++ magentoerpconnect/magento_model.py 2013-08-22 07:24:16 +0000 |
16 | @@ -218,6 +218,16 @@ |
17 | 'import_products_from_date', context=context) |
18 | return True |
19 | |
20 | + def import_product_attribute_set(self, cr, uid, ids, context=None): |
21 | + if not hasattr(ids, '__iter__'): |
22 | + ids = [ids] |
23 | + self.check_magento_structure(cr, uid, ids, context=context) |
24 | + session = ConnectorSession(cr, uid, context=context) |
25 | + for backend_id in ids: |
26 | + import_batch.delay(session, 'magento.product.attribute.set', |
27 | + backend_id) |
28 | + return True |
29 | + |
30 | def update_product_stock_qty(self, cr, uid, ids, context=None): |
31 | if not hasattr(ids, '__iter__'): |
32 | ids = [ids] |
33 | |
34 | === modified file 'magentoerpconnect/magento_model_view.xml' |
35 | --- magentoerpconnect/magento_model_view.xml 2013-08-15 08:01:46 +0000 |
36 | +++ magentoerpconnect/magento_model_view.xml 2013-08-22 07:24:16 +0000 |
37 | @@ -91,6 +91,13 @@ |
38 | string="Import in background"/> |
39 | </group> |
40 | <group> |
41 | + <label string="Import product attribute sets" class="oe_inline"/> |
42 | + <button name="import_product_attribute_set" |
43 | + type="object" |
44 | + class="oe_highlight" |
45 | + string="Import in background"/> |
46 | + </group> |
47 | + <group> |
48 | <label string="Import sales orders from all store views" class="oe_inline"/> |
49 | <button name="import_sale_orders" |
50 | type="object" |
51 | |
52 | === modified file 'magentoerpconnect/product.py' |
53 | --- magentoerpconnect/product.py 2013-07-26 09:06:53 +0000 |
54 | +++ magentoerpconnect/product.py 2013-08-22 07:24:16 +0000 |
55 | @@ -79,12 +79,34 @@ |
56 | # XXX website_ids can be computed from categories |
57 | 'website_ids': fields.many2many('magento.website', |
58 | string='Websites', |
59 | - readonly=True), |
60 | + required=True), |
61 | 'created_at': fields.date('Created At (on Magento)'), |
62 | 'updated_at': fields.date('Updated At (on Magento)'), |
63 | 'product_type': fields.selection(_product_type_get, |
64 | 'Magento Product Type', |
65 | required=True), |
66 | + 'attribute_set_id': fields.many2one('product.attribute.set', |
67 | + string='Attribute Set', |
68 | + required=True), |
69 | + 'visibility': fields.selection( |
70 | + [('1', 'Not Visible Individually'), |
71 | + ('2', 'Catalog'), |
72 | + ('3', 'Search'), |
73 | + ('4', 'Catalog, Search')], |
74 | + string='Visibility in Magento', |
75 | + required=True), |
76 | + 'tax_class': fields.selection( |
77 | + [('0', 'None'), |
78 | + ('2', 'Default'), |
79 | + ('3', 'Taxable Goods'), |
80 | + ('4', 'Shipping')], |
81 | + string='Tax Class in Magento', |
82 | + ), |
83 | + 'status': fields.selection( |
84 | + [('1', 'Enabled'), |
85 | + ('2', 'Disabled')], |
86 | + string='Status in Magento', |
87 | + required=True), |
88 | 'manage_stock': fields.selection( |
89 | [('use_default', 'Use Default Config'), |
90 | ('no', 'Do Not Manage Stock'), |
91 | @@ -195,6 +217,9 @@ |
92 | in self._call('%s.list' % self._magento_model, |
93 | [filters] if filters else [{}])] |
94 | |
95 | + def create(self, data): |
96 | + return self._call('%s.create'% self._magento_model,[data.pop('product_type'),data.pop('attrset'),data.pop('sku'),data]) |
97 | + |
98 | def read(self, id, storeview_id=None, attributes=None): |
99 | """ Returns the information of a record |
100 | |
101 | @@ -356,6 +381,9 @@ |
102 | ('type_id', 'product_type'), |
103 | ('created_at', 'created_at'), |
104 | ('updated_at', 'updated_at'), |
105 | + ('visibility', 'visibility'), |
106 | + ('tax_class_id', 'tax_class'), |
107 | + ('status', 'status') |
108 | ] |
109 | |
110 | @mapping |
111 | @@ -372,6 +400,16 @@ |
112 | return |
113 | |
114 | @mapping |
115 | + def set(self, record): |
116 | + binder = self.get_binder_for_model('magento.product.attribute.set') |
117 | + set_id = binder.to_openerp(record['set']) |
118 | + if set_id is None: |
119 | + raise MappingError("The product attribute set with " |
120 | + "magento id %s is not imported." % |
121 | + record['set']) |
122 | + return {'attribute_set_id': set_id} |
123 | + |
124 | + @mapping |
125 | def website_ids(self, record): |
126 | website_ids = [] |
127 | binder = self.get_binder_for_model('magento.website') |
128 | |
129 | === added file 'magentoerpconnect/product_attribute_set.py' |
130 | --- magentoerpconnect/product_attribute_set.py 1970-01-01 00:00:00 +0000 |
131 | +++ magentoerpconnect/product_attribute_set.py 2013-08-22 07:24:16 +0000 |
132 | @@ -0,0 +1,94 @@ |
133 | +# -*- coding: utf-8 -*- |
134 | + |
135 | +import logging |
136 | +from openerp.osv import fields, orm, osv |
137 | +import openerp.addons.decimal_precision as dp |
138 | +from openerp.addons.connector.unit.mapper import (mapping, |
139 | + ImportMapper, |
140 | + ) |
141 | +from .backend import magento |
142 | +from openerp.addons.magentoerpconnect.unit.backend_adapter import GenericAdapter |
143 | +from openerp.addons.magentoerpconnect.unit.import_synchronizer import (BatchImportSynchronizer, |
144 | + DelayedBatchImport, |
145 | + MagentoImportSynchronizer |
146 | + ) |
147 | +from openerp.addons.magentoerpconnect.unit.binder import MagentoModelBinder |
148 | +from openerp.addons.connector.queue.job import job |
149 | + |
150 | + |
151 | +from openerp.tools.translate import _ |
152 | +_logger = logging.getLogger(__name__) |
153 | + |
154 | +class product_attribute_set(orm.Model): |
155 | + _name = 'product.attribute.set' |
156 | + |
157 | + _columns = { |
158 | + 'name': fields.char('name', required=True), |
159 | + 'magento_bind_ids': fields.one2many('magento.product.attribute.set', 'openerp_id', |
160 | + string="Magento Bindings"), |
161 | + } |
162 | + |
163 | + |
164 | + |
165 | + |
166 | + |
167 | +class magento_product_attribute_set(orm.Model): |
168 | + _name = 'magento.product.attribute.set' |
169 | + _inherit = 'magento.binding' |
170 | + _inherits = {'product.attribute.set': 'openerp_id'} |
171 | + |
172 | + _columns = { |
173 | + 'openerp_id': fields.many2one('product.attribute.set', |
174 | + string='Magento order', |
175 | + required=True, |
176 | + ondelete='cascade'), |
177 | + 'created_at': fields.date('Created At (on Magento)'), |
178 | + 'updated_at': fields.date('Updated At (on Magento)'), |
179 | + } |
180 | + |
181 | + _sql_constraints = [ |
182 | + ('magento_uniq', 'unique(backend_id, magento_id)', |
183 | + 'A partner tag with same ID on Magento already exists.'), |
184 | + ] |
185 | + |
186 | + |
187 | +@magento |
188 | +class ProductAttributeSetBatchImport(MagentoImportSynchronizer): |
189 | + _model_name = ['magento.product.attribute.set'] |
190 | + |
191 | +@magento |
192 | +class ProductAttributeSetBatchImport(DelayedBatchImport): |
193 | + """ Import the Magento Products. |
194 | + |
195 | + For every product category in the list, a delayed job is created. |
196 | + Import from a date |
197 | + """ |
198 | + _model_name = ['magento.product.attribute.set'] |
199 | + |
200 | + |
201 | +@magento |
202 | +class ProductAttributeSetAdapter(GenericAdapter): |
203 | + _model_name = 'magento.product.attribute.set' |
204 | + _magento_model = 'ol_catalog_product_attributeset' |
205 | + |
206 | + |
207 | +@magento |
208 | +class ProductAttributeSetImportMapper(ImportMapper): |
209 | + _model_name = 'magento.product.attribute.set' |
210 | + |
211 | + direct = [('attribute_set_id', 'magento_id'), |
212 | + ('attribute_set_name', 'name') |
213 | + ] |
214 | + |
215 | + @mapping |
216 | + def backend_id(self, record): |
217 | + return {'backend_id': self.backend_record.id} |
218 | + |
219 | +@job |
220 | +def product_attribute_set_import_batch(session, model_name, backend_id, filters=None): |
221 | + """ Prepare a batch import of records from Magento """ |
222 | + if filters is None: |
223 | + filters = {} |
224 | + env = get_environment(session, model_name, backend_id) |
225 | + importer = env.get_connector_unit(ProductAttributeSetBatchImport) |
226 | + importer.run(filters) |
227 | \ No newline at end of file |
228 | |
229 | === modified file 'magentoerpconnect/product_category.py' |
230 | --- magentoerpconnect/product_category.py 2013-07-26 09:06:53 +0000 |
231 | +++ magentoerpconnect/product_category.py 2013-08-22 07:24:16 +0000 |
232 | @@ -49,6 +49,8 @@ |
233 | required=True, |
234 | ondelete='cascade'), |
235 | 'description': fields.text('Description', translate=True), |
236 | + 'is_active': fields.boolean('Active in magento'), |
237 | + 'include_in_menu': fields.boolean('Include in magento menu'), |
238 | 'magento_parent_id': fields.many2one( |
239 | 'magento.product.category', |
240 | string='Magento Parent Category', |
241 | @@ -99,6 +101,9 @@ |
242 | else: |
243 | raise |
244 | |
245 | + def create(self, data): |
246 | + return self._call('%s.create'% self._magento_model,[data['parent_id'],data]) |
247 | + |
248 | def search(self, filters=None, from_date=None): |
249 | """ Search records according to some criterias and returns a |
250 | list of ids |
251 | @@ -216,6 +221,8 @@ |
252 | |
253 | direct = [ |
254 | ('description', 'description'), |
255 | + ('is_active','is_active'), |
256 | + ('include_in_menu','include_in_menu') |
257 | ] |
258 | |
259 | @mapping |
260 | |
261 | === modified file 'magentoerpconnect/product_view.xml' |
262 | --- magentoerpconnect/product_view.xml 2013-04-03 12:12:56 +0000 |
263 | +++ magentoerpconnect/product_view.xml 2013-08-22 07:24:16 +0000 |
264 | @@ -68,7 +68,12 @@ |
265 | <field name="magento_id"/> |
266 | <field name="created_at" readonly="1"/> |
267 | <field name="updated_at" readonly="1"/> |
268 | + <field name="visibility" /> |
269 | + <field name="tax_class" /> |
270 | + <field name="status" /> |
271 | <field name="product_type" readonly="1"/> |
272 | + <field name="website_ids" /> |
273 | + <field name="attribute_set_id" /> |
274 | </group> |
275 | <group string="Inventory Options"> |
276 | <field name="manage_stock"/> |
277 | @@ -96,5 +101,22 @@ |
278 | </field> |
279 | </record> |
280 | |
281 | + <record id="product_attribute_set_action_form" model="ir.actions.act_window"> |
282 | + <field name="name">Product Attribute Set</field> |
283 | + <field name="type">ir.actions.act_window</field> |
284 | + <field name="res_model">product.attribute.set</field> |
285 | + <field name="view_type">form</field> |
286 | + <field name="view_mode">tree,form</field> |
287 | + <field name="help" type="html"> |
288 | + <p class="oe_view_nocontent_create"> |
289 | + Click to create a product attribute set |
290 | + </p> |
291 | + </field> |
292 | + </record> |
293 | + |
294 | + <menuitem action="product_attribute_set_action_form" |
295 | + groups="base.group_no_one" |
296 | + id="menu_product_attribute_set_action_form" |
297 | + parent="product.prod_config_main" sequence="3"/> |
298 | </data> |
299 | </openerp> |
300 | |
301 | === modified file 'magentoerpconnect/unit/binder.py' |
302 | --- magentoerpconnect/unit/binder.py 2013-05-02 12:30:40 +0000 |
303 | +++ magentoerpconnect/unit/binder.py 2013-08-22 07:24:16 +0000 |
304 | @@ -53,6 +53,7 @@ |
305 | 'magento.sale.order', |
306 | 'magento.sale.order.line', |
307 | 'magento.account.invoice', |
308 | + 'magento.product.attribute.set', |
309 | ] |
310 | |
311 | def to_openerp(self, external_id, unwrap=False): |
312 | |
313 | === modified file 'magentoerpconnect_catalog/__init__.py' |
314 | --- magentoerpconnect_catalog/__init__.py 2013-03-19 15:41:34 +0000 |
315 | +++ magentoerpconnect_catalog/__init__.py 2013-08-22 07:24:16 +0000 |
316 | @@ -1,1 +1,6 @@ |
317 | # -*- coding: utf-8 -*- |
318 | + |
319 | +import connector |
320 | +import consumer |
321 | +import product |
322 | +import product_category |
323 | \ No newline at end of file |
324 | |
325 | === modified file 'magentoerpconnect_catalog/__openerp__.py' |
326 | --- magentoerpconnect_catalog/__openerp__.py 2013-03-19 15:41:34 +0000 |
327 | +++ magentoerpconnect_catalog/__openerp__.py 2013-08-22 07:24:16 +0000 |
328 | @@ -26,7 +26,7 @@ |
329 | 'category': 'Connector', |
330 | 'depends': ['magentoerpconnect', |
331 | 'product_links', |
332 | - 'product_images', |
333 | + #'product_images', |
334 | ], |
335 | 'author': 'MagentoERPconnect Core Editors', |
336 | 'license': 'AGPL-3', |
337 | @@ -44,7 +44,7 @@ |
338 | """, |
339 | 'images': [], |
340 | 'demo': [], |
341 | - 'data': [], |
342 | + 'data': ['product_view.xml'], |
343 | 'installable': True, |
344 | 'application': False, |
345 | } |
346 | |
347 | === added file 'magentoerpconnect_catalog/connector.py' |
348 | --- magentoerpconnect_catalog/connector.py 1970-01-01 00:00:00 +0000 |
349 | +++ magentoerpconnect_catalog/connector.py 2013-08-22 07:24:16 +0000 |
350 | @@ -0,0 +1,12 @@ |
351 | +# -*- coding: utf-8 -*- |
352 | + |
353 | +from openerp.osv import orm |
354 | + |
355 | + |
356 | +class magentoerpconnect_export_partner_installed(orm.AbstractModel): |
357 | + """Empty model used to know if the module is installed on the |
358 | + database. |
359 | + |
360 | + If the model is in the registry, the module is installed. |
361 | + """ |
362 | + _name = 'magentoerpconnect_catalog.installed' |
363 | \ No newline at end of file |
364 | |
365 | === added file 'magentoerpconnect_catalog/consumer.py' |
366 | --- magentoerpconnect_catalog/consumer.py 1970-01-01 00:00:00 +0000 |
367 | +++ magentoerpconnect_catalog/consumer.py 2013-08-22 07:24:16 +0000 |
368 | @@ -0,0 +1,25 @@ |
369 | +# -*- coding: utf-8 -*- |
370 | + |
371 | +from functools import wraps |
372 | +from openerp.addons.connector.event import (on_record_write, |
373 | + on_record_create, |
374 | + on_record_unlink |
375 | + ) |
376 | +from openerp.addons.magentoerpconnect.unit.export_synchronizer import export_record |
377 | +import openerp.addons.magentoerpconnect.consumer as magentoerpconnect |
378 | + |
379 | + |
380 | +@on_record_create(model_names=['magento.product.category', 'magento.product.product']) |
381 | +@on_record_write(model_names=['magento.product.category', 'magento.product.product']) |
382 | +def delay_export(session, model_name, record_id, fields=None): |
383 | + magentoerpconnect.delay_export(session, model_name, |
384 | + record_id, fields=fields) |
385 | + |
386 | +@on_record_write(model_names=['product.category','product.product']) |
387 | +def delay_export_all_bindings(session, model_name, record_id, fields=None): |
388 | + magentoerpconnect.delay_export_all_bindings(session, model_name, |
389 | + record_id, fields=fields) |
390 | + |
391 | +@on_record_unlink(model_names=['magento.product.category', 'magento.product.product']) |
392 | +def delay_unlink(session, model_name, record_id): |
393 | + magentoerpconnect.delay_unlink(session, model_name, record_id) |
394 | |
395 | === added file 'magentoerpconnect_catalog/product.py' |
396 | --- magentoerpconnect_catalog/product.py 1970-01-01 00:00:00 +0000 |
397 | +++ magentoerpconnect_catalog/product.py 2013-08-22 07:24:16 +0000 |
398 | @@ -0,0 +1,95 @@ |
399 | +# -*- coding: utf-8 -*- |
400 | + |
401 | +from openerp.osv import fields, orm, osv |
402 | +from openerp.addons.connector.queue.job import job |
403 | +from openerp.addons.connector.unit.mapper import (mapping, |
404 | + changed_by, |
405 | + ExportMapper) |
406 | +from openerp.addons.magentoerpconnect.unit.delete_synchronizer import ( |
407 | + MagentoDeleteSynchronizer) |
408 | +from openerp.addons.magentoerpconnect.unit.export_synchronizer import ( |
409 | + MagentoExporter) |
410 | +from openerp.addons.magentoerpconnect.backend import magento |
411 | +from openerp.addons.magentoerpconnect.product import ProductProductAdapter |
412 | +from openerp.addons.connector.exception import MappingError |
413 | + |
414 | +@magento |
415 | +class ProductProductDeleteSynchronizer(MagentoDeleteSynchronizer): |
416 | + """ Partner deleter for Magento """ |
417 | + _model_name = ['magento.product.product'] |
418 | + |
419 | + |
420 | +@magento |
421 | +class ProductProductExport(MagentoExporter): |
422 | + _model_name = ['magento.product.product'] |
423 | + |
424 | +@magento |
425 | +class ProductProductExportMapper(ExportMapper): |
426 | + _model_name = 'magento.product.product' |
427 | + |
428 | + # direct = [('name', 'name'), |
429 | + # ('description', 'description'), |
430 | + # ('weight', 'weight'), |
431 | + # ('list_price', 'price'), |
432 | + # ('description_sale', 'short_description'), |
433 | + # ('default_code', 'sku'), |
434 | + # ('product_type', 'type'), |
435 | + # ('created_at', 'created_at'), |
436 | + # ('updated_at', 'updated_at'), |
437 | + # ('status', 'status'), |
438 | + # ('visibility', 'visibility'), |
439 | + # ('product_type', 'product_type') |
440 | + # ] |
441 | + @mapping |
442 | + def all(self, record): |
443 | + return {'name': record.name, |
444 | + 'description': record.description, |
445 | + 'weight': record.weight, |
446 | + 'price': record.list_price, |
447 | + 'short_description': record.description_sale, |
448 | + 'type': record.product_type, |
449 | + 'created_at': record.created_at, |
450 | + 'updated_at': record.updated_at, |
451 | + 'status': record.status, |
452 | + 'visibility': record.visibility, |
453 | + 'product_type': record.product_type } |
454 | + |
455 | + @mapping |
456 | + def sku(self, record): |
457 | + sku = record.default_code |
458 | + if not sku: |
459 | + raise MappingError("The product attribute default code cannot be empty.") |
460 | + return {'sku': sku} |
461 | + |
462 | + @mapping |
463 | + def set(self, record): |
464 | + binder = self.get_binder_for_model('magento.product.attribute.set') |
465 | + set_id = binder.to_backend(record.attribute_set_id.id) |
466 | + return {'attrset': set_id} |
467 | + |
468 | + @mapping |
469 | + def tax(self, record): |
470 | + tax_class_id = record.tax_class if record.tax_class else 0 |
471 | + return {'tax_class_id': tax_class_id} |
472 | + |
473 | + @mapping |
474 | + def website_ids(self, record): |
475 | + website_ids = [] |
476 | + for website_id in record.website_ids: |
477 | + magento_id = website_id.magento_id |
478 | + website_ids.append(magento_id) |
479 | + return {'website_ids': website_ids} |
480 | + |
481 | + @mapping |
482 | + def category(self, record): |
483 | + categ_ids = [] |
484 | + if record.categ_id: |
485 | + for m_categ in record.categ_id.magento_bind_ids: |
486 | + if m_categ.backend_id.id == self.backend_record.id: |
487 | + categ_ids.append(m_categ.magento_id) |
488 | + |
489 | + for categ in record.categ_ids: |
490 | + for m_categ in categ.magento_bind_ids: |
491 | + if m_categ.backend_id.id == self.backend_record.id: |
492 | + categ_ids.append(m_categ.magento_id) |
493 | + return {'categories': categ_ids} |
494 | |
495 | === added file 'magentoerpconnect_catalog/product_category.py' |
496 | --- magentoerpconnect_catalog/product_category.py 1970-01-01 00:00:00 +0000 |
497 | +++ magentoerpconnect_catalog/product_category.py 2013-08-22 07:24:16 +0000 |
498 | @@ -0,0 +1,55 @@ |
499 | +# -*- coding: utf-8 -*- |
500 | + |
501 | +from openerp.osv import fields, orm, osv |
502 | +from openerp.addons.connector.unit.mapper import (mapping, |
503 | + changed_by, |
504 | + ExportMapper) |
505 | +from openerp.addons.magentoerpconnect.unit.delete_synchronizer import ( |
506 | + MagentoDeleteSynchronizer) |
507 | +from openerp.addons.magentoerpconnect.unit.export_synchronizer import ( |
508 | + MagentoExporter) |
509 | +from openerp.addons.magentoerpconnect.backend import magento |
510 | +from openerp.addons.magentoerpconnect.product_category import ProductCategoryAdapter |
511 | + |
512 | +@magento |
513 | +class ProductCategoryDeleteSynchronizer(MagentoDeleteSynchronizer): |
514 | + """ Partner deleter for Magento """ |
515 | + _model_name = ['magento.product.category'] |
516 | + |
517 | + |
518 | +@magento |
519 | +class ProductCategoryExport(MagentoExporter): |
520 | + _model_name = ['magento.product.category'] |
521 | + |
522 | +@magento |
523 | +class ProductCategoryExportMapper(ExportMapper): |
524 | + _model_name = 'magento.product.category' |
525 | + |
526 | + direct = [('description', 'description'), |
527 | + ('name', 'name'), #change that to mapping top level category has no name |
528 | + ] |
529 | + @mapping |
530 | + def sort(self, record): |
531 | + return {'default_sort_by':'price', 'available_sort_by': 'price'} |
532 | + |
533 | + @mapping |
534 | + def parent(self, record): |
535 | + """ Magento root category's Id equals 1 """ |
536 | + parent_id = record.magento_parent_id.magento_id |
537 | + if not parent_id: |
538 | + parent_id = 1 |
539 | + return {'parent_id':parent_id} |
540 | + |
541 | + @mapping |
542 | + def active(self, record): |
543 | + is_active = record['is_active'] |
544 | + if not is_active: |
545 | + is_active = 0 |
546 | + return {'is_active':is_active} |
547 | + |
548 | + @mapping |
549 | + def menu(self, record): |
550 | + include_in_menu = record['include_in_menu'] |
551 | + if not include_in_menu: |
552 | + include_in_menu = 0 |
553 | + return {'include_in_menu':include_in_menu} |
554 | \ No newline at end of file |
555 | |
556 | === added file 'magentoerpconnect_catalog/product_view.xml' |
557 | --- magentoerpconnect_catalog/product_view.xml 1970-01-01 00:00:00 +0000 |
558 | +++ magentoerpconnect_catalog/product_view.xml 2013-08-22 07:24:16 +0000 |
559 | @@ -0,0 +1,16 @@ |
560 | +<?xml version="1.0" encoding="UTF-8"?> |
561 | +<openerp> |
562 | + <data> |
563 | + <record id="view_magento_product_category_form" model="ir.ui.view"> |
564 | + <field name="name">magento.product.category.form</field> |
565 | + <field name="model">magento.product.category</field> |
566 | + <field name="inherit_id" ref="magentoerpconnect.view_magento_product_category_form" /> |
567 | + <field name="arch" type="xml" > |
568 | + <field name="magento_id" position="replace"> |
569 | + <field name="is_active" /> |
570 | + <field name="include_in_menu" /> |
571 | + </field> |
572 | + </field> |
573 | + </record> |
574 | + </data> |
575 | +</openerp> |
576 | \ No newline at end of file |
Hi Augustin,
Thanks for the MP.
I read through the diff and that seems already nice, you very well understood the mechanisms and how the synchronizations are supposed to work and that makes me happy.
I'll need to take more time to do a proper review, but I'm already reassured that you go in the right direction so I am quite comfortable if let you continue in this direction.
There is just one thing I want to comment on, about the choice to push the records on save.
Basically in your diff:
push_on_save = record. backend_ id.push_ on_save
if push_on_save:
This option is to remove, any created or modified record must always me exported to Magento, that's the design we choose. So we don't need anymore the methods to export the products or categories like in l.411,498.
Another thing about the monkey patching in l.522: this is a bad idea, because OpenERP may import the python code of uninstalled modules (it wouldn't have bad effects in this case, remark). There is other techniques [0][1] for replacing ConnectorUnit classes, but in that case I would just redefine the create method in the main 'magentoerpconnect' module.
[0] https:/ /code.launchpad .net/~openerp- connector- core-editors/ openerp- connector/ 7.0-connector- replacing- connectorunit- classes/ +merge/ 172309 /code.launchpad .net/~openerp- connector- core-editors/ openerp- connector/ 7.0-magentoerpc onnect- replacing- connectorunit- classes/ +merge/ 172311
[1] https:/