Merge lp:~akretion-team/openerp-connector-magento/7.0-export-partner-and-address into lp:~openerp-connector-core-editors/openerp-connector-magento/7.0

Proposed by Florian da Costa
Status: Needs review
Proposed branch: lp:~akretion-team/openerp-connector-magento/7.0-export-partner-and-address
Merge into: lp:~openerp-connector-core-editors/openerp-connector-magento/7.0
Prerequisite: lp:~camptocamp/openerp-connector-magento/7.0-export-dependency+lock
Diff against target: 535 lines (+355/-27)
8 files modified
magentoerpconnect/partner.py (+8/-1)
magentoerpconnect/partner_view.xml (+1/-0)
magentoerpconnect/unit/export_synchronizer.py (+19/-5)
magentoerpconnect_export_partner/__init__.py (+3/-3)
magentoerpconnect_export_partner/consumer.py (+14/-3)
magentoerpconnect_export_partner/partner.py (+151/-15)
magentoerpconnect_export_partner/tests/__init__.py (+29/-0)
magentoerpconnect_export_partner/tests/test_synchronization.py (+130/-0)
To merge this branch: bzr merge lp:~akretion-team/openerp-connector-magento/7.0-export-partner-and-address
Reviewer Review Type Date Requested Status
Guewen Baconnier @ Camptocamp Needs Resubmitting
Sébastien BEAU - http://www.akretion.com Pending
Review via email: mp+224180@code.launchpad.net

This proposal supersedes a proposal from 2014-06-11.

Description of the change

I have completed the magentoerpconnect_export_partner module to fix the export of partners and add the export of addresses.

I have added a method '_after_export' in MagentoExporter so we do not need to manually add the magento bind address for each partner and contact.

I still have to implement some tests.

What do you think?

To post a comment you must log in.
Revision history for this message
Florian da Costa (florian-dacosta) wrote : Posted in a previous version of this proposal

here, I have added the tests.

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : Posted in a previous version of this proposal

Hi Florian,

Thanks for your proposal.
I left some comments in the diff.

review: Needs Fixing
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : Posted in a previous version of this proposal

Also, you should take a look at: https://code.launchpad.net/~camptocamp/openerp-connector-magento/7.0-export-dependency+lock/+merge/223508
And use this branch as base, I left some comments in the diff where you should use some of my branch's features.

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : Posted in a previous version of this proposal

What about the password?

1004. By Florian da Costa

[MERGE]

1005. By Florian da Costa

[FIX]Remove useless code + improve basic stuff to export partner

Revision history for this message
Florian da Costa (florian-dacosta) : Posted in a previous version of this proposal
Revision history for this message
Florian da Costa (florian-dacosta) wrote :

Thanks for the fast feedback!

I have re-submited in order to add your branch as a Prerequisite, and I merged it.
I have answered your diff comments in the other merge proposal so it is not lost...

About the password, I have add a field in res_partner. The purpose of this field is to contain an already coded password.

The main point I still have to change is to adapt the behavior of the export of company partner, I will do it as soon as I have your feedback on what I have commented in the diff of the other merge proposal

(https://code.launchpad.net/~akretion-team/openerp-connector-magento/7.0-export-partner-and-address/+merge/222825)

Revision history for this message
Florian da Costa (florian-dacosta) wrote :

An other remark, the method "_validate_data(data)" should be used only for creating a record, and not for an update no?
Because it seems the direct mapping is not done on the field which are not modified.

During my tests, when an address is already created in magento, and I modified it on openerp, it will fail because the _validate_data method won't find the field city and postcode.
Unless the 2 corresponding fields are modified in openerp. (then the direct mapping seems to work for theses fields.)

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

> About the password, I have add a field in res_partner. The purpose of this
> field is to contain an already coded password.

How a user can input an encrypted password? Would we have a mean to encrypt it? It would require the salt so I don't think so...

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

> An other remark, the method "_validate_data(data)" should be used only for
> creating a record, and not for an update no?
You are right, I think we should have one validate_create_data and one validate_update_data (maybe useless).

> Because it seems the direct mapping is not done on the field which are not
> modified.
That's right, we do not want to useless data when the values did not change.
In fact, you remark remind me that you should use the @changed_by() decorator on top of the @mapping methods

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Thanks for the changes so far!
I added new comments

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

> I have not changed anything about that already. The idea here, would be to simplify the behavior. If we could merge the module Alexis did into the base modules: http://bazaar.launchpad.net/~akretion-team/+junk/70-usability/files/head:/base_partner_always_multi_contacts/ We could just use the field 'is_company' instead of the new field 'consider_as_company' on magento.res.partner, it would be a lot cleaner I think. Then I would adapt the export so it has the same behavior as the import : If the partner is a company (is_company) I will export it has an account in magento, without the address if the partner is not a company, I will export it has an account And an address. (Of course, the contact will always be exported as addresses) What do you think ?

I don't think we can change that now that we have users in production. Also, it would not be really simpler: only a boolean field would change, but the handling of the addresses would still be the same.

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

> About your second comment, As I merged your branch, the table is locked at the beginning of the _run method, so it should be enought to avoid the problem of creating 2 bindings at the same time no?

No, the table is not locked. The 'magento.res.partner' *record* that is exported is locked. Then, when it creates a 'magento.address', only a unique constraint on 'magento.address' can prevent 2 concurrent jobs to create the same 'magento.address'.

Revision history for this message
Florian da Costa (florian-dacosta) wrote :

> I don't think we can change that now that we have users in production. Also,
> it would not be really simpler: only a boolean field would change, but the
> handling of the addresses would still be the same.

It would be cleaner, about the export, to use the existing is_company field instead of asking the user to fill an other new field for the same purpose.
Would it be ok to do so if I propose a migration script?

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

> > I have not changed anything about that already. The idea here, would be to
> simplify the behavior. If we could merge the module Alexis did into the base
> modules: http://bazaar.launchpad.net/~akretion-
> team/+junk/70-usability/files/head:/base_partner_always_multi_contacts/ We
> could just use the field 'is_company' instead of the new field
> 'consider_as_company' on magento.res.partner, it would be a lot cleaner I
> think. Then I would adapt the export so it has the same behavior as the import
> : If the partner is a company (is_company) I will export it has an account in
> magento, without the address if the partner is not a company, I will export it
> has an account And an address. (Of course, the contact will always be exported
> as addresses) What do you think ?
>
> I don't think we can change that now that we have users in production. Also,
> it would not be really simpler: only a boolean field would change, but the
> handling of the addresses would still be the same.

Hi Guewen, indeed having the field 'is_company' or 'consider_as_company' tick when is a company will not simplify the code. The only change is that we "fix" the OpenERP/Odoo mistake that force user to tock "is_company" when it's not a company. Our customer really do not understand why they have to tick that box for B2C customer. I think it can be a good improvement if we merge the base module in OCA and then we add the dependency on MagentoERPconnect for the next release. For sure if we do that we have to do the migration script so user can easily migrate to the new version. What do you think?

Revision history for this message
Florian da Costa (florian-dacosta) wrote :

> How a user can input an encrypted password? Would we have a mean to encrypt
> it? It would require the salt so I don't think so...

About that, the idea would be to, later, develop a kind of wizard to allow the user to enter the password and encrypt them.
For the moment, even if the user can't encrypt it yet, it will already help if one already get encrypted passwords and import it into openerp.

If it does not seem reasonable, I will change it so we have to enter none-coded password in openerp.

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

>
> Hi Guewen, indeed having the field 'is_company' or 'consider_as_company' tick
> when is a company will not simplify the code. The only change is that we "fix"
> the OpenERP/Odoo mistake that force user to tock "is_company" when it's not a
> company. Our customer really do not understand why they have to tick that box
> for B2C customer. I think it can be a good improvement if we merge the base
> module in OCA and then we add the dependency on MagentoERPconnect for the next
> release. For sure if we do that we have to do the migration script so user can
> easily migrate to the new version. What do you think?

Hi,

So the first step is to have it merged in the OCA.
I don't really figure what are the impacts at the moment. Are you sure this is matter of a view? Are the questions that were raised here https://bugs.launchpad.net/openobject-server/+bug/1151947 addressed?

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

> > How a user can input an encrypted password? Would we have a mean to encrypt
> > it? It would require the salt so I don't think so...
>
> About that, the idea would be to, later, develop a kind of wizard to allow the
> user to enter the password and encrypt them.
> For the moment, even if the user can't encrypt it yet, it will already help if
> one already get encrypted passwords and import it into openerp.
>
> If it does not seem reasonable, I will change it so we have to enter none-
> coded password in openerp.

I can't convince myself that the use case of someone having already encrypted password is a realistic scenario.

An other approach could be to display a link on partner to open the Magento admin so he can file a password, but this is not so nice since it would need to go on the partner form after the job has been executed.

1006. By Florian da Costa

[FIX] add change_by decorator on mapping methods

1007. By Florian da Costa

[FIX]change method _validate_data to make 2 different method, one for create a record, one for update + do not export a partner like an address if it is a company

Revision history for this message
Florian da Costa (florian-dacosta) wrote :

Ok, so now, the password does not need to be coded on openerp side.
The export has a similar behavior with the import. (if the field consider_as_company is ticked, it won't create magento.address binding on the main partner)
I also export the company name in the addresses and I use the field 'type' of res.partner to tick the is_default_billing and is_default_shipping.

I think I took into account all your comments, it should be quite ok now.

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

@Guewen
For the password we have encrypted one in our case because we import existing password from an existing system. But I agree it's not the main case. Regarding storing the magento_password on OpenERP side I am not sure it's a good idea. Maybe a wizard can change the password from OpenERP but the password should be not store on OpenERP side, what do you think? (By default we can remove the password field and mapping and latter we can add a wizard?)

For the partner/contact issue. I was also really surprise by Alexis work, but looking at it twice and doing a grep on "is_company" in the addons. It seem that it work correctly (OpenERP take the parent_id if the is_company is not tick). So it ok for B2C. I think OpenERP did the correct change to make it working because at the release time of 7, only changing the view was not enough.

Let's propose a merge to OCA ;)

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

On 06/24/2014 02:25 PM, Sébastien BEAU - http://www.akretion.com wrote:
> @Guewen
> For the password we have encrypted one in our case because we import existing password from an existing system. But I agree it's not the main case. Regarding storing the magento_password on OpenERP side I am not sure it's a good idea. Maybe a wizard can change the password from OpenERP but the password should be not store on OpenERP side, what do you think? (By default we can remove the password field and mapping and latter we can add a wizard?)
>
Alright. I agree, it should not be stored on OpenERP, a wizard could do it.
> For the partner/contact issue. I was also really surprise by Alexis work, but looking at it twice and doing a grep on "is_company" in the addons. It seem that it work correctly (OpenERP take the parent_id if the is_company is not tick). So it ok for B2C. I think OpenERP did the correct change to make it working because at the release time of 7, only changing the view was not enough.
>
Nice!

Revision history for this message
Florian da Costa (florian-dacosta) wrote :

So finally, should I just remove the password feature for now and it would be ready to merge?

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

This project is now hosted on https://github.com/OCA/connector-magento. Please move your proposal there. This guide may help you https://github.com/OCA/maintainers-tools/wiki/How-to-move-a-Merge-Proposal-to-GitHub

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) :
review: Needs Resubmitting
1008. By Florian da Costa

[FIX] Remove password field, it will be handle by a wizard

Unmerged revisions

1008. By Florian da Costa

[FIX] Remove password field, it will be handle by a wizard

1007. By Florian da Costa

[FIX]change method _validate_data to make 2 different method, one for create a record, one for update + do not export a partner like an address if it is a company

1006. By Florian da Costa

[FIX] add change_by decorator on mapping methods

1005. By Florian da Costa

[FIX]Remove useless code + improve basic stuff to export partner

1004. By Florian da Costa

[MERGE]

1003. By Florian da Costa

[IMP] Add tests

1002. By Florian da Costa

[IMP] fix partner export + add address export

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'magentoerpconnect/partner.py'
2--- magentoerpconnect/partner.py 2014-05-26 09:37:00 +0000
3+++ magentoerpconnect/partner.py 2014-09-10 13:43:53 +0000
4@@ -78,7 +78,7 @@
5 _inherits = {'res.partner': 'openerp_id'}
6 _description = 'Magento Partner'
7
8- _rec_name = 'website_id'
9+ _rec_name = 'name'
10
11 def _get_mag_partner_from_website(self, cr, uid, ids, context=None):
12 mag_partner_obj = self.pool['magento.res.partner']
13@@ -199,6 +199,8 @@
14 _sql_constraints = [
15 ('magento_uniq', 'unique(backend_id, magento_id)',
16 'A partner address with same ID on Magento already exists.'),
17+ ('openerp_uniq', 'unique(backend_id, openerp_id)',
18+ 'A partner address can only have one binding by backend.'),
19 ]
20
21
22@@ -568,6 +570,11 @@
23 [filters] if filters else [{}])]
24
25
26+ def create(self, data):
27+ """ Create a record on the external system """
28+ partner_id = data.pop('partner_id')
29+ return self._call('%s.create' % self._magento_model, [partner_id, data])
30+
31 @magento
32 class AddressImport(MagentoImportSynchronizer):
33 _model_name = ['magento.address']
34
35=== modified file 'magentoerpconnect/partner_view.xml'
36--- magentoerpconnect/partner_view.xml 2013-06-20 14:26:32 +0000
37+++ magentoerpconnect/partner_view.xml 2014-09-10 13:43:53 +0000
38@@ -43,6 +43,7 @@
39 <field name="emailid"/>
40 <field name="taxvat"/>
41 <field name="newsletter"/>
42+ <field name="consider_as_company"/>
43 </group>
44 </form>
45 </field>
46
47=== modified file 'magentoerpconnect/unit/export_synchronizer.py'
48--- magentoerpconnect/unit/export_synchronizer.py 2014-09-10 13:43:52 +0000
49+++ magentoerpconnect/unit/export_synchronizer.py 2014-09-10 13:43:53 +0000
50@@ -128,6 +128,7 @@
51 # The commit will also release the lock acquired on the binding
52 # record
53 self.session.commit()
54+ self._after_export()
55 return result
56
57 def _run(self):
58@@ -256,7 +257,6 @@
59 # 'product.product' record but the binding model is
60 # 'magento.product.product'
61 wrap = relation._model._name != binding_model
62-
63 if wrap and hasattr(relation, binding_field):
64 domain = [('openerp_id', '=', relation.id),
65 ('backend_id', '=', self.backend_record.id)]
66@@ -294,7 +294,6 @@
67 # "direct" binding (the binding record is the same record).
68 # If wrap is True, relation is already a binding record.
69 binding_id = relation.id
70-
71 if rel_binder.to_backend(binding_id) is None:
72 exporter = self.get_connector_unit_for_model(exporter_class,
73 binding_model)
74@@ -311,7 +310,22 @@
75 """
76 return self.mapper.map_record(self.binding_record)
77
78- def _validate_data(self, data):
79+
80+ def _after_export(self):
81+ """ Can do several actions after exporting a record on magento """
82+ pass
83+
84+ def _validate_create_data(self, data):
85+ """ Check if the values to import are correct
86+
87+ Pro-actively check before the ``Model.create`` or
88+ ``Model.update`` if some fields are missing
89+
90+ Raise `InvalidDataError`
91+ """
92+ return
93+
94+ def _validate_update_data(self, data):
95 """ Check if the values to import are correct
96
97 Pro-actively check before the ``Model.create`` or
98@@ -328,7 +342,7 @@
99 def _create(self, data):
100 """ Create the Magento record """
101 # special check on data before export
102- self._validate_data(data)
103+ self._validate_create_data(data)
104 return self.backend_adapter.create(data)
105
106 def _update_data(self, map_record, fields=None, **kwargs):
107@@ -339,7 +353,7 @@
108 """ Update an Magento record """
109 assert self.magento_id
110 # special check on data before export
111- self._validate_data(data)
112+ self._validate_update_data(data)
113 self.backend_adapter.write(self.magento_id, data)
114
115 def _run(self, fields=None):
116
117=== modified file 'magentoerpconnect_export_partner/__init__.py'
118--- magentoerpconnect_export_partner/__init__.py 2013-03-19 16:53:26 +0000
119+++ magentoerpconnect_export_partner/__init__.py 2014-09-10 13:43:53 +0000
120@@ -1,4 +1,4 @@
121 # -*- coding: utf-8 -*-
122-
123-import consumer
124-import partner
125+from . import connector
126+from . import consumer
127+from . import partner
128
129=== modified file 'magentoerpconnect_export_partner/consumer.py'
130--- magentoerpconnect_export_partner/consumer.py 2013-10-09 19:41:58 +0000
131+++ magentoerpconnect_export_partner/consumer.py 2014-09-10 13:43:53 +0000
132@@ -28,8 +28,8 @@
133 import openerp.addons.magentoerpconnect.consumer as magentoerpconnect
134
135
136-@on_record_create(model_names='magento.res.partner')
137-@on_record_write(model_names='magento.res.partner')
138+@on_record_create(model_names=['magento.address', 'magento.res.partner'])
139+@on_record_write(model_names=['magento.address', 'magento.res.partner'])
140 def delay_export(session, model_name, record_id, vals):
141 magentoerpconnect.delay_export(session, model_name,
142 record_id, vals)
143@@ -41,6 +41,17 @@
144 record_id, vals)
145
146
147-@on_record_unlink(model_names='magento.res.partner')
148+@on_record_write(model_names='res.partner')
149+def delay_export_all_bindings_for_address(session, model_name,
150+ record_id, vals):
151+ if session.context.get('connector_no_export'):
152+ return
153+ record = session.browse(model_name, record_id)
154+ for binding in record.magento_address_bind_ids:
155+ magentoerpconnect.delay_export(session, binding._model._name,
156+ binding.id, vals)
157+
158+
159+@on_record_unlink(model_names=['magento.res.partner', 'magento.address'])
160 def delay_unlink(session, model_name, record_id):
161 magentoerpconnect.delay_unlink(session, model_name, record_id)
162
163=== modified file 'magentoerpconnect_export_partner/partner.py'
164--- magentoerpconnect_export_partner/partner.py 2013-05-01 09:54:36 +0000
165+++ magentoerpconnect_export_partner/partner.py 2014-09-10 13:43:53 +0000
166@@ -23,48 +23,184 @@
167 from openerp.addons.connector.unit.mapper import (mapping,
168 changed_by,
169 ExportMapper)
170+from openerp.addons.connector.exception import InvalidDataError
171 from openerp.addons.magentoerpconnect.unit.delete_synchronizer import (
172 MagentoDeleteSynchronizer)
173 from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
174 MagentoExporter)
175+from openerp.addons.magentoerpconnect.partner import (
176+ AddressAdapter)
177 from openerp.addons.magentoerpconnect.backend import magento
178
179
180 @magento
181 class PartnerDeleteSynchronizer(MagentoDeleteSynchronizer):
182 """ Partner deleter for Magento """
183- _model_name = ['magento.res.partner']
184+ _model_name = ['magento.res.partner',
185+ 'magento.address']
186
187
188 @magento
189 class PartnerExport(MagentoExporter):
190 _model_name = ['magento.res.partner']
191
192+ def _after_export(self):
193+ data = {
194+ 'magento_partner_id': self.binding_id,
195+ }
196+ if not self.binding_record.magento_address_bind_ids \
197+ and not self.binding_record.consider_as_company:
198+ data['openerp_id'] = self.binding_record.openerp_id.id
199+
200+ if not self.binding_record.child_ids:
201+ data['is_default_billing'] = True
202+ data['is_default_shipping'] = True
203+
204+ with self._retry_unique_violation():
205+ self.session.create('magento.address', data)
206+
207+ for child in self.binding_record.child_ids:
208+ if not child.magento_address_bind_ids:
209+ if child.type == 'invoice':
210+ data['is_default_billing'] = True
211+ else:
212+ data['is_default_billing'] = False
213+ if child.type == 'delivery':
214+ data['is_default_shipping'] = True
215+ else:
216+ data['is_default_shipping'] = False
217+ data['openerp_id'] = child.id
218+ with self._retry_unique_violation():
219+ self.session.create('magento.address', data)
220+
221+ def _validate_create_data(self, data):
222+ """ Check if the values to import are correct
223+
224+ Pro-actively check before the ``Model.create`` or
225+ ``Model.update`` if some fields are missing
226+
227+ Raise `InvalidDataError`
228+ """
229+ if not data.get('email'):
230+ raise InvalidDataError("The partner does not have an email "
231+ "but it is mandatory for Magento")
232+
233+
234+@magento
235+class AddressExport(MagentoExporter):
236+ _model_name = ['magento.address']
237+
238+ def _export_dependencies(self):
239+ """ Export the dependencies for the record"""
240+ relation = self.binding_record.parent_id or self.binding_record.openerp_id
241+ self._export_dependency(relation, 'magento.res.partner',
242+ exporter_class=PartnerExport)
243+
244+ def _validate_create_data(self, data):
245+ """ Check if the values to import are correct
246+
247+ Pro-actively check before the ``Model.create`` or
248+ ``Model.update`` if some fields are missing
249+
250+ Raise `InvalidDataError`
251+ """
252+ missing_fields = []
253+ for required_key in ('city', 'street', 'postcode', 'country_id', 'telephone'):
254+ if not data.get(required_key):
255+ missing_fields.append(required_key)
256+ if missing_fields:
257+ raise InvalidDataError("The address does not contain one or several "
258+ "mandatory fields for Magento : %s" %
259+ missing_fields)
260+
261
262 @magento
263 class PartnerExportMapper(ExportMapper):
264 _model_name = 'magento.res.partner'
265
266 direct = [
267- ('emailid', 'email'),
268 ('birthday', 'dob'),
269 ('created_at', 'created_at'),
270 ('updated_at', 'updated_at'),
271- ('emailid', 'email'),
272 ('taxvat', 'taxvat'),
273 ('group_id', 'group_id'),
274 ('website_id', 'website_id'),
275 ]
276
277- @changed_by('name')
278- @mapping
279- def names(self, record):
280- # FIXME base_surname needed
281- if ' ' in record.name:
282- parts = record.name.split()
283- firstname = parts[0]
284- lastname = ' '.join(parts[1:])
285- else:
286- lastname = record.name
287- firstname = '-'
288- return {'firstname': firstname, 'lastname': lastname}
289+ @changed_by('email', 'emailid')
290+ @mapping
291+ def email(self, record):
292+ email = record.emailid or record.email
293+ return {'email': email}
294+
295+ @changed_by('name')
296+ @mapping
297+ def names(self, record):
298+ if ' ' in record.name:
299+ parts = record.name.split()
300+ firstname = parts[0]
301+ lastname = ' '.join(parts[1:])
302+ else:
303+ lastname = record.name
304+ firstname = '-'
305+ return {'firstname': firstname, 'lastname': lastname}
306+
307+
308+@magento
309+class PartnerAddressExportMapper(ExportMapper):
310+ _model_name = 'magento.address'
311+
312+ direct = [('zip', 'postcode'),
313+ ('city', 'city'),
314+ ('is_default_billing', 'is_default_billing'),
315+ ('is_default_shipping', 'is_default_shipping'),
316+ ('company', 'company'),
317+ ]
318+
319+ @changed_by('parent_id', 'openerp_id')
320+ @mapping
321+ def partner(self, record):
322+ binder = self.get_binder_for_model('magento.res.partner')
323+ erp_partner_id = record.parent_id.id if record.parent_id else record.openerp_id.id
324+ mag_partner_id = binder.to_backend(erp_partner_id, wrap=True)
325+ return {'partner_id': mag_partner_id}
326+
327+ @changed_by('name')
328+ @mapping
329+ def names(self, record):
330+ if ' ' in record.name:
331+ parts = record.name.split()
332+ firstname = parts[0]
333+ lastname = ' '.join(parts[1:])
334+ else:
335+ lastname = record.name
336+ firstname = '-'
337+ return {'firstname': firstname, 'lastname': lastname}
338+
339+ @changed_by('phone', 'mobile')
340+ @mapping
341+ def phone(self, record):
342+ return {'telephone': record.phone or record.mobile}
343+
344+ @changed_by('country_id')
345+ @mapping
346+ def country(self, record):
347+ if record.country_id:
348+ return {'country_id': record.country_id.code}
349+
350+ @changed_by('state_id')
351+ @mapping
352+ def region(self, record):
353+ if record.state_id:
354+ return {'region': record.state_id.name}
355+
356+ @changed_by('street', 'street2')
357+ @mapping
358+ def street(self, record):
359+ if record.street:
360+ street = record.street
361+ if record.street2:
362+ street = ['\n'.join([street, record.street2])]
363+ if street:
364+ return {'street': street}
365+
366
367=== added directory 'magentoerpconnect_export_partner/tests'
368=== added file 'magentoerpconnect_export_partner/tests/__init__.py'
369--- magentoerpconnect_export_partner/tests/__init__.py 1970-01-01 00:00:00 +0000
370+++ magentoerpconnect_export_partner/tests/__init__.py 2014-09-10 13:43:53 +0000
371@@ -0,0 +1,29 @@
372+# -*- coding: utf-8 -*-
373+##############################################################################
374+#
375+# Author: Florian da Costa
376+# Copyright 2014 Akretion
377+#
378+# This program is free software: you can redistribute it and/or modify
379+# it under the terms of the GNU Affero General Public License as
380+# published by the Free Software Foundation, either version 3 of the
381+# License, or (at your option) any later version.
382+#
383+# This program is distributed in the hope that it will be useful,
384+# but WITHOUT ANY WARRANTY; without even the implied warranty of
385+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
386+# GNU Affero General Public License for more details.
387+#
388+# You should have received a copy of the GNU Affero General Public License
389+# along with this program. If not, see <http://www.gnu.org/licenses/>.
390+#
391+##############################################################################
392+
393+import test_synchronization
394+
395+fast_suite = [
396+]
397+
398+checks = [
399+ test_synchronization,
400+]
401
402=== added file 'magentoerpconnect_export_partner/tests/test_synchronization.py'
403--- magentoerpconnect_export_partner/tests/test_synchronization.py 1970-01-01 00:00:00 +0000
404+++ magentoerpconnect_export_partner/tests/test_synchronization.py 2014-09-10 13:43:53 +0000
405@@ -0,0 +1,130 @@
406+# -*- coding: utf-8 -*-
407+##############################################################################
408+#
409+# Author: Florian da Costa
410+# Copyright 2014 Akretion
411+#
412+# This program is free software: you can redistribute it and/or modify
413+# it under the terms of the GNU Affero General Public License as
414+# published by the Free Software Foundation, either version 3 of the
415+# License, or (at your option) any later version.
416+#
417+# This program is distributed in the hope that it will be useful,
418+# but WITHOUT ANY WARRANTY; without even the implied warranty of
419+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
420+# GNU Affero General Public License for more details.
421+#
422+# You should have received a copy of the GNU Affero General Public License
423+# along with this program. If not, see <http://www.gnu.org/licenses/>.
424+#
425+##############################################################################
426+
427+from openerp.addons.magentoerpconnect.tests.test_synchronization import (
428+ SetUpMagentoSynchronized)
429+from openerp.addons.magentoerpconnect.tests.test_data import (
430+ magento_base_responses)
431+from openerp.addons.magentoerpconnect.tests.common import (
432+ mock_api,
433+ mock_urlopen_image)
434+from openerp.addons.magentoerpconnect.unit.export_synchronizer import (
435+ export_record)
436+
437+
438+class SetUpMagentoWithPartner(SetUpMagentoSynchronized):
439+
440+ def setUp(self):
441+ super(SetUpMagentoWithPartner, self).setUp()
442+ cr = self.cr
443+ uid = self.uid
444+ self.website_id = self.registry('magento.website').search(cr, uid, [
445+ ('backend_id', '=', self.backend_id)])[0]
446+ oe_partner_model = self.registry('res.partner')
447+ country_id = self.registry('res.country').search(cr, uid, [
448+ ('code', '=', 'BE')])[0]
449+ self.partner_id = oe_partner_model.create(
450+ cr, uid,
451+ {'name': 'Partner Partner2',
452+ 'is_company': True,
453+ 'email': 'partner@odoo.com',
454+ 'street': '15, test street',
455+ 'phone': '0000000000',
456+ 'zip': '00000',
457+ 'country_id': country_id,
458+ 'city': 'City test'})
459+ self.contact_id = oe_partner_model.create(
460+ cr, uid,
461+ {'name': 'Contact',
462+ 'parent_id': self.partner_id,
463+ 'street': '15, contact test street',
464+ 'phone': '111111111',
465+ 'zip': '11111',
466+ 'country_id': country_id,
467+ 'city': 'City contact test'})
468+
469+
470+class TestMagentoPartnerExport(SetUpMagentoWithPartner):
471+ """ Test the export from a Magento Mock.
472+ """
473+
474+ def test_1_export_partner(self):
475+ """ Test export of partner"""
476+ response = {
477+ 'customer.create': True,
478+ }
479+ cr = self.cr
480+ uid = self.uid
481+ with mock_api(response, key_func=lambda m, a: m) as calls_done:
482+ mag_address_model = self.registry('magento.address')
483+ mag_partner_model = self.registry('magento.res.partner')
484+ mag_partner_id = mag_partner_model.create(cr, uid, {
485+ 'website_id': self.website_id,
486+ 'openerp_id': self.partner_id,
487+ })
488+ export_record(self.session, 'magento.res.partner', mag_partner_id)
489+
490+ self.assertEqual(len(calls_done), 1)
491+ method, [values] = calls_done[0]
492+ self.assertEqual(method, 'customer.create')
493+ self.assertEqual(values['email'], 'partner@odoo.com')
494+ self.assertEqual(values['firstname'], 'Partner')
495+ self.assertEqual(values['lastname'], 'Partner2')
496+
497+ mag_address_ids = mag_address_model.search(cr, uid, [
498+ ('magento_partner_id', '=', mag_partner_id)])
499+ self.assertEqual(len(mag_address_ids), 2)
500+
501+
502+ def test_2_export_partner_address(self):
503+ """ Test export of address"""
504+ response = {
505+ 'customer_address.create': True,
506+ }
507+ cr = self.cr
508+ uid = self.uid
509+ with mock_api(response, key_func=lambda m, a: m) as calls_done:
510+ mag_address_model = self.registry('magento.address')
511+ mag_partner_model = self.registry('magento.res.partner')
512+ mag_partner_id = mag_partner_model.create(cr, uid, {
513+ 'website_id': self.website_id,
514+ 'openerp_id': self.partner_id,
515+ 'magento_id': 1,
516+ })
517+ mag_address_id = mag_address_model.create(cr, uid, {
518+ 'magento_partner_id': mag_partner_id,
519+ 'openerp_id': self.partner_id,
520+ })
521+ export_record(self.session, 'magento.address', mag_address_id)
522+
523+ self.assertEqual(len(calls_done), 1)
524+
525+ method, [partner, values] = calls_done[0]
526+
527+ self.assertEqual(method, 'customer_address.create')
528+ self.assertEqual(partner, 1)
529+ self.assertEqual(values['postcode'], '00000')
530+ self.assertEqual(values['city'], 'City test')
531+ self.assertEqual(values['street'], '15, test street')
532+ self.assertEqual(values['country_id'], 'BE')
533+ self.assertEqual(values['telephone'], '0000000000')
534+
535+