Merge lp:~camptocamp/magentoerpconnect/oerp61-oldstable-import-partners-2012-12-13 into lp:magentoerpconnect/oerp6.1-oldstable

Proposed by Yannick Vaucher @ Camptocamp
Status: Merged
Merged at revision: 665
Proposed branch: lp:~camptocamp/magentoerpconnect/oerp61-oldstable-import-partners-2012-12-13
Merge into: lp:magentoerpconnect/oerp6.1-oldstable
Diff against target: 365 lines (+259/-55)
3 files modified
magentoerpconnect/magerp_data.xml (+54/-40)
magentoerpconnect/partner.py (+65/-0)
magentoerpconnect/sale.py (+140/-15)
To merge this branch: bzr merge lp:~camptocamp/magentoerpconnect/oerp61-oldstable-import-partners-2012-12-13
Reviewer Review Type Date Requested Status
Guewen Baconnier @ Camptocamp Approve
Review via email: mp+139728@code.launchpad.net

Description of the change

Implement the logic for global partner import

Plus add a check on SO import from magento to make sure a partner having the same email is updated before importing SO emitter partner (in case of an outdated and forgot account of the same customer to solve)

More detail on bug report:
lp:1083592

Needs https://code.launchpad.net/~c2c/openobject-addons/extra_trunk-add-import-partners-2012-12-13/+merge/139731

To post a comment you must log in.
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

you may want to remove the FIXME tag at line 31 as you have fixed the issue ;-)

@nitpicking
l89. missing blank line
l93, l111 extra blank lines
The pep8 convention specifies 2 lines before classes and top level-functions and 1 single line between methods in class definition [0]

l112 'import_partners' should preferably be '_import_partners' because it can't be called from the outside (with XML/RPC for instance) due to the browse_record argument.

l158 useless parenthesis

l187 if website_id:
I don't think that it is possible to have a website_id which is 0, but if it could be the case we would preferably test if website is not None:

l189 mini typo s/an other/another/

l200
from A to B on a old account and create a new account with B address.
shouldn't it be?
from A to B on a old account and create a new account with A address.

Apart of these details (not all of them need to be changed, but please check the comment at l200), it sounds good to me, but I'll review the corresponding merge in extra-trunk and come back here.

[0] http://www.python.org/dev/peps/pep-0008/#blank-lines

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

l108 it must filter on the website

review: Needs Fixing
Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

l187 if website_id:
I don't think that it is possible to have a website_id which is 0, but if it could be the case we would preferably test if website is not None:

If a website_id could be 0, in that case, website_id is at first a string before we cast it to int.
It could be '0' but not 0

Seems fine to me like that

I will fix the rest ASAP

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Filter added on website if website_id is defined.

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

Yay, seems great now.
Thanks

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

Just noticed that the cron is missing, can you add it please?
Thanks

review: Needs Fixing
668. By Yannick Vaucher @ Camptocamp

[ADD] magentoerpconnect - cron job for partner import

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Here we go for the cron job

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

I fixed one thing during the merge: run_import_partners_scheduler should not return a None value.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'magentoerpconnect/magerp_data.xml'
--- magentoerpconnect/magerp_data.xml 2011-11-15 15:42:00 +0000
+++ magentoerpconnect/magerp_data.xml 2013-01-09 15:14:26 +0000
@@ -1,36 +1,36 @@
1<?xml version="1.0"?>1<?xml version="1.0"?>
2<openerp>2<openerp>
3 <data noupdate="1">3 <data noupdate="1">
4 4
5 <record id="product_product_cash_on_delivery" model="product.product">5 <record id="product_product_cash_on_delivery" model="product.product">
6 <field name="default_code">CASH ON DELIVERY MAGENTO</field>6 <field name="default_code">CASH ON DELIVERY MAGENTO</field>
7 <field name="list_price">0.0</field>7 <field name="list_price">0.0</field>
8 <field name="standard_price">0.0</field>8 <field name="standard_price">0.0</field>
9 <field name="type">service</field>9 <field name="type">service</field>
10 <field name="name">Cash on delivery</field>10 <field name="name">Cash on delivery</field>
11 <field name="magento_exportable" eval="False" />11 <field name="magento_exportable" eval="False" />
12 <field name="categ_id" ref="base_sale_multichannels.categ_0"/>12 <field name="categ_id" ref="base_sale_multichannels.categ_0"/>
13 </record>13 </record>
1414
15 <record id="product_product_gift" model="product.product">15 <record id="product_product_gift" model="product.product">
16 <field name="default_code">GIFT CERTIFICATE</field>16 <field name="default_code">GIFT CERTIFICATE</field>
17 <field name="list_price">0.0</field>17 <field name="list_price">0.0</field>
18 <field name="standard_price">0.0</field>18 <field name="standard_price">0.0</field>
19 <field name="type">service</field>19 <field name="type">service</field>
20 <field name="name">Gift Certificate</field>20 <field name="name">Gift Certificate</field>
21 <field name="magento_exportable" eval="False" />21 <field name="magento_exportable" eval="False" />
22 <field name="categ_id" ref="base_sale_multichannels.categ_0"/>22 <field name="categ_id" ref="base_sale_multichannels.categ_0"/>
23 </record>23 </record>
2424
25 <record id="product_product_discount" model="product.product">25 <record id="product_product_discount" model="product.product">
26 <field name="default_code">DISCOUNT MAGENTO</field>26 <field name="default_code">DISCOUNT MAGENTO</field>
27 <field name="list_price">0.0</field>27 <field name="list_price">0.0</field>
28 <field name="standard_price">0.0</field>28 <field name="standard_price">0.0</field>
29 <field name="type">service</field>29 <field name="type">service</field>
30 <field name="name">Discount Coupon</field>30 <field name="name">Discount Coupon</field>
31 <field name="magento_exportable" eval="False" />31 <field name="magento_exportable" eval="False" />
32 <field name="categ_id" ref="base_sale_multichannels.categ_0"/>32 <field name="categ_id" ref="base_sale_multichannels.categ_0"/>
33 </record>33 </record>
3434
35 <record forcecreate="True" id="ir_cron_import_orders_scheduler_action" model="ir.cron">35 <record forcecreate="True" id="ir_cron_import_orders_scheduler_action" model="ir.cron">
36 <field name="name">Magento Import Orders</field>36 <field name="name">Magento Import Orders</field>
@@ -136,15 +136,29 @@
136 <field eval="'()'" name="args"/>136 <field eval="'()'" name="args"/>
137 </record>137 </record>
138138
139 <record forcecreate="True" id="ir_cron_import_partners_scheduler_action" model="ir.cron">
140 <field name="name">Magento Import Partners</field>
141 <field eval="False" name="active"/>
142 <field name="user_id" ref="base.user_root"/>
143 <field name="interval_number">1</field>
144 <field name="interval_type">days</field>
145 <field name="numbercall">-1</field>
146 <field eval="False" name="doall"/>
147 <field eval="'external.shop.group'" name="model"/>
148 <field eval="'run_import_partners_scheduler'" name="function"/>
149 <field eval="'()'" name="args"/>
150 </record>
151
139 <record id="payment_type1" model="base.sale.payment.type">152 <record id="payment_type1" model="base.sale.payment.type">
140 <field name="name">checkmo;cashondelivery</field>153 <field name="name">checkmo;cashondelivery</field>
141 <field name="order_policy">manual</field>154 <field name="order_policy">manual</field>
142 </record>155 </record>
143 156
144 <record id="payment_type2" model="base.sale.payment.type">157 <record id="payment_type2" model="base.sale.payment.type">
145 <field name="name">ccsave;free;googlecheckout;paypayl_express;paybox_system;paypal_standard;servired_standard;bbva;cofidis</field>158 <field name="name">ccsave;free;googlecheckout;paypayl_express;paybox_system;paypal_standard;servired_standard;bbva;cofidis</field>
146 <field name="order_policy">prepaid</field>159 <field name="order_policy">prepaid</field>
147 </record>160 </record>
148161
149 </data>162
163 </data>
150</openerp>164</openerp>
151165
=== modified file 'magentoerpconnect/partner.py'
--- magentoerpconnect/partner.py 2012-05-16 09:15:39 +0000
+++ magentoerpconnect/partner.py 2013-01-09 15:14:26 +0000
@@ -317,4 +317,69 @@
317317
318 return False, partner_id318 return False, partner_id
319319
320 def _ext_import_one(self, cr, uid, external_id, vals, external_data, referential_id, defaults=None, context=None):
321 """ Import one external resource
322
323 This method can be inherited to do an action which have to be done
324 within the same transaction than the import of the resource.
325 All the database operations done within _ext_import_one
326 will be rollbacked if any error occurs.
327 So no action on an external referential should be done within this method.
328
329 :param int external_id: id of the resource on the external referential
330 :param dict vals: vals converted to openerp
331 :param dict external_data: vals of the external resource before conversion
332 :param int referential_id: external referential id from where we import the resource
333 :param dict defaults: defaults value for fields which are not in vals
334 :return: tuple created id, updated id
335 """
336 cid, wid = super(res_partner, self)._ext_import_one(
337 cr, uid, external_id, vals, external_data, referential_id, defaults=defaults, context=context)
338
339 partner_id = cid or wid
340 if partner_id:
341 partner = self.browse(cr, uid, partner_id, context=context)
342
343 # As a partner without addresses can't be opened
344 # we create a dummy empty address
345 if not partner.address:
346 new_empty_address = [(0, 0, {})]
347 partner.write({'address': new_empty_address}, context=context)
348
349 return cid, wid
350
351 def _import_partner_from_external(
352 self,
353 cr, uid,
354 partner_ext_id,
355 connection,
356 referential_id,
357 context=None):
358 """
359 Import partner data from magento for a given id
360
361 :param partner_ext_id: magento id of customer to import
362 :param connection: connection data to magento
363 :param referential_id: referential id from where we import the ressource
364 """
365 if context is None:
366 context = {}
367 imp_ctx = dict(context,
368 id=partner_ext_id)
369 result = self.get_external_data(
370 cr, uid,
371 connection,
372 referential_id,
373 defaults={},
374 context=imp_ctx)
375 partner_id = self.extid_to_oeid(
376 cr, uid, partner_ext_id, referential_id, context=context)
377
378 # update the address book of the customer, this addresses
379 # will be available in the partner form and the searches
380 self.import_magento_address_book(
381 cr, uid, partner_id, referential_id, context=context)
382
383 return result
384
320res_partner()385res_partner()
321386
=== modified file 'magentoerpconnect/sale.py'
--- magentoerpconnect/sale.py 2012-12-06 08:08:36 +0000
+++ magentoerpconnect/sale.py 2013-01-09 15:14:26 +0000
@@ -30,6 +30,7 @@
30from tools.translate import _30from tools.translate import _
31import string31import string
32#from datetime import datetime32#from datetime import datetime
33from contextlib import closing
33import tools34import tools
34import time35import time
35from tools import DEFAULT_SERVER_DATETIME_FORMAT36from tools import DEFAULT_SERVER_DATETIME_FORMAT
@@ -49,6 +50,113 @@
49 'waiting_date': 'holded'}50 'waiting_date': 'holded'}
50SALE_ORDER_IMPORT_STEP = 20051SALE_ORDER_IMPORT_STEP = 200
5152
53
54class external_shop_group(magerp_osv.magerp_osv):
55 _inherit = 'external.shop.group'
56
57 @staticmethod
58 def _get_magento_partners(connection, from_date=False, website_id=False):
59 """
60 Get data from magento of new and updated customers since a specific_date
61
62 :param connection: connection data to magento
63 :param from_data: date from which we get the changes
64 """
65 filters = []
66 if from_date:
67 filters = [
68 {'created_at': {'gt': from_date}}, # OR
69 {'updated_at': {'gt': from_date}}
70 ]
71 if website_id:
72 if filters:
73 for f in filters:
74 f.update(website_id={'eq': website_id})
75 else:
76 filters = [{'website_id': {'eq': website_id}}]
77
78 data = connection.call('customer.list', filters)
79 return data
80
81 def _import_partners(self, cr, uid, group, context=None):
82 """
83 Import partners for a single shop group
84
85 :param group: browse record of an external.shop.group
86 """
87 if context is None: context = {}
88
89 referential_id = group.referential_id.id
90 from_date = group.import_partners_from_date
91 website_id = self.oeid_to_extid(cr, uid, group.id, referential_id)
92 partner_obj = self.pool.get('res.partner')
93 result = super(external_shop_group, self)._import_partners(
94 cr, uid, group,
95 context=context)
96
97 ref_obj = self.pool.get('external.referential')
98 connection = context.get('conn_obj') or \
99 ref_obj.external_connection(
100 cr, uid, referential_id, context=context)
101
102 [result.setdefault(key, []) for key in ['create_ids', 'write_ids', 'unchanged_ids']]
103
104 # Get partners from magento which where created or updated
105 # since last import
106 data = self._get_magento_partners(connection, from_date, website_id)
107
108 data.sort(key=lambda customer: customer['updated_at'] or customer['created_at'])
109
110 imp_ctx = dict(context, import_no_new_cr=True)
111 with closing(pooler.get_db(cr.dbname).cursor()) as local_cr:
112 # here we commit each partner updated or created as it can
113 # be an long processing and we want to be able to restart
114 # from the state when it failed
115 for customer in data:
116 ext_id = customer['customer_id']
117 change_date = customer['updated_at'] or customer['created_at']
118 try:
119 current_result = partner_obj._import_partner_from_external(
120 local_cr, uid, ext_id,
121 connection, referential_id,
122 context=imp_ctx)
123 except Exception as e:
124 local_cr.rollback()
125 if "res_partner_emailid_uniq" in e.message:
126 message = _("Cannot import a partner: "
127 "A partner with email %s already exists ")\
128 % customer['email']
129 raise osv.except_osv(_("Import Error"), message)
130 else:
131 raise
132 else:
133 self.write(
134 local_cr, uid,
135 group.id,
136 {'import_partners_from_date': change_date},
137 context=context)
138 local_cr.commit()
139 result['create_ids'] += current_result.get('create_ids')
140 result['write_ids'] += current_result.get('write_ids')
141
142 return result
143
144 def run_import_partners_scheduler(self, cr, uid, context=None):
145 """
146 Methode to launch the import on all external shop groups
147 to be used by a cron job
148 """
149 group_ids = self.search(cr, uid, [], context=context)
150
151 if group_ids:
152 shop_groups = self.browse(cr, uid, ids, context=context)
153
154 for group in shop_groups:
155 self._import_partners(cr, uid, group, context=context)
156
157
158external_shop_group()
159
52class sale_shop(magerp_osv.magerp_osv):160class sale_shop(magerp_osv.magerp_osv):
53 _inherit = "sale.shop"161 _inherit = "sale.shop"
54162
@@ -340,22 +448,39 @@
340 cr, uid, customer_record, referential_id,448 cr, uid, customer_record, referential_id,
341 defaults=partner_defaults, context=context)449 defaults=partner_defaults, context=context)
342 else:450 else:
451 ext_id = data_record['customer_id']
452 connection = context.get('conn_obj')
453 website_id = data_record.get('website_id')
454 if website_id:
455 website_id = int(data_record['website_id'])
456 # check if another customer exists
457 existing_id = partner_obj.search_magento_partner(
458 cr, uid,
459 data_record['customer_email'],
460 website_id,
461 context=context)
462 if existing_id:
463 # check if the ext_id is the same
464 # to make sure it isn't some outdated data
465 # This could happen when a customer change his email
466 # from A to B on a old account and create
467 # a new account with A address.
468 # in such case we want to make sure the old account is
469 # updated
470 existing_ext_id = partner_obj.oeid_to_extid(cr, uid, existing_id, referential_id)
471 if existing_ext_id != ext_id:
472 partner_obj._import_partner_from_external(
473 cr, uid, existing_ext_id,
474 connection, referential_id,
475 context=context)
476
343 # always update the customer when importing an order477 # always update the customer when importing an order
344 imp_ctx = dict(context)478 result = partner_obj._import_partner_from_external(
345 imp_ctx['id'] = data_record['customer_id']479 cr, uid, ext_id,
346 partner_obj.get_external_data(480 connection, referential_id,
347 cr, uid,481 context=context)
348 context.get('conn_obj'),482 partner_id = (result['create_ids'] and result['create_ids'][0]
349 referential_id,483 or result['write_ids'] and result['write_ids'][0])
350 defaults={},
351 context=imp_ctx)
352 partner_id = partner_obj.extid_to_oeid(
353 cr, uid, data_record['customer_id'], referential_id)
354
355 # update the address book of the customer, this addresses
356 # will be available in the partner form and the searches
357 partner_obj.import_magento_address_book(
358 cr, uid, partner_id, referential_id, context=context)
359484
360 # The addresses of the sale order are imported as active=false485 # The addresses of the sale order are imported as active=false
361 # so they are linked with the sale order but they are not displayed486 # so they are linked with the sale order but they are not displayed