From 6e26537af6e7c21745f14e13ff3ab8b473deebca Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 19 Feb 2015 08:33:41 +0100 Subject: [PATCH 01/18] Move connector_ecommerce in the root folder and set installable --- .../connector_ecommerce => connector_ecommerce}/__init__.py | 0 .../connector_ecommerce => connector_ecommerce}/__openerp__.py | 2 +- .../connector_ecommerce => connector_ecommerce}/account.py | 0 .../account_view.xml | 0 .../ecommerce_data.xml | 0 .../connector_ecommerce => connector_ecommerce}/event.py | 0 .../i18n/connector_ecommerce.pot | 0 .../connector_ecommerce => connector_ecommerce}/i18n/de.po | 0 .../connector_ecommerce => connector_ecommerce}/i18n/es.po | 0 .../connector_ecommerce => connector_ecommerce}/i18n/fr.po | 0 .../connector_ecommerce => connector_ecommerce}/i18n/nl.po | 0 .../connector_ecommerce => connector_ecommerce}/invoice.py | 0 .../invoice_view.xml | 0 .../payment_method.py | 0 .../payment_method_view.xml | 0 .../connector_ecommerce => connector_ecommerce}/product.py | 0 .../connector_ecommerce => connector_ecommerce}/sale.py | 0 .../connector_ecommerce => connector_ecommerce}/sale_view.xml | 0 .../security/ir.model.access.csv | 0 .../security/security.xml | 0 .../connector_ecommerce => connector_ecommerce}/stock.py | 0 .../connector_ecommerce => connector_ecommerce}/stock_view.xml | 0 .../tests/__init__.py | 0 .../tests/test_invoice_event.py | 0 .../tests/test_onchange.py | 0 .../unit/__init__.py | 0 .../unit/sale_order_onchange.py | 0 .../wizard/__init__.py | 0 .../wizard/sale_ignore_cancel.py | 0 .../wizard/sale_ignore_cancel_view.xml | 0 30 files changed, 1 insertion(+), 1 deletion(-) rename {__unported__/connector_ecommerce => connector_ecommerce}/__init__.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/__openerp__.py (99%) rename {__unported__/connector_ecommerce => connector_ecommerce}/account.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/account_view.xml (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/ecommerce_data.xml (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/event.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/i18n/connector_ecommerce.pot (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/i18n/de.po (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/i18n/es.po (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/i18n/fr.po (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/i18n/nl.po (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/invoice.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/invoice_view.xml (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/payment_method.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/payment_method_view.xml (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/product.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/sale.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/sale_view.xml (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/security/ir.model.access.csv (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/security/security.xml (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/stock.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/stock_view.xml (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/tests/__init__.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/tests/test_invoice_event.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/tests/test_onchange.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/unit/__init__.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/unit/sale_order_onchange.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/wizard/__init__.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/wizard/sale_ignore_cancel.py (100%) rename {__unported__/connector_ecommerce => connector_ecommerce}/wizard/sale_ignore_cancel_view.xml (100%) diff --git a/__unported__/connector_ecommerce/__init__.py b/connector_ecommerce/__init__.py similarity index 100% rename from __unported__/connector_ecommerce/__init__.py rename to connector_ecommerce/__init__.py diff --git a/__unported__/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py similarity index 99% rename from __unported__/connector_ecommerce/__openerp__.py rename to connector_ecommerce/__openerp__.py index a0ef9380..5d211c6a 100644 --- a/__unported__/connector_ecommerce/__openerp__.py +++ b/connector_ecommerce/__openerp__.py @@ -76,5 +76,5 @@ 'payment_method_view.xml', 'account_view.xml', ], - 'installable': False, + 'installable': True, } diff --git a/__unported__/connector_ecommerce/account.py b/connector_ecommerce/account.py similarity index 100% rename from __unported__/connector_ecommerce/account.py rename to connector_ecommerce/account.py diff --git a/__unported__/connector_ecommerce/account_view.xml b/connector_ecommerce/account_view.xml similarity index 100% rename from __unported__/connector_ecommerce/account_view.xml rename to connector_ecommerce/account_view.xml diff --git a/__unported__/connector_ecommerce/ecommerce_data.xml b/connector_ecommerce/ecommerce_data.xml similarity index 100% rename from __unported__/connector_ecommerce/ecommerce_data.xml rename to connector_ecommerce/ecommerce_data.xml diff --git a/__unported__/connector_ecommerce/event.py b/connector_ecommerce/event.py similarity index 100% rename from __unported__/connector_ecommerce/event.py rename to connector_ecommerce/event.py diff --git a/__unported__/connector_ecommerce/i18n/connector_ecommerce.pot b/connector_ecommerce/i18n/connector_ecommerce.pot similarity index 100% rename from __unported__/connector_ecommerce/i18n/connector_ecommerce.pot rename to connector_ecommerce/i18n/connector_ecommerce.pot diff --git a/__unported__/connector_ecommerce/i18n/de.po b/connector_ecommerce/i18n/de.po similarity index 100% rename from __unported__/connector_ecommerce/i18n/de.po rename to connector_ecommerce/i18n/de.po diff --git a/__unported__/connector_ecommerce/i18n/es.po b/connector_ecommerce/i18n/es.po similarity index 100% rename from __unported__/connector_ecommerce/i18n/es.po rename to connector_ecommerce/i18n/es.po diff --git a/__unported__/connector_ecommerce/i18n/fr.po b/connector_ecommerce/i18n/fr.po similarity index 100% rename from __unported__/connector_ecommerce/i18n/fr.po rename to connector_ecommerce/i18n/fr.po diff --git a/__unported__/connector_ecommerce/i18n/nl.po b/connector_ecommerce/i18n/nl.po similarity index 100% rename from __unported__/connector_ecommerce/i18n/nl.po rename to connector_ecommerce/i18n/nl.po diff --git a/__unported__/connector_ecommerce/invoice.py b/connector_ecommerce/invoice.py similarity index 100% rename from __unported__/connector_ecommerce/invoice.py rename to connector_ecommerce/invoice.py diff --git a/__unported__/connector_ecommerce/invoice_view.xml b/connector_ecommerce/invoice_view.xml similarity index 100% rename from __unported__/connector_ecommerce/invoice_view.xml rename to connector_ecommerce/invoice_view.xml diff --git a/__unported__/connector_ecommerce/payment_method.py b/connector_ecommerce/payment_method.py similarity index 100% rename from __unported__/connector_ecommerce/payment_method.py rename to connector_ecommerce/payment_method.py diff --git a/__unported__/connector_ecommerce/payment_method_view.xml b/connector_ecommerce/payment_method_view.xml similarity index 100% rename from __unported__/connector_ecommerce/payment_method_view.xml rename to connector_ecommerce/payment_method_view.xml diff --git a/__unported__/connector_ecommerce/product.py b/connector_ecommerce/product.py similarity index 100% rename from __unported__/connector_ecommerce/product.py rename to connector_ecommerce/product.py diff --git a/__unported__/connector_ecommerce/sale.py b/connector_ecommerce/sale.py similarity index 100% rename from __unported__/connector_ecommerce/sale.py rename to connector_ecommerce/sale.py diff --git a/__unported__/connector_ecommerce/sale_view.xml b/connector_ecommerce/sale_view.xml similarity index 100% rename from __unported__/connector_ecommerce/sale_view.xml rename to connector_ecommerce/sale_view.xml diff --git a/__unported__/connector_ecommerce/security/ir.model.access.csv b/connector_ecommerce/security/ir.model.access.csv similarity index 100% rename from __unported__/connector_ecommerce/security/ir.model.access.csv rename to connector_ecommerce/security/ir.model.access.csv diff --git a/__unported__/connector_ecommerce/security/security.xml b/connector_ecommerce/security/security.xml similarity index 100% rename from __unported__/connector_ecommerce/security/security.xml rename to connector_ecommerce/security/security.xml diff --git a/__unported__/connector_ecommerce/stock.py b/connector_ecommerce/stock.py similarity index 100% rename from __unported__/connector_ecommerce/stock.py rename to connector_ecommerce/stock.py diff --git a/__unported__/connector_ecommerce/stock_view.xml b/connector_ecommerce/stock_view.xml similarity index 100% rename from __unported__/connector_ecommerce/stock_view.xml rename to connector_ecommerce/stock_view.xml diff --git a/__unported__/connector_ecommerce/tests/__init__.py b/connector_ecommerce/tests/__init__.py similarity index 100% rename from __unported__/connector_ecommerce/tests/__init__.py rename to connector_ecommerce/tests/__init__.py diff --git a/__unported__/connector_ecommerce/tests/test_invoice_event.py b/connector_ecommerce/tests/test_invoice_event.py similarity index 100% rename from __unported__/connector_ecommerce/tests/test_invoice_event.py rename to connector_ecommerce/tests/test_invoice_event.py diff --git a/__unported__/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py similarity index 100% rename from __unported__/connector_ecommerce/tests/test_onchange.py rename to connector_ecommerce/tests/test_onchange.py diff --git a/__unported__/connector_ecommerce/unit/__init__.py b/connector_ecommerce/unit/__init__.py similarity index 100% rename from __unported__/connector_ecommerce/unit/__init__.py rename to connector_ecommerce/unit/__init__.py diff --git a/__unported__/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py similarity index 100% rename from __unported__/connector_ecommerce/unit/sale_order_onchange.py rename to connector_ecommerce/unit/sale_order_onchange.py diff --git a/__unported__/connector_ecommerce/wizard/__init__.py b/connector_ecommerce/wizard/__init__.py similarity index 100% rename from __unported__/connector_ecommerce/wizard/__init__.py rename to connector_ecommerce/wizard/__init__.py diff --git a/__unported__/connector_ecommerce/wizard/sale_ignore_cancel.py b/connector_ecommerce/wizard/sale_ignore_cancel.py similarity index 100% rename from __unported__/connector_ecommerce/wizard/sale_ignore_cancel.py rename to connector_ecommerce/wizard/sale_ignore_cancel.py diff --git a/__unported__/connector_ecommerce/wizard/sale_ignore_cancel_view.xml b/connector_ecommerce/wizard/sale_ignore_cancel_view.xml similarity index 100% rename from __unported__/connector_ecommerce/wizard/sale_ignore_cancel_view.xml rename to connector_ecommerce/wizard/sale_ignore_cancel_view.xml From 09403bf2cdfb9affc0c010231eafa75c17a56302 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 19 Feb 2015 08:38:04 +0100 Subject: [PATCH 02/18] It now depends on sale_payment_automatic_workflow In v7. sale_automatic_workflow had a dependency on sale_payment_method. This is no longer true, now the module sale_payment_automatic_workflow makes the glue between sale_automatic_workflow and sale_payment_method. --- connector_ecommerce/__openerp__.py | 2 +- connector_ecommerce/payment_method_view.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py index 5d211c6a..d9f558d4 100644 --- a/connector_ecommerce/__openerp__.py +++ b/connector_ecommerce/__openerp__.py @@ -60,7 +60,7 @@ """, 'depends': [ 'connector', - 'sale_automatic_workflow', + 'sale_payment_method_automatic_workflow', 'sale_exceptions', 'delivery', 'connector_base_product', diff --git a/connector_ecommerce/payment_method_view.xml b/connector_ecommerce/payment_method_view.xml index 788b3bd3..a6ef4428 100644 --- a/connector_ecommerce/payment_method_view.xml +++ b/connector_ecommerce/payment_method_view.xml @@ -12,7 +12,7 @@ payment.method.connector_ecommerce.form payment.method - + @@ -40,7 +40,7 @@ payment.method.connector_ecommerce.tree payment.method - + From 4b0ceb25463a637f1caa84d05db97d0795ffd211 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 19 Feb 2015 08:44:04 +0100 Subject: [PATCH 03/18] sale.shop has passed away --- connector_ecommerce/sale.py | 20 ------------------- connector_ecommerce/tests/test_onchange.py | 3 --- .../unit/sale_order_onchange.py | 16 +-------------- 3 files changed, 1 insertion(+), 38 deletions(-) diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py index f6526bcc..95d8251c 100644 --- a/connector_ecommerce/sale.py +++ b/connector_ecommerce/sale.py @@ -31,26 +31,6 @@ _logger = logging.getLogger(__name__) -class sale_shop(orm.Model): - _inherit = 'sale.shop' - - def _get_payment_default(self, cr, uid, context=None): - """ Return a arbitrary account.payment.term record for the sale.shop - - ``sale.shop`` records are created dynamically from the backends - and the field ``payment_default_id`` needs a default value. - """ - data_obj = self.pool.get('ir.model.data') - __, payment_id = data_obj.get_object_reference( - cr, uid, 'account', 'account_payment_term_immediate') - return payment_id - - _defaults = { - # see method docstring for explanation - 'payment_default_id': _get_payment_default, - } - - class sale_order(orm.Model): """ Add a cancellation mecanism in the sales orders diff --git a/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py index f857f050..a70ef582 100644 --- a/connector_ecommerce/tests/test_onchange.py +++ b/connector_ecommerce/tests/test_onchange.py @@ -43,7 +43,6 @@ def test_play_onchange(self): """ Play the onchange ConnectorUnit on a sale order """ product_model = self.registry('product.product') partner_model = self.registry('res.partner') - shop_model = self.registry('sale.shop') tax_model = self.registry('account.tax') cr, uid = self.cr, self.uid @@ -66,10 +65,8 @@ def test_play_onchange(self): 'name': 'My Product', 'weight': 15, 'taxes_id': [(6, 0, [tax_id])]}) - shop_id = shop_model.create(cr, uid, {'name': 'My shop'}) order_input = { - 'shop_id': shop_id, 'name': 'mag_10000001', 'partner_id': partner_id, 'order_line': [ diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py index 06702067..da63f469 100644 --- a/connector_ecommerce/unit/sale_order_onchange.py +++ b/connector_ecommerce/unit/sale_order_onchange.py @@ -52,12 +52,6 @@ def _get_partner_id_onchange_param(self, order): kwargs = {'context': self.session.context} return args, kwargs - def _get_shop_id_onchange_param(self, order): - args = [None, - order['shop_id']] - kwargs = {'context': self.session.context} - return args, kwargs - def _get_payment_method_id_onchange_param(self, order): args = [None, order['payment_method_id']] @@ -93,13 +87,6 @@ def _play_order_onchange(self, order): sale_model = self.session.pool.get('sale.order') # Play partner_id onchange - args, kwargs = self._get_shop_id_onchange_param(order) - res = sale_model.onchange_shop_id(self.session.cr, - self.session.uid, - *args, - **kwargs) - self.merge_values(order, res) - args, kwargs = self._get_partner_id_onchange_param(order) res = sale_model.onchange_partner_id(self.session.cr, self.session.uid, @@ -237,8 +224,7 @@ def play(self, order, order_lines): :rtype: dict """ # play onchange on sale order - with self.session.change_context(dict(shop_id=order.get('shop_id'))): - order = self._play_order_onchange(order) + order = self._play_order_onchange(order) # play onchange on sale order line processed_order_lines = [] line_lists = [order_lines] From f8b79293091d9c65512f7bf203dae3d166cf5f06 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 19 Feb 2015 08:46:01 +0100 Subject: [PATCH 04/18] Remove the deprecated methods used to generate special lines, yeah! --- connector_ecommerce/sale.py | 142 ------------------------------------ 1 file changed, 142 deletions(-) diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py index 95d8251c..606ca0a8 100644 --- a/connector_ecommerce/sale.py +++ b/connector_ecommerce/sale.py @@ -271,148 +271,6 @@ def action_view_parent(self, cr, uid, ids, context=None): action['res_id'] = parent.id return action - # TODO: remove in odoo 8.0 - def _convert_special_fields(self, cr, uid, vals, order_lines, - context=None): - """ Deprecated! Replaced by LineBuilder classes - - Convert the special 'fake' field into an order line. - - Special fields are: - - shipping amount and shipping_tax_rate - - cash_on_delivery and cash_on_delivery_taxe_rate - - gift_certificates - - :param vals: values of the sale order to create - :type vals: dict - :param order_lines: lines of the orders to import - :return: the value for the sale order with the special field converted - :rtype: dict - """ - _logger.warning('sale_order._convert_special_fields() has been ' - 'deprecated. Use a specialized ' - 'SpecialOrderLineBuilder class instead.') - shipping_fields = ['shipping_amount_tax_excluded', - 'shipping_amount_tax_included', - 'shipping_tax_amount'] - - def check_key(keys): - return len(set(shipping_fields) & set(keys)) >= 2 - - vals.setdefault('order_line', []) - for line in order_lines: - for field in shipping_fields: - if field in line[2]: - vals[field] = vals.get(field, 0.0) + line[2][field] - del line[2][field] - - if 'shipping_tax_rate' not in vals and check_key(vals.keys()): - if 'shipping_amount_tax_excluded' not in vals: - amount_incl = vals['shipping_amount_tax_included'] - tax_amount = vals['shipping_tax_amount'] - tax_excl = (amount_incl - tax_amount) - vals['shipping_amount_tax_excluded'] = tax_excl - - elif 'shipping_tax_amount' not in vals: - amount_incl = vals['shipping_amount_tax_included'] - amount_excl = vals['shipping_amount_tax_excluded'] - vals['shipping_tax_amount'] = (amount_incl - amount_excl) - if vals['shipping_amount_tax_excluded']: - tax_amount = vals['shipping_tax_amount'] - tax_amount_excl = vals['shipping_amount_tax_excluded'] - vals['shipping_tax_rate'] = (tax_amount / tax_amount_excl) - else: - vals['shipping_tax_rate'] = 0. - del vals['shipping_tax_amount'] - for option in self._get_special_fields(cr, uid, context=context): - vals = self._add_order_extra_line(cr, uid, vals, - option, context=context) - return vals - - # TODO: remove in odoo 8.0 - def _get_special_fields(self, cr, uid, context=None): - """ Deprecated! Replaced by LineBuilder classes """ - return [ - {'price_unit_tax_excluded': 'shipping_amount_tax_excluded', - 'price_unit_tax_included': 'shipping_amount_tax_included', - 'tax_rate_field': 'shipping_tax_rate', - 'product_ref': ('connector_ecommerce', - 'product_product_shipping'), - }, - {'tax_rate_field': 'cash_on_delivery_taxe_rate', - 'price_unit_tax_excluded': 'cash_on_delivery_amount_tax_excluded', - 'price_unit_tax_included': 'cash_on_delivery_amount_tax_included', - 'product_ref': ('connector_ecommerce', - 'product_product_cash_on_delivery'), - }, - # gift certificate doesn't have any tax - {'price_unit_tax_excluded': 'gift_certificates_amount', - 'price_unit_tax_included': 'gift_certificates_amount', - 'product_ref': ('connector_ecommerce', 'product_product_gift'), - 'code_field': 'gift_certificates_code', - 'sign': -1, - }, - ] - - # TODO: remove in odoo 8.0 - def _get_order_extra_line_vals(self, cr, uid, vals, option, product, - price_unit, context=None): - """ Deprecated! Replaced by LineBuilder classes """ - return { - 'product_id': product.id, - 'name': product.name, - 'product_uom': product.uom_id.id, - 'product_uom_qty': 1, - 'price_unit': price_unit - } - - # TODO: remove in odoo 8.0 - def _add_order_extra_line(self, cr, uid, vals, option, context=None): - """ Deprecated! Replaced by LineBuilder classes - - Add or substract amount on order as a separate line item - with single quantity for each type of amounts like: shipping, - cash on delivery, discount, gift certificates... - - :param dict vals: values of the sale order to create - :param option: dictionary of options for the special field to process - """ - if context is None: - context = {} - sign = option.get('sign', 1) - if (context.get('is_tax_included') and - vals.get(option['price_unit_tax_included'])): - price_unit = vals.pop(option['price_unit_tax_included']) * sign - elif vals.get(option['price_unit_tax_excluded']): - price_unit = vals.pop(option['price_unit_tax_excluded']) * sign - else: - return self._clean_special_fields(option, vals) - model_data_obj = self.pool.get('ir.model.data') - product_obj = self.pool.get('product.product') - __, product_id = model_data_obj.get_object_reference( - cr, uid, *option['product_ref']) - product = product_obj.browse(cr, uid, product_id, context=context) - - extra_line = self._get_order_extra_line_vals( - cr, uid, vals, option, product, price_unit, context=context) - - ext_code_field = option.get('code_field') - if ext_code_field and vals.get(ext_code_field): - extra_line['name'] = "%s [%s]" % (extra_line['name'], - vals[ext_code_field]) - vals['order_line'].append((0, 0, extra_line)) - return self._clean_special_fields(option, vals) - - # TODO: remove in odoo 8.0 - def _clean_special_fields(self, option, vals): - """ Deprecated! Replaced by LineBuilder classes """ - for key in ['price_unit_tax_excluded', - 'price_unit_tax_included', - 'tax_rate_field']: - if option.get(key) and option[key] in vals: - del vals[option[key]] - return vals # if there is no price, we have nothing to import - class SpecialOrderLineBuilder(ConnectorUnit): """ Base class to build a sale order line for a sale order From 1561704f9f0291b36e18df9e942de71bc2a84fce Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 19 Feb 2015 08:57:59 +0100 Subject: [PATCH 05/18] stock.picking.out is no longer there --- connector_ecommerce/stock.py | 20 +++++++------------- connector_ecommerce/stock_view.xml | 30 +++++++++++++++--------------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py index 121633f0..607b7c72 100644 --- a/connector_ecommerce/stock.py +++ b/connector_ecommerce/stock.py @@ -39,18 +39,16 @@ def action_done(self, cr, uid, ids, context=None): ids, context=context) session = ConnectorSession(cr, uid, context=context) # Look if it exists a backorder, in that case call for partial - picking_records = self.read(cr, uid, ids, - ['id', 'related_backorder_ids', 'type'], - context=context) - for picking_vals in picking_records: - if picking_vals['type'] != 'out': + pickings = self.browse(cr, uid, ids, context=context) + for picking in pickings: + if picking.picking_type_id.code != 'outgoing': continue - if picking_vals['related_backorder_ids']: + if picking.related_backorder_ids: picking_method = 'partial' else: picking_method = 'complete' on_picking_out_done.fire(session, self._name, - picking_vals['id'], picking_method) + picking.id, picking_method) return res def copy(self, cr, uid, id, default=None, context=None): @@ -62,15 +60,11 @@ def copy(self, cr, uid, id, default=None, context=None): return super(stock_picking, self).copy(cr, uid, id, default, context=context) - -class stock_picking_out(orm.Model): - _inherit = 'stock.picking.out' - def write(self, cr, uid, ids, vals, context=None): if not hasattr(ids, '__iter__'): ids = [ids] - res = super(stock_picking_out, self).write(cr, uid, ids, - vals, context=context) + res = super(stock_picking, self).write(cr, uid, ids, + vals, context=context) if vals.get('carrier_tracking_ref'): session = ConnectorSession(cr, uid, context=context) for record_id in ids: diff --git a/connector_ecommerce/stock_view.xml b/connector_ecommerce/stock_view.xml index cc102b30..954c7050 100644 --- a/connector_ecommerce/stock_view.xml +++ b/connector_ecommerce/stock_view.xml @@ -1,18 +1,18 @@ - - - stock.picking.out.connector.form - stock.picking.out - - - - - - - - - - + + + stock.picking.form + stock.picking + + + + + + + + + + From 45bf1e8f06525e81b36b1be6c54629f4b3f5d4a7 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 19 Feb 2015 09:45:45 +0100 Subject: [PATCH 06/18] Remove the fiscal position rule onchange As something similar has been implemented in v8, I'm not sure that the fiscal position rule will be used and if it will, the onchange signature will change, so let's remove it and add it again if necessary later. --- .../unit/sale_order_onchange.py | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py index da63f469..b318eb5c 100644 --- a/connector_ecommerce/unit/sale_order_onchange.py +++ b/connector_ecommerce/unit/sale_order_onchange.py @@ -64,17 +64,6 @@ def _get_workflow_process_id_onchange_param(self, order): kwargs = {'context': self.session.context} return args, kwargs - def _get_partner_address_id_onchange_param(self, order): - args = [ - None, - order['partner_invoice_id'], - order['partner_shipping_id'], - order['partner_id'], - order['shop_id'], - ] - kwargs = {'context': self.session.context} - return args, kwargs - def _play_order_onchange(self, order): """ Play the onchange of the sale order @@ -101,13 +90,6 @@ def _play_order_onchange(self, order): self.session.uid, *args, **kwargs) - # If the onchange return a False fiscal position - # We do not merge it, because the onchange on the address - # will not set correctly the fiscal position as the field - # already exists in the order dict - if res.get('value') and 'fiscal_position' in res['value']: - if not res['value']['fiscal_position']: - res['value'].pop('fiscal_position') self.merge_values(order, res) @@ -119,17 +101,6 @@ def _play_order_onchange(self, order): *args, **kwargs) self.merge_values(order, res) - - # Play onchange on address - if hasattr(sale_model, 'onchange_address_id'): - args, kwargs = self._get_partner_address_id_onchange_param(order) - res = sale_model.onchange_address_id(self.session.cr, - self.session.uid, - *args, - **kwargs) - if res.get('value') and 'fiscal_position' in res['value']: - order['fiscal_position'] = res['value']['fiscal_position'] - self.merge_values(order, res) return order def _get_product_id_onchange_param(self, line, previous_lines, order): From 197713e7f86a08ad22631b0747c0be36c136fac7 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 19 Feb 2015 14:09:29 +0100 Subject: [PATCH 07/18] Adapt the onchange players to the new API Thanks to Model.onchange(), we apply the onchanges on a temporary 'new record' and get back the changed values. Then we apply these values on our order values. --- connector_ecommerce/tests/test_onchange.py | 80 ++++++---- .../unit/sale_order_onchange.py | 140 +++++++++--------- 2 files changed, 125 insertions(+), 95 deletions(-) diff --git a/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py index a70ef582..2d437e0b 100644 --- a/connector_ecommerce/tests/test_onchange.py +++ b/connector_ecommerce/tests/test_onchange.py @@ -21,6 +21,7 @@ ############################################################################### import mock +from operator import attrgetter from openerp.addons.connector_ecommerce.unit.sale_order_onchange import ( SaleOrderOnChange) @@ -41,50 +42,73 @@ def setUp(self): def test_play_onchange(self): """ Play the onchange ConnectorUnit on a sale order """ - product_model = self.registry('product.product') - partner_model = self.registry('res.partner') - tax_model = self.registry('account.tax') - cr, uid = self.cr, self.uid + product_model = self.env['product.product'] + partner_model = self.env['res.partner'] + tax_model = self.env['account.tax'] + sale_model = self.env['sale.order'] + sale_line_model = self.env['sale.order.line'] + payment_method_model = self.env['payment.method'] backend_record = mock.Mock() env = Environment(backend_record, self.session, 'sale.order') - partner_id = partner_model.create(cr, uid, - {'name': 'seb', - 'zip': '69100', - 'city': 'Villeurbanne'}) - partner_invoice_id = partner_model.create(cr, uid, - {'name': 'Guewen', - 'zip': '1015', - 'city': 'Lausanne', - 'type': 'invoice', - 'parent_id': partner_id}) - tax_id = tax_model.create(cr, uid, {'name': 'My Tax'}) - product_id = product_model.create(cr, uid, - {'default_code': 'MyCode', - 'name': 'My Product', - 'weight': 15, - 'taxes_id': [(6, 0, [tax_id])]}) + partner = partner_model.create({'name': 'seb', + 'zip': '69100', + 'city': 'Villeurbanne'}) + partner_invoice = partner_model.create({'name': 'Guewen', + 'zip': '1015', + 'city': 'Lausanne', + 'type': 'invoice', + 'parent_id': partner.id}) + tax = tax_model.create({'name': 'My Tax'}) + product = product_model.create({'default_code': 'MyCode', + 'name': 'My Product', + 'weight': 15, + 'taxes_id': [(6, 0, [tax.id])]}) + payment_term = self.env.ref('account.account_payment_term_advance') + payment_method = payment_method_model.create({ + 'name': 'Cash', + 'payment_term_id': payment_term.id, + }) - order_input = { + order_vals = { 'name': 'mag_10000001', - 'partner_id': partner_id, + 'partner_id': partner.id, + 'payment_method_id': payment_method.id, 'order_line': [ - (0, 0, {'product_id': product_id, + (0, 0, {'product_id': product.id, 'price_unit': 20, 'name': 'My Real Name', 'product_uom_qty': 1, + 'sequence': 1, } ), - ] + ], + # fake field for the lines coming from a backend + 'backend_order_line': [ + (0, 0, {'product_id': product.id, + 'price_unit': 10, + 'name': 'Line 2', + 'product_uom_qty': 2, + 'sequence': 2, + } + ), + ], } + extra_lines = order_vals['backend_order_line'] + onchange = SaleOrderOnChange(env) - order = onchange.play(order_input, - order_input['order_line']) + order = onchange.play(order_vals, extra_lines) - self.assertEqual(order['partner_invoice_id'], partner_invoice_id) + self.assertEqual(order['partner_invoice_id'], partner_invoice.id) + self.assertEqual(order['payment_term'], payment_term.id) + self.assertEqual(len(order['order_line']), 1) line = order['order_line'][0][2] self.assertEqual(line['name'], 'My Real Name') self.assertEqual(line['th_weight'], 15) - self.assertEqual(line['tax_id'][0][2][0], tax_id) + self.assertEqual(line['tax_id'], [(6, 0, [tax.id])]) + line = order['backend_order_line'][0][2] + self.assertEqual(line['name'], 'Line 2') + self.assertEqual(line['th_weight'], 30) + self.assertEqual(line['tax_id'], [(6, 0, [tax.id])]) diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py index b318eb5c..014ca40a 100644 --- a/connector_ecommerce/unit/sale_order_onchange.py +++ b/connector_ecommerce/unit/sale_order_onchange.py @@ -24,11 +24,22 @@ class OnChangeManager(ConnectorUnit): - def merge_values(self, record, on_change_result): + + def merge_values(self, record, on_change_result, model=None): + record.update(self.get_new_values(record, on_change_result, + model=model)) + + def get_new_values(self, record, on_change_result, model=None): vals = on_change_result.get('value', {}) - for key in vals: - if key not in record: - record[key] = vals[key] + new_values = {} + for fieldname, value in vals.iteritems(): + if fieldname not in record: + if model: + column = self.env[model]._fields[fieldname] + if column.type == 'many2many': + value = [(6, 0, value)] + new_values[fieldname] = value + return new_values class SaleOrderOnChange(OnChangeManager): @@ -46,22 +57,9 @@ def _get_partner_id_onchange_param(self, order): :rtype: tuple """ args = [ - None, # sale order ids not needed - order['partner_id'], + order.get('partner_id'), ] - kwargs = {'context': self.session.context} - return args, kwargs - - def _get_payment_method_id_onchange_param(self, order): - args = [None, - order['payment_method_id']] - kwargs = {'context': self.session.context} - return args, kwargs - - def _get_workflow_process_id_onchange_param(self, order): - args = [None, - order['workflow_process_id']] - kwargs = {'context': self.session.context} + kwargs = {} return args, kwargs def _play_order_onchange(self, order): @@ -73,35 +71,45 @@ def _play_order_onchange(self, order): :return: the value of the sale order updated with the onchange result :rtype: dict """ - sale_model = self.session.pool.get('sale.order') + sale_model = self.env['sale.order'] + onchange_specs = sale_model._onchange_spec() + + # we need all fields in the dict even the empty ones + # otherwise 'onchange()' will not apply changes to them + all_values = order.copy() + for field in sale_model._fields: + if field not in all_values: + all_values[field] = False + + # we work on a temporary record + order_record = sale_model.new(all_values) + + new_values = {} # Play partner_id onchange args, kwargs = self._get_partner_id_onchange_param(order) - res = sale_model.onchange_partner_id(self.session.cr, - self.session.uid, - *args, - **kwargs) - self.merge_values(order, res) - - if order.get('payment_method_id'): - # apply payment method - args, kwargs = self._get_payment_method_id_onchange_param(order) - res = sale_model.onchange_payment_method_id(self.session.cr, - self.session.uid, - *args, - **kwargs) - - self.merge_values(order, res) - - if order.get('workflow_process_id'): - # apply default values from the workflow - args, kwargs = self._get_workflow_process_id_onchange_param(order) - res = sale_model.onchange_workflow_process_id(self.session.cr, - self.session.uid, - *args, - **kwargs) - self.merge_values(order, res) - return order + values = order_record.onchange_partner_id(*args, **kwargs) + new_values.update(self.get_new_values(order, values, + model='sale.order')) + all_values.update(new_values) + + values = order_record.onchange(all_values, + 'payment_method_id', + onchange_specs) + new_values.update(self.get_new_values(order, values, + model='sale.order')) + all_values.update(new_values) + + values = order_record.onchange(all_values, + 'workflow_process_id', + onchange_specs) + new_values.update(self.get_new_values(order, values, + model='sale.order')) + all_values.update(new_values) + + res = {f: v for f, v in all_values.iteritems() + if f in order or f in new_values} + return res def _get_product_id_onchange_param(self, line, previous_lines, order): """ Prepare the arguments for calling the product_id change @@ -119,16 +127,15 @@ def _get_product_id_onchange_param(self, line, previous_lines, order): :rtype: tuple """ args = [ - None, # sale order line ids not needed order.get('pricelist_id'), - line.get('product_id') + line.get('product_id'), ] # used in sale_markup: this is to ensure the unit price # sent by the e-commerce connector is used for markup calculation - onchange_context = self.session.context.copy() - if line.get('unit_price', False): - onchange_context.update({'unit_price': line['unit_price'], + onchange_context = self.env.context.copy() + if line.get('price_unit'): + onchange_context.update({'unit_price': line.get('price_unit'), 'force_unit_price': True}) uos_qty = float(line.get('product_uos_qty', 0)) @@ -165,37 +172,36 @@ def _play_line_onchange(self, line, previous_lines, order): :return: the value of the sale order updated with the onchange result :rtype: dict """ - sale_line_model = self.session.pool.get('sale.order.line') - + line_model = self.env['sale.order.line'] # Play product_id onchange args, kwargs = self._get_product_id_onchange_param(line, previous_lines, order) - res = sale_line_model.product_id_change(self.session.cr, - self.session.uid, - *args, - **kwargs) - # TODO refactor this with merge_values - vals = res.get('value', {}) - for key in vals: - if key not in line: - if sale_line_model._columns[key]._type == 'many2many': - line[key] = [(6, 0, vals[key])] - else: - line[key] = vals[key] + context = kwargs.pop('context', {}) + values = line_model.with_context(context).product_id_change(*args, + **kwargs) + self.merge_values(line, values, model='sale.order.line') return line def play(self, order, order_lines): """ Play the onchange of the sale order and it's lines + It expects to receive a recordset containing one sale order. + It could have been generated with + ``self.env['sale.order'].new(values)`` or + ``self.env['sale.order'].create(values)``. + :param order: data of the sale order - :type: dict + :type: recordset + :param order_lines: data of the sale order lines + :type: recordset - :return: the value of the sale order updated with the onchange result - :rtype: dict + :return: the sale order updated by the onchanges + :rtype: recordset """ # play onchange on sale order order = self._play_order_onchange(order) + # play onchange on sale order line processed_order_lines = [] line_lists = [order_lines] From 735d8eb281a431d0fb7e47c8f38e30b3e54e6ce0 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 19 Feb 2015 14:17:16 +0100 Subject: [PATCH 08/18] Use relative imports and remove fast_suite, checks in tests --- connector_ecommerce/__init__.py | 18 +++++++++--------- connector_ecommerce/tests/__init__.py | 12 ++---------- connector_ecommerce/unit/__init__.py | 2 +- connector_ecommerce/wizard/__init__.py | 2 +- 4 files changed, 13 insertions(+), 21 deletions(-) diff --git a/connector_ecommerce/__init__.py b/connector_ecommerce/__init__.py index bac99af0..8a51dd0b 100644 --- a/connector_ecommerce/__init__.py +++ b/connector_ecommerce/__init__.py @@ -19,12 +19,12 @@ # ############################################################################## -import stock -import account -import product -import invoice -import payment_method -import event -import unit -import sale -import wizard +from . import stock +from . import account +from . import product +from . import invoice +from . import payment_method +from . import event +from . import unit +from . import sale +from . import wizard diff --git a/connector_ecommerce/tests/__init__.py b/connector_ecommerce/tests/__init__.py index 988e9d44..6fae4820 100644 --- a/connector_ecommerce/tests/__init__.py +++ b/connector_ecommerce/tests/__init__.py @@ -19,13 +19,5 @@ # ############################################################################## -import test_onchange -import test_invoice_event - -fast_suite = [ -] - -checks = [ - test_onchange, - test_invoice_event, -] +from . import test_onchange +from . import test_invoice_event diff --git a/connector_ecommerce/unit/__init__.py b/connector_ecommerce/unit/__init__.py index b9150933..45443ad8 100644 --- a/connector_ecommerce/unit/__init__.py +++ b/connector_ecommerce/unit/__init__.py @@ -1,2 +1,2 @@ # -*- coding: utf-8 -*- -import sale_order_onchange +from . import sale_order_onchange diff --git a/connector_ecommerce/wizard/__init__.py b/connector_ecommerce/wizard/__init__.py index f5c43f15..3935a40e 100644 --- a/connector_ecommerce/wizard/__init__.py +++ b/connector_ecommerce/wizard/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -import sale_ignore_cancel +from . import sale_ignore_cancel From 7b7661dee50421108cef7a6411ff8a19f863ec7e Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 24 Feb 2015 13:14:44 +0100 Subject: [PATCH 09/18] Use the new env when building special lines --- connector_ecommerce/sale.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py index 606ca0a8..1ab7c345 100644 --- a/connector_ecommerce/sale.py +++ b/connector_ecommerce/sale.py @@ -23,6 +23,7 @@ import logging +from openerp import models from openerp.osv import orm, fields, osv from openerp.tools.translate import _ from openerp import netsvc @@ -304,16 +305,13 @@ def __init__(self, environment): def get_line(self): assert self.product_ref or self.product assert self.price_unit is not None - session = self.session - product = product_id = self.product - if product_id is None: - model_data_obj = session.pool.get('ir.model.data') - __, product_id = model_data_obj.get_object_reference( - session.cr, session.uid, *self.product_ref) + product = self.product + if product is None: + product = self.env.ref('.'.join(self.product_ref)) - if not isinstance(product_id, orm.browse_record): - product = session.browse('product.product', product_id) + if not isinstance(product, models.BaseModel): + product = self.env['product.product'].browse(product) return {'product_id': product.id, 'name': product.name, 'product_uom': product.uom_id.id, From e7c21630f8f314b45814409e4e6ef3c5b6cedf34 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 24 Feb 2015 13:16:17 +0100 Subject: [PATCH 10/18] Rename environment to connector_env (follows connector's changes) --- connector_ecommerce/sale.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py index 1ab7c345..536bec16 100644 --- a/connector_ecommerce/sale.py +++ b/connector_ecommerce/sale.py @@ -292,8 +292,8 @@ class SpecialOrderLineBuilder(ConnectorUnit): """ _model_name = None - def __init__(self, environment): - super(SpecialOrderLineBuilder, self).__init__(environment) + def __init__(self, connector_env): + super(SpecialOrderLineBuilder, self).__init__(connector_env) self.product = None # id or browse_record # when no product_id, fallback to a product_ref self.product_ref = None # tuple (module, xmlid) @@ -324,8 +324,8 @@ class ShippingLineBuilder(SpecialOrderLineBuilder): """ Return values for a Shipping line """ _model_name = None - def __init__(self, environment): - super(ShippingLineBuilder, self).__init__(environment) + def __init__(self, connector_env): + super(ShippingLineBuilder, self).__init__(connector_env) self.product_ref = ('connector_ecommerce', 'product_product_shipping') self.sequence = 999 @@ -335,8 +335,8 @@ class CashOnDeliveryLineBuilder(SpecialOrderLineBuilder): _model_name = None _model_name = None - def __init__(self, environment): - super(CashOnDeliveryLineBuilder, self).__init__(environment) + def __init__(self, connector_env): + super(CashOnDeliveryLineBuilder, self).__init__(connector_env) self.product_ref = ('connector_ecommerce', 'product_product_cash_on_delivery') self.sequence = 995 @@ -346,8 +346,8 @@ class GiftOrderLineBuilder(SpecialOrderLineBuilder): """ Return values for a Gift line """ _model_name = None - def __init__(self, environment): - super(GiftOrderLineBuilder, self).__init__(environment) + def __init__(self, connector_env): + super(GiftOrderLineBuilder, self).__init__(connector_env) self.product_ref = ('connector_ecommerce', 'product_product_gift') self.sign = -1 From 8e5d96db67ef3f84dd83f5d4527664b829b58f62 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Mon, 2 Mar 2015 14:49:51 +0100 Subject: [PATCH 11/18] Use the new API --- connector_ecommerce/invoice.py | 37 ++- connector_ecommerce/payment_method.py | 68 +++--- connector_ecommerce/product.py | 198 +++++++-------- connector_ecommerce/sale.py | 230 ++++++++---------- connector_ecommerce/stock.py | 52 ++-- .../tests/test_invoice_event.py | 57 ++--- connector_ecommerce/tests/test_onchange.py | 7 +- .../wizard/sale_ignore_cancel.py | 28 +-- 8 files changed, 283 insertions(+), 394 deletions(-) diff --git a/connector_ecommerce/invoice.py b/connector_ecommerce/invoice.py index 0d72c44a..56c67572 100644 --- a/connector_ecommerce/invoice.py +++ b/connector_ecommerce/invoice.py @@ -19,37 +19,28 @@ # ############################################################################## -from openerp.osv import fields, orm +from openerp import models, api from openerp.addons.connector.session import ConnectorSession from .event import on_invoice_paid, on_invoice_validated -class account_invoice(orm.Model): +class AccountInvoice(models.Model): _inherit = 'account.invoice' - _columns = { - 'sale_order_ids': fields.many2many( - # TODO duplicate with 'sale_ids', replace - 'sale.order', - 'sale_order_invoice_rel', - 'invoice_id', - 'order_id', - string='Sale Orders', readonly=True, - help="This is the list of sale orders related to this invoice."), - } - - def confirm_paid(self, cr, uid, ids, context=None): - res = super(account_invoice, self).confirm_paid( - cr, uid, ids, context=context) - session = ConnectorSession(cr, uid, context=context) - for record_id in ids: + @api.multi + def confirm_paid(self): + res = super(AccountInvoice, self).confirm_paid() + session = ConnectorSession(self.env.cr, self.env.uid, + context=self.env.context) + for record_id in self.ids: on_invoice_paid.fire(session, self._name, record_id) return res - def invoice_validate(self, cr, uid, ids, context=None): - res = super(account_invoice, self).invoice_validate( - cr, uid, ids, context=context) - session = ConnectorSession(cr, uid, context=context) - for record_id in ids: + @api.multi + def invoice_validate(self): + res = super(AccountInvoice, self).invoice_validate() + session = ConnectorSession(self.env.cr, self.env.uid, + context=self.env.context) + for record_id in self.ids: on_invoice_validated.fire(session, self._name, record_id) return res diff --git a/connector_ecommerce/payment_method.py b/connector_ecommerce/payment_method.py index 928fc148..ae4a67a4 100644 --- a/connector_ecommerce/payment_method.py +++ b/connector_ecommerce/payment_method.py @@ -19,54 +19,44 @@ # ############################################################################## -from openerp.osv import orm, fields +from openerp import models, fields, api -class payment_method(orm.Model): +class PaymentMethod(models.Model): _inherit = "payment.method" - def _get_import_rules(self, cr, uid, context=None): + @api.model + def _get_import_rules(self): return [('always', 'Always'), ('never', 'Never'), ('paid', 'Paid'), ('authorized', 'Authorized'), ] - def __get_import_rules(self, cr, uid, context=None): - return self._get_import_rules(cr, uid, context=context) - - _columns = { - # the logic around the 2 following fields has to be implemented - # in the connectors (magentoerpconnect, prestashoperpconnect,...) - 'days_before_cancel': fields.integer( - 'Days before cancel', - help="After 'n' days, if the 'Import Rule' is not fulfilled, the " - "import of the sale order will be canceled."), - 'import_rule': fields.selection(__get_import_rules, - string="Import Rule", - required=True) - } - - _defaults = { - 'import_rule': 'always', - 'days_before_cancel': 30, - } - - def get_or_create_payment_method(self, cr, uid, payment_method, - context=None): - """ - try to get id of 'payment_method' or create if not exists - :param str payment_method: payment method like PayPal, etc. - :rtype: int - :return: id of required payment method + # the logic around the 2 following fields has to be implemented + # in the connectors (magentoerpconnect, prestashoperpconnect,...) + days_before_cancel = fields.Integer( + string='Days before cancel', + default=30, + help="After 'n' days, if the 'Import Rule' is not fulfilled, the " + "import of the sale order will be canceled.", + ) + import_rule = fields.Selection(selection='_get_import_rules', + string="Import Rule", + default='always', + required=True) + + @api.model + def get_or_create_payment_method(self, payment_method): + """ try to get id of 'payment_method' or create if not exists + + :param payment_method: payment method like PayPal, etc. + :type payment_method: str + :return: required payment method + :rtype: recordset """ - pay_method_obj = self.pool.get('payment.method') domain = [('name', '=ilike', payment_method)] - method_ids = pay_method_obj.search(cr, uid, domain, context=context) - if method_ids: - method_id = method_ids[0] - else: - method_id = pay_method_obj.create(cr, uid, - {'name': payment_method}, - context=context) - return method_id + method = self.search(domain, limit=1) + if not method: + method = self.create({'name': payment_method}) + return method diff --git a/connector_ecommerce/product.py b/connector_ecommerce/product.py index dcf88ef2..320c93fc 100644 --- a/connector_ecommerce/product.py +++ b/connector_ecommerce/product.py @@ -19,36 +19,33 @@ # ############################################################################## -from openerp.osv import orm, fields +from openerp import models, fields, api from openerp.addons.connector.session import ConnectorSession from .event import on_product_price_changed -class product_template(orm.Model): +class ProductTemplate(models.Model): _inherit = 'product.template' # TODO implement set function and also support multi tax - def _get_tax_group_id(self, cr, uid, ids, field_name, args, context=None): - result = {} - for product in self.browse(cr, uid, ids, context=context): - taxes = product.taxes_id - result[product.id] = taxes[0].group_id.id if taxes else False - return result - - _columns = { - 'tax_group_id': fields.function( - _get_tax_group_id, - string='Tax Group', - type='many2one', - relation='account.tax.group', - store=False, - help='Tax group are used with some external ' - 'system like Prestashop'), - } - - def _price_changed(self, cr, uid, ids, vals, context=None): + @api.depends('taxes_id', 'taxes_id.group_id') + def _get_tax_group_id(self): + for template in self: + taxes = template.taxes_id + template.tax_group_id = taxes[0].group_id.id if taxes else False + + tax_group_id = fields.Many2one( + comodel_name='account.tax.group', + compute='_get_tax_group_id', + string='Tax Group', + help='Tax group are used with some external ' + 'system like Prestashop', + ) + + @api.multi + def _price_changed(self, vals): """ Fire the ``on_product_price_changed`` on all the variants of - the template if the price if the product could have changed. + the template if the price of the product could have changed. If one of the field used in a sale pricelist item has been modified, we consider that the price could have changed. @@ -56,69 +53,61 @@ def _price_changed(self, cr, uid, ids, vals, context=None): There is no guarantee that's the price actually changed, because it depends on the pricelists. """ - if context is None: - context = {} - type_obj = self.pool['product.price.type'] - price_fields = type_obj.sale_price_fields(cr, uid, context=context) + type_model = self.env['product.price.type'] + price_fields = type_model.sale_price_fields() # restrict the fields to the template ones only, so if # the write has been done on product.product, we won't - # update all the variant if a price field of the + # update all the variants if a price field of the # variant has been changed - tmpl_fields = [field for field in vals if field in self._columns] + tmpl_fields = [field for field in vals if field in self._fields] if any(field in price_fields for field in tmpl_fields): - product_obj = self.pool['product.product'] - session = ConnectorSession(cr, uid, context=context) - product_ids = product_obj.search(cr, uid, - [('product_tmpl_id', 'in', ids)], - context=context) + product_model = self.env['product.product'] + session = ConnectorSession(self.env.cr, self.env.uid, + context=self.env.context) + products = product_model.search( + [('product_tmpl_id', 'in', self.ids)] + ) # when the write is done on the product.product, avoid # to fire the event 2 times - if context.get('from_product_ids'): - product_ids = list(set(product_ids) - - set(context['from_product_ids'])) - for prod_id in product_ids: + if self.env.context.get('from_product_ids'): + from_product_ids = self.env.context['from_product_ids'] + remove_products = product_model.browse(from_product_ids) + products -= remove_products + for product in products: on_product_price_changed.fire(session, - product_obj._name, - prod_id) - - def write(self, cr, uid, ids, vals, context=None): - if isinstance(ids, (int, long)): - ids = [ids] - result = super(product_template, self).write(cr, uid, ids, - vals, context=context) - self._price_changed(cr, uid, ids, vals, context=context) + product_model._name, + product.id) + + @api.multi + def write(self, vals): + result = super(ProductTemplate, self).write(vals) + self._price_changed(vals) return result -class product_product(orm.Model): +class ProductProduct(models.Model): _inherit = 'product.product' - def _get_checkpoint(self, cr, uid, ids, name, arg, context=None): - result = {} - checkpoint_obj = self.pool.get('connector.checkpoint') - model_obj = self.pool.get('ir.model') - model_id = model_obj.search(cr, uid, - [('model', '=', 'product.product')], - context=context)[0] - for product_id in ids: - point_ids = checkpoint_obj.search(cr, uid, - [('model_id', '=', model_id), - ('record_id', '=', product_id), - ('state', '=', 'need_review')], - context=context) - result[product_id] = bool(point_ids) - return result - - _columns = { - 'has_checkpoint': fields.function(_get_checkpoint, - type='boolean', - readonly=True, - string='Has Checkpoint'), - } - - def _price_changed(self, cr, uid, ids, vals, context=None): + @api.depends() + def _get_checkpoint(self): + checkpoint_model = self.env['connector.checkpoint'] + model_model = self.env['ir.model'] + model = model_model.search([('model', '=', 'product.product')]) + for product in self: + points = checkpoint_model.search([('model_id', '=', model.id), + ('record_id', '=', product.id), + ('state', '=', 'need_review')], + limit=1, + ) + product.has_checkpoint = bool(points) + + has_checkpoint = fields.Boolean(compute='_get_checkpoint', + string='Has Checkpoint') + + @api.multi + def _price_changed(self, vals): """ Fire the ``on_product_price_changed`` if the price - if the product could have changed. + of the product could have changed. If one of the field used in a sale pricelist item has been modified, we consider that the price could have changed. @@ -126,54 +115,47 @@ def _price_changed(self, cr, uid, ids, vals, context=None): There is no guarantee that's the price actually changed, because it depends on the pricelists. """ - type_obj = self.pool['product.price.type'] - price_fields = type_obj.sale_price_fields(cr, uid, context=context) + type_model = self.env['product.price.type'] + price_fields = type_model.sale_price_fields() if any(field in price_fields for field in vals): - session = ConnectorSession(cr, uid, context=context) - for prod_id in ids: + session = ConnectorSession(self.env.cr, self.env.uid, + context=self.env.context) + for prod_id in self.ids: on_product_price_changed.fire(session, self._name, prod_id) - def write(self, cr, uid, ids, vals, context=None): - if context is None: - context = {} - if isinstance(ids, (int, long)): - ids = [ids] - context = context.copy() - context['from_product_ids'] = ids - result = super(product_product, self).write( - cr, uid, ids, vals, context=context) - self._price_changed(cr, uid, ids, vals, context=context) + @api.multi + def write(self, vals): + self_context = self.with_context(from_product_ids=self.ids) + result = super(ProductProduct, self_context).write(vals) + self._price_changed(vals) return result - def create(self, cr, uid, vals, context=None): - product_ids = super(product_product, self).create( - cr, uid, vals, context=context) - self._price_changed(cr, uid, [product_ids], vals, context=context) - return product_ids + @api.model + def create(self, vals): + product = super(ProductProduct, self).create(vals) + self._price_changed(vals) + return product -class product_price_type(orm.Model): +class ProductPriceType(models.Model): _inherit = 'product.price.type' - _columns = { - 'pricelist_item_ids': fields.one2many( - 'product.pricelist.item', 'base', - string='Pricelist Items', - readonly=True) - } + pricelist_item_ids = fields.One2many( + comodel_name='product.pricelist.item', + inverse_name='base', + string='Pricelist Items', + readonly=True, + ) - def sale_price_fields(self, cr, uid, context=None): + @api.model + def sale_price_fields(self): """ Returns a list of fields used by sale pricelists. Used to know if the sale price could have changed when one of these fields has changed. """ - item_obj = self.pool['product.pricelist.item'] - item_ids = item_obj.search( - cr, uid, + item_model = self.env['product.pricelist.item'] + items = item_model.search( [('price_version_id.pricelist_id.type', '=', 'sale')], - context=context) - type_ids = self.search(cr, uid, - [('pricelist_item_ids', 'in', item_ids)], - context=context) - types = self.read(cr, uid, type_ids, ['field'], context=context) - return [t['field'] for t in types] + ) + types = self.search([('pricelist_item_ids', 'in', items.ids)]) + return [t.field for t in types] diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py index 536bec16..feda0a36 100644 --- a/connector_ecommerce/sale.py +++ b/connector_ecommerce/sale.py @@ -23,16 +23,13 @@ import logging -from openerp import models -from openerp.osv import orm, fields, osv -from openerp.tools.translate import _ -from openerp import netsvc +from openerp import models, fields, api, exceptions, _, osv from openerp.addons.connector.connector import ConnectorUnit _logger = logging.getLogger(__name__) -class sale_order(orm.Model): +class SaleOrder(models.Model): """ Add a cancellation mecanism in the sales orders When a sale order is canceled in a backend, the connectors can flag @@ -55,80 +52,65 @@ class sale_order(orm.Model): """ _inherit = 'sale.order' - def _get_parent_id(self, cr, uid, ids, name, arg, context=None): - return self.get_parent_id(cr, uid, ids, context=context) - - def get_parent_id(self, cr, uid, ids, context=None): + canceled_in_backend = fields.Boolean(string='Canceled in backend', + readonly=True) + # set to True when the cancellation from the backend is + # resolved, either because the SO has been canceled or + # because the user manually chosed to keep it open + cancellation_resolved = fields.Boolean(string='Cancellation from the ' + 'backend resolved') + parent_id = fields.Many2one(comodel_name='sale.order', + compute='get_parent_id', + string='Parent Order', + help='A parent sales order is a sales ' + 'order replaced by this one.') + need_cancel = fields.Boolean(compute='_need_cancel', + string='Need to be canceled', + help='Has been canceled on the backend' + ', need to be canceled.') + parent_need_cancel = fields.Boolean( + compute='_parent_need_cancel', + string='A parent sales orders needs cancel', + help='A parent sales orders has been canceled on the backend' + ' and needs to be canceled.', + ) + + @api.one + @api.depends() + def get_parent_id(self): """ Need to be inherited in the connectors to implement the parent logic. See an implementation example in ``magentoerpconnect``. """ - return dict.fromkeys(ids, False) - - def _get_need_cancel(self, cr, uid, ids, name, arg, context=None): - result = {} - for order in self.browse(cr, uid, ids, context=context): - result[order.id] = self._need_cancel(cr, uid, order, - context=context) - return result - - def _get_parent_need_cancel(self, cr, uid, ids, name, arg, context=None): - result = {} - for order in self.browse(cr, uid, ids, context=context): - result[order.id] = self._parent_need_cancel(cr, uid, order, - context=context) - return result + self.parent_id = False - _columns = { - 'canceled_in_backend': fields.boolean('Canceled in backend', - readonly=True), - # set to True when the cancellation from the backend is - # resolved, either because the SO has been canceled or - # because the user manually chosed to keep it open - 'cancellation_resolved': fields.boolean('Cancellation from the ' - 'backend resolved'), - 'parent_id': fields.function(_get_parent_id, - string='Parent Order', - type='many2one', - help='A parent sales order is a sales ' - 'order replaced by this one.', - relation='sale.order'), - 'need_cancel': fields.function(_get_need_cancel, - string='Need to be canceled', - type='boolean', - help='Has been canceled on the backend' - ', need to be canceled.'), - 'parent_need_cancel': fields.function( - _get_parent_need_cancel, - string='A parent sales orders needs cancel', - type='boolean', - help='A parent sales orders has been canceled on the backend' - ' and needs to be canceled.'), - } - - def _need_cancel(self, cr, uid, order, context=None): + @api.one + @api.depends('canceled_in_backend', 'cancellation_resolved') + def _need_cancel(self): """ Return True if the sales order need to be canceled - (has been canceled on the Backend) """ - return order.canceled_in_backend and not order.cancellation_resolved + (has been canceled on the Backend) + """ + self.need_cancel = (self.canceled_in_backend and + not self.cancellation_resolved) - def _parent_need_cancel(self, cr, uid, order, context=None): + @api.one + @api.depends('need_cancel', 'parent_id', + 'parent_id.need_cancel', 'parent_id.parent_need_cancel') + def _parent_need_cancel(self): """ Return True if at least one parent sales order need to be canceled (has been canceled on the backend). Follows all the parent sales orders. """ - def need_cancel(order): - if self._need_cancel(cr, uid, order, context=context): - return True - if order.parent_id: - return need_cancel(order.parent_id) - else: - return False - if not order.parent_id: - return False - return need_cancel(order.parent_id) - - def _try_auto_cancel(self, cr, uid, ids, context=None): + self.parent_need_cancel = False + order = self.parent_id + while order: + if order.need_cancel: + self.parent_need_cancel = True + order = order.parent_id + + @api.multi + def _try_auto_cancel(self): """ Try to automatically cancel a sales order canceled in a backend. @@ -136,15 +118,13 @@ def _try_auto_cancel(self, cr, uid, ids, context=None): """ wkf_states = ('draft', 'sent') action_states = ('manual', 'progress') - wf_service = netsvc.LocalService("workflow") resolution_msg = _("

Resolution:

    " "
  1. Cancel the linked invoices, delivery " "orders, automatic payments.
  2. " "
  3. Cancel the sales order manually.
  4. " "

") - for order_id in ids: - state = self.read(cr, uid, order_id, - ['state'], context=context)['state'] + for order in self: + state = order.state if state == 'cancel': continue elif state == 'done': @@ -156,13 +136,13 @@ def _try_auto_cancel(self, cr, uid, ids, context=None): # the sales order view: quotations use the workflow # action, sales orders use the action_cancel method. if state in wkf_states: - wf_service.trg_validate(uid, 'sale.order', - order_id, 'cancel', cr) + order.signal_workflow('cancel') elif state in action_states: - self.action_cancel(cr, uid, order_id, context=context) + order.action_cancel() else: raise ValueError('%s should not fall here.' % state) - except osv.except_osv: + except (osv.except_osv, osv.orm.except_orm, + exceptions.Warning): # the 'cancellation_resolved' flag will stay to False message = _("The sales order could not be automatically " "canceled.") + resolution_msg @@ -176,58 +156,48 @@ def _try_auto_cancel(self, cr, uid, ids, context=None): # resolve message = _("The sales order could not be automatically " "canceled for this status.") + resolution_msg - self.message_post(cr, uid, [order_id], body=message, - context=context) + order.message_post(body=message) - def _log_canceled_in_backend(self, cr, uid, ids, context=None): + @api.multi + def _log_canceled_in_backend(self): message = _("The sales order has been canceled on the backend.") - self.message_post(cr, uid, ids, body=message, context=context) - for order in self.browse(cr, uid, ids, context=context): + self.message_post(body=message) + for order in self: message = _("Warning: the origin sales order %s has been canceled " "on the backend.") % order.name if order.picking_ids: - picking_obj = self.pool.get('stock.picking') - picking_obj.message_post(cr, uid, order.picking_ids, - body=message, context=context) + order.picking_ids.message_post(body=message) if order.invoice_ids: - picking_obj = self.pool.get('account.invoice') - picking_obj.message_post(cr, uid, order.invoice_ids, - body=message, context=context) + order.invoice_ids.message_post(body=message) - def create(self, cr, uid, values, context=None): - order_id = super(sale_order, self).create(cr, uid, values, - context=context) + @api.model + def create(self, values): + order = super(SaleOrder, self).create(values) if values.get('canceled_in_backend'): - self._log_canceled_in_backend(cr, uid, [order_id], context=context) - self._try_auto_cancel(cr, uid, [order_id], context=context) - return order_id + order._log_canceled_in_backend() + order._try_auto_cancel() + return order - def write(self, cr, uid, ids, values, context=None): - result = super(sale_order, self).write(cr, uid, ids, values, - context=context) + @api.multi + def write(self, values): + result = super(SaleOrder, self).write(values) if values.get('canceled_in_backend'): - self._log_canceled_in_backend(cr, uid, ids, context=context) - self._try_auto_cancel(cr, uid, ids, context=context) + self._log_canceled_in_backend() + self._try_auto_cancel() return result - def action_cancel(self, cr, uid, ids, context=None): - if not hasattr(ids, '__iter__'): - ids = [ids] - super(sale_order, self).action_cancel(cr, uid, ids, context=context) - sales = self.read(cr, uid, ids, - ['canceled_in_backend', - 'cancellation_resolved'], - context=context) - for sale in sales: + @api.multi + def action_cancel(self): + res = super(SaleOrder, self).action_cancel() + for sale in self: # the sale order is canceled => considered as resolved - if (sale['canceled_in_backend'] and - not sale['cancellation_resolved']): - self.write(cr, uid, sale['id'], - {'cancellation_resolved': True}, - context=context) - return True + if (sale.canceled_in_backend and + not sale.cancellation_resolved): + sale.write({'cancellation_resolved': True}) + return res - def ignore_cancellation(self, cr, uid, ids, reason, context=None): + @api.multi + def ignore_cancellation(self, reason): """ Manually set the cancellation from the backend as resolved. The user can choose to keep the sale order active for some reason, @@ -236,39 +206,29 @@ def ignore_cancellation(self, cr, uid, ids, reason, context=None): message = (_("Despite the cancellation of the sales order on the " "backend, it should stay open.

Reason: %s") % reason) - self.message_post(cr, uid, ids, body=message, context=context) - self.write(cr, uid, ids, - {'cancellation_resolved': True}, - context=context) + self.message_post(body=message) + self.write({'cancellation_resolved': True}) return True - def action_view_parent(self, cr, uid, ids, context=None): + @api.multi + def action_view_parent(self): """ Return an action to display the parent sale order """ - if isinstance(ids, (list, tuple)): - assert len(ids) == 1 - ids = ids[0] - - mod_obj = self.pool.get('ir.model.data') - act_obj = self.pool.get('ir.actions.act_window') + self.ensure_one() - parent = self.browse(cr, uid, ids, context=context).parent_id + parent = self.parent_id if not parent: return - view_xmlid = ('sale', 'view_order_form') + view_xmlid = 'sale.view_order_form' if parent.state in ('draft', 'sent', 'cancel'): - action_xmlid = ('sale', 'action_quotations') + action_xmlid = 'sale.action_quotations' else: - action_xmlid = ('sale', 'action_orders') + action_xmlid = 'sale.action_orders' - ref = mod_obj.get_object_reference(cr, uid, *action_xmlid) - action_id = False - if ref: - __, action_id = ref - action = act_obj.read(cr, uid, [action_id], context=context)[0] + action = self.env.ref(action_xmlid).read()[0] - ref = mod_obj.get_object_reference(cr, uid, *view_xmlid) - action['views'] = [(ref[1] if ref else False, 'form')] + view = self.env.ref(view_xmlid) + action['views'] = [(view.id if view else False, 'form')] action['res_id'] = parent.id return action diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py index 607b7c72..d8649785 100644 --- a/connector_ecommerce/stock.py +++ b/connector_ecommerce/stock.py @@ -2,7 +2,7 @@ ############################################################################## # # Author: Joel Grand-Guillaume -# Copyright 2013 Camptocamp SA +# Copyright 2013-2015 Camptocamp SA # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -19,28 +19,28 @@ # ############################################################################## -from openerp.osv import orm, fields +from openerp import models, fields, api from openerp.addons.connector.session import ConnectorSession from .event import on_picking_out_done, on_tracking_number_added -class stock_picking(orm.Model): +class StockPicking(models.Model): _inherit = 'stock.picking' - _columns = { - 'related_backorder_ids': fields.one2many( - 'stock.picking', 'backorder_id', - string="Related backorders"), - } - - def action_done(self, cr, uid, ids, context=None): - res = super(stock_picking, self).action_done(cr, uid, - ids, context=context) - session = ConnectorSession(cr, uid, context=context) + related_backorder_ids = fields.One2many( + comodel_name='stock.picking', + inverse_name='backorder_id', + string="Related backorders", + ) + + @api.multi + def action_done(self): + res = super(StockPicking, self).action_done() + session = ConnectorSession(self.env.cr, self.env.uid, + context=self.env.context) # Look if it exists a backorder, in that case call for partial - pickings = self.browse(cr, uid, ids, context=context) - for picking in pickings: + for picking in self: if picking.picking_type_id.code != 'outgoing': continue if picking.related_backorder_ids: @@ -51,22 +51,12 @@ def action_done(self, cr, uid, ids, context=None): picking.id, picking_method) return res - def copy(self, cr, uid, id, default=None, context=None): - if default is None: - default = {} - else: - default = default.copy() - default['related_backorder_ids'] = False - return super(stock_picking, self).copy(cr, uid, - id, default, context=context) - - def write(self, cr, uid, ids, vals, context=None): - if not hasattr(ids, '__iter__'): - ids = [ids] - res = super(stock_picking, self).write(cr, uid, ids, - vals, context=context) + @api.multi + def write(self, vals): + res = super(StockPicking, self).write(vals) if vals.get('carrier_tracking_ref'): - session = ConnectorSession(cr, uid, context=context) - for record_id in ids: + session = ConnectorSession(self.env.cr, self.env.uid, + context=self.env.context) + for record_id in self.ids: on_tracking_number_added.fire(session, self._name, record_id) return res diff --git a/connector_ecommerce/tests/test_invoice_event.py b/connector_ecommerce/tests/test_invoice_event.py index f5c7195a..9a240a55 100644 --- a/connector_ecommerce/tests/test_invoice_event.py +++ b/connector_ecommerce/tests/test_invoice_event.py @@ -20,48 +20,39 @@ ############################################################################## import mock -from functools import partial import openerp.tests.common as common -from openerp import netsvc -class test_invoice_event(common.TransactionCase): +class TestInvoiceEvent(common.TransactionCase): """ Test if the events on the invoice are fired correctly """ def setUp(self): - super(test_invoice_event, self).setUp() - cr, uid = self.cr, self.uid - self.invoice_model = self.registry('account.invoice') - partner_model = self.registry('res.partner') - partner_id = partner_model.create(cr, uid, {'name': 'Hodor'}) - data_model = self.registry('ir.model.data') - self.get_ref = partial(data_model.get_object_reference, cr, uid) - product_id = self.get_ref('product', 'product_product_6')[1] - invoice_vals = {'partner_id': partner_id, + super(TestInvoiceEvent, self).setUp() + self.invoice_model = self.env['account.invoice'] + partner_model = self.env['res.partner'] + partner = partner_model.create({'name': 'Hodor'}) + product = self.env.ref('product.product_product_6') + invoice_vals = {'partner_id': partner.id, 'type': 'out_invoice', 'invoice_line': [(0, 0, {'name': "LCD Screen", - 'product_id': product_id, + 'product_id': product.id, 'quantity': 5, 'price_unit': 200})], } - onchange_res = self.invoice_model.onchange_partner_id( - cr, uid, [], 'out_invoice', partner_id) + onchange_res = self.invoice_model.onchange_partner_id('out_invoice', + partner.id) invoice_vals.update(onchange_res['value']) - invoice_id = self.invoice_model.create(cr, uid, invoice_vals) - self.invoice = self.invoice_model.browse(cr, uid, invoice_id) + self.invoice = self.invoice_model.create(invoice_vals) def test_event_validated(self): """ Test if the ``on_invoice_validated`` event is fired when an invoice is validated """ - cr, uid = self.cr, self.uid assert self.invoice, "The invoice has not been created" - wf_service = netsvc.LocalService('workflow') event = ('openerp.addons.connector_ecommerce.' 'invoice.on_invoice_validated') with mock.patch(event) as event_mock: - wf_service.trg_validate(uid, 'account.invoice', - self.invoice.id, 'invoice_open', cr) + self.invoice.signal_workflow('invoice_open') self.assertEqual(self.invoice.state, 'open') event_mock.fire.assert_called_with(mock.ANY, 'account.invoice', @@ -70,27 +61,23 @@ def test_event_validated(self): def test_event_paid(self): """ Test if the ``on_invoice_paid`` event is fired when an invoice is paid """ - cr, uid = self.cr, self.uid assert self.invoice, "The invoice has not been created" - wf_service = netsvc.LocalService('workflow') - wf_service.trg_validate(uid, 'account.invoice', - self.invoice.id, 'invoice_open', cr) + self.invoice.signal_workflow('invoice_open') self.assertEqual(self.invoice.state, 'open') - journal_id = self.get_ref('account', 'bank_journal')[1] - pay_account_id = self.get_ref('account', 'cash')[1] - period_id = self.get_ref('account', 'period_10')[1] + journal = self.env.ref('account.bank_journal') + pay_account = self.env.ref('account.cash') + period = self.env.ref('account.period_10') event = 'openerp.addons.connector_ecommerce.invoice.on_invoice_paid' with mock.patch(event) as event_mock: self.invoice.pay_and_reconcile( pay_amount=self.invoice.amount_total, - pay_account_id=pay_account_id, - period_id=period_id, - pay_journal_id=journal_id, - writeoff_acc_id=pay_account_id, - writeoff_period_id=period_id, - writeoff_journal_id=journal_id, + pay_account_id=pay_account.id, + period_id=period.id, + pay_journal_id=journal.id, + writeoff_acc_id=pay_account.id, + writeoff_period_id=period.id, + writeoff_journal_id=journal.id, name="Payment for test of the event on_invoice_paid") - self.invoice.refresh() self.assertEqual(self.invoice.state, 'paid') event_mock.fire.assert_called_with(mock.ANY, 'account.invoice', diff --git a/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py index 2d437e0b..de8df8c7 100644 --- a/connector_ecommerce/tests/test_onchange.py +++ b/connector_ecommerce/tests/test_onchange.py @@ -21,7 +21,6 @@ ############################################################################### import mock -from operator import attrgetter from openerp.addons.connector_ecommerce.unit.sale_order_onchange import ( SaleOrderOnChange) @@ -33,11 +32,11 @@ ADMIN_USER_ID = common.ADMIN_USER_ID -class test_onchange(common.TransactionCase): +class TestOnchange(common.TransactionCase): """ Test if the onchanges are applied correctly on a sale order""" def setUp(self): - super(test_onchange, self).setUp() + super(TestOnchange, self).setUp() self.session = ConnectorSession(self.cr, self.uid) def test_play_onchange(self): @@ -45,8 +44,6 @@ def test_play_onchange(self): product_model = self.env['product.product'] partner_model = self.env['res.partner'] tax_model = self.env['account.tax'] - sale_model = self.env['sale.order'] - sale_line_model = self.env['sale.order.line'] payment_method_model = self.env['payment.method'] backend_record = mock.Mock() diff --git a/connector_ecommerce/wizard/sale_ignore_cancel.py b/connector_ecommerce/wizard/sale_ignore_cancel.py index aa57c9dd..e58de7db 100644 --- a/connector_ecommerce/wizard/sale_ignore_cancel.py +++ b/connector_ecommerce/wizard/sale_ignore_cancel.py @@ -19,28 +19,20 @@ # ############################################################################## -from openerp.osv import orm, fields +from openerp import models, fields, api -class sale_ignore_cancel(orm.TransientModel): +class SaleIgnoreCancel(models.TransientModel): _name = 'sale.ignore.cancel' _description = 'Ignore Sales Order Cancel' - _columns = { - 'reason': fields.html('Reason', required=True), - } + reason = fields.Html(required=True) - def confirm_ignore_cancel(self, cr, uid, ids, context=None): - if context is None: - context = {} - if isinstance(ids, (list, tuple)): - assert len(ids) == 1 - ids = ids[0] - order_ids = context.get('active_ids') - if order_ids is None: - return - form = self.browse(cr, uid, ids, context=context) - self.pool.get('sale.order').ignore_cancellation(cr, uid, order_ids, - form.reason, - context=context) + @api.multi + def confirm_ignore_cancel(self): + self.ensure_one() + sale_ids = self.env.context.get('active_ids') + assert sale_ids + sales = self.env['sale.order'].browse(sale_ids) + sales.ignore_cancellation(self.reason) return {'type': 'ir.actions.act_window_close'} From 86dc4edd23944cd40a81674fe4d9075ca3bf9a86 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 3 Mar 2015 22:25:29 +0100 Subject: [PATCH 12/18] Correctly raise the event when a picking becomes 'done' --- connector_ecommerce/stock.py | 41 ++++++----- connector_ecommerce/tests/__init__.py | 1 + .../tests/test_picking_event.py | 70 +++++++++++++++++++ 3 files changed, 95 insertions(+), 17 deletions(-) create mode 100644 connector_ecommerce/tests/test_picking_event.py diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py index d8649785..59ad5ac3 100644 --- a/connector_ecommerce/stock.py +++ b/connector_ecommerce/stock.py @@ -34,23 +34,6 @@ class StockPicking(models.Model): string="Related backorders", ) - @api.multi - def action_done(self): - res = super(StockPicking, self).action_done() - session = ConnectorSession(self.env.cr, self.env.uid, - context=self.env.context) - # Look if it exists a backorder, in that case call for partial - for picking in self: - if picking.picking_type_id.code != 'outgoing': - continue - if picking.related_backorder_ids: - picking_method = 'partial' - else: - picking_method = 'complete' - on_picking_out_done.fire(session, self._name, - picking.id, picking_method) - return res - @api.multi def write(self, vals): res = super(StockPicking, self).write(vals) @@ -60,3 +43,27 @@ def write(self, vals): for record_id in self.ids: on_tracking_number_added.fire(session, self._name, record_id) return res + + +class StockMove(models.Model): + _inherit = 'stock.move' + + @api.multi + def action_done(self): + pickings = self.mapped('picking_id') + states = {p.id: p.state for p in pickings} + result = super(StockMove, self).action_done() + session = ConnectorSession(self.env.cr, self.env.uid, + context=self.env.context) + for picking in pickings: + if states[picking.id] != 'done' and picking.state == 'done': + if picking.picking_type_id.code != 'outgoing': + continue + if picking.related_backorder_ids: + picking_method = 'partial' + else: + picking_method = 'complete' + on_picking_out_done.fire(session, 'stock.picking', + picking.id, picking_method) + + return result diff --git a/connector_ecommerce/tests/__init__.py b/connector_ecommerce/tests/__init__.py index 6fae4820..f514ea16 100644 --- a/connector_ecommerce/tests/__init__.py +++ b/connector_ecommerce/tests/__init__.py @@ -21,3 +21,4 @@ from . import test_onchange from . import test_invoice_event +from . import test_picking_event diff --git a/connector_ecommerce/tests/test_picking_event.py b/connector_ecommerce/tests/test_picking_event.py new file mode 100644 index 00000000..a3f0084d --- /dev/null +++ b/connector_ecommerce/tests/test_picking_event.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Copyright 2015 Camptocamp SA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import mock + +import openerp.tests.common as common + + +class TestPickingEvent(common.TransactionCase): + """ Test if the events on the pickings are fired correctly """ + + def setUp(self): + super(TestPickingEvent, self).setUp() + self.picking_model = self.env['stock.picking'] + self.sale_model = self.env['sale.order'] + self.sale_line_model = self.env['sale.order.line'] + + partner_model = self.env['res.partner'] + partner = partner_model.create({'name': 'Benjy'}) + self.sale = self.sale_model.create({'partner_id': partner.id}) + self.sale_line_model.create({ + 'order_id': self.sale.id, + 'product_id': self.env.ref('product.product_product_33').id, + 'name': "[HEAD-USB] Headset USB", + 'product_uom_qty': 42, + 'product_uom': self.env.ref('product.product_uom_unit').id, + 'price_unit': 65, + }) + self.sale_line_model.create({ + 'order_id': self.sale.id, + 'product_id': self.env.ref('product.product_product_28').id, + 'name': "[EXT-HDD] External Hard disk", + 'product_uom_qty': 2, + 'product_uom': self.env.ref('product.product_uom_unit').id, + 'price_unit': 405, + }) + self.sale.signal_workflow('order_confirm') + self.picking = self.sale.picking_ids + + def test_event_on_picking_out_done(self): + """ Test if the ``on_picking_out_done`` event is fired + when an outgoing picking is done """ + self.picking.force_assign() + event = ('openerp.addons.connector_ecommerce.' + 'stock.on_picking_out_done') + with mock.patch(event) as event_mock: + self.picking.action_done() + self.assertEquals(self.picking.state, 'done') + event_mock.fire.assert_called_with(mock.ANY, + 'stock.picking', + self.picking.id, + 'complete') From 322689f4cebceb5e11838a0502aa65c33da08429 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 5 Mar 2015 10:31:07 +0100 Subject: [PATCH 13/18] Test that on_tracking_number_added is fired --- connector_ecommerce/tests/test_picking_event.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/connector_ecommerce/tests/test_picking_event.py b/connector_ecommerce/tests/test_picking_event.py index a3f0084d..4ea0bdb3 100644 --- a/connector_ecommerce/tests/test_picking_event.py +++ b/connector_ecommerce/tests/test_picking_event.py @@ -68,3 +68,14 @@ def test_event_on_picking_out_done(self): 'stock.picking', self.picking.id, 'complete') + + def test_event_on_tracking_number_added(self): + """ Test if the ``on_tracking_number_added`` event is fired + when a tracking number is added """ + event = ('openerp.addons.connector_ecommerce.' + 'stock.on_tracking_number_added') + with mock.patch(event) as event_mock: + self.picking.carrier_tracking_ref = 'XYZ' + event_mock.fire.assert_called_with(mock.ANY, + 'stock.picking', + self.picking.id) From b65f2b8e7cfa2deefc30119b6bd8cc49ab339bbd Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 5 Mar 2015 11:08:03 +0100 Subject: [PATCH 14/18] Correctly fire the event for partial pickings --- connector_ecommerce/stock.py | 51 ++++++++++++++----- .../tests/test_picking_event.py | 17 +++++++ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py index 59ad5ac3..f0132c79 100644 --- a/connector_ecommerce/stock.py +++ b/connector_ecommerce/stock.py @@ -44,26 +44,49 @@ def write(self, vals): on_tracking_number_added.fire(session, self._name, record_id) return res + @api.multi + def do_transfer(self): + # The key in the context avoid the event to be fired in + # StockMove.action_done(). Allow to handle the partial pickings + self_context = self.with_context(__no_on_event_out_done=True) + result = super(StockPicking, self_context).do_transfer() + session = ConnectorSession(self.env.cr, self.env.uid, + context=self.env.context) + for picking in self: + if picking.picking_type_id.code != 'outgoing': + continue + if picking.related_backorder_ids: + method = 'partial' + else: + method = 'complete' + on_picking_out_done.fire(session, 'stock.picking', + picking.id, method) + + return result + class StockMove(models.Model): _inherit = 'stock.move' @api.multi def action_done(self): - pickings = self.mapped('picking_id') - states = {p.id: p.state for p in pickings} + fire_event = not self.env.context.get('__no_on_event_out_done') + if fire_event: + pickings = self.mapped('picking_id') + states = {p.id: p.state for p in pickings} + result = super(StockMove, self).action_done() - session = ConnectorSession(self.env.cr, self.env.uid, - context=self.env.context) - for picking in pickings: - if states[picking.id] != 'done' and picking.state == 'done': - if picking.picking_type_id.code != 'outgoing': - continue - if picking.related_backorder_ids: - picking_method = 'partial' - else: - picking_method = 'complete' - on_picking_out_done.fire(session, 'stock.picking', - picking.id, picking_method) + + if fire_event: + session = ConnectorSession(self.env.cr, self.env.uid, + context=self.env.context) + for picking in pickings: + if states[picking.id] != 'done' and picking.state == 'done': + if picking.picking_type_id.code != 'outgoing': + continue + # partial pickings are handled in + # StockPicking.do_transfer() + on_picking_out_done.fire(session, 'stock.picking', + picking.id, 'complete') return result diff --git a/connector_ecommerce/tests/test_picking_event.py b/connector_ecommerce/tests/test_picking_event.py index 4ea0bdb3..b4d03cfc 100644 --- a/connector_ecommerce/tests/test_picking_event.py +++ b/connector_ecommerce/tests/test_picking_event.py @@ -69,6 +69,23 @@ def test_event_on_picking_out_done(self): self.picking.id, 'complete') + def test_event_on_picking_out_done_partial(self): + """ Test if the ``on_picking_out_done`` informs of the partial + pickings """ + self.picking.force_assign() + self.picking.do_prepare_partial() + for operation in self.picking.pack_operation_ids: + operation.product_qty = 1 + event = ('openerp.addons.connector_ecommerce.' + 'stock.on_picking_out_done') + with mock.patch(event) as event_mock: + self.picking.do_transfer() + self.assertEquals(self.picking.state, 'done') + event_mock.fire.assert_called_with(mock.ANY, + 'stock.picking', + self.picking.id, + 'partial') + def test_event_on_tracking_number_added(self): """ Test if the ``on_tracking_number_added`` event is fired when a tracking number is added """ From 33156d6debf1c4eef3d64d1f91950faa007289a6 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 19 Feb 2015 09:58:07 +0100 Subject: [PATCH 15/18] Update the manifest and description; bump to 3.0.0 --- connector_ecommerce/README.rst | 66 ++++++++++++++++++++++++++++++ connector_ecommerce/__openerp__.py | 39 ++---------------- 2 files changed, 69 insertions(+), 36 deletions(-) create mode 100644 connector_ecommerce/README.rst diff --git a/connector_ecommerce/README.rst b/connector_ecommerce/README.rst new file mode 100644 index 00000000..7130e2ae --- /dev/null +++ b/connector_ecommerce/README.rst @@ -0,0 +1,66 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :alt: License + +Connector for E-Commerce +======================== + +This modules aims to be a common layer for the connectors dealing with +e-commerce. + +It sits on top of the `connector`_ framework and is used by the +e-commerce connectors, like `magentoerpconnect`_ or +`prestashoperpconnect`_. + +That's a technical module, which include amongst other things: + +Events + + On which the connectors can subscribe consumers + (tracking number added, invoice paid, picking sent, ...) + +ConnectorUnit + + A piece of code which allows to play all the ``onchanges`` required + when we create a sale order. + + Another one which allows to add special lines in imported sales orders + such as Shipping fees, Cash on Delivery or Discounts. + +Data Model + + Add structures shared for e-commerce connectors + +.. _`connector`: http://odoo-connector.com +.. _`magentoerpconnect`: http://odoo-magento-connector.com +.. _`prestashoperpconnect`: https://github.com/OCA/connector-prestashop + +Installation +============ + +This module is a dependency for more advanced connectors. It does +nothing on its own and there is no reason to install it alone. + +Credits +======= + +Contributors +------------ + +See `contributors' list`_ + +.. _contributors' list: ./AUTHORS + +Maintainer +---------- + +.. image:: http://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: http://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization +whose mission is to support the collaborative development of Odoo +features and promote its widespread use. + +To contribute to this module, please visit http://odoo-community.org. diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py index d9f558d4..172ee88e 100644 --- a/connector_ecommerce/__openerp__.py +++ b/connector_ecommerce/__openerp__.py @@ -20,44 +20,11 @@ ############################################################################## {'name': 'Connector for E-Commerce', - 'version': '2.2.0', - 'category': 'Connector', - 'author': "Connector Core Editors,Odoo Community Association (OCA)", + 'version': '3.0.0', + 'category': 'Hidden', + 'author': "Camptocamp,Akretion,Odoo Community Association (OCA)", 'website': 'http://openerp-connector.com', 'license': 'AGPL-3', - 'description': """ -Connector for E-Commerce -======================== - -This modules aims to be a common layer for the connectors dealing with -e-commerce. - -It sits on top of the `connector`_ framework and is used by the -e-commerce connectors, like `magentoerpconnect`_ or -`prestashoperpconnect`_. - -That's a technical module, which include amongst other things: - -Events - - On which the connectors can subscribe consumers - (tracking number added, invoice paid, picking sent, ...) - - -ConnectorUnit - - A piece of code which allows to play all the ``onchanges`` required - when we create a sale order. - -Data Model - - Add structures shared for e-commerce connectors - - - .. _`connector`: http://openerp-connector.com -.. _`magentoerpconnect`: http://openerp-magento-connector.com -.. _`prestashoperpconnect`: https://launchpad.net/prestashoperpconnect -""", 'depends': [ 'connector', 'sale_payment_method_automatic_workflow', From 6afc8d56f59a453c407ae5ebe73c1e35665bfe3a Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 13 May 2015 11:40:12 +0200 Subject: [PATCH 16/18] Correction of typos --- connector_ecommerce/i18n/connector_ecommerce.pot | 2 +- connector_ecommerce/i18n/de.po | 2 +- connector_ecommerce/i18n/es.po | 2 +- connector_ecommerce/i18n/fr.po | 2 +- connector_ecommerce/i18n/nl.po | 2 +- connector_ecommerce/payment_method.py | 2 +- connector_ecommerce/product.py | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/connector_ecommerce/i18n/connector_ecommerce.pot b/connector_ecommerce/i18n/connector_ecommerce.pot index f2f7538d..5b338932 100644 --- a/connector_ecommerce/i18n/connector_ecommerce.pot +++ b/connector_ecommerce/i18n/connector_ecommerce.pot @@ -163,7 +163,7 @@ msgstr "" #. module: connector_ecommerce #: help:product.template,tax_group_id:0 -msgid "Tax group are used with some external system like magento or prestashop" +msgid "Tax groups are used with some external system like magento or prestashop" msgstr "" #. module: connector_ecommerce diff --git a/connector_ecommerce/i18n/de.po b/connector_ecommerce/i18n/de.po index 40d89a8c..5b72bb71 100644 --- a/connector_ecommerce/i18n/de.po +++ b/connector_ecommerce/i18n/de.po @@ -185,7 +185,7 @@ msgstr "Weitere Informationen" #. module: connector_ecommerce #: help:product.template,tax_group_id:0 msgid "" -"Tax group are used with some external system like magento or prestashop" +"Tax groups are used with some external system like magento or prestashop" msgstr "" "Steuergruppen werden für einige externe Systeme wie Magento oder Prestashop " "genutzt." diff --git a/connector_ecommerce/i18n/es.po b/connector_ecommerce/i18n/es.po index 6a476ce3..56d569dd 100644 --- a/connector_ecommerce/i18n/es.po +++ b/connector_ecommerce/i18n/es.po @@ -186,7 +186,7 @@ msgstr "Otra información" #. module: connector_ecommerce #: help:product.template,tax_group_id:0 msgid "" -"Tax group are used with some external system like magento or prestashop" +"Tax groups are used with some external system like magento or prestashop" msgstr "" "El grupo fiscal se usa con algún sistema externo como magento do prestashop" diff --git a/connector_ecommerce/i18n/fr.po b/connector_ecommerce/i18n/fr.po index 19357ee2..391c21ce 100644 --- a/connector_ecommerce/i18n/fr.po +++ b/connector_ecommerce/i18n/fr.po @@ -184,7 +184,7 @@ msgstr "Autres informations" #. module: connector_ecommerce #: help:product.template,tax_group_id:0 msgid "" -"Tax group are used with some external system like magento or prestashop" +"Tax groups are used with some external system like magento or prestashop" msgstr "" "Les groupes de taxes sont utilisés avec des systèmes externes comme Magento " "ou Prestashop." diff --git a/connector_ecommerce/i18n/nl.po b/connector_ecommerce/i18n/nl.po index 67153249..2e873297 100644 --- a/connector_ecommerce/i18n/nl.po +++ b/connector_ecommerce/i18n/nl.po @@ -183,7 +183,7 @@ msgstr "Overige informatie" #. module: connector_ecommerce #: help:product.template,tax_group_id:0 msgid "" -"Tax group are used with some external system like magento or prestashop" +"Tax groups are used with some external system like magento or prestashop" msgstr "" "BTW groepen worden gebruikt met sommige externe systemen, zoals Magento of " "Prestashop." diff --git a/connector_ecommerce/payment_method.py b/connector_ecommerce/payment_method.py index ae4a67a4..58bd1372 100644 --- a/connector_ecommerce/payment_method.py +++ b/connector_ecommerce/payment_method.py @@ -48,7 +48,7 @@ def _get_import_rules(self): @api.model def get_or_create_payment_method(self, payment_method): - """ try to get id of 'payment_method' or create if not exists + """ Try to get a payment method or create if it doesn't exist :param payment_method: payment method like PayPal, etc. :type payment_method: str diff --git a/connector_ecommerce/product.py b/connector_ecommerce/product.py index 320c93fc..f2c975a9 100644 --- a/connector_ecommerce/product.py +++ b/connector_ecommerce/product.py @@ -38,7 +38,7 @@ def _get_tax_group_id(self): comodel_name='account.tax.group', compute='_get_tax_group_id', string='Tax Group', - help='Tax group are used with some external ' + help='Tax groups are used with some external ' 'system like Prestashop', ) From 1732c87b56da643cb52a2aabb015909f5e66bef4 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 13 May 2015 11:41:22 +0200 Subject: [PATCH 17/18] Use @api.one as we have nothing outside the loop --- connector_ecommerce/product.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/connector_ecommerce/product.py b/connector_ecommerce/product.py index f2c975a9..7abb6fa8 100644 --- a/connector_ecommerce/product.py +++ b/connector_ecommerce/product.py @@ -28,11 +28,11 @@ class ProductTemplate(models.Model): _inherit = 'product.template' # TODO implement set function and also support multi tax + @api.one @api.depends('taxes_id', 'taxes_id.group_id') def _get_tax_group_id(self): - for template in self: - taxes = template.taxes_id - template.tax_group_id = taxes[0].group_id.id if taxes else False + taxes = self.taxes_id + self.tax_group_id = taxes[0].group_id.id if taxes else False tax_group_id = fields.Many2one( comodel_name='account.tax.group', From 628e030a945ef9062886e9b66ba1a1959a37f3d5 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 13 May 2015 11:53:45 +0200 Subject: [PATCH 18/18] Corrections of more typos --- connector_ecommerce/README.rst | 2 +- .../i18n/connector_ecommerce.pot | 10 ++--- connector_ecommerce/i18n/de.po | 10 ++--- connector_ecommerce/i18n/es.po | 10 ++--- connector_ecommerce/i18n/fr.po | 10 ++--- connector_ecommerce/i18n/nl.po | 10 ++--- connector_ecommerce/payment_method.py | 2 +- connector_ecommerce/sale.py | 24 +++++------ connector_ecommerce/tests/test_onchange.py | 4 +- .../unit/sale_order_onchange.py | 40 +++++++++---------- 10 files changed, 61 insertions(+), 61 deletions(-) diff --git a/connector_ecommerce/README.rst b/connector_ecommerce/README.rst index 7130e2ae..56e5087a 100644 --- a/connector_ecommerce/README.rst +++ b/connector_ecommerce/README.rst @@ -21,7 +21,7 @@ Events ConnectorUnit A piece of code which allows to play all the ``onchanges`` required - when we create a sale order. + when we create a sales order. Another one which allows to add special lines in imported sales orders such as Shipping fees, Cash on Delivery or Discounts. diff --git a/connector_ecommerce/i18n/connector_ecommerce.pot b/connector_ecommerce/i18n/connector_ecommerce.pot index 5b338932..09671056 100644 --- a/connector_ecommerce/i18n/connector_ecommerce.pot +++ b/connector_ecommerce/i18n/connector_ecommerce.pot @@ -173,7 +173,7 @@ msgstr "" #. module: connector_ecommerce #: field:sale.order,parent_need_cancel:0 -msgid "A parent sales orders needs cancel" +msgid "A parent sales order needs cancel" msgstr "" #. module: connector_ecommerce @@ -215,7 +215,7 @@ msgstr "" #. module: connector_ecommerce #: help:sale.order,parent_need_cancel:0 -msgid "A parent sales orders has been canceled on the backend and needs to be canceled." +msgid "A parent sales order has been canceled on the backend and needs to be canceled." msgstr "" #. module: connector_ecommerce @@ -251,7 +251,7 @@ msgstr "" #. module: connector_ecommerce #: help:payment.method,days_before_cancel:0 -msgid "After 'n' days, if the 'Import Rule' is not fulfilled, the import of the sale order will be canceled." +msgid "After 'n' days, if the 'Import Rule' is not fulfilled, the import of the sales order will be canceled." msgstr "" #. module: connector_ecommerce @@ -281,7 +281,7 @@ msgstr "" #. module: connector_ecommerce #: help:account.invoice,sale_order_ids:0 -msgid "This is the list of sale orders related to this invoice." +msgid "This is the list of sales orders related to this invoice." msgstr "" #. module: connector_ecommerce @@ -329,7 +329,7 @@ msgstr "" #. module: connector_ecommerce #: field:account.invoice,sale_order_ids:0 -msgid "Sale Orders" +msgid "Sales Orders" msgstr "" #. module: connector_ecommerce diff --git a/connector_ecommerce/i18n/de.po b/connector_ecommerce/i18n/de.po index 5b72bb71..b9e01765 100644 --- a/connector_ecommerce/i18n/de.po +++ b/connector_ecommerce/i18n/de.po @@ -197,7 +197,7 @@ msgstr "Preislistenartikel" #. module: connector_ecommerce #: field:sale.order,parent_need_cancel:0 -msgid "A parent sales orders needs cancel" +msgid "A parent sales order needs cancel" msgstr "Eine übergeordnete" #. module: connector_ecommerce @@ -246,7 +246,7 @@ msgstr "" #. module: connector_ecommerce #: help:sale.order,parent_need_cancel:0 msgid "" -"A parent sales orders has been canceled on the backend and needs to be " +"A parent sales order has been canceled on the backend and needs to be " "canceled." msgstr "" "Ein übergeordneter VK-Auftrag wurde im Backend abgebrochen und muss " @@ -287,7 +287,7 @@ msgstr "VK-Auftrag" #: help:payment.method,days_before_cancel:0 msgid "" "After 'n' days, if the 'Import Rule' is not fulfilled, the import of the " -"sale order will be canceled." +"sales order will be canceled." msgstr "" "Nach 'n' Tagen, wenn die 'Import Regel' nicht erfüllt ist, wird der Import " "abgebrochen." @@ -319,7 +319,7 @@ msgstr "Im Backend abgebrochen" #. module: connector_ecommerce #: help:account.invoice,sale_order_ids:0 -msgid "This is the list of sale orders related to this invoice." +msgid "This is the list of sales orders related to this invoice." msgstr "" "Dies ist die Liste der VK-Aufträge welche mit dieser Rechnung in beziehung " "stehen." @@ -369,7 +369,7 @@ msgstr "Name" #. module: connector_ecommerce #: field:account.invoice,sale_order_ids:0 -msgid "Sale Orders" +msgid "Sales Orders" msgstr "VK-Aufträge" #. module: connector_ecommerce diff --git a/connector_ecommerce/i18n/es.po b/connector_ecommerce/i18n/es.po index 56d569dd..3701bc7f 100644 --- a/connector_ecommerce/i18n/es.po +++ b/connector_ecommerce/i18n/es.po @@ -197,7 +197,7 @@ msgstr "Listado de Precios de Artículos" #. module: connector_ecommerce #: field:sale.order,parent_need_cancel:0 -msgid "A parent sales orders needs cancel" +msgid "A parent sales order needs cancel" msgstr "Una orden de venta padre debe cancelar" #. module: connector_ecommerce @@ -248,7 +248,7 @@ msgstr "Debe ser cancelado" #. module: connector_ecommerce #: help:sale.order,parent_need_cancel:0 msgid "" -"A parent sales orders has been canceled on the backend and needs to be " +"A parent sales order has been canceled on the backend and needs to be " "canceled." msgstr "" "Una orden de venta padre ha sido cancelada en el área de administración y " @@ -289,7 +289,7 @@ msgstr "Pedidos de venta" #: help:payment.method,days_before_cancel:0 msgid "" "After 'n' days, if the 'Import Rule' is not fulfilled, the import of the " -"sale order will be canceled." +"sales order will be canceled." msgstr "" "Después de 'n' días, si la 'Regla de Importación' no está realizada, la " "importación de la orden de venta será cancelada." @@ -321,7 +321,7 @@ msgstr "Cancelado en el área de administración" #. module: connector_ecommerce #: help:account.invoice,sale_order_ids:0 -msgid "This is the list of sale orders related to this invoice." +msgid "This is the list of sales orders related to this invoice." msgstr "Esta es la lista de pedidos de venta relacionados con esta factura." #. module: connector_ecommerce @@ -370,7 +370,7 @@ msgstr "Nombre" #. module: connector_ecommerce #: field:account.invoice,sale_order_ids:0 -msgid "Sale Orders" +msgid "Sales Orders" msgstr "Pedido de Venta" #. module: connector_ecommerce diff --git a/connector_ecommerce/i18n/fr.po b/connector_ecommerce/i18n/fr.po index 391c21ce..7c98b831 100644 --- a/connector_ecommerce/i18n/fr.po +++ b/connector_ecommerce/i18n/fr.po @@ -196,7 +196,7 @@ msgstr "Lignes de liste de prix" #. module: connector_ecommerce #: field:sale.order,parent_need_cancel:0 -msgid "A parent sales orders needs cancel" +msgid "A parent sales order needs cancel" msgstr "Une commande parente doit être annulée" #. module: connector_ecommerce @@ -248,7 +248,7 @@ msgstr "Doit être annulée" #. module: connector_ecommerce #: help:sale.order,parent_need_cancel:0 msgid "" -"A parent sales orders has been canceled on the backend and needs to be " +"A parent sales order has been canceled on the backend and needs to be " "canceled." msgstr "" "Une commande parente a été annulée sur le backend et doit être annulée." @@ -288,7 +288,7 @@ msgstr "Bon de commande" #: help:payment.method,days_before_cancel:0 msgid "" "After 'n' days, if the 'Import Rule' is not fulfilled, the import of the " -"sale order will be canceled." +"sales order will be canceled." msgstr "" "Après \"n\" jours, si la règle d'import n'est pas satisfaite, l'import de la " "commande sera annulé." @@ -320,7 +320,7 @@ msgstr "Annulée dans le backend" #. module: connector_ecommerce #: help:account.invoice,sale_order_ids:0 -msgid "This is the list of sale orders related to this invoice." +msgid "This is the list of sales orders related to this invoice." msgstr "Liste des commandes liées à cette facture." #. module: connector_ecommerce @@ -368,7 +368,7 @@ msgstr "Nom" #. module: connector_ecommerce #: field:account.invoice,sale_order_ids:0 -msgid "Sale Orders" +msgid "Sales Orders" msgstr "Bons de commande" #. module: connector_ecommerce diff --git a/connector_ecommerce/i18n/nl.po b/connector_ecommerce/i18n/nl.po index 2e873297..b05be271 100644 --- a/connector_ecommerce/i18n/nl.po +++ b/connector_ecommerce/i18n/nl.po @@ -195,7 +195,7 @@ msgstr "Prijslijst items" #. module: connector_ecommerce #: field:sale.order,parent_need_cancel:0 -msgid "A parent sales orders needs cancel" +msgid "A parent sales order needs cancel" msgstr "Een bovenliggende verkooporder dient te worden geannuleerd" #. module: connector_ecommerce @@ -246,7 +246,7 @@ msgstr "Dient te worden geannuleerd" #. module: connector_ecommerce #: help:sale.order,parent_need_cancel:0 msgid "" -"A parent sales orders has been canceled on the backend and needs to be " +"A parent sales order has been canceled on the backend and needs to be " "canceled." msgstr "" "Een bovenliggende verkooporder is geannuleerd in de backend en dient te " @@ -287,7 +287,7 @@ msgstr "Verkooporder" #: help:payment.method,days_before_cancel:0 msgid "" "After 'n' days, if the 'Import Rule' is not fulfilled, the import of the " -"sale order will be canceled." +"sales order will be canceled." msgstr "" "Als na 'n' dagen niet aan de 'import regel' is voldaan, wordt de import van " "de verkooporder geannuleerd." @@ -319,7 +319,7 @@ msgstr "Geannuleerd in backend" #. module: connector_ecommerce #: help:account.invoice,sale_order_ids:0 -msgid "This is the list of sale orders related to this invoice." +msgid "This is the list of sales orders related to this invoice." msgstr "" "Dit is een lijst met alle verkooporders gerelateerd aan deze factuur." @@ -370,7 +370,7 @@ msgstr "Naam" #. module: connector_ecommerce #: field:account.invoice,sale_order_ids:0 -msgid "Sale Orders" +msgid "Sales Orders" msgstr "Verkooporders" #. module: connector_ecommerce diff --git a/connector_ecommerce/payment_method.py b/connector_ecommerce/payment_method.py index 58bd1372..028b19bd 100644 --- a/connector_ecommerce/payment_method.py +++ b/connector_ecommerce/payment_method.py @@ -39,7 +39,7 @@ def _get_import_rules(self): string='Days before cancel', default=30, help="After 'n' days, if the 'Import Rule' is not fulfilled, the " - "import of the sale order will be canceled.", + "import of the sales order will be canceled.", ) import_rule = fields.Selection(selection='_get_import_rules', string="Import Rule", diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py index feda0a36..e8fe1b93 100644 --- a/connector_ecommerce/sale.py +++ b/connector_ecommerce/sale.py @@ -32,7 +32,7 @@ class SaleOrder(models.Model): """ Add a cancellation mecanism in the sales orders - When a sale order is canceled in a backend, the connectors can flag + When a sales order is canceled in a backend, the connectors can flag the 'canceled_in_backend' flag. It will: * try to automatically cancel the sales order @@ -42,9 +42,9 @@ class SaleOrder(models.Model): to 'keep it open', the flag 'cancellation_resolved' is set to True. The second axe which can be used by the connectors is the 'parent' - sale order. When a sales order has a parent sales order (logic to + sales order. When a sales order has a parent sales order (logic to link with the parent to be defined by each connector), it will be - blocked until the cancellation of the sale order is resolved. + blocked until the cancellation of the sales order is resolved. This is used by, for instance, the magento connector, when one modifies a sales order, Magento cancels it and create a new one with @@ -56,7 +56,7 @@ class SaleOrder(models.Model): readonly=True) # set to True when the cancellation from the backend is # resolved, either because the SO has been canceled or - # because the user manually chosed to keep it open + # because the user manually chose to keep it open cancellation_resolved = fields.Boolean(string='Cancellation from the ' 'backend resolved') parent_id = fields.Many2one(comodel_name='sale.order', @@ -70,8 +70,8 @@ class SaleOrder(models.Model): ', need to be canceled.') parent_need_cancel = fields.Boolean( compute='_parent_need_cancel', - string='A parent sales orders needs cancel', - help='A parent sales orders has been canceled on the backend' + string='A parent sales order needs cancel', + help='A parent sales order has been canceled on the backend' ' and needs to be canceled.', ) @@ -190,7 +190,7 @@ def write(self, values): def action_cancel(self): res = super(SaleOrder, self).action_cancel() for sale in self: - # the sale order is canceled => considered as resolved + # the sales order is canceled => considered as resolved if (sale.canceled_in_backend and not sale.cancellation_resolved): sale.write({'cancellation_resolved': True}) @@ -200,8 +200,8 @@ def action_cancel(self): def ignore_cancellation(self, reason): """ Manually set the cancellation from the backend as resolved. - The user can choose to keep the sale order active for some reason, - so it just push a button to keep it alive. + The user can choose to keep the sales order active for some reason, + it only requires to push a button to keep it alive. """ message = (_("Despite the cancellation of the sales order on the " "backend, it should stay open.

Reason: %s") % @@ -212,7 +212,7 @@ def ignore_cancellation(self, reason): @api.multi def action_view_parent(self): - """ Return an action to display the parent sale order """ + """ Return an action to display the parent sales order """ self.ensure_one() parent = self.parent_id @@ -234,9 +234,9 @@ def action_view_parent(self): class SpecialOrderLineBuilder(ConnectorUnit): - """ Base class to build a sale order line for a sale order + """ Base class to build a sales order line for a sales order - Used when extra order lines have to be added in a sale order + Used when extra order lines have to be added in a sales order but we only know some parameters (product, price, ...), for instance, a line for the shipping costs or the gift coupons. diff --git a/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py index de8df8c7..bced71b0 100644 --- a/connector_ecommerce/tests/test_onchange.py +++ b/connector_ecommerce/tests/test_onchange.py @@ -33,14 +33,14 @@ class TestOnchange(common.TransactionCase): - """ Test if the onchanges are applied correctly on a sale order""" + """ Test if the onchanges are applied correctly on a sales order""" def setUp(self): super(TestOnchange, self).setUp() self.session = ConnectorSession(self.cr, self.uid) def test_play_onchange(self): - """ Play the onchange ConnectorUnit on a sale order """ + """ Play the onchange ConnectorUnit on a sales order """ product_model = self.env['product.product'] partner_model = self.env['res.partner'] tax_model = self.env['account.tax'] diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py index 014ca40a..015832c8 100644 --- a/connector_ecommerce/unit/sale_order_onchange.py +++ b/connector_ecommerce/unit/sale_order_onchange.py @@ -47,10 +47,10 @@ class SaleOrderOnChange(OnChangeManager): def _get_partner_id_onchange_param(self, order): """ Prepare the arguments for calling the partner_id change - on sale order. You can overwrite this method in your own + on sales order. You can overwrite this method in your own module if they modify the onchange signature - :param order: a dictionary of the value of your sale order + :param order: a dictionary of the value of your sales order :type: dict :return: a tuple of args and kwargs for the onchange @@ -63,12 +63,12 @@ def _get_partner_id_onchange_param(self, order): return args, kwargs def _play_order_onchange(self, order): - """ Play the onchange of the sale order + """ Play the onchange of the sales order - :param order: a dictionary of the value of your sale order + :param order: a dictionary of the value of your sales order :type: dict - :return: the value of the sale order updated with the onchange result + :return: the value of the sales order updated with the onchange result :rtype: dict """ sale_model = self.env['sale.order'] @@ -113,14 +113,14 @@ def _play_order_onchange(self, order): def _get_product_id_onchange_param(self, line, previous_lines, order): """ Prepare the arguments for calling the product_id change - on sale order line. You can overwrite this method in your own + on sales order line. You can overwrite this method in your own module if they modify the onchange signature - :param line: the sale order line to process + :param line: the sales order line to process :type: dict :param previous_lines: list of dict of the previous lines processed :type: list - :param order: data of the sale order + :param order: data of the sales order :type: dict :return: a tuple of args and kwargs for the onchange @@ -160,16 +160,16 @@ def _get_product_id_onchange_param(self, line, previous_lines, order): return args, kwargs def _play_line_onchange(self, line, previous_lines, order): - """ Play the onchange of the sale order line + """ Play the onchange of the sales order line - :param line: the sale order line to process + :param line: the sales order line to process :type: dict :param previous_lines: list of dict of the previous line processed :type: list - :param order: data of the sale order + :param order: data of the sales order :type: dict - :return: the value of the sale order updated with the onchange result + :return: the value of the sales order updated with the onchange result :rtype: dict """ line_model = self.env['sale.order.line'] @@ -184,25 +184,25 @@ def _play_line_onchange(self, line, previous_lines, order): return line def play(self, order, order_lines): - """ Play the onchange of the sale order and it's lines + """ Play the onchange of the sales order and it's lines - It expects to receive a recordset containing one sale order. + It expects to receive a recordset containing one sales order. It could have been generated with ``self.env['sale.order'].new(values)`` or ``self.env['sale.order'].create(values)``. - :param order: data of the sale order + :param order: data of the sales order :type: recordset - :param order_lines: data of the sale order lines + :param order_lines: data of the sales order lines :type: recordset - :return: the sale order updated by the onchanges + :return: the sales order updated by the onchanges :rtype: recordset """ - # play onchange on sale order + # play onchange on sales order order = self._play_order_onchange(order) - # play onchange on sale order line + # play onchange on sales order line processed_order_lines = [] line_lists = [order_lines] if 'order_line' in order and order['order_line'] is not order_lines: @@ -223,6 +223,6 @@ def play(self, order, order_lines): command_line[1], new_line_data) processed_order_lines.append(new_line) - # in place modification of the sale order line in the list + # in place modification of the sales order line in the list line_list[idx] = new_line return order