~camptocamp/magentoerpconnect/oerp6.1-oldstable-stock-config-1070726

« back to all changes in this revision

Viewing changes to magentoerpconnect/sale.py

[MRG] from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
# Copyright (C) 2011  Sharoon Thomas                                    #
7
7
# Copyright (C) 2009  Raphaël Valyi                                     #
8
8
# Copyright (C) 2011 Akretion Sébastien BEAU sebastien.beau@akretion.com#
9
 
# Copyright (C) 2011 Camptocamp Guewen Baconnier                        #
 
9
# Copyright (C) 2011-2012 Camptocamp Guewen Baconnier                   #
10
10
#                                                                       #
11
11
#This program is free software: you can redistribute it and/or modify   #
12
12
#it under the terms of the GNU General Public License as published by   #
27
27
import magerp_osv
28
28
import netsvc
29
29
from tools.translate import _
30
 
from collections import defaultdict
31
30
import string
32
31
#from datetime import datetime
33
32
import tools
160
159
        return result
161
160
 
162
161
    def check_need_to_update(self, cr, uid, ids, context=None):
163
 
        '''This function will update the order status in OpenERP for the order which are in the state 'need to update' '''
164
 
        logger = netsvc.Logger()
 
162
        """ This function will update the order status in OpenERP for
 
163
        the order which are in the state 'need to update' """
165
164
        so_obj = self.pool.get('sale.order')
166
165
 
167
166
        for shop in self.browse(cr, uid, ids):
170
169
            # from the Magento's corresponding orders
171
170
    
172
171
            # Get all need_to_update orders in OERP
173
 
            orders_to_update = so_obj.search(cr,uid,[('need_to_update', '=', True), ('shop_id', '=', shop.id)])
174
 
            for order in so_obj.browse(cr, uid, orders_to_update):
175
 
                mag_status = ORDER_STATUS_MAPPING.get(order.state, False)
176
 
                # For each one, check if the status has change in Magento
177
 
                # We dont use oeid_to_extid function cause it only handle int id
178
 
                # Magento can have something like '100000077-2'
179
 
                model_data_ids = self.pool.get('ir.model.data').search(cr, uid, [('model', '=', so_obj._name), ('res_id', '=', order.id), ('external_referential_id', '=', shop.referential_id.id)])
180
 
                if model_data_ids:
181
 
                    prefixed_id = self.pool.get('ir.model.data').read(cr, uid, model_data_ids[0], ['name'])['name']
182
 
                    ext_id = so_obj.id_from_prefixed_id(prefixed_id)
183
 
                else:
184
 
                    return False
185
 
                data_record=conn.call('sales_order.info', [ext_id])
186
 
                updated = False
187
 
                if data_record['status'] == 'canceled':
188
 
                    wf_service = netsvc.LocalService("workflow")
189
 
                    wf_service.trg_validate(uid, 'sale.order', order.id, 'cancel', cr)
190
 
                    updated = True
191
 
                    self.log(cr, uid, order.id, "order %s canceled when updated from external system" % (order.id,))
192
 
                    logger.notifyChannel('ext synchro', netsvc.LOG_INFO, "order %s canceled when updated from external system" % (order.id,))
193
 
                # If the order isn't canceled and was blocked, 
194
 
                # so we follow the standard flow according to ext_payment_method:
195
 
                else:
196
 
                    paid = so_obj.create_payments(cr, uid, order.id, data_record, context)                        
197
 
                    so_obj.oe_status(cr, uid, order.id, paid, context)
198
 
                    updated = paid
199
 
                    if paid:
200
 
                        self.log(cr, uid, order.id, "order %s paid when updated from external system" % (order.id,))
201
 
                        logger.notifyChannel('ext synchro', netsvc.LOG_INFO, "order %s paid when updated from external system" % (order.id,))
202
 
                # Untick the need_to_update if updated (if so was canceled in magento
203
 
                # or if it has been paid through magento)
204
 
                if updated:
205
 
                    so_obj.write(cr, uid, order.id, {'need_to_update': False})
206
 
                cr.commit();
 
172
            orders_to_update = so_obj.search(
 
173
                cr, uid,
 
174
                [('need_to_update', '=', True),
 
175
                 ('shop_id', '=', shop.id)],
 
176
                context=context)
 
177
            so_obj.check_need_to_update(
 
178
                cr, uid, orders_to_update, conn, context=context)
207
179
        return False
208
180
 
209
 
    def _create_magento_invoice(self, cr, uid, order, conn, ext_id, context=None):
210
 
        """ Creation of an invoice on Magento."""
211
 
        cr.execute("select account_invoice.id "
212
 
                   "from account_invoice "
213
 
                   "inner join sale_order_invoice_rel "
214
 
                   "on invoice_id = account_invoice.id "
215
 
                   "where order_id = %s" % order.id)
216
 
        resultset = cr.fetchone()
217
 
        created = False
218
 
        if resultset and len(resultset) == 1:
219
 
            invoice = self.pool.get("account.invoice").browse(
220
 
                cr, uid, resultset[0], context=context)
221
 
            if (invoice.amount_total == order.amount_total and
222
 
                not invoice.magento_ref):
223
 
                try:
224
 
                    magento_invoice_ref = conn.call(
225
 
                        'sales_order_invoice.create',
226
 
                        [order.magento_incrementid,
227
 
                         [],
228
 
                         _("Invoice Created"),
229
 
                         True,
230
 
                         order.shop_id.allow_magento_notification])
231
 
                    self.pool.get("account.invoice").write(
232
 
                        cr, uid,
233
 
                        invoice.id,
234
 
                        {'magento_ref': magento_invoice_ref,
235
 
                         'origin': magento_invoice_ref})
236
 
                    self.log(cr, uid, order.id,
237
 
                             "created Magento invoice for order %s" %
238
 
                             (order.id,))
239
 
                    created = True
240
 
                except Exception, e:
241
 
                    self.log(cr, uid, order.id,
242
 
                             "failed to create Magento invoice for order %s" %
243
 
                             (order.id,))
244
 
                    # TODO make sure that's because Magento invoice already
245
 
                    # exists and then re-attach it!
246
 
        return created
247
 
 
248
181
    def update_shop_orders(self, cr, uid, order, ext_id, context=None):
249
182
        if context is None: context = {}
250
183
        result = {}
251
184
 
252
185
        if order.shop_id.allow_magento_order_status_push:
 
186
            sale_obj = self.pool.get('sale.order')
253
187
            #status update:
254
188
            conn = context.get('conn_obj', False)
255
189
            status = ORDER_STATUS_MAPPING.get(order.state, False)
262
196
                # then we consider the update is done
263
197
                # remove the 'need_to_update': True
264
198
                if order.need_to_update:
265
 
                    self.pool.get('sale.order').write(
 
199
                    sale_obj.write(
266
200
                        cr, uid, order.id, {'need_to_update': False})
267
201
 
268
 
            self._create_magento_invoice(
 
202
            sale_obj.export_invoice(
269
203
                cr, uid, order, conn, ext_id, context=context)
270
204
        return result
271
205
 
279
213
        if ids:
280
214
            callback(cr, uid, ids, context=context)
281
215
 
282
 
        tools.debug(callback)
283
 
        tools.debug(ids)
 
216
        # tools.debug(callback)
 
217
        # tools.debug(ids)
284
218
        return True
285
219
 
286
220
    # Schedules functions ============ #
309
243
    _inherit = "sale.order"
310
244
    
311
245
    _columns = {
312
 
                'magento_incrementid': fields.char('Magento Increment ID', size=32),
313
 
                'magento_storeview_id': fields.many2one('magerp.storeviews', 'Magento Store View'),
 
246
        'magento_incrementid': fields.char('Magento Increment ID', size=32),
 
247
        'magento_storeview_id': fields.many2one('magerp.storeviews', 'Magento Store View'),
 
248
        'is_magento': fields.related(
 
249
            'shop_id', 'referential_id', 'magento_referential',
 
250
            type='boolean',
 
251
            string='Is a Magento Sale Order')
314
252
    }
315
253
    
316
254
    def _auto_init(self, cr, context=None):
321
259
        super(sale_order, self)._auto_init(cr, context)
322
260
        
323
261
    def get_mage_customer_address_id(self, address_data):
324
 
        if address_data.get('customer_address_id', False):
 
262
        # sometimes magento put nothing or '0' for the id, in such case
 
263
        # we have to create an new address
 
264
        if address_data.get('customer_address_id') and \
 
265
           address_data['customer_address_id'] != '0':
325
266
            return {'customer_address_id': address_data['customer_address_id'], 'is_magento_order_address': False}
326
267
        else:
327
268
            return {'customer_address_id': 'mag_order' + str(address_data['address_id']), 'is_magento_order_address': True}
340
281
        if 'address_type' in data_record['shipping_address']:
341
282
            data_record['shipping_address'].update(self.get_mage_customer_address_id(data_record['shipping_address']))
342
283
        shipping_default = {}
343
 
        billing_default = {}
344
 
        res['partner_id'] = self.pool.get('res.partner').extid_to_oeid(cr, uid, data_record['customer_id'], external_referential_id)
 
284
 
 
285
        if res is None:
 
286
            res = {}
 
287
 
 
288
        # always update the customer when importing an order
 
289
        partner_obj.get_external_data(
 
290
            cr, uid,
 
291
            context.get('conn_obj'),
 
292
            external_referential_id,
 
293
            defaults={},
 
294
            context={'id': data_record['customer_id']})
 
295
        res['partner_id'] = partner_obj.extid_to_oeid(cr, uid, data_record['customer_id'], external_referential_id)
 
296
 
345
297
        if res.get('partner_id', False):
346
298
            shipping_default = {'partner_id': res.get('partner_id', False)}
347
299
        billing_default = shipping_default.copy()
348
300
        billing_default.update({'email' : data_record.get('customer_email', False)})
349
301
 
350
 
        inv_res = partner_address_obj.ext_import(cr, uid, [data_record['billing_address']], external_referential_id, billing_default, context)
351
 
        if 'address_type' in data_record['shipping_address']:
352
 
            ship_res = partner_address_obj.ext_import(cr, uid, [data_record['shipping_address']], external_referential_id, shipping_default, context)
353
 
        else:
354
 
            ship_res = partner_address_obj.ext_import(cr, uid, [data_record['billing_address']], external_referential_id, shipping_default, context)
355
 
 
356
 
        res['partner_order_id'] = len(inv_res['create_ids']) > 0 and inv_res['create_ids'][0] or inv_res['write_ids'][0]
 
302
        inv_res = partner_address_obj.ext_import(
 
303
            cr, uid, [data_record['billing_address']], external_referential_id, billing_default, context)
 
304
        res['partner_order_id'] = inv_res.get('create_ids') and inv_res['create_ids'][0] or inv_res['write_ids'][0]
357
305
        res['partner_invoice_id'] = res['partner_order_id']
358
 
        res['partner_shipping_id'] = (len(ship_res['create_ids']) > 0 and ship_res['create_ids'][0]) or (len(ship_res['write_ids']) > 0 and ship_res['write_ids'][0]) or res['partner_order_id'] #shipping might be the same as invoice address
359
 
        
 
306
 
 
307
        if data_record['shipping_address']:
 
308
            ship_res = partner_address_obj.ext_import(
 
309
                cr, uid, [data_record['shipping_address']], external_referential_id, shipping_default, context)
 
310
            res['partner_shipping_id'] = (ship_res.get('create_ids') and ship_res['create_ids'][0]) or \
 
311
                                         (ship_res.get('write_ids') and ship_res['write_ids'][0]) \
 
312
                                         or False
 
313
 
 
314
        # when there is no shipping address, use the order's one
 
315
        if not res.get('partner_shipping_id'):
 
316
            res['partner_shipping_id'] = res['partner_order_id']
 
317
 
360
318
        result = partner_address_obj.read(cr, uid, res['partner_order_id'], ['partner_id'])
361
319
        if result and result['partner_id']:
362
320
            partner_id = result['partner_id'][0]
410
368
            partner_obj.write(cr, uid, [partner_id], partner_vals)
411
369
        return res
412
370
    
413
 
    def get_order_lines(self, cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context=None):
414
 
        if context is None: context = {}
415
 
        mapping_id = self.pool.get('external.mapping').search(cr,uid,[('model','=','sale.order.line'),('referential_id','=',external_referential_id)])
416
 
        if mapping_id:
417
 
            mapping_line_ids = self.pool.get('external.mapping.line').search(cr,uid,[('mapping_id','=',mapping_id[0]),('type','in',['in_out','in'])])
418
 
            mapping_lines = self.pool.get('external.mapping.line').read(cr,uid,mapping_line_ids,['external_field','external_type','in_function'])
419
 
            if mapping_lines:
420
 
                lines_vals = []
421
 
                is_tax_included = defaults.get('price_type', False) == 'tax_included'
422
 
                for line_data in data_record.get('items', []):
423
 
                    # Setting the UoM in sale order line as defined in product definition in openerp
424
 
                    product_id = self.pool.get('product.product').extid_to_oeid(cr, uid, line_data['product_id'], external_referential_id)
425
 
                    product = self.pool.get('product.product').browse(cr, uid, product_id)
426
 
                    defaults_line = {'product_uom': product.uom_id.id}
427
 
                    #simple VAT tax on order line (else override method):
428
 
                    line_tax_vat = float(line_data.get('tax_percent', False) or 0) / 100.0
429
 
                    if line_tax_vat > 0:
430
 
                        line_tax_ids = self.pool.get('account.tax').search(cr, uid, ['|', ('type_tax_use', '=', 'all'), ('type_tax_use', '=', 'sale'), ('price_include', '=', is_tax_included), ('amount', '>=', line_tax_vat - 0.001), ('amount', '<=', line_tax_vat + 0.001)])
431
 
                        if line_tax_ids and len(line_tax_ids) > 0:
432
 
                            defaults_line['tax_id'] = [(6, 0, [line_tax_ids[0]])]
433
 
                    context.update({'partner_id': res['partner_id'], 'pricelist_id': res['pricelist_id']})
434
 
                    if defaults.get('price_type', False) == 'tax_included':
435
 
                        context.update({'price_is_tax_included': True})
436
 
                    line_val = self.oevals_from_extdata(cr, uid, external_referential_id, line_data, 'item_id', mapping_lines, defaults_line, context)
437
 
                    if line_val['product_id']:
438
 
                        line_val['type'] = self.pool.get('product.product').read(cr, uid, line_val['product_id'], ['procure_method'], context)['procure_method']
439
 
                    if not line_val.has_key('_CANCEL_IMPORT'):
440
 
                        lines_vals.append((0, 0, line_val))
441
 
                res['order_line'] = lines_vals
442
 
        return res
443
 
 
444
371
 
445
372
    def add_order_extra_line(self, cr, uid, res, data_record, ext_field, product_ref, defaults, context=None):
446
373
        """ Add or substract amount on order as a separate line item with single quantity for each type of amounts like :
464
391
 
465
392
        model, product_id = model_data_obj.get_object_reference(cr, uid, *product_ref)
466
393
        product = self.pool.get('product.product').browse(cr, uid, product_id, context)
467
 
        is_tax_included = defaults.get('price_type', False) == 'tax_included'
 
394
        is_tax_included = context.get('price_is_tax_included', False)
468
395
        amount = float(data_record[ext_field]) * sign
469
 
        tax_id = []
470
 
        if ext_tax_field:
471
 
            if data_record[ext_tax_field] and float(data_record[ext_tax_field]) != 0:
472
 
                tax_vat = abs(float(data_record[ext_tax_field]) / amount)
473
 
                tax_ids = self.pool.get('account.tax').search(cr, uid, [('price_include', '=', is_tax_included), ('type_tax_use', '=', 'sale'), ('amount', '>=', tax_vat - 0.001), ('amount', '<=', tax_vat + 0.001)])
474
 
                if tax_ids and len(tax_ids) > 0:
475
 
                    tax_id = [(6, 0, [tax_ids[0]])]
476
 
                else:
477
 
                    #try to find a tax with less precision 
478
 
                    tax_ids = self.pool.get('account.tax').search(cr, uid, [('price_include', '=', is_tax_included), ('type_tax_use', '=', 'sale'), ('amount', '>=', tax_vat - 0.01), ('amount', '<=', tax_vat + 0.01)])
479
 
                if tax_ids and len(tax_ids) > 0:
480
 
                    tax_id = [(6, 0, [tax_ids[0]])]
481
 
 
482
396
        name = product.name
483
397
        if ext_code_field and data_record.get(ext_code_field, False):
484
398
            name = "%s [%s]" % (name, data_record[ext_code_field])
488
402
        else:
489
403
            price_unit = float(amount)
490
404
 
491
 
        res['order_line'].append((0, 0, {
492
 
                                    'product_id': product.id,
493
 
                                    'name': name,
494
 
                                    'product_uom': product.uom_id.id,
495
 
                                    'product_uom_qty': 1,
496
 
                                    'price_unit': price_unit,
497
 
                                    'tax_id': tax_id
498
 
                                }))
 
405
        extra_line = {
 
406
                        'product_id': product.id,
 
407
                        'name': name,
 
408
                        'product_uom': product.uom_id.id,
 
409
                        'product_uom_qty': 1,
 
410
                        'price_unit': price_unit,
 
411
                    }
 
412
 
 
413
        if not res.get('order_line'):
 
414
            res['order_line'] = []
 
415
 
 
416
        if context.get('use_external_tax'):
 
417
            # get the tax computed by the external system
 
418
            tax_vat = abs(float(data_record[ext_tax_field]) / amount)
 
419
            line_tax_id = self.pool.get('account.tax').get_tax_from_rate(cr, uid, tax_vat, context.get('is_tax_included'), context=context)
 
420
            extra_line['tax_id'] = [(6, 0, line_tax_id)]
 
421
        else:
 
422
            # compute the taxes, apply fiscal positions, default values and so on
 
423
            extra_line = self.pool.get('sale.order.line').play_sale_order_line_onchange(cr, uid, extra_line, res, res['order_line'], defaults, context=context)
 
424
        res['order_line'].append((0, 0, extra_line))
 
425
 
499
426
        return res
500
427
    
501
 
    def add_order_shipping(self, cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context=None):
 
428
    def add_order_shipping(self, cr, uid, res, external_referential_id, data_record, defaults, context=None):
502
429
        if context is None: context = {}
503
430
        if data_record.get('shipping_amount', False) and float(data_record.get('shipping_amount', False)) > 0:
504
431
            ctx = context.copy()
509
436
            res = self.add_order_extra_line(cr, uid, res, data_record, 'shipping_amount', product_ref, defaults, ctx)
510
437
        return res
511
438
 
512
 
    def add_gift_certificates(self, cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context=None):
 
439
    def add_gift_certificates(self, cr, uid, res, external_referential_id, data_record, defaults, context=None):
513
440
        if context is None: context = {}
514
441
        if data_record.get('giftcert_amount', False) and float(data_record.get('giftcert_amount', False)) > 0:
515
442
            ctx = context.copy()
521
448
            res = self.add_order_extra_line(cr, uid, res, data_record, 'giftcert_amount', product_ref, defaults, ctx)
522
449
        return res
523
450
 
524
 
    def add_discount(self, cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context=None):
 
451
    def add_discount(self, cr, uid, res, external_referential_id, data_record, defaults, context=None):
525
452
        #TODO fix me rev 476
526
453
        #if data_record.get('discount_amount', False) and float(data_record.get('discount_amount', False)) < 0:
527
454
        #    ctx = context.copy()
532
459
        #    res = self.add_order_extra_line(cr, uid, res, data_record, 'discount_amount', product_ref, defaults, ctx)
533
460
        return res
534
461
 
535
 
    def add_cash_on_delivery(self, cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context=None):
 
462
    def add_cash_on_delivery(self, cr, uid, res, external_referential_id, data_record, defaults, context=None):
536
463
        if context is None: context = {}
537
464
        if data_record.get('cod_fee', False) and float(data_record.get('cod_fee', False)) > 0:
538
465
            ctx = context.copy()
542
469
            product_ref = ('magentoerpconnect', 'product_product_cash_on_delivery')
543
470
            res = self.add_order_extra_line(cr, uid, res, data_record, 'cod_fee', product_ref, defaults, ctx)
544
471
        return res
 
472
    
 
473
    def convert_extdata_into_oedata(self, cr, uid, external_data, external_referential_id, parent_data=None, defaults=None, context=None):
 
474
        res = super(sale_order, self).convert_extdata_into_oedata(cr, uid, external_data, external_referential_id, parent_data=parent_data, defaults=defaults, context=context)
 
475
        res=res[0]
 
476
        external_data = external_data[0]
 
477
        res = self.add_order_shipping(cr, uid, res, external_referential_id, external_data, defaults, context)
 
478
        res = self.add_gift_certificates(cr, uid, res, external_referential_id, external_data, defaults, context)
 
479
        res = self.add_discount(cr, uid, res, external_referential_id, external_data, defaults, context)
 
480
        res = self.add_cash_on_delivery(cr, uid, res, external_referential_id, external_data, defaults, context)
 
481
        return [res]
545
482
 
546
483
    def _merge_sub_items(self, cr, uid, product_type, top_item, child_items, context=None):
547
484
        """
592
529
        
593
530
        data_record['items'] = all_items
594
531
        return data_record
595
 
    
596
 
    
597
 
    def get_all_order_lines(self, cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context=None):
598
 
        res = self.get_order_lines(cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context)
599
 
        res = self.add_order_shipping(cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context)
600
 
        res = self.add_gift_certificates(cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context)
601
 
        res = self.add_discount(cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context)
602
 
        res = self.add_cash_on_delivery(cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context)
603
 
        return res
604
532
 
605
 
    def oevals_from_extdata(self, cr, uid, external_referential_id, data_record, key_field, mapping_lines, defaults, context=None):
 
533
    def oevals_from_extdata(self, cr, uid, external_referential_id, data_record, key_field, mapping_lines, parent_data=None, previous_lines=None, defaults=None, context=None):
606
534
        if context is None: context = {}
607
535
        if data_record.get('items', False):
608
536
            data_record = self.data_record_filter(cr, uid, data_record, context=context)
609
 
        
 
537
        #TODO refactor this code regarding the new feature of sub-mapping in base_external_referential
610
538
        if not context.get('one_by_one', False):
611
539
            if data_record.get('billing_address', False):
612
540
                defaults = self.get_order_addresses(cr, uid, defaults, external_referential_id, data_record, key_field, mapping_lines, defaults, context)
613
 
        
614
 
        res = super(magerp_osv.magerp_osv, self).oevals_from_extdata(cr, uid, external_referential_id, data_record, key_field, mapping_lines, defaults, context)
 
541
        res = super(magerp_osv.magerp_osv, self).oevals_from_extdata(cr, uid, external_referential_id, data_record, key_field, mapping_lines, parent_data, previous_lines, defaults, context)
615
542
 
616
 
        if not context.get('one_by_one', False):
617
 
            if data_record.get('items', False):
618
 
                if NOTRY:
619
 
                    res = self.get_all_order_lines(cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context)
620
 
                else:
621
 
                    #TODO fix me error should be raise correctly in the reporting system
622
 
                    res = self.get_all_order_lines(cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context)
623
 
                    #try:
624
 
                    #    res = self.get_all_order_lines(cr, uid, res, external_referential_id, data_record, key_field, mapping_lines, defaults, context)
625
 
                    #except Exception, e:
626
 
                    #    print "order has errors with items lines, data are: ", data_record
627
 
                    #    print e
628
 
                        #TODO flag that the order has an error, especially.
629
 
            
 
543
        #Move me in a mapping
 
544
        if not context.get('one_by_one', False):            
630
545
            if data_record.get('status_history', False) and len(data_record['status_history']) > 0:
631
546
                res['date_order'] = data_record['status_history'][len(data_record['status_history'])-1]['created_at']
632
547
        return res
633
 
    
 
548
 
 
549
    def _parse_external_payment(self, cr, uid, order_data, context=None):
 
550
        """
 
551
        Parse the external order data and return if the sale order
 
552
        has been paid and the amount to pay or to be paid
 
553
 
 
554
        :param dict order_data: payment information of the magento sale
 
555
            order
 
556
        :return: tuple where :
 
557
            - first item indicates if the payment has been done (True or False)
 
558
            - second item represents the amount paid or to be paid
 
559
        """
 
560
        paid = amount = False
 
561
        payment_info = order_data.get('payment')
 
562
        if payment_info:
 
563
            amount = False
 
564
            if payment_info.get('amount_paid', False):
 
565
                amount =  payment_info.get('amount_paid', False)
 
566
                paid = True
 
567
            elif payment_info.get('amount_ordered', False):
 
568
                amount = payment_info.get('amount_ordered', False)
 
569
        return paid, amount
 
570
 
634
571
    def create_payments(self, cr, uid, order_id, data_record, context=None):
635
 
        if context is None: context = {}
636
 
        if context.get('external_referential_type', False) and 'Magento' in context['external_referential_type']:
637
 
            paid = False
638
 
            if data_record.get('payment', False):
639
 
                payment = data_record['payment']
640
 
                amount = False
641
 
                if payment.get('amount_paid', False):
642
 
                    amount =  payment.get('amount_paid', False)
643
 
                    paid = True
644
 
                elif payment.get('amount_ordered', False):
645
 
                    amount =  payment.get('amount_ordered', False)
646
 
                if amount:
647
 
                    order = self.pool.get('sale.order').browse(cr, uid, order_id, context)
648
 
                    self.generate_payment_with_pay_code(cr, uid, payment['method'], order.partner_id.id, float(amount), "mag_" + payment['payment_id'], "mag_" + data_record['increment_id'], order.date_order, paid, context)
 
572
        if context is None:
 
573
            context = {}
 
574
 
 
575
        if 'Magento' in context.get('external_referential_type', ''):
 
576
            payment_info = data_record.get('payment')
 
577
            paid, amount = self._parse_external_payment(
 
578
                cr, uid, data_record, context=context)
 
579
            if amount:
 
580
                order = self.pool.get('sale.order').browse(
 
581
                    cr, uid, order_id, context)
 
582
                self.generate_payment_with_pay_code(
 
583
                    cr, uid,
 
584
                    payment_info['method'],
 
585
                    order.partner_id.id,
 
586
                    float(amount),
 
587
                    "mag_" + payment_info['payment_id'],
 
588
                    "mag_" + data_record['increment_id'],
 
589
                    order.date_order,
 
590
                    paid,
 
591
                    context=context)
649
592
        else:
650
 
            paid = super(sale_order, self).create_payments(cr, uid, order_id, data_record, context=context)
 
593
            paid = super(sale_order, self).create_payments(
 
594
                cr, uid, order_id, data_record, context=context)
651
595
        return paid
652
596
 
653
597
    def _chain_cancel_orders(self, cr, uid, external_id, external_referential_id, defaults=None, context=None):
772
716
            result['unchanged_ids'] = unchanged_ids
773
717
        return result
774
718
 
775
 
# UPDATE ORDER STATUS FROM MAGENTO TO OPENERP IS UNSTABLE, AND NOT VERY USEFULL. MAYBE IT WILL BE REFACTORED 
776
 
 
777
 
    #def oe_update(self,cr, uid, existing_rec_id, vals, data, external_referential_id, defaults, context):
778
 
        #order_line_ids = self.pool.get('sale.order.line').search(cr,uid,[('order_id','=', existing_rec_id)])
779
 
        #self.pool.get('sale.order.line').unlink(cr, uid, order_line_ids)
780
 
        #TODO update order status eventually (that would be easier if they were linked by some foreign key...)
781
 
        #self.oe_status(cr, uid, data, existing_rec_id, context)
782
 
        #return super(magerp_osv.magerp_osv, self).oe_update(cr, uid, existing_rec_id, vals, data, external_referential_id, defaults, context)
783
 
 
784
 
    #def oe_status(self, cr, uid, data, order_id, context):
785
 
        #wf_service = netsvc.LocalService("workflow")
786
 
        #if data.get('status_history', False) and len(data['status_history']) > 0 and data['status_history'][0]['status'] == 'canceled':
787
 
        #   wf_service.trg_validate(uid, 'sale.order', order_id, 'cancel', cr)
788
 
        #else:
789
 
        #   super(magerp_osv.magerp_osv, self).oe_status(cr, uid, order_id, context)
790
 
    
 
719
    def _check_need_to_update_single(self, cr, uid, order, conn, context=None):
 
720
        """
 
721
        For one order, check on Magento if it has been paid since last
 
722
        check. If so, it will launch the defined flow based on the
 
723
        payment type (validate order, invoice, ...)
 
724
 
 
725
        :param browse_record order: browseable sale.order
 
726
        :param Connection conn: connection with Magento
 
727
        :return: True
 
728
        """
 
729
        model_data_obj = self.pool.get('ir.model.data')
 
730
        # check if the status has changed in Magento
 
731
        # We don't use oeid_to_extid function cause it only handles integer ids
 
732
        # Magento can have something like '100000077-2'
 
733
        model_data_ids = model_data_obj.search(
 
734
            cr, uid,
 
735
            [('model', '=', self._name),
 
736
             ('res_id', '=', order.id),
 
737
             ('external_referential_id', '=', order.shop_id.referential_id.id)],
 
738
            context=context)
 
739
 
 
740
        if model_data_ids:
 
741
            prefixed_id = model_data_obj.read(
 
742
                cr, uid, model_data_ids[0], ['name'], context=context)['name']
 
743
            ext_id = self.id_from_prefixed_id(prefixed_id)
 
744
        else:
 
745
            return False
 
746
 
 
747
        data_record = conn.call('sales_order.info', [ext_id])
 
748
 
 
749
        if data_record['status'] == 'canceled':
 
750
            wf_service = netsvc.LocalService("workflow")
 
751
            wf_service.trg_validate(uid, 'sale.order', order.id, 'cancel', cr)
 
752
            updated = True
 
753
            self.log(cr, uid, order.id, "order %s canceled when updated from external system" % (order.id,))
 
754
        # If the order isn't canceled and was waiting for a payment,
 
755
        # so we follow the standard flow according to ext_payment_method:
 
756
        else:
 
757
            paid, __ = self._parse_external_payment(
 
758
                cr, uid, data_record, context=context)
 
759
            self.oe_status(cr, uid, order.id, paid, context)
 
760
            # create_payments has to be done after oe_status
 
761
            # because oe_status creates the invoice
 
762
            # and create_payment could reconcile the payment
 
763
            # with the invoice
 
764
 
 
765
            updated = self.create_payments(
 
766
                cr, uid, order.id, data_record, context)
 
767
            if updated:
 
768
                self.log(
 
769
                    cr, uid, order.id,
 
770
                    "order %s paid when updated from external system" %
 
771
                    (order.id,))
 
772
        # Untick the need_to_update if updated (if so was canceled in magento
 
773
        # or if it has been paid through magento)
 
774
        if updated:
 
775
            self.write(cr, uid, order.id, {'need_to_update': False})
 
776
        cr.commit()
 
777
        return True
 
778
 
 
779
    def check_need_to_update(self, cr, uid, ids, conn, context=None):
 
780
        """
 
781
        For each order, check on Magento if it has been paid since last
 
782
        check. If so, it will launch the defined flow based on the
 
783
        payment type (validate order, invoice, ...)
 
784
 
 
785
        :param Connection conn: connection with Magento
 
786
        :return: True
 
787
        """
 
788
        for order in self.browse(cr, uid, ids, context=context):
 
789
            self._check_need_to_update_single(
 
790
                cr, uid, order, conn, context=context)
 
791
        return True
 
792
 
 
793
    def _create_external_invoice(self, cr, uid, order, conn, ext_id,
 
794
                                context=None):
 
795
        """ Creation of an invoice on Magento."""
 
796
        magento_invoice_ref = conn.call(
 
797
            'sales_order_invoice.create',
 
798
            [order.magento_incrementid,
 
799
            [],
 
800
             _("Invoice Created"),
 
801
             True,
 
802
             order.shop_id.allow_magento_notification])
 
803
        return magento_invoice_ref
 
804
 
 
805
    # TODO Move in base_sale_multichannels?
 
806
    def export_invoice(self, cr, uid, order, conn, ext_id, context=None):
 
807
        """ Export an invoice on external referential """
 
808
        cr.execute("select account_invoice.id "
 
809
                   "from account_invoice "
 
810
                   "inner join sale_order_invoice_rel "
 
811
                   "on invoice_id = account_invoice.id "
 
812
                   "where order_id = %s" % order.id)
 
813
        resultset = cr.fetchone()
 
814
        created = False
 
815
        if resultset and len(resultset) == 1:
 
816
            invoice = self.pool.get("account.invoice").browse(
 
817
                cr, uid, resultset[0], context=context)
 
818
            if (invoice.amount_total == order.amount_total and
 
819
                not invoice.magento_ref):
 
820
                try:
 
821
                    self._create_external_invoice(
 
822
                        cr, uid, order, conn, ext_id, context=context)
 
823
                    created = True
 
824
                except Exception, e:
 
825
                    self.log(cr, uid, order.id,
 
826
                             "failed to create Magento invoice for order %s" %
 
827
                             (order.id,))
 
828
                    # TODO make sure that's because Magento invoice already
 
829
                    # exists and then re-attach it!
 
830
        return created
 
831
 
791
832
sale_order()
792
833