From 58ea7849c40be4d3946ae29e72ea21a9af16b497 Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Tue, 19 Feb 2013 12:19:16 +0100
Subject: [PATCH 01/86] [CHG] rename 'base_sale_multichannels' to
'connector_ecommerce'
[FIX] decimal_precision import does not use openerp.addons namespace
---
connector_ecommerce/__init__.py | 34 +
connector_ecommerce/__openerp__.py | 85 ++
connector_ecommerce/account.py | 59 ++
connector_ecommerce/account_view.xml | 49 +
connector_ecommerce/base_sale_data.xml | 46 +
connector_ecommerce/connector.py | 37 +
connector_ecommerce/delivery.py | 30 +
connector_ecommerce/delivery_view.xml | 19 +
connector_ecommerce/external_referential.py | 83 ++
.../i18n/base_sale_multichannels.pot | 306 ++++++
connector_ecommerce/i18n/ca.po | 380 +++++++
connector_ecommerce/i18n/ca_ES.po | 334 ++++++
connector_ecommerce/i18n/es.po | 379 +++++++
connector_ecommerce/i18n/fr.po | 356 +++++++
connector_ecommerce/i18n/pt.po | 379 +++++++
connector_ecommerce/i18n/sv.po | 327 ++++++
connector_ecommerce/invoice.py | 43 +
connector_ecommerce/invoice_view.xml | 18 +
connector_ecommerce/partner.py | 50 +
connector_ecommerce/partner_view.xml | 28 +
connector_ecommerce/payment_method.py | 54 +
connector_ecommerce/payment_method_view.xml | 37 +
connector_ecommerce/product.py | 170 +++
connector_ecommerce/sale.py | 993 ++++++++++++++++++
connector_ecommerce/sale_view.xml | 200 ++++
.../security/ir.model.access.csv | 18 +
.../external.referential.category.csv | 2 +
.../settings/sale.exception.csv | 12 +
connector_ecommerce/stock.py | 50 +
connector_ecommerce/stock_view.xml | 15 +
connector_ecommerce/wizard/__init__.py | 23 +
connector_ecommerce/wizard/import_order.py | 42 +
connector_ecommerce/wizard/import_order.xml | 34 +
33 files changed, 4692 insertions(+)
create mode 100644 connector_ecommerce/__init__.py
create mode 100644 connector_ecommerce/__openerp__.py
create mode 100644 connector_ecommerce/account.py
create mode 100644 connector_ecommerce/account_view.xml
create mode 100644 connector_ecommerce/base_sale_data.xml
create mode 100644 connector_ecommerce/connector.py
create mode 100644 connector_ecommerce/delivery.py
create mode 100644 connector_ecommerce/delivery_view.xml
create mode 100644 connector_ecommerce/external_referential.py
create mode 100644 connector_ecommerce/i18n/base_sale_multichannels.pot
create mode 100644 connector_ecommerce/i18n/ca.po
create mode 100644 connector_ecommerce/i18n/ca_ES.po
create mode 100644 connector_ecommerce/i18n/es.po
create mode 100644 connector_ecommerce/i18n/fr.po
create mode 100644 connector_ecommerce/i18n/pt.po
create mode 100644 connector_ecommerce/i18n/sv.po
create mode 100644 connector_ecommerce/invoice.py
create mode 100644 connector_ecommerce/invoice_view.xml
create mode 100644 connector_ecommerce/partner.py
create mode 100644 connector_ecommerce/partner_view.xml
create mode 100644 connector_ecommerce/payment_method.py
create mode 100644 connector_ecommerce/payment_method_view.xml
create mode 100644 connector_ecommerce/product.py
create mode 100644 connector_ecommerce/sale.py
create mode 100644 connector_ecommerce/sale_view.xml
create mode 100755 connector_ecommerce/security/ir.model.access.csv
create mode 100644 connector_ecommerce/settings/external.referential.category.csv
create mode 100644 connector_ecommerce/settings/sale.exception.csv
create mode 100644 connector_ecommerce/stock.py
create mode 100644 connector_ecommerce/stock_view.xml
create mode 100644 connector_ecommerce/wizard/__init__.py
create mode 100644 connector_ecommerce/wizard/import_order.py
create mode 100644 connector_ecommerce/wizard/import_order.xml
diff --git a/connector_ecommerce/__init__.py b/connector_ecommerce/__init__.py
new file mode 100644
index 00000000..9650e6b2
--- /dev/null
+++ b/connector_ecommerce/__init__.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2009 Akretion (). All Rights Reserved
+# authors: Raphaël Valyi, Sharoon Thomas
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+import sale
+import stock
+import wizard
+import delivery
+import partner
+import account
+import external_referential
+import product
+import invoice
+import payment_method
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py
new file mode 100644
index 00000000..c5fc44a8
--- /dev/null
+++ b/connector_ecommerce/__openerp__.py
@@ -0,0 +1,85 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2009 Akretion (). All Rights Reserved
+# authors: Raphaël Valyi, Sharoon Thomas
+# Copyright (C) 2010-2011 Akretion Sébastien BEAU
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+
+{
+ 'name': 'Connector for E-Commerce',
+ 'version': '2.0.0',
+ 'category': 'Connector',
+ 'description': """
+Connector for E-Commerce
+========================
+
+TODO
+----
+
+Review the description
+
+Old Description
+---------------
+
+This module provide an abstract common minimal base to multi-channels sales.
+Say you want to expose your product catalog to
+* several instances of flashy-sluggish Magento web sites
+* a cutting edge Spree web shop
+* a Neteven online Marketplace
+* EBay
+* Amazon
+* Google Base
+* an external Point Of Sale system
+* ...
+Then this module allows you to:
+* use several external references ids on every OpenERP object matching those all those external referentials
+* per referential instance, use several sale sub platform entities (ex: several Magento websites per instance)
+* per sub platform, use several shops (ex: several Magento web shops per website)
+
+For each sale shop (matching OpenERP sale.shop object), this module abstract the interfaces to:
+* export the catalog, shop warehouse stock level wise, shop pricelist wise
+* import the catalog
+* import orders
+* export orders/picking status
+ """,
+ 'author': 'MagentoERPConnect Core Editors',
+ 'website': 'http://www.magentoerpconnect.com',
+ 'depends': [
+ 'sale_automatic_workflow',
+ 'sale_exceptions',
+ 'connector',
+ 'delivery',
+ 'base_onchange_player', # TODO remove dependency
+ ],
+ 'data': [
+ 'security/ir.model.access.csv',
+ 'sale_view.xml',
+ 'partner_view.xml',
+ 'invoice_view.xml',
+ 'wizard/import_order.xml',
+ 'delivery_view.xml',
+ 'base_sale_data.xml',
+ 'settings/sale.exception.csv',
+ 'settings/external.referential.category.csv',
+ 'stock_view.xml',
+ 'payment_method_view.xml',
+ 'account_view.xml',
+ ],
+ 'installable': True,
+}
diff --git a/connector_ecommerce/account.py b/connector_ecommerce/account.py
new file mode 100644
index 00000000..affcdacf
--- /dev/null
+++ b/connector_ecommerce/account.py
@@ -0,0 +1,59 @@
+# -*- encoding: utf-8 -*-
+#################################################################################
+# #
+# connector_ecommerce for OpenERP #
+# Copyright (C) 2011 Akretion Sébastien BEAU #
+# #
+# 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 . #
+# #
+#################################################################################
+
+from openerp.osv.orm import Model
+from openerp.osv import fields
+
+class account_tax_code(Model):
+ _inherit='account.tax'
+
+ def get_tax_from_rate(self, cr, uid, rate, is_tax_included=False, context=None):
+ #TODO improve, if tax are not correctly mapped the order should be in exception (integration with sale_execption)
+ tax_ids = self.pool.get('account.tax').search(cr, uid, [('price_include', '=', is_tax_included),
+ ('type_tax_use', 'in', ['sale', 'all']), ('amount', '>=', rate - 0.001), ('amount', '<=', rate + 0.001)])
+ if tax_ids and len(tax_ids) > 0:
+ return tax_ids[0]
+ else:
+ #try to find a tax with less precision
+ tax_ids = self.pool.get('account.tax').search(cr, uid, [('price_include', '=', is_tax_included),
+ ('type_tax_use', 'in', ['sale', 'all']), ('amount', '>=', rate - 0.01), ('amount', '<=', rate + 0.01)])
+ if tax_ids and len(tax_ids) > 0:
+ return tax_ids[0]
+ return False
+
+class account_tax_group(Model):
+ _name = 'account.tax.group'
+ _description = 'account tax group'
+
+ _columns = {
+ 'name': fields.char('Name', size=64),
+ 'tax_ids': fields.one2many('account.tax', 'group_id', 'Taxes'),
+ }
+
+class account_tax(Model):
+ _inherit = 'account.tax'
+
+ _columns = {
+ 'group_id': fields.many2one('account.tax.group', 'Tax Group', help=("Choose the tax group."
+ " This is needed for example with magento or prestashop")),
+ }
+
+
diff --git a/connector_ecommerce/account_view.xml b/connector_ecommerce/account_view.xml
new file mode 100644
index 00000000..8f1c22e6
--- /dev/null
+++ b/connector_ecommerce/account_view.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+ connector_ecommerce.view_tax_form
+ account.tax
+
+
+
+
+
+
+
+
+
+
+ account.tax.group
+ account.tax.group
+
+
+
+
+
+
+
+
+
+ account.tax.group
+ account.tax.group
+
+
+
+
+
+
+ Tax Groups
+ account.tax.group
+ form
+ tree,form
+
+
+
+
+
+
diff --git a/connector_ecommerce/base_sale_data.xml b/connector_ecommerce/base_sale_data.xml
new file mode 100644
index 00000000..d749b9ff
--- /dev/null
+++ b/connector_ecommerce/base_sale_data.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+ Services
+
+
+
+ SHIP
+ 0.0
+ 0.0
+ service
+ Shipping costs
+
+
+
+
+ CASH ON DELIVERY
+ 0.0
+ 0.0
+ service
+ Cash on delivery
+
+
+
+
+ GIFT CERTIFICATE
+ 0.0
+ 0.0
+ service
+ Gift Certificate
+
+
+
+
+ DISCOUNT
+ 0.0
+ 0.0
+ service
+ Discount Coupon
+
+
+
+
+
diff --git a/connector_ecommerce/connector.py b/connector_ecommerce/connector.py
new file mode 100644
index 00000000..91f1a794
--- /dev/null
+++ b/connector_ecommerce/connector.py
@@ -0,0 +1,37 @@
+# -*- encoding: utf-8 -*-
+###############################################################################
+# #
+# product_custom_attributes for OpenERP #
+# Copyright (C) 2012 Camptocamp Alexandre Fayolle #
+# Copyright (C) 2012 Akretion Sebastien Beau #
+# #
+# 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 . #
+# #
+###############################################################################
+
+from openerp.addons.connector.connector import AbstractConnector
+
+class BaseConnector(AbstractConnector):
+ def _get_import_defaults_res_partner(self, cr, uid, context=None):
+ pass
+ def _get_import_defaults_res_partner(self, cr, uid, context=None):
+ pass
+ def _get_import_defaults_external_shop_group(self, cr, uid, context=None):
+ pass
+
+ def _get_import_defaults_sale_order(self, cr, uid, context=None):
+ pass
+
+ def _record_one_sale_order(self, cr, uid, res_obj, resource, defaults, context):
+ pass
diff --git a/connector_ecommerce/delivery.py b/connector_ecommerce/delivery.py
new file mode 100644
index 00000000..a1e16539
--- /dev/null
+++ b/connector_ecommerce/delivery.py
@@ -0,0 +1,30 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# Author Guewen Baconnier. Copyright 2011 Camptocamp SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from openerp.osv.orm import Model
+from openerp.osv import fields
+
+class delivery_carrier(Model):
+ _inherit = "delivery.carrier"
+
+ _columns = {
+ # TODO to be removed once the job export tracking is there
+ 'export_needs_tracking': fields.boolean('Export only shippings with a tracking number'),
+ }
diff --git a/connector_ecommerce/delivery_view.xml b/connector_ecommerce/delivery_view.xml
new file mode 100644
index 00000000..5c09a060
--- /dev/null
+++ b/connector_ecommerce/delivery_view.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+ delivery.carrier.form.inherit
+ delivery.carrier
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/connector_ecommerce/external_referential.py b/connector_ecommerce/external_referential.py
new file mode 100644
index 00000000..ccda9493
--- /dev/null
+++ b/connector_ecommerce/external_referential.py
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+# #
+# connector_ecommerce for OpenERP #
+# Copyright (C) 2011 Akretion Sébastien BEAU #
+# #
+# 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 . #
+# #
+###############################################################################
+from openerp.osv import orm, fields
+
+
+class external_referential(orm.Model):
+ _inherit = "external.referential"
+
+ _columns = {
+ 'last_imported_product_id': fields.integer(
+ 'Last Imported Product Id',
+ help="Product are imported one by one. "
+ "This is the magento id of the last product imported. "
+ "If you clear it all product will be imported"),
+ # TODO replace by last import date (at website level)
+ 'last_imported_partner_id': fields.integer(
+ 'Last Imported Partner Id',
+ help="Partners are imported one by one. "
+ "This is the magento id of the last partner imported. "
+ "If you clear it all partners will be imported"),
+ 'import_all_attributs': fields.boolean(
+ 'Import all attributs',
+ help="If the option is uncheck only the attributs "
+ "that doesn't exist in OpenERP will be imported "),
+ 'import_image_with_product': fields.boolean(
+ 'With image',
+ help="If the option is check the product's image and "
+ "the product will be imported at the same time and"
+ "so the step '7-import images' is not needed"),
+ 'import_links_with_product': fields.boolean(
+ 'With links',
+ help="If the option is check the product's links "
+ "(Up-Sell, Cross-Sell, Related) and the product will "
+ "be imported at the same time and so the step "
+ "'8-import links' is not needed"),
+ }
+
+ def import_customer_groups(self, cr, uid, ids, context=None):
+ self.import_resources(cr, uid, ids, 'res.partner.category', context=context)
+ return True
+
+ def import_product_categories(self, cr, uid, ids, context=None):
+ self.import_resources(cr, uid, ids, 'product.category', context=context)
+ return True
+
+ def import_customers(self, cr, uid, ids, context=None):
+ self.import_resources(cr, uid, ids, 'res.partner', context=context)
+ return True
+
+# def import_product_attributes_sets(self, cr, uid, ids, context=None):
+# return self.import_resources(cr, uid, ids, 'TODO', context=context)
+#
+# def import_product_attributes_groups(self, cr, uid, ids, context=None):
+# return self.import_resources(cr, uid, ids, 'TODO', context=context)
+#
+# def import_product_attributes(self, cr, uid, ids, context=None):
+# return self.import_resources(cr, uid, ids, 'TODO', context=context)
+
+ def import_products(self, cr, uid, ids, context=None):
+ self.import_resources(cr, uid, ids, 'product.product', context=context)
+ return True
+
+ def import_product_links(self, cr, uid, ids, context=None):
+ self.import_resources(cr, uid, ids, 'product.link', context=context)
+ return True
diff --git a/connector_ecommerce/i18n/base_sale_multichannels.pot b/connector_ecommerce/i18n/base_sale_multichannels.pot
new file mode 100644
index 00000000..a46f0c73
--- /dev/null
+++ b/connector_ecommerce/i18n/base_sale_multichannels.pot
@@ -0,0 +1,306 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * connector_ecommerce
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 5.0.6\n"
+"Report-Msgid-Bugs-To: support@openerp.com\n"
+"POT-Creation-Date: 2009-12-20 17:22:08+0000\n"
+"PO-Revision-Date: 2009-12-20 17:22:08+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Partial Delivery"
+msgstr ""
+
+#. module: connector_ecommerce
+#: constraint:ir.model:0
+msgid "The Object name must start with x_ and not contain any special character !"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.module.module,description:connector_ecommerce.module_meta_information
+msgid "\n"
+"This module provide an abstract common minimal base to multi-channels sales.\n"
+"Say you want to expose your product catalog to\n"
+"* several instances of flashy-sluggish Magento web sites\n"
+"* a cutting edge Spree web shop\n"
+"* a Neteven online Marketplace\n"
+"* EBay\n"
+"* Amazon\n"
+"* Google Base\n"
+"* an external Point Of Sale system\n"
+"* ...\n"
+"Then this module allows you to:\n"
+"* use several external references ids on every OpenERP object matching those all those external referentials\n"
+"* per referential instance, use several sale sub platform entities (ex: several Magento websites per instance)\n"
+"* per sub platform, use several shops (ex: several Magento web shops per website)\n"
+"\n"
+"For each sale shop (matching OpenERP sale.shop object), this module abstract the interfaces to:\n"
+"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
+"* import the catalog\n"
+"* import orders\n"
+"* export orders/picking status\n"
+" "
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,order_policy:0
+msgid "Shipping Policy"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "None"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Shipped Quantities"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:external.shop.group,referential_id:0
+msgid "Referential"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Draft"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_quantity:0
+msgid "The sale order will automatically create the invoice proposition (draft invoice). Ordered and delivered quantities may not be the same. You have to choose if you invoice based on ordered or shipped quantities. If the product is a service, shipped quantities means hours spent on the associated tasks."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,shop_group_id:0
+msgid "Shop Group"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:product.category,recursive_childen_ids:0
+msgid "All Child Categories"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Update Orders Status"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_policy:0
+msgid "If you don't have enough stock available to deliver all at once, do you accept partial shipments or not?"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:account.journal,external_payment_codes:0
+msgid "Enter the external payment codes, comma separated. They will be used to select the payment journal."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_policy:0
+msgid "Packing Policy"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Complete Delivery"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_generation_policy:0
+msgid "Invoice Generation Policy"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Ordered Quantities"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,is_tax_included:0
+msgid "Requires sale_tax_include module to be installed"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Catalog"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "External Shop Settings"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Catalog"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice from the Packing"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Order Generation"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:account.journal,external_payment_codes:0
+msgid "External Payment Codes"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice on Order After Delivery"
+msgstr ""
+
+#. module: connector_ecommerce
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:external.shop.group,shop_ids:0
+msgid "Sale Shops"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:external.shop.group,name:0
+msgid "Name"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_quantity:0
+msgid "Invoice on"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,order_policy:0
+msgid "The Shipping Policy is used to synchronise invoice and delivery operations.\n"
+" - The 'Pay before delivery' choice will first generate the invoice and then generate the packing order after the payment of this invoice.\n"
+" - The 'Shipping & Manual Invoice' will create the packing order directly and wait for the user to manually click on the 'Invoice' button to generate the draft invoice.\n"
+" - The 'Invoice on Order After Delivery' choice will generate the draft invoice based on sale order after all packing lists have been finished.\n"
+" - The 'Invoice from the packing' choice is used to create an invoice during the packing process."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_inventory_export_date:0
+msgid "Last Inventory Export Time"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:external.referential,shop_group_ids:0
+msgid "Sub Entities"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,referential_id:0
+msgid "External Referential"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Payment Before Delivery"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
+msgid "Base Sale MultiChannels"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+#: field:sale.shop,exportable_product_ids:0
+msgid "Exportable Products"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Import Orders"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_generation_policy:0
+msgid "Picking Generation Policy"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_generation_policy:0
+msgid "Should orders create an invoice after import?"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_update_order_export_date:0
+msgid "Last Order Update Time"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_generation_policy:0
+msgid "Should orders create a picking after import?"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Validated"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_external_shop_group
+msgid "External Referential Shop Group"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Stock Levels Only"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Shipping & Manual Invoice"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Actions"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,exportable_root_category_ids:0
+msgid "Root Category"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,is_tax_included:0
+msgid "Prices Include Tax?"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Shop"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Multi Channels"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Orders"
+msgstr ""
+
diff --git a/connector_ecommerce/i18n/ca.po b/connector_ecommerce/i18n/ca.po
new file mode 100644
index 00000000..741eb7a9
--- /dev/null
+++ b/connector_ecommerce/i18n/ca.po
@@ -0,0 +1,380 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * connector_ecommerce
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 5.0.6\n"
+"Report-Msgid-Bugs-To: support@openerp.com\n"
+"POT-Creation-Date: 2009-12-20 17:22+0000\n"
+"PO-Revision-Date: 2011-02-14 10:04+0000\n"
+"Last-Translator: Jordi Esteve (www.zikzakmedia.com) "
+"\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2012-01-17 05:05+0000\n"
+"X-Generator: Launchpad (build 14676)\n"
+"X-Poedit-Language: Catalan\n"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Partial Delivery"
+msgstr "Enviament parcial"
+
+#. module: connector_ecommerce
+#: constraint:ir.model:0
+msgid ""
+"The Object name must start with x_ and not contain any special character !"
+msgstr ""
+"El nom de l'objecte ha de començar amb x_ i no contenir cap caràcter "
+"especial!"
+
+#. module: connector_ecommerce
+#: model:ir.module.module,description:connector_ecommerce.module_meta_information
+msgid ""
+"\n"
+"This module provide an abstract common minimal base to multi-channels "
+"sales.\n"
+"Say you want to expose your product catalog to\n"
+"* several instances of flashy-sluggish Magento web sites\n"
+"* a cutting edge Spree web shop\n"
+"* a Neteven online Marketplace\n"
+"* EBay\n"
+"* Amazon\n"
+"* Google Base\n"
+"* an external Point Of Sale system\n"
+"* ...\n"
+"Then this module allows you to:\n"
+"* use several external references ids on every OpenERP object matching those "
+"all those external referentials\n"
+"* per referential instance, use several sale sub platform entities (ex: "
+"several Magento websites per instance)\n"
+"* per sub platform, use several shops (ex: several Magento web shops per "
+"website)\n"
+"\n"
+"For each sale shop (matching OpenERP sale.shop object), this module abstract "
+"the interfaces to:\n"
+"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
+"* import the catalog\n"
+"* import orders\n"
+"* export orders/picking status\n"
+" "
+msgstr ""
+"\n"
+"Aquest mòdul proporciona una mínima base d'abstracció comuna a diversos "
+"canals de vendes.\n"
+"Suposem que voleu exposar el vostre catàleg de productes a:\n"
+"* Diverses instàncies de botiga web de Magento\n"
+"* Una botiga web d'última generació Spree\n"
+"* Un mercat Neteven\n"
+"* EBay\n"
+"* Amazon\n"
+"* Google Base\n"
+"* Un sistema punt de venda extern\n"
+"* ...\n"
+"Llavors, aquest mòdul us permet:\n"
+"* L'ús de diverses referències externes a tots els identificadors d'objectes "
+"OpenERP que apunten a totes aquestes referències externes.\n"
+"* Referències per instància, l'ús de diverses sub entitats de vendes (per "
+"exemple diversos llocs web Magento per instància)\n"
+"* Referències per sub entitat, l'ús de diverses botigues (per exemple "
+"diverses botigues web Magento per lloc web)\n"
+"\n"
+"Per a cada botiga de venda (que es correspondrà a l'objecte sale.shop de "
+"OpenERP), aquest mòdul abstreu les interfícies de:\n"
+"* Exportar el catàleg, nivell d'estoc del magatzem de la botiga, tarifa de "
+"preus de la botiga\n"
+"* Importar el catàleg\n"
+"* Importar comandes\n"
+"* Exportar l'estat de les comandes/albarans\n"
+" "
+
+#. module: connector_ecommerce
+#: field:sale.shop,order_policy:0
+msgid "Shipping Policy"
+msgstr "Política de facturació"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "None"
+msgstr "Cap"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Shipped Quantities"
+msgstr "Quantitats enviades"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,referential_id:0
+msgid "Referential"
+msgstr "Referència"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Draft"
+msgstr "Esborrany"
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_quantity:0
+msgid ""
+"The sale order will automatically create the invoice proposition (draft "
+"invoice). Ordered and delivered quantities may not be the same. You have to "
+"choose if you invoice based on ordered or shipped quantities. If the product "
+"is a service, shipped quantities means hours spent on the associated tasks."
+msgstr ""
+"La comanda de venda crearà automàticament la proposta de factura (factura "
+"esborrany). Les quantitats demanades i les quantitats enviades poden no ser "
+"les mateixes. Heu de decidir si factureu basat en quantitats demanades o "
+"enviades. Si el producte és un servei, quantitats enviades significa hores "
+"dedicades a les tasques associades."
+
+#. module: connector_ecommerce
+#: field:sale.shop,shop_group_id:0
+msgid "Shop Group"
+msgstr "Grup botigues"
+
+#. module: connector_ecommerce
+#: field:product.category,recursive_childen_ids:0
+msgid "All Child Categories"
+msgstr "Totes categories filles"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Update Orders Status"
+msgstr "Actualitza estat comandes"
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_policy:0
+msgid ""
+"If you don't have enough stock available to deliver all at once, do you "
+"accept partial shipments or not?"
+msgstr ""
+"Si no disposeu de suficient estoc disponible per a enviar-ho tot a la "
+"vegada, accepteu enviaments parcials?"
+
+#. module: connector_ecommerce
+#: help:account.journal,external_payment_codes:0
+msgid ""
+"Enter the external payment codes, comma separated. They will be used to "
+"select the payment journal."
+msgstr ""
+"Indiqueu els codis de pagament externs, separats per coma. S'utilitzaran per "
+"a seleccionar el diari de pagament."
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_policy:0
+msgid "Packing Policy"
+msgstr "Política d'enviament"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Complete Delivery"
+msgstr "Enviament complet"
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_generation_policy:0
+msgid "Invoice Generation Policy"
+msgstr "Política generació de factures"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Ordered Quantities"
+msgstr "Quantitats ordenades"
+
+#. module: connector_ecommerce
+#: help:sale.shop,is_tax_included:0
+msgid "Requires sale_tax_include module to be installed"
+msgstr "Requereix que el mòdul sale_tax_include sigui instal·lat."
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Catalog"
+msgstr "Catàleg"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "External Shop Settings"
+msgstr "Configuració botiga externa"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Catalog"
+msgstr "Exporta catàleg"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice from the Packing"
+msgstr "Factura des d'albarà"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Order Generation"
+msgstr "Generació comanda"
+
+#. module: connector_ecommerce
+#: field:account.journal,external_payment_codes:0
+msgid "External Payment Codes"
+msgstr "Codis de pagament externs"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice on Order After Delivery"
+msgstr "Factura comanda després de l'enviament"
+
+#. module: connector_ecommerce
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr "XML invàlid per a la definició de la vista!"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,shop_ids:0
+msgid "Sale Shops"
+msgstr "Botigues venda"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,name:0
+msgid "Name"
+msgstr "Nom"
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_quantity:0
+msgid "Invoice on"
+msgstr "Factura les"
+
+#. module: connector_ecommerce
+#: help:sale.shop,order_policy:0
+msgid ""
+"The Shipping Policy is used to synchronise invoice and delivery operations.\n"
+" - The 'Pay before delivery' choice will first generate the invoice and "
+"then generate the packing order after the payment of this invoice.\n"
+" - The 'Shipping & Manual Invoice' will create the packing order directly "
+"and wait for the user to manually click on the 'Invoice' button to generate "
+"the draft invoice.\n"
+" - The 'Invoice on Order After Delivery' choice will generate the draft "
+"invoice based on sale order after all packing lists have been finished.\n"
+" - The 'Invoice from the packing' choice is used to create an invoice "
+"during the packing process."
+msgstr ""
+"La política d'enviament s'utilitza per sincronitzar la factura i les "
+"operacions d'enviament.\n"
+" - L'opció 'Pagament abans de l'enviament' primer genera la factura i "
+"després genera l'albarà al fer efectiu el pagament d'aquesta factura.\n"
+" - L'opció 'Enviament' & Factura manual 'crearà l'albarà directament i "
+"esperarà que l'usuari faci clic manualment al botó' Factura 'per generar la "
+"factura esborrany.\n"
+" - L'opció 'Factura segons comanda després enviament' generarà la factura "
+"esborrany basada en la comanda de venda després que tots els albarans es "
+"processin.\n"
+" - L'opció 'Factura des d'albarà' s'utilitza per a crear una factura des "
+"dels albarans processats."
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_inventory_export_date:0
+msgid "Last Inventory Export Time"
+msgstr "Data última exportació inventari"
+
+#. module: connector_ecommerce
+#: field:external.referential,shop_group_ids:0
+msgid "Sub Entities"
+msgstr "Sub entitats"
+
+#. module: connector_ecommerce
+#: field:sale.shop,referential_id:0
+msgid "External Referential"
+msgstr "Referència externa"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Payment Before Delivery"
+msgstr "Pagament abans de l'enviament"
+
+#. module: connector_ecommerce
+#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
+msgid "Base Sale MultiChannels"
+msgstr "Base vendes multicanal"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+#: field:sale.shop,exportable_product_ids:0
+msgid "Exportable Products"
+msgstr "Productes exportables"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Import Orders"
+msgstr "Importa comandes"
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_generation_policy:0
+msgid "Picking Generation Policy"
+msgstr "Política generació d'albarans"
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_generation_policy:0
+msgid "Should orders create an invoice after import?"
+msgstr "Les comandes haurien de crear una factura després de la importació?"
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_update_order_export_date:0
+msgid "Last Order Update Time"
+msgstr "Data última actualització comandes"
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_generation_policy:0
+msgid "Should orders create a picking after import?"
+msgstr "Les comandes haurien de crear un albarà després de la importació?"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Validated"
+msgstr "Validat"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_external_shop_group
+msgid "External Referential Shop Group"
+msgstr "Referència externa grup botigues"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Stock Levels Only"
+msgstr "Exporta només nivells d'estoc"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Shipping & Manual Invoice"
+msgstr "Envia & Factura manual"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Actions"
+msgstr "Accions"
+
+#. module: connector_ecommerce
+#: field:sale.shop,exportable_root_category_ids:0
+msgid "Root Category"
+msgstr "Categoria arrel"
+
+#. module: connector_ecommerce
+#: field:sale.shop,is_tax_included:0
+msgid "Prices Include Tax?"
+msgstr "Preus inclouen impostos?"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Shop"
+msgstr "Botiga venda"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Multi Channels"
+msgstr "Vendes Multi canal"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Orders"
+msgstr "Comandes"
diff --git a/connector_ecommerce/i18n/ca_ES.po b/connector_ecommerce/i18n/ca_ES.po
new file mode 100644
index 00000000..d0830688
--- /dev/null
+++ b/connector_ecommerce/i18n/ca_ES.po
@@ -0,0 +1,334 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * connector_ecommerce
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 5.0.6\n"
+"Report-Msgid-Bugs-To: support@openerp.com\n"
+"POT-Creation-Date: 2009-12-20 17:22:08+0000\n"
+"PO-Revision-Date: 2010-03-02 13:08+0100\n"
+"Last-Translator: Jordi Esteve (Zikzakmedia) \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: Catalan\n"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Partial Delivery"
+msgstr "Enviament parcial"
+
+#. module: connector_ecommerce
+#: constraint:ir.model:0
+msgid "The Object name must start with x_ and not contain any special character !"
+msgstr "El nom de l'objecte ha de començar amb x_ i no contenir cap caràcter especial!"
+
+#. module: connector_ecommerce
+#: model:ir.module.module,description:connector_ecommerce.module_meta_information
+msgid ""
+"\n"
+"This module provide an abstract common minimal base to multi-channels sales.\n"
+"Say you want to expose your product catalog to\n"
+"* several instances of flashy-sluggish Magento web sites\n"
+"* a cutting edge Spree web shop\n"
+"* a Neteven online Marketplace\n"
+"* EBay\n"
+"* Amazon\n"
+"* Google Base\n"
+"* an external Point Of Sale system\n"
+"* ...\n"
+"Then this module allows you to:\n"
+"* use several external references ids on every OpenERP object matching those all those external referentials\n"
+"* per referential instance, use several sale sub platform entities (ex: several Magento websites per instance)\n"
+"* per sub platform, use several shops (ex: several Magento web shops per website)\n"
+"\n"
+"For each sale shop (matching OpenERP sale.shop object), this module abstract the interfaces to:\n"
+"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
+"* import the catalog\n"
+"* import orders\n"
+"* export orders/picking status\n"
+" "
+msgstr ""
+"\n"
+"Aquest mòdul proporciona una mínima base d'abstracció comuna a diversos canals de vendes.\n"
+"Suposem que voleu exposar el vostre catàleg de productes a:\n"
+"* Diverses instàncies de botiga web de Magento\n"
+"* Una botiga web d'última generació Spree\n"
+"* Un mercat Neteven\n"
+"* EBay\n"
+"* Amazon\n"
+"* Google Base\n"
+"* Un sistema punt de venda extern\n"
+"* ...\n"
+"Llavors, aquest mòdul us permet:\n"
+"* L'ús de diverses referències externes a tots els identificadors d'objectes OpenERP que apunten a totes aquestes referències externes.\n"
+"* Referències per instància, l'ús de diverses sub entitats de vendes (per exemple diversos llocs web Magento per instància)\n"
+"* Referències per sub entitat, l'ús de diverses botigues (per exemple diverses botigues web Magento per lloc web)\n"
+"\n"
+"Per a cada botiga de venda (que es correspondrà a l'objecte sale.shop de OpenERP), aquest mòdul abstreu les interfícies de:\n"
+"* Exportar el catàleg, nivell d'estoc del magatzem de la botiga, tarifa de preus de la botiga\n"
+"* Importar el catàleg\n"
+"* Importar comandes\n"
+"* Exportar l'estat de les comandes/albarans\n"
+
+#. module: connector_ecommerce
+#: field:sale.shop,order_policy:0
+msgid "Shipping Policy"
+msgstr "Política de facturació"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "None"
+msgstr "Cap"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Shipped Quantities"
+msgstr "Quantitats enviades"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,referential_id:0
+msgid "Referential"
+msgstr "Referència"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Draft"
+msgstr "Esborrany"
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_quantity:0
+msgid "The sale order will automatically create the invoice proposition (draft invoice). Ordered and delivered quantities may not be the same. You have to choose if you invoice based on ordered or shipped quantities. If the product is a service, shipped quantities means hours spent on the associated tasks."
+msgstr "La comanda de venda crearà automàticament la proposta de factura (factura esborrany). Les quantitats demanades i les quantitats enviades poden no ser les mateixes. Heu de decidir si factureu basat en quantitats demanades o enviades. Si el producte és un servei, quantitats enviades significa hores dedicades a les tasques associades."
+
+#. module: connector_ecommerce
+#: field:sale.shop,shop_group_id:0
+msgid "Shop Group"
+msgstr "Grup botigues"
+
+#. module: connector_ecommerce
+#: field:product.category,recursive_childen_ids:0
+msgid "All Child Categories"
+msgstr "Totes categories filles"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Update Orders Status"
+msgstr "Actualitza estat comandes"
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_policy:0
+msgid "If you don't have enough stock available to deliver all at once, do you accept partial shipments or not?"
+msgstr "Si no disposeu de suficient estoc disponible per a enviar-ho tot a la vegada, accepteu enviaments parcials?"
+
+#. module: connector_ecommerce
+#: help:account.journal,external_payment_codes:0
+msgid "Enter the external payment codes, comma separated. They will be used to select the payment journal."
+msgstr "Indiqueu els codis de pagament externs, separats per coma. S'utilitzaran per a seleccionar el diari de pagament."
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_policy:0
+msgid "Packing Policy"
+msgstr "Política d'enviament"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Complete Delivery"
+msgstr "Enviament complet"
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_generation_policy:0
+msgid "Invoice Generation Policy"
+msgstr "Política generació de factures"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Ordered Quantities"
+msgstr "Quantitats ordenades"
+
+#. module: connector_ecommerce
+#: help:sale.shop,is_tax_included:0
+msgid "Requires sale_tax_include module to be installed"
+msgstr "Requereix que el mòdul sale_tax_include sigui instal·lat."
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Catalog"
+msgstr "Catàleg"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "External Shop Settings"
+msgstr "Configuració botiga externa"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Catalog"
+msgstr "Exporta catàleg"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice from the Packing"
+msgstr "Factura des d'albarà"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Order Generation"
+msgstr "Generació comanda"
+
+#. module: connector_ecommerce
+#: field:account.journal,external_payment_codes:0
+msgid "External Payment Codes"
+msgstr "Codis de pagament externs"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice on Order After Delivery"
+msgstr "Factura comanda després de l'enviament"
+
+#. module: connector_ecommerce
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr "XML invàlid per a la definició de la vista!"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,shop_ids:0
+msgid "Sale Shops"
+msgstr "Botigues venda"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,name:0
+msgid "Name"
+msgstr "Nom"
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_quantity:0
+msgid "Invoice on"
+msgstr "Factura les"
+
+#. module: connector_ecommerce
+#: help:sale.shop,order_policy:0
+msgid ""
+"The Shipping Policy is used to synchronise invoice and delivery operations.\n"
+" - The 'Pay before delivery' choice will first generate the invoice and then generate the packing order after the payment of this invoice.\n"
+" - The 'Shipping & Manual Invoice' will create the packing order directly and wait for the user to manually click on the 'Invoice' button to generate the draft invoice.\n"
+" - The 'Invoice on Order After Delivery' choice will generate the draft invoice based on sale order after all packing lists have been finished.\n"
+" - The 'Invoice from the packing' choice is used to create an invoice during the packing process."
+msgstr ""
+"La política d'enviament s'utilitza per sincronitzar la factura i les operacions d'enviament.\n"
+" - L'opció 'Pagament abans de l'enviament' primer genera la factura i després genera l'albarà al fer efectiu el pagament d'aquesta factura.\n"
+" - L'opció 'Enviament' & Factura manual 'crearà l'albarà directament i esperarà que l'usuari faci clic manualment al botó' Factura 'per generar la factura esborrany.\n"
+" - L'opció 'Factura segons comanda després enviament' generarà la factura esborrany basada en la comanda de venda després que tots els albarans es processin.\n"
+" - L'opció 'Factura des d'albarà' s'utilitza per a crear una factura des dels albarans processats."
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_inventory_export_date:0
+msgid "Last Inventory Export Time"
+msgstr "Data última exportació inventari"
+
+#. module: connector_ecommerce
+#: field:external.referential,shop_group_ids:0
+msgid "Sub Entities"
+msgstr "Sub entitats"
+
+#. module: connector_ecommerce
+#: field:sale.shop,referential_id:0
+msgid "External Referential"
+msgstr "Referència externa"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Payment Before Delivery"
+msgstr "Pagament abans de l'enviament"
+
+#. module: connector_ecommerce
+#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
+msgid "Base Sale MultiChannels"
+msgstr "Base vendes multicanal"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+#: field:sale.shop,exportable_product_ids:0
+msgid "Exportable Products"
+msgstr "Productes exportables"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Import Orders"
+msgstr "Importa comandes"
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_generation_policy:0
+msgid "Picking Generation Policy"
+msgstr "Política generació d'albarans"
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_generation_policy:0
+msgid "Should orders create an invoice after import?"
+msgstr "Les comandes haurien de crear una factura després de la importació?"
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_update_order_export_date:0
+msgid "Last Order Update Time"
+msgstr "Data última actualització comandes"
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_generation_policy:0
+msgid "Should orders create a picking after import?"
+msgstr "Les comandes haurien de crear un albarà després de la importació?"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Validated"
+msgstr "Validat"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_external_shop_group
+msgid "External Referential Shop Group"
+msgstr "Referència externa grup botigues"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Stock Levels Only"
+msgstr "Exporta només nivells d'estoc"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Shipping & Manual Invoice"
+msgstr "Envia & Factura manual"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Actions"
+msgstr "Accions"
+
+#. module: connector_ecommerce
+#: field:sale.shop,exportable_root_category_ids:0
+msgid "Root Category"
+msgstr "Categoria arrel"
+
+#. module: connector_ecommerce
+#: field:sale.shop,is_tax_included:0
+msgid "Prices Include Tax?"
+msgstr "Preus inclouen impostos?"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Shop"
+msgstr "Botiga venda"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Multi Channels"
+msgstr "Vendes Multi canal"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Orders"
+msgstr "Comandes"
+
diff --git a/connector_ecommerce/i18n/es.po b/connector_ecommerce/i18n/es.po
new file mode 100644
index 00000000..07cbd78c
--- /dev/null
+++ b/connector_ecommerce/i18n/es.po
@@ -0,0 +1,379 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * connector_ecommerce
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 5.0.6\n"
+"Report-Msgid-Bugs-To: support@openerp.com\n"
+"POT-Creation-Date: 2009-12-20 17:22+0000\n"
+"PO-Revision-Date: 2011-02-14 10:04+0000\n"
+"Last-Translator: Jordi Esteve (www.zikzakmedia.com) "
+"\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2012-01-17 05:05+0000\n"
+"X-Generator: Launchpad (build 14676)\n"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Partial Delivery"
+msgstr "Envío parcial"
+
+#. module: connector_ecommerce
+#: constraint:ir.model:0
+msgid ""
+"The Object name must start with x_ and not contain any special character !"
+msgstr ""
+"¡El nombre del objeto debe empezar con x_ y no contener ningún carácter "
+"especial!"
+
+#. module: connector_ecommerce
+#: model:ir.module.module,description:connector_ecommerce.module_meta_information
+msgid ""
+"\n"
+"This module provide an abstract common minimal base to multi-channels "
+"sales.\n"
+"Say you want to expose your product catalog to\n"
+"* several instances of flashy-sluggish Magento web sites\n"
+"* a cutting edge Spree web shop\n"
+"* a Neteven online Marketplace\n"
+"* EBay\n"
+"* Amazon\n"
+"* Google Base\n"
+"* an external Point Of Sale system\n"
+"* ...\n"
+"Then this module allows you to:\n"
+"* use several external references ids on every OpenERP object matching those "
+"all those external referentials\n"
+"* per referential instance, use several sale sub platform entities (ex: "
+"several Magento websites per instance)\n"
+"* per sub platform, use several shops (ex: several Magento web shops per "
+"website)\n"
+"\n"
+"For each sale shop (matching OpenERP sale.shop object), this module abstract "
+"the interfaces to:\n"
+"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
+"* import the catalog\n"
+"* import orders\n"
+"* export orders/picking status\n"
+" "
+msgstr ""
+"\n"
+"Este módulo proporciona una mínima base de abstracción común a varios "
+"canales de ventas.\n"
+"Supongamos que quiere exponer su catálogo de productos en:\n"
+"* Varias instancias de tiendas web de Magento\n"
+"* Una tienda web de última generación Spree\n"
+"* Un mercado Neteven\n"
+"* EBay\n"
+"* Amazon\n"
+"* Google Base\n"
+"* Un sistema punto de venta externo\n"
+"* ...\n"
+"Entonces, este módulo le permite:\n"
+"* El uso de varias referencias externas en todos los identificadores de "
+"objetos OpenERP que mapean todas estas referencias externas.\n"
+"* Referencias por instancia, el uso de varias subentidades de ventas (por "
+"ejemplo varios sitios web Magento por instancia)\n"
+"* Referencias por subentidad, el uso de varias tiendas (por ejemplo varias "
+"tiendas web Magento por sitio web)\n"
+"\n"
+"Para cada tienda de venta (que se corresponda al objeto sale.shop de "
+"OpenERP), este módulo abstrae las interfaces de:\n"
+"* Exportar el catálogo, nivel de stock del almacén de la tienda, tarifa de "
+"precios de la tienda\n"
+"* Importar el catálogo\n"
+"* Importar pedidos\n"
+"* Exportar el estado de pedidos/albaranes\n"
+" "
+
+#. module: connector_ecommerce
+#: field:sale.shop,order_policy:0
+msgid "Shipping Policy"
+msgstr "Política de facturación"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "None"
+msgstr "Ninguno/a"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Shipped Quantities"
+msgstr "Cantidades enviadas"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,referential_id:0
+msgid "Referential"
+msgstr "Referencia"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Draft"
+msgstr "Borrador"
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_quantity:0
+msgid ""
+"The sale order will automatically create the invoice proposition (draft "
+"invoice). Ordered and delivered quantities may not be the same. You have to "
+"choose if you invoice based on ordered or shipped quantities. If the product "
+"is a service, shipped quantities means hours spent on the associated tasks."
+msgstr ""
+"El pedido de venta creará automáticamente la propuesta de factura (factura "
+"borrador). Las cantidades pedidas y las cantidades enviadas pueden no ser "
+"las mismas. Tiene que decidir si factura basado en cantidades pedidas o "
+"enviadas. Si el producto es un servicio, cantidades enviadas significa horas "
+"dedicadas a las tareas asociadas."
+
+#. module: connector_ecommerce
+#: field:sale.shop,shop_group_id:0
+msgid "Shop Group"
+msgstr "Grupo tiendas"
+
+#. module: connector_ecommerce
+#: field:product.category,recursive_childen_ids:0
+msgid "All Child Categories"
+msgstr "Todas categorías hijas"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Update Orders Status"
+msgstr "Actualizar estado pedidos"
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_policy:0
+msgid ""
+"If you don't have enough stock available to deliver all at once, do you "
+"accept partial shipments or not?"
+msgstr ""
+"Si no dispone de suficiente stock disponible para enviarlo todo a la vez, "
+"¿acepta envíos parciales?"
+
+#. module: connector_ecommerce
+#: help:account.journal,external_payment_codes:0
+msgid ""
+"Enter the external payment codes, comma separated. They will be used to "
+"select the payment journal."
+msgstr ""
+"Indique los códigos de pago externos, separados por coma. Serán utilizados "
+"para seleccionar el diario de pago."
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_policy:0
+msgid "Packing Policy"
+msgstr "Política de envío"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Complete Delivery"
+msgstr "Envío completo"
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_generation_policy:0
+msgid "Invoice Generation Policy"
+msgstr "Política generación de facturas"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Ordered Quantities"
+msgstr "Cantidades ordenadas"
+
+#. module: connector_ecommerce
+#: help:sale.shop,is_tax_included:0
+msgid "Requires sale_tax_include module to be installed"
+msgstr "Requiere que el módulo sale_tax_include sea instalado."
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Catalog"
+msgstr "Catálogo"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "External Shop Settings"
+msgstr "Configuración tienda externa"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Catalog"
+msgstr "Exportar catálogo"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice from the Packing"
+msgstr "Factura desde albarán"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Order Generation"
+msgstr "Generación pedido"
+
+#. module: connector_ecommerce
+#: field:account.journal,external_payment_codes:0
+msgid "External Payment Codes"
+msgstr "Códigos de pago externos"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice on Order After Delivery"
+msgstr "Facturar pedido después del envío"
+
+#. module: connector_ecommerce
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr "¡XML inválido para la definición de la vista!"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,shop_ids:0
+msgid "Sale Shops"
+msgstr "Tiendas venta"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,name:0
+msgid "Name"
+msgstr "Nombre"
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_quantity:0
+msgid "Invoice on"
+msgstr "Facturar las"
+
+#. module: connector_ecommerce
+#: help:sale.shop,order_policy:0
+msgid ""
+"The Shipping Policy is used to synchronise invoice and delivery operations.\n"
+" - The 'Pay before delivery' choice will first generate the invoice and "
+"then generate the packing order after the payment of this invoice.\n"
+" - The 'Shipping & Manual Invoice' will create the packing order directly "
+"and wait for the user to manually click on the 'Invoice' button to generate "
+"the draft invoice.\n"
+" - The 'Invoice on Order After Delivery' choice will generate the draft "
+"invoice based on sale order after all packing lists have been finished.\n"
+" - The 'Invoice from the packing' choice is used to create an invoice "
+"during the packing process."
+msgstr ""
+"La política de envío se utiliza para sincronizar la factura y las "
+"operaciones de envío.\n"
+" - La opción 'Pago antes del envío' primero genera la factura y luego "
+"genera el albarán después del pago de esta factura.\n"
+" - La opción 'Envío '& Factura manual' creará el albarán directamente y "
+"esperará a que el usuario haga clic manualmente en el botón 'Factura' para "
+"generar la factura borrador.\n"
+" - La opción 'Factura según pedido después envío' generará la factura "
+"borrador basada en el pedido de venta después de que todos los albaranes se "
+"hayan procesado.\n"
+" - La opción 'Factura desde albarán' se utiliza para crear una factura "
+"durante el proceso de los albaranes."
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_inventory_export_date:0
+msgid "Last Inventory Export Time"
+msgstr "Fecha última exportación inventario"
+
+#. module: connector_ecommerce
+#: field:external.referential,shop_group_ids:0
+msgid "Sub Entities"
+msgstr "Sub entidades"
+
+#. module: connector_ecommerce
+#: field:sale.shop,referential_id:0
+msgid "External Referential"
+msgstr "Referencia externa"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Payment Before Delivery"
+msgstr "Pago antes del envío"
+
+#. module: connector_ecommerce
+#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
+msgid "Base Sale MultiChannels"
+msgstr "Base ventas multicanal"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+#: field:sale.shop,exportable_product_ids:0
+msgid "Exportable Products"
+msgstr "Productos exportables"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Import Orders"
+msgstr "Importar pedidos"
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_generation_policy:0
+msgid "Picking Generation Policy"
+msgstr "Política generación de albaranes"
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_generation_policy:0
+msgid "Should orders create an invoice after import?"
+msgstr "¿Los pedidos deberían crear una factura después de la importación?"
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_update_order_export_date:0
+msgid "Last Order Update Time"
+msgstr "Fecha última actualización pedidos"
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_generation_policy:0
+msgid "Should orders create a picking after import?"
+msgstr "¿Los pedidos deberían crear un albarán después de la importación?"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Validated"
+msgstr "Validado"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_external_shop_group
+msgid "External Referential Shop Group"
+msgstr "Referencia externa grupo tiendas"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Stock Levels Only"
+msgstr "Exportar sólo niveles de stock"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Shipping & Manual Invoice"
+msgstr "Enviar & Factura manual"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Actions"
+msgstr "Accions"
+
+#. module: connector_ecommerce
+#: field:sale.shop,exportable_root_category_ids:0
+msgid "Root Category"
+msgstr "Categoría raíz"
+
+#. module: connector_ecommerce
+#: field:sale.shop,is_tax_included:0
+msgid "Prices Include Tax?"
+msgstr "¿Precios incluyen impuestos?"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Shop"
+msgstr "Tienda venta"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Multi Channels"
+msgstr "Ventas Multi canal"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Orders"
+msgstr "Pedidos"
diff --git a/connector_ecommerce/i18n/fr.po b/connector_ecommerce/i18n/fr.po
new file mode 100644
index 00000000..793cdcda
--- /dev/null
+++ b/connector_ecommerce/i18n/fr.po
@@ -0,0 +1,356 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * connector_ecommerce
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 6.1beta\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-12-20 17:22+0000\n"
+"PO-Revision-Date: 2011-12-05 12:42+0000\n"
+"Last-Translator: OpenERP Administrators \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2012-01-17 05:05+0000\n"
+"X-Generator: Launchpad (build 14676)\n"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Partial Delivery"
+msgstr "Livraison Partielle"
+
+#. module: connector_ecommerce
+#: constraint:ir.model:0
+msgid ""
+"The Object name must start with x_ and not contain any special character !"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.module.module,description:connector_ecommerce.module_meta_information
+msgid ""
+"\n"
+"This module provide an abstract common minimal base to multi-channels "
+"sales.\n"
+"Say you want to expose your product catalog to\n"
+"* several instances of flashy-sluggish Magento web sites\n"
+"* a cutting edge Spree web shop\n"
+"* a Neteven online Marketplace\n"
+"* EBay\n"
+"* Amazon\n"
+"* Google Base\n"
+"* an external Point Of Sale system\n"
+"* ...\n"
+"Then this module allows you to:\n"
+"* use several external references ids on every OpenERP object matching those "
+"all those external referentials\n"
+"* per referential instance, use several sale sub platform entities (ex: "
+"several Magento websites per instance)\n"
+"* per sub platform, use several shops (ex: several Magento web shops per "
+"website)\n"
+"\n"
+"For each sale shop (matching OpenERP sale.shop object), this module abstract "
+"the interfaces to:\n"
+"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
+"* import the catalog\n"
+"* import orders\n"
+"* export orders/picking status\n"
+" "
+msgstr ""
+"\n"
+"Ce module fourni une couche d'abstracion minimale pour les ventes en multi-"
+"canaux.\n"
+"Vous voulez exposer votre catalogue produits sur\n"
+"* plusieurs instances de sites web magento\n"
+"* une boutique en ligne Spree d'avant garde\n"
+"* un marché en ligne Neteven\n"
+"* EBay\n"
+"* Amazon\n"
+"* Google Base\n"
+"* un système de point de vente externe\n"
+"* ...\n"
+"Ce module vous permet donc:\n"
+"* d'utiliser plusieurs identifiants externes dans tout les objets OpenERP "
+"correspondant entre eux use several external references ids on every OpenERP "
+"object matching those all those external referentials\n"
+"* par instance référentielle, d'utiliser plusieurs entités de sous "
+"plateforme de vente (ex: plusieurs sites web Magento par instance)\n"
+"* par sous plateforme, d'utiliser plusieurs boutiques (ex: plusieurs "
+"boutiques en ligne Magento par site web)\n"
+"\n"
+"Pour chaque boutique de vente (correspondant aux objets OpenERP sale.shop), "
+"ce module extrait les interfaces pour:\n"
+"* exporter le catalogue, le niveau de stock du magasin, les listes de prix "
+"du magasin\n"
+"* importer le catalogue\n"
+"* importer les commandes\n"
+"* exporter les commandes/status picking\n"
+" "
+
+#. module: connector_ecommerce
+#: field:sale.shop,order_policy:0
+msgid "Shipping Policy"
+msgstr "Politique d'expédition"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "None"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Shipped Quantities"
+msgstr "Quantités Expédiées"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,referential_id:0
+msgid "Referential"
+msgstr "Référentiel"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Draft"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_quantity:0
+msgid ""
+"The sale order will automatically create the invoice proposition (draft "
+"invoice). Ordered and delivered quantities may not be the same. You have to "
+"choose if you invoice based on ordered or shipped quantities. If the product "
+"is a service, shipped quantities means hours spent on the associated tasks."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,shop_group_id:0
+msgid "Shop Group"
+msgstr "Groupe de Magasin"
+
+#. module: connector_ecommerce
+#: field:product.category,recursive_childen_ids:0
+msgid "All Child Categories"
+msgstr "Toute les Catégories Enfant"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Update Orders Status"
+msgstr "Mettre à Jour les Status des Commmandes"
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_policy:0
+msgid ""
+"If you don't have enough stock available to deliver all at once, do you "
+"accept partial shipments or not?"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:account.journal,external_payment_codes:0
+msgid ""
+"Enter the external payment codes, comma separated. They will be used to "
+"select the payment journal."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_policy:0
+msgid "Packing Policy"
+msgstr "Politique d'Emballage"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Complete Delivery"
+msgstr "Livraison Complète"
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_generation_policy:0
+msgid "Invoice Generation Policy"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Ordered Quantities"
+msgstr "Quantités Commandées"
+
+#. module: connector_ecommerce
+#: help:sale.shop,is_tax_included:0
+msgid "Requires sale_tax_include module to be installed"
+msgstr "Requière le module sale_tax_include pour pouvoir être installé"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Catalog"
+msgstr "Catalogue"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "External Shop Settings"
+msgstr "Paramètres du Magasin Externe"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Catalog"
+msgstr "Exporter le Catalogue"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice from the Packing"
+msgstr "Facture de l'emballage"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Order Generation"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:account.journal,external_payment_codes:0
+msgid "External Payment Codes"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice on Order After Delivery"
+msgstr "Facture sur Commande Après Livraison"
+
+#. module: connector_ecommerce
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:external.shop.group,shop_ids:0
+msgid "Sale Shops"
+msgstr "Magasins de Vente"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,name:0
+msgid "Name"
+msgstr "Nom"
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_quantity:0
+msgid "Invoice on"
+msgstr "Facture sur"
+
+#. module: connector_ecommerce
+#: help:sale.shop,order_policy:0
+msgid ""
+"The Shipping Policy is used to synchronise invoice and delivery operations.\n"
+" - The 'Pay before delivery' choice will first generate the invoice and "
+"then generate the packing order after the payment of this invoice.\n"
+" - The 'Shipping & Manual Invoice' will create the packing order directly "
+"and wait for the user to manually click on the 'Invoice' button to generate "
+"the draft invoice.\n"
+" - The 'Invoice on Order After Delivery' choice will generate the draft "
+"invoice based on sale order after all packing lists have been finished.\n"
+" - The 'Invoice from the packing' choice is used to create an invoice "
+"during the packing process."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_inventory_export_date:0
+msgid "Last Inventory Export Time"
+msgstr "Date du Dernier Export d'Inventaire"
+
+#. module: connector_ecommerce
+#: field:external.referential,shop_group_ids:0
+msgid "Sub Entities"
+msgstr "Sous Entité"
+
+#. module: connector_ecommerce
+#: field:sale.shop,referential_id:0
+msgid "External Referential"
+msgstr "Référentiel Externe"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Payment Before Delivery"
+msgstr "Paiement Avant Livraison"
+
+#. module: connector_ecommerce
+#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
+msgid "Base Sale MultiChannels"
+msgstr "Ventes en Multi Canaux"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+#: field:sale.shop,exportable_product_ids:0
+msgid "Exportable Products"
+msgstr "Produits Exportables"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Import Orders"
+msgstr "Import des Commandes"
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_generation_policy:0
+msgid "Picking Generation Policy"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_generation_policy:0
+msgid "Should orders create an invoice after import?"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_update_order_export_date:0
+msgid "Last Order Update Time"
+msgstr "Date de la dernière mise à jour des commandes"
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_generation_policy:0
+msgid "Should orders create a picking after import?"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Validated"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_external_shop_group
+msgid "External Referential Shop Group"
+msgstr "Référence Externe du Groupe de Magasin"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Stock Levels Only"
+msgstr "Export des niveaux de Stock Seulement"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Shipping & Manual Invoice"
+msgstr "Expédition et Facture Manuelle"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Actions"
+msgstr "Actions"
+
+#. module: connector_ecommerce
+#: field:sale.shop,exportable_root_category_ids:0
+msgid "Root Category"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,is_tax_included:0
+msgid "Prices Include Tax?"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Shop"
+msgstr "Magasin de Vente"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Multi Channels"
+msgstr "Vente Multi Canaux"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Orders"
+msgstr "Commandes"
diff --git a/connector_ecommerce/i18n/pt.po b/connector_ecommerce/i18n/pt.po
new file mode 100644
index 00000000..34c89660
--- /dev/null
+++ b/connector_ecommerce/i18n/pt.po
@@ -0,0 +1,379 @@
+# Portuguese translation for openobject-addons
+# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2011.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2009-12-20 17:22+0000\n"
+"PO-Revision-Date: 2011-02-14 10:04+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Portuguese \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2012-01-17 05:05+0000\n"
+"X-Generator: Launchpad (build 14676)\n"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Partial Delivery"
+msgstr "Entrega Parcial"
+
+#. module: connector_ecommerce
+#: constraint:ir.model:0
+msgid ""
+"The Object name must start with x_ and not contain any special character !"
+msgstr ""
+"O nome do Objecto deve começar com x_ e não pode conter nenhum caracter "
+"especial !"
+
+#. module: connector_ecommerce
+#: model:ir.module.module,description:connector_ecommerce.module_meta_information
+msgid ""
+"\n"
+"This module provide an abstract common minimal base to multi-channels "
+"sales.\n"
+"Say you want to expose your product catalog to\n"
+"* several instances of flashy-sluggish Magento web sites\n"
+"* a cutting edge Spree web shop\n"
+"* a Neteven online Marketplace\n"
+"* EBay\n"
+"* Amazon\n"
+"* Google Base\n"
+"* an external Point Of Sale system\n"
+"* ...\n"
+"Then this module allows you to:\n"
+"* use several external references ids on every OpenERP object matching those "
+"all those external referentials\n"
+"* per referential instance, use several sale sub platform entities (ex: "
+"several Magento websites per instance)\n"
+"* per sub platform, use several shops (ex: several Magento web shops per "
+"website)\n"
+"\n"
+"For each sale shop (matching OpenERP sale.shop object), this module abstract "
+"the interfaces to:\n"
+"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
+"* import the catalog\n"
+"* import orders\n"
+"* export orders/picking status\n"
+" "
+msgstr ""
+"\n"
+"Este módulo fornece uma base comum mínima abstrata para vendas multi-"
+"canais.\n"
+"Digamos que queira expor o seu catálogo de produto para\n"
+"* várias instâncias de wev sites Magento flashy-sluggish\n"
+"* Uma loja online Spree de ponta\n"
+"* Uma Mercado Local online de Neteven\n"
+"* EBay\n"
+"* Amazon\n"
+"* Google Base\n"
+"* um sistema externo de Ponto de Venda\n"
+"* ...\n"
+"Então, este módulo permite-lhe fazer:\n"
+"* utilizar vários id externos de referência em cada objecto OpenERP "
+"correspondente a todas as referências externas\n"
+"* por referência de instância utilizar várias entradas de sub-plantaformas "
+"de vendas (ex: várias páginas web Magento por instância)\n"
+"* por sub-plantaforma, utilizar várias lojas (ec: várias lojas web Magento "
+"por página web)\n"
+"\n"
+"Para cada loja de venda (sale.shop.object correspondente OpenERP), este "
+"módulo abstrata as interfaces para:\n"
+"* exportar o catálogo,nível sensato de stock no armazém da loja, lista de "
+"preço justo da loja \n"
+"* importar o catálogo\n"
+"* importar ordens\n"
+"* exportar ordens/estado da recolha\n"
+" "
+
+#. module: connector_ecommerce
+#: field:sale.shop,order_policy:0
+msgid "Shipping Policy"
+msgstr "Política de Expedição"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "None"
+msgstr "Nenhum"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Shipped Quantities"
+msgstr "Quantidades Enviadas"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,referential_id:0
+msgid "Referential"
+msgstr "Referencial"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Draft"
+msgstr "Rascunho"
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_quantity:0
+msgid ""
+"The sale order will automatically create the invoice proposition (draft "
+"invoice). Ordered and delivered quantities may not be the same. You have to "
+"choose if you invoice based on ordered or shipped quantities. If the product "
+"is a service, shipped quantities means hours spent on the associated tasks."
+msgstr ""
+"A ordem de venda vai automáticamente criar uma proposta de factura (factura "
+"de rascunho). Quantidades entregues e ordenadas podem não ser a mesma. Vai "
+"ter que escolher se a sua factura é baseada em ordenada ou quantidades "
+"enviadas. Se o produto é um serviço, quantidades enviadas significa horas "
+"gastas nas tarefas associadas."
+
+#. module: connector_ecommerce
+#: field:sale.shop,shop_group_id:0
+msgid "Shop Group"
+msgstr "Grupo de Loja"
+
+#. module: connector_ecommerce
+#: field:product.category,recursive_childen_ids:0
+msgid "All Child Categories"
+msgstr "Todas as Categorias Descendentes"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Update Orders Status"
+msgstr "Estado das Ordens Actualizadas"
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_policy:0
+msgid ""
+"If you don't have enough stock available to deliver all at once, do you "
+"accept partial shipments or not?"
+msgstr ""
+"Se não tiver stock sufeciente desponível para entregar de uma vez, aceita "
+"transferência parciais ou não?"
+
+#. module: connector_ecommerce
+#: help:account.journal,external_payment_codes:0
+msgid ""
+"Enter the external payment codes, comma separated. They will be used to "
+"select the payment journal."
+msgstr ""
+"Entrar com os códigos de pagamento externo, vírgula separada. Eles serão "
+"utilizados para selecionar o diário de pagamento."
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_policy:0
+msgid "Packing Policy"
+msgstr "Política de Embalagem"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Complete Delivery"
+msgstr "Entrega completa"
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_generation_policy:0
+msgid "Invoice Generation Policy"
+msgstr "Politica de Geração de Factura"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Ordered Quantities"
+msgstr "Quantidades Ordenadas"
+
+#. module: connector_ecommerce
+#: help:sale.shop,is_tax_included:0
+msgid "Requires sale_tax_include module to be installed"
+msgstr "Requere que o módulo sale_tax_include seja instalado"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Catalog"
+msgstr "Catálogo"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "External Shop Settings"
+msgstr "Definições da Loja Externa"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Catalog"
+msgstr "Exportar Catálogo"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice from the Packing"
+msgstr "Factura de Embalagem"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Order Generation"
+msgstr "Ordem de Geração"
+
+#. module: connector_ecommerce
+#: field:account.journal,external_payment_codes:0
+msgid "External Payment Codes"
+msgstr "Códigos de Pagamento Externo"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice on Order After Delivery"
+msgstr "Ordem Facturada Antes da Entrega"
+
+#. module: connector_ecommerce
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr "XML Inválido para a Arquitectura de Vista!"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,shop_ids:0
+msgid "Sale Shops"
+msgstr "Lojas de Vendas"
+
+#. module: connector_ecommerce
+#: field:external.shop.group,name:0
+msgid "Name"
+msgstr "Nome"
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_quantity:0
+msgid "Invoice on"
+msgstr "Facturado em"
+
+#. module: connector_ecommerce
+#: help:sale.shop,order_policy:0
+msgid ""
+"The Shipping Policy is used to synchronise invoice and delivery operations.\n"
+" - The 'Pay before delivery' choice will first generate the invoice and "
+"then generate the packing order after the payment of this invoice.\n"
+" - The 'Shipping & Manual Invoice' will create the packing order directly "
+"and wait for the user to manually click on the 'Invoice' button to generate "
+"the draft invoice.\n"
+" - The 'Invoice on Order After Delivery' choice will generate the draft "
+"invoice based on sale order after all packing lists have been finished.\n"
+" - The 'Invoice from the packing' choice is used to create an invoice "
+"during the packing process."
+msgstr ""
+"A Políca de Entrega é utilizada para sincronizar a factura e as operações de "
+"entrega.\n"
+" - A escolha 'Pagar antes de entregar' vai gerar a factura e em seguida "
+"gerar uma ordem de embalagem depois do pagamento desta factura.\n"
+" - O 'Envio & Factura Manual' vai criar directamente a ordem de embalagem "
+"e esperar para que o utilizador clique manualmente no botão 'factura' para "
+"gerar uma factura rascunho.\n"
+" - A escolha 'Factura em Ordem Antes da Entrega' vai gerar uma factura "
+"rascunho baseada na ordem de venda depois de todas as listas de embalagem "
+"tenham terminado.\n"
+" - A escolha 'Factura a partir da embalagem' é utilizada para criar uma "
+"factura durante o processo de embalagem."
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_inventory_export_date:0
+msgid "Last Inventory Export Time"
+msgstr "Último Inventário de Exportação de Tempo"
+
+#. module: connector_ecommerce
+#: field:external.referential,shop_group_ids:0
+msgid "Sub Entities"
+msgstr "Sub Movimentos"
+
+#. module: connector_ecommerce
+#: field:sale.shop,referential_id:0
+msgid "External Referential"
+msgstr "Referencial Externa"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Payment Before Delivery"
+msgstr "Pagamento Antes da Entrega"
+
+#. module: connector_ecommerce
+#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
+msgid "Base Sale MultiChannels"
+msgstr "Venda Base de Multi-Canais"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+#: field:sale.shop,exportable_product_ids:0
+msgid "Exportable Products"
+msgstr "Produtos Exportados"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Import Orders"
+msgstr "Importar Ordem"
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_generation_policy:0
+msgid "Picking Generation Policy"
+msgstr "Política de Recolha de Geração"
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_generation_policy:0
+msgid "Should orders create an invoice after import?"
+msgstr "As ordens devem criar uma factura depois da importação?"
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_update_order_export_date:0
+msgid "Last Order Update Time"
+msgstr "Última Actualização da Ordem Tempo"
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_generation_policy:0
+msgid "Should orders create a picking after import?"
+msgstr "As ordens devem criar uma recolha depois da importação?"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Validated"
+msgstr "Validado"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_external_shop_group
+msgid "External Referential Shop Group"
+msgstr "Referencia Externa Grupo de Loja"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Stock Levels Only"
+msgstr "Exportar Somente os Níveis de Stock"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Shipping & Manual Invoice"
+msgstr "Expedição e Factura Manual"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Actions"
+msgstr "Acção"
+
+#. module: connector_ecommerce
+#: field:sale.shop,exportable_root_category_ids:0
+msgid "Root Category"
+msgstr "Categoria Raíz"
+
+#. module: connector_ecommerce
+#: field:sale.shop,is_tax_included:0
+msgid "Prices Include Tax?"
+msgstr "Preços Incluem Impostos?"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Shop"
+msgstr "Loja de Venda"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Multi Channels"
+msgstr "Venda Multi Canais"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Orders"
+msgstr "Ordem"
diff --git a/connector_ecommerce/i18n/sv.po b/connector_ecommerce/i18n/sv.po
new file mode 100644
index 00000000..6efbea0e
--- /dev/null
+++ b/connector_ecommerce/i18n/sv.po
@@ -0,0 +1,327 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * connector_ecommerce
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 5.0.14\n"
+"Report-Msgid-Bugs-To: support@openerp.com\n"
+"POT-Creation-Date: 2009-12-20 17:22+0000\n"
+"PO-Revision-Date: 2011-02-14 11:51+0000\n"
+"Last-Translator: Olivier Dony (OpenERP) \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2012-01-17 05:05+0000\n"
+"X-Generator: Launchpad (build 14676)\n"
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Partial Delivery"
+msgstr ""
+
+#. module: connector_ecommerce
+#: constraint:ir.model:0
+msgid ""
+"The Object name must start with x_ and not contain any special character !"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.module.module,description:connector_ecommerce.module_meta_information
+msgid ""
+"\n"
+"This module provide an abstract common minimal base to multi-channels "
+"sales.\n"
+"Say you want to expose your product catalog to\n"
+"* several instances of flashy-sluggish Magento web sites\n"
+"* a cutting edge Spree web shop\n"
+"* a Neteven online Marketplace\n"
+"* EBay\n"
+"* Amazon\n"
+"* Google Base\n"
+"* an external Point Of Sale system\n"
+"* ...\n"
+"Then this module allows you to:\n"
+"* use several external references ids on every OpenERP object matching those "
+"all those external referentials\n"
+"* per referential instance, use several sale sub platform entities (ex: "
+"several Magento websites per instance)\n"
+"* per sub platform, use several shops (ex: several Magento web shops per "
+"website)\n"
+"\n"
+"For each sale shop (matching OpenERP sale.shop object), this module abstract "
+"the interfaces to:\n"
+"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
+"* import the catalog\n"
+"* import orders\n"
+"* export orders/picking status\n"
+" "
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,order_policy:0
+msgid "Shipping Policy"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "None"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Shipped Quantities"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:external.shop.group,referential_id:0
+msgid "Referential"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Draft"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_quantity:0
+msgid ""
+"The sale order will automatically create the invoice proposition (draft "
+"invoice). Ordered and delivered quantities may not be the same. You have to "
+"choose if you invoice based on ordered or shipped quantities. If the product "
+"is a service, shipped quantities means hours spent on the associated tasks."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,shop_group_id:0
+msgid "Shop Group"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:product.category,recursive_childen_ids:0
+msgid "All Child Categories"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Update Orders Status"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_policy:0
+msgid ""
+"If you don't have enough stock available to deliver all at once, do you "
+"accept partial shipments or not?"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:account.journal,external_payment_codes:0
+msgid ""
+"Enter the external payment codes, comma separated. They will be used to "
+"select the payment journal."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_policy:0
+msgid "Packing Policy"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,picking_policy:0
+msgid "Complete Delivery"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_generation_policy:0
+msgid "Invoice Generation Policy"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_quantity:0
+msgid "Ordered Quantities"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,is_tax_included:0
+msgid "Requires sale_tax_include module to be installed"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Catalog"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "External Shop Settings"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Catalog"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice from the Packing"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Order Generation"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:account.journal,external_payment_codes:0
+msgid "External Payment Codes"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Invoice on Order After Delivery"
+msgstr ""
+
+#. module: connector_ecommerce
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:external.shop.group,shop_ids:0
+msgid "Sale Shops"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:external.shop.group,name:0
+msgid "Name"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,invoice_quantity:0
+msgid "Invoice on"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,order_policy:0
+msgid ""
+"The Shipping Policy is used to synchronise invoice and delivery operations.\n"
+" - The 'Pay before delivery' choice will first generate the invoice and "
+"then generate the packing order after the payment of this invoice.\n"
+" - The 'Shipping & Manual Invoice' will create the packing order directly "
+"and wait for the user to manually click on the 'Invoice' button to generate "
+"the draft invoice.\n"
+" - The 'Invoice on Order After Delivery' choice will generate the draft "
+"invoice based on sale order after all packing lists have been finished.\n"
+" - The 'Invoice from the packing' choice is used to create an invoice "
+"during the packing process."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_inventory_export_date:0
+msgid "Last Inventory Export Time"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:external.referential,shop_group_ids:0
+msgid "Sub Entities"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,referential_id:0
+msgid "External Referential"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Payment Before Delivery"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
+msgid "Base Sale MultiChannels"
+msgstr "Base Sale MultiChannels"
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+#: field:sale.shop,exportable_product_ids:0
+msgid "Exportable Products"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Import Orders"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,picking_generation_policy:0
+msgid "Picking Generation Policy"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,invoice_generation_policy:0
+msgid "Should orders create an invoice after import?"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,last_update_order_export_date:0
+msgid "Last Order Update Time"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.shop,picking_generation_policy:0
+msgid "Should orders create a picking after import?"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,invoice_generation_policy:0
+#: selection:sale.shop,picking_generation_policy:0
+msgid "Validated"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_external_shop_group
+msgid "External Referential Shop Group"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Export Stock Levels Only"
+msgstr ""
+
+#. module: connector_ecommerce
+#: selection:sale.shop,order_policy:0
+msgid "Shipping & Manual Invoice"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Actions"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,exportable_root_category_ids:0
+msgid "Root Category"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.shop,is_tax_included:0
+msgid "Prices Include Tax?"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Shop"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Sale Multi Channels"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.shop:0
+msgid "Orders"
+msgstr ""
diff --git a/connector_ecommerce/invoice.py b/connector_ecommerce/invoice.py
new file mode 100644
index 00000000..53b0b3af
--- /dev/null
+++ b/connector_ecommerce/invoice.py
@@ -0,0 +1,43 @@
+# -*- encoding: utf-8 -*-
+###############################################################################
+# #
+# connector_ecommerce for OpenERP #
+# Copyright (C) 2011 Akretion Sébastien BEAU #
+# #
+# 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 . #
+# #
+###############################################################################
+from openerp.osv.orm import Model
+from openerp.osv import fields
+
+class account_invoice(Model):
+ _inherit='account.invoice'
+
+ _columns={
+ 'shop_id': fields.many2one('sale.shop', 'Shop', readonly=True, states={'draft': [('readonly', False)]}),
+ 'do_not_export': fields.boolean(
+ 'Do not export',
+ help="This delivery order will not be exported "
+ "to the external referential."),
+ }
+
+ def _prepare_invoice_refund(self, cr, uid, ids, invoice_vals, date=None, period_id=None, description=None, journal_id=None, context=None):
+ invoice = self.browse(cr, uid, invoice_vals['id'], context=context)
+ invoice_vals = super(account_invoice, self)._prepare_invoice_refund(cr, uid, ids, invoice_vals, date=date, period_id=period_id,
+ description=description, journal_id=journal_id, context=context)
+ invoice_vals.update({
+ 'sale_ids': [(6,0, [sale.id for sale in invoice.sale_ids])],
+ 'shop_id': invoice.shop_id.id,
+ })
+ return invoice_vals
diff --git a/connector_ecommerce/invoice_view.xml b/connector_ecommerce/invoice_view.xml
new file mode 100644
index 00000000..5b6812bc
--- /dev/null
+++ b/connector_ecommerce/invoice_view.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+ base_sale_multichannel_invoice_form
+ account.invoice
+
+
+
+
+
+
+
+
+
+
+
diff --git a/connector_ecommerce/partner.py b/connector_ecommerce/partner.py
new file mode 100644
index 00000000..48fca23f
--- /dev/null
+++ b/connector_ecommerce/partner.py
@@ -0,0 +1,50 @@
+# -*- encoding: utf-8 -*-
+#################################################################################
+# #
+# connector_ecommerce for OpenERP #
+# Copyright (C) 2011 Akretion Sébastien BEAU #
+# #
+# 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 . #
+# #
+#################################################################################
+
+from openerp.osv import orm, fields
+
+
+class res_partner(orm.Model):
+ _inherit = 'res.partner'
+
+ _columns = {
+ 'shop_ids': fields.many2many(
+ 'sale.shop',
+ 'sale_shop_res_partner_rel',
+ 'shop_id',
+ 'partner_id',
+ string='Present in Shops',
+ readonly=True,
+ help="List of shops in which this customer exists."),
+ }
+
+ # xxx move to BaseConnector _get_import_defaults_res_partner
+ def _get_default_import_values(self, cr, uid, external_session, mapping_id=None, defaults=None, context=None):
+ if external_session.sync_from_object._name == 'sale.shop':
+ shop = external_session.sync_from_object
+ if not defaults: defaults = {}
+ defaults.update({
+ 'lang': shop.default_customer_lang.code,
+ 'property_account_position': shop.default_fiscal_position.id,
+ 'property_account_receivable': shop.default_customer_account,
+ 'shop_ids': [(4, shop.id)],
+ })
+ return defaults
diff --git a/connector_ecommerce/partner_view.xml b/connector_ecommerce/partner_view.xml
new file mode 100644
index 00000000..e52390b5
--- /dev/null
+++ b/connector_ecommerce/partner_view.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+ shop_ids.partner.form
+ res.partner
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/connector_ecommerce/payment_method.py b/connector_ecommerce/payment_method.py
new file mode 100644
index 00000000..6f4c2021
--- /dev/null
+++ b/connector_ecommerce/payment_method.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+#################################################################################
+# #
+# connector_ecommerce for OpenERP #
+# Copyright (C) 2011 Akretion Sébastien BEAU #
+# #
+# 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 . #
+# #
+#################################################################################
+
+
+from openerp.osv import orm, fields
+
+
+
+class payment_method(orm.Model):
+ _inherit = "payment.method"
+
+ _columns = {
+ 'automatic_update': fields.boolean(
+ 'Automatic Update',
+ help="If the order is not paid, OpenERP will call the "
+ "external system before each order import in order to know "
+ "if this order is paid"),
+ }
+
+ 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
+ """
+
+ pay_method_obj = self.pool.get('payment.method')
+ method_ids = pay_method_obj.search(cr, uid, [['name', '=ilike', payment_method]],
+ 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
diff --git a/connector_ecommerce/payment_method_view.xml b/connector_ecommerce/payment_method_view.xml
new file mode 100644
index 00000000..fd22077a
--- /dev/null
+++ b/connector_ecommerce/payment_method_view.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+ sale_automatic_workflow.payment_method.view_form
+ payment.method
+
+
+
+
+
+
+
+
+
+
+ sale_automatic_workflow.payment_method.view_tree
+ payment.method
+
+
+
+
+
+
+
+
+
+
+
diff --git a/connector_ecommerce/product.py b/connector_ecommerce/product.py
new file mode 100644
index 00000000..dc4e5419
--- /dev/null
+++ b/connector_ecommerce/product.py
@@ -0,0 +1,170 @@
+ # -*- encoding: utf-8 -*-
+###############################################################################
+# #
+# connector_ecommerce for OpenERP #
+# Copyright (C) 2011 Akretion Sébastien BEAU #
+# #
+# 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 . #
+# #
+###############################################################################
+
+
+from openerp.osv.orm import Model
+from openerp.osv import fields
+
+from openerp.addons.connector.decorator import only_for_referential
+from openerp.addons.connector.decorator import commit_now
+
+class product_product(Model):
+ _inherit='product.product'
+
+ def _check_if_export(self, cr, uid, external_session, product, context=None):
+ if context.get('export_product') == 'simple':
+ return True
+ return False
+
+ @only_for_referential(ref_categ ='Multichannel Sale')
+ def _get_last_exported_date(self, cr, uid, external_session, context=None):
+ shop = external_session.sync_from_object
+ if context.get('export_product') == 'simple':
+ return shop.last_products_export_date
+ elif context.get('export_product') == 'special':
+ return shop.last_special_products_export_date
+ return False
+
+ @only_for_referential(ref_categ ='Multichannel Sale')
+ @commit_now
+ def _set_last_exported_date(self, cr, uid, external_session, date, context=None):
+ shop = external_session.sync_from_object
+ if context.get('export_product') == 'simple':
+ return self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_products_export_date': date}, context=context)
+ elif context.get('export_product') == 'special':
+ return self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_special_products_export_date': date}, context=context)
+
+ @only_for_referential(ref_categ ='Multichannel Sale')
+ def get_ids_and_update_date(self, cr, uid, external_session, ids=None, last_exported_date=None, context=None):
+ res = (), {} # list of ids, dict of ids to date_changed
+ shop = external_session.sync_from_object
+ if shop.exportable_product_ids:
+ product_ids = [product.id for product in shop.exportable_product_ids if self._check_if_export(cr, uid, external_session, product, context=context)]
+ if ids:
+ product_ids = set(ids).intersection(set(product_ids))
+ if product_ids:
+ res = super(product_product, self).get_ids_and_update_date(cr, uid, external_session,
+ ids=product_ids,
+ last_exported_date=last_exported_date,
+ context=context)
+ return res
+
+
+ def _get_categories_ids_for_shop(self, cr, uid, product_id, shop_id, context=None):
+ shop_categ_ids = self.pool.get('sale.shop').read(cr, uid, shop_id,
+ ['exportable_category_ids'],
+ context=context)['exportable_category_ids']
+ product = self.read(cr, uid, product_id, ['categ_ids', 'categ_id'], context=context)
+ product_categ_ids = product['categ_ids']
+ if product['categ_id'][0] not in product_categ_ids:
+ product_categ_ids.append(product['categ_id'][0])
+ res = []
+ for categ in product_categ_ids:
+ if categ in shop_categ_ids:
+ res.append(categ)
+ return res
+
+ def _get_categories_ids_for_shop(self, cr, uid, product_id, shop_id, context=None):
+ shop_obj = self.pool.get('sale.shop')
+ shop_values = shop_obj.read(cr, uid, shop_id,
+ ['exportable_category_ids'],
+ context=context)
+ shop_categ_ids = set(shop_values['exportable_category_ids'])
+ product = self.read(cr, uid, product_id, ['categ_ids', 'categ_id'], context=context)
+ product_categ_ids = set(product['categ_ids'])
+ product_categ_ids.add(product['categ_id'][0])
+ return list(prod_categ_ids & shop_categ_ids)
+
+ def _get_or_create_ext_category_ids_for_shop(self, cr, uid, external_session, product_id, context=None):
+ res = []
+ categ_obj = self.pool.get('product.category')
+ for oe_categ_id in self._get_categories_ids_for_shop(cr, uid, product_id, external_session.sync_from_object.id, context=context):
+ res.append(categ_obj.get_or_create_extid(cr, uid, external_session, oe_categ_id, context=context))
+ return res
+
+
+
+class product_template(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):
+ result[product.id] = product.taxes_id and product.taxes_id[0].group_id.id
+ 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 use with some external',
+ ' system like magento or prestashop')),
+ }
+
+
+class product_category(Model):
+ _inherit = "product.category"
+
+ def collect_children(self, category, children=None):
+ if children is None:
+ children = []
+
+ for child in category.child_id:
+ children.append(child.id)
+ self.collect_children(child, children)
+
+ return children
+
+ def _get_recursive_children_ids(self, cr, uid, ids, name, args, context=None):
+ res = {}
+ for category in self.browse(cr, uid, ids):
+ res[category.id] = self.collect_children(category, [category.id])
+ return res
+
+ _columns = {
+ 'recursive_children_ids': fields.function(_get_recursive_children_ids, method=True, type='one2many', relation="product.category", string='All Child Categories'),
+ }
+
+ @only_for_referential(ref_categ ='Multichannel Sale')
+ def _get_last_exported_date(self, cr, uid, external_session, context=None):
+ shop = external_session.sync_from_object
+ return shop.last_category_export_date
+
+ @only_for_referential(ref_categ ='Multichannel Sale')
+ @commit_now
+ def _set_last_exported_date(self, cr, uid, external_session, date, context=None):
+ shop = external_session.sync_from_object
+ return self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_category_export_date': date}, context=context)
+
+ def get_ids_and_update_date(self, cr, uid, external_session, ids=None, last_exported_date=None, context=None):
+ shop = external_session.sync_from_object
+ if shop.exportable_category_ids:
+ res = super(product_category, self).get_ids_and_update_date(cr, uid, external_session,
+ ids=[categ.id for categ in shop.exportable_category_ids],
+ last_exported_date=last_exported_date,
+ context=context)
+ else:
+ res = (), {} # list of ids, dict of ids to date_changed
+ return res
+
diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py
new file mode 100644
index 00000000..13827b3b
--- /dev/null
+++ b/connector_ecommerce/sale.py
@@ -0,0 +1,993 @@
+# -*- encoding: utf-8 -*-
+#########################################################################
+# #
+# Copyright (C) 2009 Raphaël Valyi #
+# Copyright (C) 2010-2011 Akretion Sébastien BEAU #
+# #
+# Copyright (C) 2011-2012 Camptocamp Guewen Baconnier #
+# Copyright (C) 2011 by Openlabs Technologies & Consulting (P) Limited #
+# #
+#This program is free software: you can redistribute it and/or modify #
+#it under the terms of the GNU 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 General Public License for more details. #
+# #
+#You should have received a copy of the GNU General Public License #
+#along with this program. If not, see . #
+#########################################################################
+
+from openerp.osv.orm import Model
+from openerp.osv import fields
+from openerp.osv.osv import except_osv
+from openerp import pooler
+from sets import Set as set
+from openerp import netsvc
+from openerp.tools.translate import _
+import time
+import openerp.addons.decimal_precision as dp
+from datetime import datetime, timedelta
+from dateutil.relativedelta import relativedelta
+from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
+from openerp.addons.connector.external_osv import ExternalSession
+from openerp.addons.connector.decorator import open_report
+from openerp.addons.connector.decorator import catch_error_in_report
+
+import logging
+_logger = logging.getLogger(__name__)
+
+
+class external_shop_group(Model):
+ _name = 'external.shop.group'
+ _description = 'External Referential Shop Group'
+
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True),
+ 'referential_id': fields.many2one('external.referential', 'Referential', select=True,
+ ondelete='cascade'),
+ 'shop_ids': fields.one2many('sale.shop', 'shop_group_id', 'Sale Shops'),
+ }
+
+ # xxx move to BaseConnector _get_import_defaults_external_shop_group
+ def _get_default_import_values(self, cr, uid, external_session, **kwargs):
+ return {'referential_id' : external_session.referential_id.id}
+
+
+class external_referential(Model):
+ _inherit = 'external.referential'
+
+ _columns = {
+ 'shop_group_ids': fields.one2many('external.shop.group', 'referential_id', 'Sub Entities'),
+ }
+
+
+
+class ExternalShippingCreateError(Exception):
+ """
+ This error has to be raised when we tried to create a stock.picking on
+ the external referential and the external referential has failed
+ to create it. It must be raised only when we are SURE that the
+ external referential will never be able to create it!
+ """
+ pass
+
+
+class sale_shop(Model):
+ _inherit = "sale.shop"
+
+ def _get_exportable_category_ids(self, cr, uid, ids, name, args, context=None):
+ res = {}
+ for shop in self.browse(cr, uid, ids, context=context):
+ res[shop.id] = set()
+ for category in shop.exportable_root_category_ids:
+ res[shop.id] = res[shop.id].union(set(self.pool.get('product.category')._get_recursive_children_ids(cr, uid, [category.id], "", [], context)[category.id]))
+ res[shop.id] = list(res[shop.id])
+ return res
+
+ def _get_exportable_product_ids(self, cr, uid, ids, name, args, context=None):
+ res = {}
+ for shop in self.read(cr, uid, ids, ['exportable_category_ids'], context=context):
+ all_categories = shop['exportable_category_ids']
+
+ # If product_m2mcategories module is installed search in main category
+ # and extra categories. If not, only in main category
+ cr.execute('select * from ir_module_module where name=%s and state=%s',
+ ('product_m2mcategories','installed'))
+ if cr.fetchone():
+ res[shop['id']] = self.pool.get("product.product").search(cr, uid, ['|',
+ ('categ_id', 'in', all_categories),('categ_ids', 'in', all_categories)])
+ else:
+ res[shop['id']] = self.pool.get("product.product").search(cr, uid,
+ [('categ_id', 'in', all_categories)])
+ return res
+
+ def _get_referential_id(self, cr, uid, ids, name, args, context=None):
+ res = {}
+ for shop in self.browse(cr, uid, ids, context=context):
+ if shop.shop_group_id:
+ res[shop.id] = shop.shop_group_id.referential_id.id
+ else:
+ res[shop.id] = shop.referential_integer_id
+ return res
+
+ def _get_shop_from_shop_group(self, cr, uid, ids, context=None):
+ return self.pool.get('sale.shop').search(cr, uid, [('shop_group_id', 'in', ids)], context=context)
+
+ def _set_referential_id(self, cr, uid, id, name, value, arg, context=None):
+ shop = self.browse(cr, uid, id, context=context)
+ if shop.shop_group_id:
+ raise except_osv(_("User Error"), _("You can not change the referential of this shop, please change the referential of the shop group!"))
+ else:
+ self.write(cr, uid, id, {'referential_integer_id': value}, context=context)
+ return True
+
+ def _get_shop_ids(self, cr, uid, ids, context=None):
+ shop_ids=[]
+ for group in self.pool.get('external.shop.group').browse(cr, uid, ids, context=context):
+ shop_ids += [shop.id for shop in group.shop_ids]
+ return shop_ids
+
+ def _get_stock_field_id(self, cr, uid, context=None):
+ if self.pool.get('ir.module.module').search(cr, uid, [
+ ['name', '=', 'stock_available_immediately'],
+ ['state', 'in', ['installed', 'to upgrade']],
+ ], context=context):
+ stock_field = 'immediately_usable_qty'
+ else:
+ stock_field = 'virtual_available'
+
+ field_ids = self.pool.get('ir.model.fields').search(
+ cr, uid,
+ [('model', '=', 'product.product'),
+ ('name', '=', stock_field)],
+ context=context)
+ return field_ids[0]
+
+ #Depending of the e-commerce solution use you can have one or more root category
+ #If you need only one the value will be stored in the exportable_root_category_ids fields
+ def _get_rootcategory(self, cr, uid, ids, name, value, context=None):
+ res = {}
+ for shop in self.browse(cr, uid, ids, context):
+ res[shop.id] = shop.exportable_root_category_ids and shop.exportable_root_category_ids[0].id or False
+ return res
+
+ def _set_rootcategory(self, cr, uid, id, name, value, fnct_inv_arg, context=None):
+ return self.write(cr, uid, id, {'exportable_root_category_ids': [(6,0,[value])]}, context=context)
+
+ def _get_referential_type_name(self, cr, uid, ids, field_name, arg, context=None):
+ result = {}
+ for shop in self.browse(cr, uid, ids):
+ if shop.referential_id:
+ result[shop.id] = shop.referential_id.type_id.name
+ else:
+ result[shop.id] = False
+ return result
+
+ _columns = {
+ 'exportable_category_ids': fields.function(_get_exportable_category_ids, type='many2many', relation="product.category", string='Exportable Categories'),
+ 'exportable_root_category_ids': fields.many2many('product.category', 'shop_category_rel', 'categ_id', 'shop_id', 'Exportable Root Categories'),
+ 'exportable_root_category_id':fields.function(_get_rootcategory, fnct_inv = _set_rootcategory, type="many2one", relation="product.category", string="Root Category"),
+ 'exportable_product_ids': fields.function(_get_exportable_product_ids, type='many2many', relation="product.product", string='Exportable Products'),
+ 'shop_group_id': fields.many2one('external.shop.group', 'Shop Group', ondelete='cascade'),
+ # to remove?
+ 'last_inventory_export_date': fields.datetime('Last Inventory Export Time'),
+ # to remove
+ 'last_images_export_date': fields.datetime('Last Images Export Time'),
+ # to remove
+ 'last_update_order_export_date' : fields.datetime('Last Order Update Time'),
+ # to remove
+ 'last_products_export_date' : fields.datetime('Last Product Export Time'),
+ # to remove
+ 'last_special_products_export_date' : fields.datetime('Last Special Product Export Time'),
+ # to remove
+ 'last_category_export_date' : fields.datetime('Last Category Export Time'),
+ 'referential_id': fields.function(
+ _get_referential_id,
+ fnct_inv=_set_referential_id,
+ type='many2one',
+ relation='external.referential',
+ string='External Referential',
+ store={
+ 'sale.shop': (
+ lambda self, cr, uid, ids, c=None: ids,
+ ['referential_integer_id', 'shop_group_id'],
+ 10),
+ 'external.shop.group': (
+ _get_shop_from_shop_group,
+ ['referential_id'],
+ 20),
+ }),
+ # wat?
+ 'referential_integer_id': fields.integer('Referential Integer ID'),
+ 'is_tax_included': fields.boolean(
+ 'Prices Include Tax',
+ help="Does the external system work with Taxes Inclusive prices ?"),
+ 'sale_journal': fields.many2one('account.journal', 'Sale Journal'),
+ 'order_prefix': fields.char('Order Prefix', size=64),
+ 'default_payment_method_id': fields.many2one('payment.method', 'Payment Method'),
+ 'default_language': fields.many2one('res.lang', 'Default Language'),
+ 'default_fiscal_position': fields.many2one('account.fiscal.position', 'Default Fiscal Position'),
+ 'default_customer_account': fields.many2one('account.account', 'Default Customer Account'),
+ 'default_customer_lang': fields.many2one('res.lang', 'Default Customer Language'),
+ 'auto_import': fields.boolean('Automatic Import'),
+ # 'address_id':fields.many2one('res.partner.address', 'Address'),
+ # TODO migrate from address to partner?
+ 'partner_id':fields.many2one('res.partner', 'Partner'),
+ 'website': fields.char('Website', size=64),
+ 'image':fields.binary('Image', filters='*.png,*.jpg,*.gif'),
+ # to remove? (always computed by openerp)
+ 'use_external_tax': fields.boolean(
+ 'Use External Taxes',
+ help="If activated, the external taxes will be applied.\n"
+ "If not activated, OpenERP will compute them "
+ "according to default values and fiscal positions."),
+ 'import_orders_from_date': fields.datetime('Only created after'),
+ # to remove? always check
+ 'check_total_amount': fields.boolean('Check Total Amount', help="The total amount computed by OpenERP should match with the external amount, if not the sale order can not be confirmed."),
+ # to remove
+ 'type_name': fields.function(_get_referential_type_name, type='char', string='Referential type',
+ store={
+ 'sale.shop': (lambda self, cr, uid, ids, c={}: ids, ['referential_id', 'shop_group_id'],10)}),
+ 'product_stock_field_id': fields.many2one(
+ 'ir.model.fields',
+ string='Stock Field',
+ domain="[('model', 'in', ['product.product', 'product.template']),"
+ " ('ttype', '=', 'float')]",
+ help="Choose the field of the product which will be used for "
+ "stock inventory updates.\nIf empty, Quantity Available "
+ "is used"),
+ }
+
+ _defaults = {
+ # FIXME, WTF with that default value
+ 'payment_default_id': 1, #required field that would cause trouble if not set when importing
+ 'auto_import': True,
+ 'use_external_tax': True,
+ 'product_stock_field_id': _get_stock_field_id,
+ }
+
+ def init_context_before_exporting_resource(self, cr, uid, external_session, object_id, resource_name, context=None):
+ context = super(sale_shop, self).init_context_before_exporting_resource(cr, uid, external_session, object_id, resource_name, context=context)
+ context['pricelist'] = external_session.sync_from_object.get_pricelist(context=context)
+ return context
+
+ def get_pricelist(self, cr, uid, id, context=None):
+ if isinstance(id, list):
+ id=id[0]
+ shop = self.browse(cr, uid, id, context=context)
+ if shop.pricelist_id:
+ return shop.pricelist_id.id
+ else:
+ return self.pool.get('product.pricelist').search(cr, uid, [('type', '=', 'sale'), ('active', '=', True)], context=context)[0]
+
+ def export_catalog(self, cr, uid, ids, context=None):
+ if context is None: context={}
+ self.export_resources(cr, uid, ids, 'product.category', context=context)
+ # In various e-commerce system product can depend of other products
+ # So the simple product (with no dependency) are exported in priority
+ # Then the special product (with dependency) are exported at the end
+ context['export_product'] = 'simple'
+ self.export_resources(cr, uid, ids, 'product.product', context=context)
+ context['export_product'] = 'special'
+ self.export_resources(cr, uid, ids, 'product.product', context=context)
+ #Export Images
+ self.export_resources(cr, uid, ids, 'product.images', context=context)
+
+ #TODO export link
+ #TODO update the last date
+ #I don't know where it's the best to update it here or in the export functions
+ #take care about concurent write with different cursor
+
+
+ return True
+
+ def export_inventory(self, cr, uid, ids, context=None):
+ if context is None:
+ context = {}
+ for shop in self.browse(cr, uid, ids):
+ external_session = ExternalSession(shop.referential_id, shop)
+ self._export_inventory(cr, uid, external_session, ids, context=context)
+ return True
+
+ def _get_product_ids_for_stock_to_export(self, cr, uid, shop, context=None):
+ return [product.id for product in shop.exportable_product_ids]
+
+ def _export_inventory(self, cr, uid, external_session, ids, context=None):
+ shop = external_session.sync_from_object
+ stock_move_obj = self.pool.get('stock.move')
+ for shop in self.browse(cr, uid, ids):
+ external_session = ExternalSession(shop.referential_id, shop)
+
+ product_ids = self._get_product_ids_for_stock_to_export(cr, uid, shop, context=context)
+
+ if shop.last_inventory_export_date:
+ # we do not exclude canceled moves because it means
+ # some stock levels could have increased since last export
+ recent_move_ids = stock_move_obj.search(
+ cr, uid,
+ [('write_date', '>', shop.last_inventory_export_date),
+ ('product_id', 'in', product_ids),
+ ('product_id.type', '!=', 'service'),
+ ('state', '!=', 'draft')],
+ context=context)
+ else:
+ recent_move_ids = stock_move_obj.search(
+ cr, uid,
+ [('product_id', 'in', product_ids)],
+ context=context)
+
+ recent_moves = stock_move_obj.browse(
+ cr, uid, recent_move_ids, context=context)
+
+ product_ids = [move.product_id.id
+ for move
+ in recent_moves
+ if move.product_id.state != 'obsolete']
+ product_ids = list(set(product_ids))
+ external_session.logger.info('Export Stock for %s products' %len(product_ids))
+ self.pool.get('product.product').export_inventory(
+ cr, uid, external_session, product_ids, context=context)
+ shop.write({'last_inventory_export_date':
+ time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
+ return True
+
+ def import_catalog(self, cr, uid, ids, context):
+ #TODO import categories, then products
+ raise except_osv(_("Not Implemented"), _("Not Implemented in abstract base module!"))
+
+ def import_orders(self, cr, uid, ids, context=None):
+ self.import_resources(cr, uid, ids, 'sale.order', context=context)
+ return True
+
+ def check_need_to_update(self, cr, uid, ids, context=None):
+ """ This function will update the order status in OpenERP for
+ the order which are in the state 'need to update' """
+ for shop in self.browse(cr, uid, ids, context=context):
+ external_session = ExternalSession(shop.referential_id, shop)
+ so_obj = self.pool.get('sale.order')
+ orders_to_update = so_obj.search(cr, uid,
+ [('need_to_update', '=', True),
+ ('shop_id', '=', shop.id)],
+ context=context)
+ so_obj._check_need_to_update(cr, uid, external_session, orders_to_update, context=context)
+ return False
+
+ def _update_order_query(self, cr, uid, shop, context=None):
+ req = """
+ SELECT ir_model_data.res_id, ir_model_data.name
+ FROM sale_order
+ INNER JOIN ir_model_data ON sale_order.id = ir_model_data.res_id
+ WHERE ir_model_data.model='sale.order' AND sale_order.shop_id=%s
+ AND ir_model_data.referential_id NOTNULL
+ """
+ params = (shop.id,)
+ if shop.last_update_order_export_date:
+ req += "AND sale_order.update_state_date > %s"
+ params = (shop.id, shop.last_update_order_export_date)
+ return req, params
+
+ def update_orders(self, cr, uid, ids, context=None):
+ if context is None:
+ context = {}
+ for shop in self.browse(cr, uid, ids):
+ external_session = ExternalSession(shop.referential_id, shop)
+ #get all orders, which the state is not draft and the date of modification is superior to the last update, to exports
+ cr.execute(*self._update_order_query(cr, uid, shop, context=context))
+ results = cr.fetchall()
+ for result in results:
+ ids = self.pool.get('sale.order').search(cr, uid, [('id', '=', result[0])])
+ if ids:
+ id = ids[0]
+ order = self.pool.get('sale.order').browse(cr, uid, id, context)
+ order_ext_id = result[1].split('sale_order/')[1]
+ res = self.update_shop_orders(cr, uid, external_session, order, order_ext_id, context)
+ if res:
+ external_session.logger.info(_("Successfully updated order with OpenERP id %s and ext id %s in external sale system") % (id, order_ext_id))
+ self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_update_order_export_date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
+ return False
+
+ def export_shop_partners(self, cr, uid, ids, context=None):
+ if context is None: context={}
+ self.export_resources(cr, uid, ids, 'res.partner', context=context)
+ return True
+
+ def update_shop_orders(self, cr, uid, external_session, order, ext_id, context):
+ raise except_osv(_("Not Implemented"), _("Not Implemented in abstract base module!"))
+
+ def _export_shipping_query(self, cr, uid, shop, context=None):
+ query = """
+ SELECT stock_picking.id AS picking_id,
+ sale_order.id AS order_id,
+ count(pickings.id) AS picking_number
+ FROM stock_picking
+ LEFT JOIN sale_order
+ ON sale_order.id = stock_picking.sale_id
+ LEFT JOIN stock_picking as pickings
+ ON (sale_order.id = pickings.sale_id
+ AND pickings.type='out'
+ AND pickings.state!='cancel')
+ LEFT JOIN ir_model_data
+ ON stock_picking.id = ir_model_data.res_id
+ AND ir_model_data.model = 'stock.picking'
+ LEFT JOIN delivery_carrier
+ ON delivery_carrier.id = stock_picking.carrier_id
+ WHERE sale_order.shop_id = %(shop_id)s
+ AND ir_model_data.res_id ISNULL
+ AND stock_picking.state = 'done'
+ AND stock_picking.type = 'out'
+ AND NOT stock_picking.do_not_export
+ AND (NOT delivery_carrier.export_needs_tracking
+ OR stock_picking.carrier_tracking_ref IS NOT NULL)
+ GROUP BY stock_picking.id,
+ sale_order.id,
+ delivery_carrier.export_needs_tracking,
+ stock_picking.carrier_tracking_ref,
+ stock_picking.backorder_id
+ ORDER BY sale_order.id ASC,
+ COALESCE(stock_picking.backorder_id, NULL, 0) ASC"""
+ params = {'shop_id': shop.id}
+ return query, params
+
+ def export_shipping(self, cr, uid, ids, context):
+ picking_obj = self.pool.get('stock.picking')
+ for shop in self.browse(cr, uid, ids):
+ cr.execute(*self._export_shipping_query(
+ cr, uid, shop, context=context))
+ results = cr.dictfetchall()
+ if not results:
+ _logger.info("There is no shipping to export for the shop '%s' to the external referential", shop.name)
+ continue
+ context['conn_obj'] = shop.referential_id.external_connection()
+
+
+ picking_cr = pooler.get_db(cr.dbname).cursor()
+ try:
+ for result in results:
+ picking_id = result['picking_id']
+
+ if result["picking_number"] == 1:
+ picking_type = 'complete'
+ else:
+ picking_type = 'partial'
+
+ ext_shipping_id = False
+ try:
+ ext_shipping_id = picking_obj.create_ext_shipping(
+ picking_cr, uid, picking_id, picking_type,
+ shop.referential_id.id, context)
+ except ExternalShippingCreateError, e:
+ # when the creation has failed on the external
+ # referential and we know that we can never
+ # create it, we flag it as do_not_export
+ # ExternalShippingCreateError raising has to be
+ # correctly handled by create_ext_shipping()
+ picking_obj.write(
+ picking_cr, uid,
+ picking_id,
+ {'do_not_export': True},
+ context=context)
+
+ if ext_shipping_id:
+ picking_obj.create_external_id_vals(
+ picking_cr,
+ uid,
+ picking_id,
+ ext_shipping_id,
+ shop.referential_id.id,
+ context=context)
+ _logger.info("Successfully creating shipping with OpenERP id %s and ext id %s in external sale system", result["picking_id"], ext_shipping_id)
+ picking_cr.commit()
+ finally:
+ picking_cr.close()
+ return True
+
+ def export_invoices(self, cr, uid, ids, context=None):
+ invoice_obj = self.pool.get('account.invoice')
+ for shop in self.browse(cr, uid, ids, context=None):
+ external_session = ExternalSession(shop.referential_id, shop)
+ invoice_ids = self.get_invoice_to_export(cr, uid, shop.id, context=context)
+ if not invoice_ids:
+ external_session.logger.info("There is no invoice to export for the shop '%s' to the external referential" % (shop.name,))
+ for invoice_id in invoice_ids:
+ self.pool.get('account.invoice')._export_one_resource(cr, uid, external_session, invoice_id, context=context)
+ return True
+
+ def get_invoice_to_export(self, cr, uid, shop_id, context=None):
+ shop = self.browse(cr, uid, shop_id, context=context)
+ cr.execute(*self._export_invoice_query(cr, uid, shop, context=context))
+ results = cr.dictfetchall()
+ return [res['invoice_id'] for res in results]
+
+ def _export_invoice_query(self, cr, uid, shop, context=None):
+ query = """
+ SELECT account_invoice.id AS invoice_id
+ FROM account_invoice
+ LEFT JOIN ir_model_data
+ ON account_invoice.id = ir_model_data.res_id
+ AND ir_model_data.model = 'account.invoice'
+ AND referential_id = %(referential_id)s
+ WHERE shop_id = %(shop_id)s
+ AND ir_model_data.res_id ISNULL
+ AND account_invoice.state in ('paid', 'open')
+ AND NOT account_invoice.do_not_export
+ """
+ params = {'shop_id': shop.id, 'referential_id': shop.referential_id.id}
+ return query, params
+
+sale_shop()
+
+
+class sale_order(Model):
+ _inherit = "sale.order"
+
+ _columns = {
+ # to remove? will the orders be created as draft when they
+ # wait a payment or are they not imported at all? (the job
+ # retries at intervals)
+ 'need_to_update': fields.boolean('Need To Update'),
+ 'ext_total_amount': fields.float(
+ 'Origin External Amount',
+ digits_compute=dp.get_precision('Sale Price'),
+ readonly=True),
+ 'ext_total_amount_tax': fields.float(
+ 'Origin External Tax Amount',
+ digits_compute=dp.get_precision('Sale Price'),
+ readonly=True),
+ 'referential_id': fields.related(
+ 'shop_id',
+ 'referential_id',
+ type='many2one',
+ relation='external.referential',
+ string='External Referential'),
+ 'update_state_date': fields.datetime('Update State Date'),
+ # FIXME WTF are these 3 fields
+ 'shipping_tax_amount': fields.dummy(string = 'Shipping Taxe Amount'),
+ 'shipping_amount_tax_excluded': fields.dummy(string = 'Shipping Price Tax Exclude'),
+ 'shipping_amount_tax_included': fields.dummy(string = 'Shipping Price Tax Include'),
+ }
+
+ _defaults = {
+ 'need_to_update': False,
+ }
+
+ def write(self, cr, uid, ids, vals, context=None):
+ if 'state' in vals:
+ vals['update_state_date'] = datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT)
+ return super(sale_order, self).write(cr, uid, ids, vals, context=context)
+
+ # xxx move to BaseConnector _get_import_defaults_sale_order
+ def _get_default_import_values(self, cr, uid, external_session, mapping_id=None, defaults=None, context=None):
+ shop = False
+ if external_session.sync_from_object._name == 'sale.shop':
+ shop = external_session.sync_from_object
+ elif context.get('sale_shop_id'):
+ shop = self.pool.get('sale.shop').browse(cr, uid, context['sale_shop_id'], context=context)
+ if shop:
+ if defaults is None: defaults = {}
+ defaults.update({
+ 'pricelist_id': shop.get_pricelist(context=context),
+ 'shop_id': shop.id,
+ 'fiscal_position': shop.default_fiscal_position.id,
+ 'payment_method_id': shop.default_payment_method_id.id,
+ 'company_id': shop.company_id.id,
+ })
+ #TODO we should avoid passing this parameter in the context
+ #for now we new it for importing order from wizard correctly
+ #refactor for V7
+ context.update({
+ 'use_external_tax': shop.use_external_tax,
+ 'is_tax_included': shop.is_tax_included,
+ })
+ return defaults
+
+ @open_report
+ def _import_resources(self, cr, uid, external_session, defaults=None, method="search_then_read", context=None):
+ if context is None: context={}
+ shop = external_session.sync_from_object
+ if shop:
+ context.update({
+ 'use_external_tax': shop.use_external_tax,
+ 'is_tax_included': shop.is_tax_included,
+ })
+ return super(sale_order, self)._import_resources(cr, uid, external_session, defaults=defaults, method=method, context=context)
+
+
+ def check_if_order_exist(self, cr, uid, external_session, resource, order_mapping=None, defaults=None, context=None):
+ mapping_name = False
+ for line in order_mapping['mapping_lines']:
+ if line['internal_field'] == 'name':
+ mapping_name = line
+ if mapping_name:
+ local_mapping = {1: {'mapping_lines': [mapping_name]}}
+ vals = self._transform_one_resource(cr, uid, external_session,
+ 'from_external_to_openerp', resource,
+ mapping=local_mapping,
+ mapping_id=1,
+ defaults=defaults,
+ context=context)
+ if vals.get('name'):
+ exist_id = self.search(cr, uid, [['name', '=', vals['name']]], context=context)
+ if exist_id:
+ external_session.logger.info("Sale Order %s already exist in OpenERP,"
+ "no need to import it again"%vals['name'])
+ return True
+
+ return False
+
+ # xxx a deplacer dans BaseConnector sale_order
+ @catch_error_in_report
+ def _record_one_external_resource(self, cr, uid, external_session, resource, defaults=None,
+ mapping=None, mapping_id=None, context=None):
+ mapping, mapping_id = self._init_mapping(cr, uid, external_session.referential_id.id,
+ mapping=mapping, mapping_id=mapping_id, context=context)
+ exist_id = self.check_if_order_exist(cr, uid, external_session, resource,
+ order_mapping=mapping[mapping_id], defaults=defaults, context=context)
+ if exist_id:
+ return {}
+ else:
+ return super(sale_order, self)._record_one_external_resource(cr, uid, external_session, resource,
+ defaults=defaults, mapping=mapping, mapping_id=mapping_id, context=context)
+
+ def _check_need_to_update(self, cr, uid, external_session, ids, context=None):
+ """
+ For each order, check in external system if it has been paid since last
+ check. If so, it will launch the defined flow based on the
+ payment type (validate order, invoice, ...)
+ """
+ for order in self.browse(cr, uid, ids, context=context):
+ self._check_need_to_update_single(cr, uid, external_session, order, context=context)
+ return True
+
+ def _check_need_to_update_single(self, cr, uid, external_session, order, context=None):
+ """Not implemented in this abstract module"""
+ return True
+
+ def _get_params_onchange_partner_id(self, cr, uid, vals, context=None):
+ args = [
+ 'None',
+ vals.get('partner_id'),
+ ]
+ return args, {}
+
+ #I will probably extract this code in order to put it in a "glue" module
+ def _get_params_onchange_address_id(self, cr, uid, vals, context=None):
+ args = [
+ None,
+ vals.get('partner_invoice_id'),
+ vals.get('partner_shipping_id'),
+ vals.get('partner_id'),
+ ]
+ kwargs = {
+ 'shop_id': vals.get('shop_id'),
+ }
+ return args, kwargs
+
+ def play_sale_order_onchange(self, cr, uid, vals, defaults=None, context=None):
+ ir_module_obj= self.pool.get('ir.module.module')
+ if ir_module_obj.search(cr, uid, [
+ ['name', '=', 'account_fiscal_position_rule_sale'],
+ ['state', 'in', ['installed', 'to upgrade']],
+ ], context=context):
+ vals = self.call_onchange(cr, uid, 'onchange_partner_id', vals, defaults, context=context)
+ vals = self.call_onchange(cr, uid, 'onchange_address_id', vals, defaults, context=context)
+ else:
+ vals = self.call_onchange(cr, uid, 'onchange_partner_id', vals, defaults, context=context)
+
+
+ return vals
+
+ def _merge_with_default_values(self, cr, uid, external_session, ressource, vals, sub_mapping_list, defaults=None, context=None):
+ if vals.get('name'):
+ shop = external_session.sync_from_object
+ if shop.order_prefix:
+ vals['name'] = '%s%s' %(shop.order_prefix, vals['name'])
+ if context is None: context ={}
+ if vals.get('payment_method_id'):
+ payment_method = self.pool.get('payment.method').browse(cr, uid, vals['payment_method_id'], context=context)
+ workflow_process = payment_method.workflow_process_id
+ if workflow_process:
+ vals['order_policy'] = workflow_process.order_policy
+ vals['picking_policy'] = workflow_process.picking_policy
+ vals['invoice_quantity'] = workflow_process.invoice_quantity
+ # update vals with order onchange in order to compute taxes
+ vals = self.play_sale_order_onchange(cr, uid, vals, defaults=defaults, context=context)
+ return super(sale_order, self)._merge_with_default_values(cr, uid, external_session, ressource, vals, sub_mapping_list, defaults=defaults, context=context)
+
+ def oe_create(self, cr, uid, external_session, vals, resource, defaults, context):
+ #depending of the external system the contact address can be optionnal
+ vals = self._convert_special_fields(cr, uid, vals, external_session.referential_id.id, context=context)
+ if not vals.get('partner_order_id'):
+ vals['partner_order_id'] = vals['partner_invoice_id']
+ if not vals.get('partner_shipping_id'):
+ vals['partner_shipping_id'] = vals['partner_invoice_id']
+ order_id = super(sale_order, self).oe_create(cr, uid, external_session, vals, resource, defaults, context)
+ self.paid_and_update(cr, uid, external_session, order_id, resource, context=context)
+ return order_id
+
+ def paid_and_update(self, cr, uid, external_session, order_id, resource, context=None):
+ wf_service = netsvc.LocalService("workflow")
+ paid = self.create_external_payment(cr, uid, external_session, order_id, resource, context)
+ order = self.browse(cr, uid, order_id, context=context)
+ validate_order = order.workflow_process_id.validate_order
+ if validate_order == 'always' or validate_order == 'if_paid' and paid:
+ try:
+ wf_service.trg_validate(uid, 'sale.order', order.id, 'order_confirm', cr)
+ except:
+ raise
+ #What we should do?? creating the order but not validating it???
+ #Maybe setting a special flag can be a good solution? with a retry method?
+ return True
+
+ elif validate_order == 'if_paid' and order.payment_method_id.automatic_update:
+ days_before_order_cancel = order.workflow_process_id.days_before_order_cancel or 30
+ order_date = datetime.strptime(order.date_order, DEFAULT_SERVER_DATE_FORMAT)
+ order_cancel_date = order_date + relativedelta(days=days_before_order_cancel)
+ if order.state == 'draft' and order_cancel_date < datetime.now():
+ wf_service.trg_validate(uid, 'sale.order', order.id, 'cancel', cr)
+ self.write(cr, uid, order.id, {'need_to_update': False})
+ self.log(cr, uid, order.id, ("order %s canceled in OpenERP because older than % days"
+ "and still not confirmed") % (order.id, days_before_order_cancel))
+ #TODO eventually call a trigger to cancel the order in the external system too
+ external_session.logger.info(("order %s canceled in OpenERP because older than % days and "
+ "still not confirmed") %(order.id, days_before_order_cancel))
+ else:
+ self.write(cr, uid, order_id, {'need_to_update': True}, context=context)
+ return False
+
+ def create_external_payment(self, cr, uid, external_session, order_id, resource, context):
+ """
+ Fonction that will create a payment from the external resource
+ """
+ vals = self._get_payment_information(cr, uid, external_session, order_id, resource, context=context)
+ if vals.get('paid'):
+ if not vals.get('journal_id'):
+ external_session.logger.warning(_("Not journal found for payment method %s. Can not create payment")%vals['payment_method'])
+ vals['paid'] = False
+ else:
+ self.pay_sale_order(cr, uid, order_id, vals['journal_id'], vals['amount'], vals['date'], context=context)
+ return vals.get('paid')
+
+ def _get_payment_information(self, cr, uid, external_session, order_id, resource, context=None):
+ """
+ Function that will return the information in order to create the payment
+ """
+ vals = {}
+ sale = self.browse(cr, uid, order_id, context=context)
+ vals['payment_method'] = sale.payment_method_id.name
+ vals['journal_id'] = sale.payment_method_id.journal_id and sale.payment_method_id.journal_id.id
+ vals['date'] = sale.date_order
+ return vals
+
+ def _prepare_invoice(self, cr, uid, order, lines, context=None):
+ """Prepare the dict of values to create the new invoice for a
+ sale order. This method may be overridden to implement custom
+ invoice generation (making sure to call super() to establish
+ a clean extension chain).
+
+ :param browse_record order: sale.order record to invoice
+ :param list(int) lines: list of invoice line IDs that must be
+ attached to the invoice
+ :return: dict of value to create() the invoice
+ """
+ vals = super(sale_order, self)._prepare_invoice(cr, uid, order, lines, context=context)
+ if order.shop_id.sale_journal:
+ vals['journal_id'] = order.shop_id.sale_journal.id
+ vals['shop_id'] = order.shop_id.id
+ return vals
+
+ def _prepare_order_picking(self, cr, uid, order, context=None):
+ vals = super(sale_order, self)._prepare_order_picking(cr, uid, order, context=context)
+ vals['shop_id'] = order.shop_id.id
+ return vals
+
+ def oe_update(self, cr, uid, external_session, existing_rec_id, vals, resource, defaults, context=None):
+ '''Not implemented in this abstract module, if it's not implemented in your module it will raise an error'''
+ # Explication :
+ # sometime customer can do ugly thing like renamming a sale_order and try to reimported it,
+ # sometime openerp run two scheduler at the same time, or the customer launch two openerp at the same time
+ # or the external system give us again an already imported order
+ # As the update of an existing order (this is not the update of the status but the update of the line, the address...)
+ # is not supported by connector_ecommerce and also not in magentoerpconnect.
+ # It's better to don't allow this feature to avoid hidding a problem.
+ # It's better to have the order not imported and to know it than having order with duplicated line.
+ if not (context and context.get('oe_update_supported', False)):
+ #TODO found a clean solution to raise the except_osv error in the try except of the function import_with_try
+ raise except_osv(_("Not Implemented"), _(("The order with the id %s try to be updated from the external system."
+ " This feature is not supported. Maybe the import try to reimport an existing sale order"%(existing_rec_id,))))
+ return super(sale_order, self).oe_update(cr, uid, external_session, existing_rec_id, vals, resource, defaults, context=context)
+
+ def _convert_special_fields(self, cr, uid, vals, referential_id, context=None):
+ """
+ Convert the special 'fake' field into an order line
+ special field are :
+ - shipping amount and shipping_tax_rate
+ - cash_on_delivery and cash_on_delivery_taxe_rate
+ - gift_certificates
+
+ :param dict vals : values of the sale order to create
+ :param int referential_id : external referential id
+ :return: the value for the sale order with the special field converted
+ :rtype: dict
+ """
+ def check_key(keys):
+ return len(set([
+ 'shipping_amount_tax_excluded',
+ 'shipping_amount_tax_included',
+ 'shipping_tax_amount'])
+ & set(keys)) >= 2
+
+ for line in vals['order_line']:
+ for field in ['shipping_amount_tax_excluded','shipping_amount_tax_included', 'shipping_tax_amount']:
+ if field in line[2]:
+ vals[field] = vals.get(field, 0.0) + line[2][field]
+ del line[2][field]
+
+ if not 'shipping_tax_rate' in vals and check_key(vals.keys()):
+ if not 'shipping_amount_tax_excluded' in vals:
+ vals['shipping_amount_tax_excluded'] = vals['shipping_amount_tax_included'] - vals['shipping_tax_amount']
+ elif not 'shipping_tax_amount' in vals:
+ vals['shipping_tax_amount'] = vals['shipping_amount_tax_included'] - vals['shipping_amount_tax_excluded']
+ vals['shipping_tax_rate'] = vals['shipping_amount_tax_excluded'] and \
+ vals['shipping_tax_amount'] / vals['shipping_amount_tax_excluded'] or 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
+
+
+ def _get_special_fields(self, cr, uid, context=None):
+ 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'),
+ },
+ {
+ 'price_unit_tax_excluded' : 'gift_certificates_amount', #gift certificate doesn't have any tax
+ 'price_unit_tax_included' : 'gift_certificates_amount',
+ 'product_ref' : ('connector_ecommerce', 'product_product_gift'),
+ 'code_field': 'gift_certificates_code',
+ 'sign': -1,
+ },
+ ]
+
+ def _add_order_extra_line(self, cr, uid, vals, option, context):
+ """ 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: dictionnary of option 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:
+ 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 not price, we have nothing to import
+
+ model_data_obj = self.pool.get('ir.model.data')
+ model, product_id = model_data_obj.get_object_reference(cr, uid, *option['product_ref'])
+ product = self.pool.get('product.product').browse(cr, uid, product_id, context)
+
+ extra_line = {
+ 'product_id': product.id,
+ 'name': product.name,
+ 'product_uom': product.uom_id.id,
+ 'product_uom_qty': 1,
+ 'price_unit': price_unit,
+ }
+
+ extra_line = self.pool.get('sale.order.line').play_sale_order_line_onchange(cr, uid, extra_line, vals, vals['order_line'], context=context)
+ if context.get('use_external_tax') and option.get('tax_rate_field'):
+ tax_rate = vals.pop(option['tax_rate_field'])
+ if tax_rate:
+ line_tax_id = self.pool.get('account.tax').get_tax_from_rate(cr, uid, tax_rate, context.get('is_tax_included'), context=context)
+ if not line_tax_id:
+ raise except_osv(_('Error'), _('No tax id found for the rate %s with the tax include = %s')%(tax_rate, context.get('is_tax_included')))
+ extra_line['tax_id'] = [(6, 0, [line_tax_id])]
+ else:
+ extra_line['tax_id'] = False
+ if not option.get('tax_rate_field'):
+ del extra_line['tax_id']
+ 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 vals
+
+class sale_order_line(Model):
+ _inherit='sale.order.line'
+
+ _columns = {
+ 'ext_product_ref': fields.char('Product Ext Ref',
+ help="This is the original external product reference", size=256),
+ # FIXME WTF are these 3 fields
+ 'shipping_tax_amount': fields.dummy(string = 'Shipping Taxe Amount'),
+ 'shipping_amount_tax_excluded': fields.dummy(string = 'Shipping Price Tax Exclude'),
+ 'shipping_amount_tax_included': fields.dummy(string = 'Shipping Price Tax Include'),
+ 'ext_ref_line': fields.char('Ext. Ref Line', size=64,
+ help='Unique order line id delivered by external application'),
+ }
+
+ def _get_params_product_id_change(self, cr, uid, line, parent_data, previous_lines, context=None):
+ args = [
+ None,
+ parent_data.get('pricelist_id'),
+ line.get('product_id')
+ ]
+ kwargs ={
+ 'qty': float(line.get('product_uom_qty')),
+ 'uom': line.get('product_uom'),
+ 'qty_uos': float(line.get('product_uos_qty') or line.get('product_uom_qty')),
+ 'uos': line.get('product_uos'),
+ 'name': line.get('name'),
+ 'partner_id': parent_data.get('partner_id'),
+ 'lang': False,
+ 'update_tax': True,
+ 'date_order': parent_data.get('date_order'),
+ 'packaging': line.get('product_packaging'),
+ 'fiscal_position': parent_data.get('fiscal_position'),
+ 'flag': False,
+ 'context': context,
+ }
+ return args, kwargs
+
+ # XXX what is the added value of those 'play' onchanges?
+ def play_sale_order_line_onchange(self, cr, uid, line, parent_data, previous_lines, defaults=None, context=None):
+ original_line = line.copy()
+ if not context.get('use_external_tax') and 'tax_id' in line:
+ del line['tax_id']
+ line = self.call_onchange(cr, uid, 'product_id_change', line, defaults=defaults, parent_data=parent_data, previous_lines=previous_lines, context=context)
+ #TODO all m2m should be mapped correctly
+ if context.get('use_external_tax'):
+ #if we use the external tax and the onchange have added a taxe,
+ #them we remove it.
+ #Indeed we have to make the difference between a real tax_id
+ #imported and a default value set by the onchange
+ if not 'tax_id' in original_line and 'tax_id' in line:
+ del line['tax_id']
+ elif line.get('tax_id'):
+ line['tax_id'] = [(6, 0, line['tax_id'])]
+ return line
+
+ def _transform_one_resource(self, cr, uid, external_session, convertion_type, resource, mapping, mapping_id,
+ mapping_line_filter_ids=None, parent_data=None, previous_result=None, defaults=None, context=None):
+ if context is None: context={}
+ line = super(sale_order_line, self)._transform_one_resource(cr, uid, external_session, convertion_type, resource,
+ mapping, mapping_id, mapping_line_filter_ids=mapping_line_filter_ids, parent_data=parent_data,
+ previous_result=previous_result, defaults=defaults, context=context)
+
+ if context.get('is_tax_included') and 'price_unit_tax_included' in line:
+ line['price_unit'] = line['price_unit_tax_included']
+ elif 'price_unit_tax_excluded' in line:
+ line['price_unit'] = line['price_unit_tax_excluded']
+
+ line = self.play_sale_order_line_onchange(cr, uid, line, parent_data, previous_result,
+ defaults, context=context)
+ if context.get('use_external_tax'):
+ if not 'tax_id' in line and line.get('tax_rate'):
+ line_tax_id = self.pool.get('account.tax').get_tax_from_rate(cr, uid, line['tax_rate'], context.get('is_tax_included', False), context=context)
+ if not line_tax_id:
+ raise except_osv(_('Error'), _('No tax id found for the rate %s with the tax include = %s')%(line['tax_rate'], context.get('is_tax_included')))
+ line['tax_id'] = [(6, 0, [line_tax_id])]
+ else:
+ line['tax_id'] = False
+ return line
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/connector_ecommerce/sale_view.xml b/connector_ecommerce/sale_view.xml
new file mode 100644
index 00000000..05e76e0b
--- /dev/null
+++ b/connector_ecommerce/sale_view.xml
@@ -0,0 +1,200 @@
+
+
+
+
+
+ connector_ecommerce_view_shop_form
+ sale.shop
+
+
+
+
+
+
+
+
+
+
+
+
+
+ base_sale_multichannel_view_order_tree
+ sale.order
+
+
+
+
+
+
+
+
+
+
+
+
+ base_sale_multichannel.view_sales_order_filter
+ sale.order
+
+
+
+
+
+
+
+
+
+
+
+ base_sale_multichannel_view_order_form
+ sale.order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ base_sale_multichannel_view_order_tree
+ sale.order.line
+
+
+
+
+
+
+
+
+
+
+
+ base_sale_multichannel_view_order_form
+ sale.order.line
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ base.sale.external.shop.group.form
+ external.shop.group
+
+
+
+
+
+
+ base.sale.external.shop.group.tree
+ external.shop.group
+
+
+
+
+
+
+
+
+
+
+ External referential shop groups
+ external.shop.group
+ form
+ tree,form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/connector_ecommerce/security/ir.model.access.csv b/connector_ecommerce/security/ir.model.access.csv
new file mode 100755
index 00000000..a1170aff
--- /dev/null
+++ b/connector_ecommerce/security/ir.model.access.csv
@@ -0,0 +1,18 @@
+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
+"access_connector_ecommerce_external_shop_group_manager","connector_ecommerce_external_shop_group","model_external_shop_group","base.group_sale_manager",1,1,1,1
+"access_connector_external_referential","connector_external_referential","connector.model_external_referential","base.group_sale_manager",1,1,1,1
+"access_connector_external_referential_type","connector_external_referential_type","connector.model_external_referential_type","base.group_sale_manager",1,1,1,1
+"access_connector_external_referential_version","connector_external_referential_version","connector.model_external_referential_version","base.group_sale_manager",1,1,1,1
+"access_connector_external_mapping_template","connector_external_mapping_template","connector.model_external_mapping_template","base.group_sale_manager",1,1,1,1
+"access_connector_external_mappinglines_template","connector_external_mappinglines_template","connector.model_external_mappinglines_template","base.group_sale_manager",1,1,1,1
+"access_connector_external_referential","connector_external_referential","connector.model_external_referential","base.group_sale_manager",1,1,1,1
+"access_connector_external_mapping_line","connector_external_mapping_line","connector.model_external_mapping_line","base.group_sale_manager",1,1,1,1
+"access_connector_external_mapping","connector_external_mapping","connector.model_external_mapping","base.group_sale_manager",1,1,1,1
+"access_connector_external_report","connector_external_report","connector.model_external_report","base.group_sale_manager",1,1,1,1
+"access_connector_external_report_history","connector_external_report_history","connector.model_external_report_history","base.group_sale_manager",1,1,1,1
+"access_connector_external_report_line","connector_external_report_line","connector.model_external_report_line","base.group_sale_manager",1,1,1,1
+"access_sale_sale_shop","sale_sale_shop","sale.model_sale_shop","base.group_sale_manager",1,1,1,1
+"access_connector_ecommerce_ir_model_data","connector_ecommerce_ir_model_data","base.model_ir_model_data","base.group_sale_manager",1,1,1,1
+"access_connector_ecommerce_external_shop_group","connector_ecommerce_external_shop_group","model_external_shop_group","base.group_user",1,0,0,0
+"access_account_tax_group_user","Read-only access to account.tax.group","model_account_tax_group","base.group_user",1,0,0,0
+"access_account_tax_group_account_manager","RW access to account.tax.group","model_account_tax_group","account.group_account_manager",1,1,1,1
diff --git a/connector_ecommerce/settings/external.referential.category.csv b/connector_ecommerce/settings/external.referential.category.csv
new file mode 100644
index 00000000..fb399328
--- /dev/null
+++ b/connector_ecommerce/settings/external.referential.category.csv
@@ -0,0 +1,2 @@
+"id","name"
+"multichannels","Multichannel Sale"
diff --git a/connector_ecommerce/settings/sale.exception.csv b/connector_ecommerce/settings/sale.exception.csv
new file mode 100644
index 00000000..58491b7b
--- /dev/null
+++ b/connector_ecommerce/settings/sale.exception.csv
@@ -0,0 +1,12 @@
+id,name,description,sequence,model,code
+excep_wrong_total_amount,Total Amount differs from external system,"The amount computed doesn't match with the external amount because the taxes have not been configured properly (maybe some fiscal positions have changed the final price).
+Please fix it manually and check your taxes rules.
+
+NB : This check have being applied because you have checked the option \check total amount\"" on the shop of this sale order""",30,sale.order,"if order.shop_id.check_total_amount and abs(order.amount_total - order.ext_total_amount) >= 0.01:
+ failed = True"
+excep_wrong_total_amount_tax,Total Tax Amount differs from external system,"The tax amount computed doesn't match with the external tax amount because the taxes have not been configured properly (maybe some fiscal positions have changed the final price).
+Please fix it manually and check your taxes rules.
+
+NB : This check have being applied because you have checked the option \check total amount\"" on the shop of this sale order""",30,sale.order,"#By default we allow a cent of difference for the taxe, feel free to customise it in your own module
+if order.shop_id.check_total_amount and abs(order.amount_tax - order.ext_total_amount_tax) > 0.01:
+ failed = True"
diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py
new file mode 100644
index 00000000..12cb4dc1
--- /dev/null
+++ b/connector_ecommerce/stock.py
@@ -0,0 +1,50 @@
+# -*- encoding: utf-8 -*-
+#########################################################################
+# #
+#########################################################################
+# #
+# Copyright (C) 2010 BEAU Sébastien #
+# #
+#This program is free software: you can redistribute it and/or modify #
+#it under the terms of the GNU 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 General Public License for more details. #
+# #
+#You should have received a copy of the GNU General Public License #
+#along with this program. If not, see . #
+#########################################################################
+
+from openerp.osv import orm, fields, osv
+from openerp.tools.translate import _
+
+
+class stock_picking(orm.Model):
+ _inherit = "stock.picking"
+
+ _columns = {
+ 'do_not_export': fields.boolean(
+ 'Do not export',
+ help="This delivery order will not be exported to the "
+ "external referential."
+ ),
+ 'shop_id': fields.many2one(
+ 'sale.shop',
+ 'Shop',
+ readonly=True,
+ states={'draft': [('readonly', False)]}),
+ }
+
+ def create_ext_shipping(self, cr, uid, id, picking_type, external_referential_id, context):
+ raise osv.except_osv(_("Not Implemented"),
+ _("Not Implemented in abstract base module!"))
+
+ def _prepare_invoice(self, cr, uid, picking, partner, inv_type, journal_id, context=None):
+ vals = super(stock_picking, self)._prepare_invoice(cr, uid, picking, partner, \
+ inv_type, journal_id, context=context)
+ vals['shop_id'] = picking.shop_id.id
+ return vals
diff --git a/connector_ecommerce/stock_view.xml b/connector_ecommerce/stock_view.xml
new file mode 100644
index 00000000..0701f37a
--- /dev/null
+++ b/connector_ecommerce/stock_view.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ stock.picking.out.form.ext
+ stock.picking
+
+
+
+
+
+
+
+
+
diff --git a/connector_ecommerce/wizard/__init__.py b/connector_ecommerce/wizard/__init__.py
new file mode 100644
index 00000000..6a92c0ab
--- /dev/null
+++ b/connector_ecommerce/wizard/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Base_sale_multichannels module for OpenERP
+# Copyright (C) 2010 Sébastien BEAU
+#
+# 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 import_order
+
diff --git a/connector_ecommerce/wizard/import_order.py b/connector_ecommerce/wizard/import_order.py
new file mode 100644
index 00000000..6f347781
--- /dev/null
+++ b/connector_ecommerce/wizard/import_order.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Base_sale_multichannels module for OpenERP
+# Copyright (C) 2010 Sébastien BEAU
+#
+# 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 .
+#
+##############################################################################
+
+
+from osv import fields,osv
+from tools.translate import _
+from openerp.addons.connector.external_osv import ExternalSession
+
+class sale_order_import_wizard(osv.osv_memory):
+ _name = 'sale.order.import.wizard'
+ _description = 'sale order import wizard'
+
+ _columns = {
+ 'order_number': fields.char('Order Number', size=64),
+ }
+
+ def import_order(self, cr, uid, ids, context=None):
+ if context is None:
+ context={}
+ shop = self.pool.get('sale.shop').browse(cr, uid, context['active_id'], context=context)
+ external_session = ExternalSession(shop.referential_id, shop)
+ wizard = self.browse(cr, uid, ids[0], context=context)
+ self.pool.get('sale.order')._import_one_resource(cr, uid, external_session, wizard.order_number, context=context)
+ return {'type': 'ir.actions.act_window_close'}
diff --git a/connector_ecommerce/wizard/import_order.xml b/connector_ecommerce/wizard/import_order.xml
new file mode 100644
index 00000000..b5b53763
--- /dev/null
+++ b/connector_ecommerce/wizard/import_order.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ sale.order.import.wizard.view
+ sale.order.import.wizard
+
+
+
+
+
+
+ Import Order
+ ir.actions.act_window
+ sale.order.import.wizard
+ form
+ form
+ new
+ {}
+
+
+
+ client_action_multi
+ sale.shop
+ Import Order
+
+
+
+
+
From 9e3783052af00aeb17c31d759dc60e27bca75524 Mon Sep 17 00:00:00 2001
From: Joel Grand-Guillaume
Date: Tue, 12 Mar 2013 20:10:00 +0100
Subject: [PATCH 02/86] [ADD] Base support to export picking (partial and
complete)
---
connector_ecommerce/__init__.py | 1 +
connector_ecommerce/event.py | 35 ++++++++++++++++++++++++++
connector_ecommerce/stock.py | 44 +++++++++++++++++----------------
3 files changed, 59 insertions(+), 21 deletions(-)
create mode 100644 connector_ecommerce/event.py
diff --git a/connector_ecommerce/__init__.py b/connector_ecommerce/__init__.py
index 9650e6b2..0cf0ee35 100644
--- a/connector_ecommerce/__init__.py
+++ b/connector_ecommerce/__init__.py
@@ -30,5 +30,6 @@
import product
import invoice
import payment_method
+import event
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/connector_ecommerce/event.py b/connector_ecommerce/event.py
new file mode 100644
index 00000000..6b6f5c88
--- /dev/null
+++ b/connector_ecommerce/event.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Joel Grand-Guillaume
+# Copyright 2013 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 .
+#
+##############################################################################
+
+from openerp.addons.connector.event import Event
+
+
+on_picking_done = Event()
+"""
+``on_picking_done`` is fired when a picking has been marked as done.
+
+Listeners should take the following arguments:
+
+ * session: `Session` object
+ * model_name: name of the model
+ * record_id: id of the record
+ * type: 'partial' or 'complete' depending on the picking done
+"""
diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py
index 12cb4dc1..f4f4dc17 100644
--- a/connector_ecommerce/stock.py
+++ b/connector_ecommerce/stock.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
#########################################################################
# #
#########################################################################
@@ -19,32 +19,34 @@
#along with this program. If not, see . #
#########################################################################
-from openerp.osv import orm, fields, osv
+from openerp.osv.orm import Model
+from openerp.osv import orm, fields
from openerp.tools.translate import _
+from openerp.connector.queue import job
+
+from openerp.connector.session import ConnectorSession
+from .event import on_picking_done
class stock_picking(orm.Model):
_inherit = "stock.picking"
_columns = {
- 'do_not_export': fields.boolean(
- 'Do not export',
- help="This delivery order will not be exported to the "
- "external referential."
- ),
- 'shop_id': fields.many2one(
- 'sale.shop',
- 'Shop',
- readonly=True,
- states={'draft': [('readonly', False)]}),
+ 'related_backorder_ids': fields.one2many(
+ 'stock.picking', 'backorder_id',
+ string="Related backorders"),
}
- def create_ext_shipping(self, cr, uid, id, picking_type, external_referential_id, context):
- raise osv.except_osv(_("Not Implemented"),
- _("Not Implemented in abstract base module!"))
-
- def _prepare_invoice(self, cr, uid, picking, partner, inv_type, journal_id, context=None):
- vals = super(stock_picking, self)._prepare_invoice(cr, uid, picking, partner, \
- inv_type, journal_id, context=context)
- vals['shop_id'] = picking.shop_id.id
- return vals
+ def action_done(self, cr, uid, ids, context=None):
+ res = super(stock_picking, self).action_done(self, cr, uid, ids, context=context)
+ session = ConnectorSession(cr, uid, context=context)
+ # Look if it exists a backorder, in that case call for partial
+ picking_vals = self.read(cr, uid, ids, ['id','related_backorder_ids'], context=context)
+ for record_id, related_backorder_ids in picking_vals:
+ if related_backorder_ids:
+ picking_type = 'partial'
+ else:
+ picking_type = 'complete'
+ on_picking_done.fire(session, self._name, record_id, picking_type)
+ return res
+
From 155c52a0ab479cac794c27e3ac3b1474f57385e8 Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Tue, 12 Mar 2013 20:18:25 +0100
Subject: [PATCH 03/86] [FIX] improve styling, remove unused imports, fix
license (done by Joel)
[FIX] fix import
---
connector_ecommerce/event.py | 2 +-
connector_ecommerce/stock.py | 53 ++++++++++++++++++------------------
2 files changed, 27 insertions(+), 28 deletions(-)
diff --git a/connector_ecommerce/event.py b/connector_ecommerce/event.py
index 6b6f5c88..d457c66b 100644
--- a/connector_ecommerce/event.py
+++ b/connector_ecommerce/event.py
@@ -21,7 +21,7 @@
from openerp.addons.connector.event import Event
-
+
on_picking_done = Event()
"""
``on_picking_done`` is fired when a picking has been marked as done.
diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py
index f4f4dc17..423dd4b7 100644
--- a/connector_ecommerce/stock.py
+++ b/connector_ecommerce/stock.py
@@ -1,35 +1,32 @@
# -*- coding: utf-8 -*-
-#########################################################################
-# #
-#########################################################################
-# #
-# Copyright (C) 2010 BEAU Sébastien #
-# #
-#This program is free software: you can redistribute it and/or modify #
-#it under the terms of the GNU 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 General Public License for more details. #
-# #
-#You should have received a copy of the GNU General Public License #
-#along with this program. If not, see . #
-#########################################################################
+##############################################################################
+#
+# Author: Joel Grand-Guillaume
+# Copyright 2013 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 .
+#
+##############################################################################
-from openerp.osv.orm import Model
from openerp.osv import orm, fields
-from openerp.tools.translate import _
-from openerp.connector.queue import job
-from openerp.connector.session import ConnectorSession
+from openerp.addons.connector.session import ConnectorSession
from .event import on_picking_done
class stock_picking(orm.Model):
- _inherit = "stock.picking"
+ _inherit = 'stock.picking'
_columns = {
'related_backorder_ids': fields.one2many(
@@ -38,10 +35,13 @@ class stock_picking(orm.Model):
}
def action_done(self, cr, uid, ids, context=None):
- res = super(stock_picking, self).action_done(self, cr, uid, ids, context=context)
+ res = super(stock_picking, self).action_done(
+ self, cr, uid, ids, context=context)
session = ConnectorSession(cr, uid, context=context)
# Look if it exists a backorder, in that case call for partial
- picking_vals = self.read(cr, uid, ids, ['id','related_backorder_ids'], context=context)
+ picking_vals = self.read(cr, uid, ids,
+ ['id', 'related_backorder_ids'],
+ context=context)
for record_id, related_backorder_ids in picking_vals:
if related_backorder_ids:
picking_type = 'partial'
@@ -49,4 +49,3 @@ def action_done(self, cr, uid, ids, context=None):
picking_type = 'complete'
on_picking_done.fire(session, self._name, record_id, picking_type)
return res
-
From dd9bb2cdc8962d6ee79cb5122318db70ce28062d Mon Sep 17 00:00:00 2001
From: Joel Grand-Guillaume
Date: Wed, 13 Mar 2013 11:29:33 +0100
Subject: [PATCH 04/86] [ADD] Event to handle the adding of the tracking number
on picking
---
connector_ecommerce/event.py | 13 +++++++++++++
connector_ecommerce/stock.py | 11 +++++++++++
2 files changed, 24 insertions(+)
diff --git a/connector_ecommerce/event.py b/connector_ecommerce/event.py
index d457c66b..2c9e6d60 100644
--- a/connector_ecommerce/event.py
+++ b/connector_ecommerce/event.py
@@ -33,3 +33,16 @@
* record_id: id of the record
* type: 'partial' or 'complete' depending on the picking done
"""
+
+on_tracking_number_added = Event()
+"""
+``on_tracking_number_added`` is fired when a picking has been marked as
+ done and a tracking number has been added to it (write).
+
+Listeners should take the following arguments:
+
+ * session: `Session` object
+ * model_name: name of the model
+ * record_id: id of the record
+ * tracking_number: char of the tracking number
+"""
diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py
index 423dd4b7..40ba011b 100644
--- a/connector_ecommerce/stock.py
+++ b/connector_ecommerce/stock.py
@@ -49,3 +49,14 @@ def action_done(self, cr, uid, ids, context=None):
picking_type = 'complete'
on_picking_done.fire(session, self._name, record_id, picking_type)
return res
+
+ def write(self, cr, uid, ids, vals, context=None):
+ if context is None:
+ context = {}
+ res = super(stock_picking, self).write(cr, uid, ids, vals, context=context)
+ if vals.get('carrier_tracking_ref', False):
+ session = ConnectorSession(cr, uid, context=context)
+ for record_id in ids:
+ on_tracking_number_added.fire(session, self._name, record_id, vals['carrier_tracking_ref'])
+ return res
+
From 2aa847a929c3655f67a3f3d86596040f16bf8729 Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Wed, 13 Mar 2013 16:42:13 +0100
Subject: [PATCH 05/86] [FIX] remove the carrier tracking number from the
event, fix missing import
---
connector_ecommerce/event.py | 5 ++---
connector_ecommerce/stock.py | 16 ++++++++--------
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/connector_ecommerce/event.py b/connector_ecommerce/event.py
index 2c9e6d60..c5fc9bae 100644
--- a/connector_ecommerce/event.py
+++ b/connector_ecommerce/event.py
@@ -28,7 +28,7 @@
Listeners should take the following arguments:
- * session: `Session` object
+ * session: `connector.session.ConnectorSession` object
* model_name: name of the model
* record_id: id of the record
* type: 'partial' or 'complete' depending on the picking done
@@ -41,8 +41,7 @@
Listeners should take the following arguments:
- * session: `Session` object
+ * session: `connector.session.ConnectorSession` object
* model_name: name of the model
* record_id: id of the record
- * tracking_number: char of the tracking number
"""
diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py
index 40ba011b..7fc944ea 100644
--- a/connector_ecommerce/stock.py
+++ b/connector_ecommerce/stock.py
@@ -22,7 +22,7 @@
from openerp.osv import orm, fields
from openerp.addons.connector.session import ConnectorSession
-from .event import on_picking_done
+from .event import on_picking_done, on_tracking_number_added
class stock_picking(orm.Model):
@@ -49,14 +49,14 @@ def action_done(self, cr, uid, ids, context=None):
picking_type = 'complete'
on_picking_done.fire(session, self._name, record_id, picking_type)
return res
-
+
def write(self, cr, uid, ids, vals, context=None):
- if context is None:
- context = {}
- res = super(stock_picking, self).write(cr, uid, ids, vals, context=context)
- if vals.get('carrier_tracking_ref', False):
+ if not hasattr(ids, '__iter__'):
+ ids = [ids]
+ 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:
- on_tracking_number_added.fire(session, self._name, record_id, vals['carrier_tracking_ref'])
+ on_tracking_number_added.fire(session, self._name, record_id)
return res
-
From aed4f0a899ea35a84daf2690c87137ab7023c928 Mon Sep 17 00:00:00 2001
From: Joel Grand-Guillaume
Date: Wed, 13 Mar 2013 17:09:22 +0100
Subject: [PATCH 06/86] [ADD] Support for exporting the account_invoice to
Magento
---
connector_ecommerce/event.py | 12 ++++++
connector_ecommerce/invoice.py | 69 ++++++++++++++++++++++++++--------
2 files changed, 66 insertions(+), 15 deletions(-)
diff --git a/connector_ecommerce/event.py b/connector_ecommerce/event.py
index c5fc9bae..6f7c8bc0 100644
--- a/connector_ecommerce/event.py
+++ b/connector_ecommerce/event.py
@@ -45,3 +45,15 @@
* model_name: name of the model
* record_id: id of the record
"""
+
+on_invoice_paid = Event()
+"""
+``on_invoice_paid`` is fired when an invoice related to an order
+ has been paid.
+
+Listeners should take the following arguments:
+
+ * session: `Session` object
+ * model_name: name of the model
+ * record_id: id of the record
+"""
diff --git a/connector_ecommerce/invoice.py b/connector_ecommerce/invoice.py
index 53b0b3af..17c56262 100644
--- a/connector_ecommerce/invoice.py
+++ b/connector_ecommerce/invoice.py
@@ -20,24 +20,63 @@
###############################################################################
from openerp.osv.orm import Model
from openerp.osv import fields
+from openerp.addons.connector.session import ConnectorSession
+from .event import on_invoice_validated, on_invoice_paid
class account_invoice(Model):
_inherit='account.invoice'
- _columns={
- 'shop_id': fields.many2one('sale.shop', 'Shop', readonly=True, states={'draft': [('readonly', False)]}),
- 'do_not_export': fields.boolean(
- 'Do not export',
- help="This delivery order will not be exported "
- "to the external referential."),
+ _columns = {
+ 'sale_order_ids': fields.many2many('sale.order', 'sale_order_invoice_rel',
+ 'invoice_id', 'order_id', 'Sale Orders', readonly=True,
+ help="This is the list of sale orders related to this invoice."),
}
+
+ def _get_related_so_shop(self, invoice):
+ """
+ As several SO can be linked to several Invoice, we try to get the common
+ shop between them all. The goal is further, in the consummer implementation,
+ to be able to retieve the right backend to use.
+
+ :param invoice is a browse record of account.invoice
+ :type browse record
+ :return a common sale.shop browse record between all related sale order or
+ :raise an ValueError exception if we didn't found exactly one common shop
+ """
+ shop = set()
+ for so in invoice.sale_order_ids:
+ shop.append(so.shop_id)
+ if len(shop) != 1:
+ raise ValueError("Wrong value for sale_order_ids, an invoice cannot"
+ "be related to sale orders that doesn't belong to the same shop, "
+ "but must belong to one at least (shop: %s)."%(shop))
+ return shop[0]
+
+ def confirm_paid(self, cr, uid, ids, context=None):
+ if context is None:
+ context = {}
+ res = super(account_invoice, self).confirm_paid(cr, uid, ids, context)
+ session = ConnectorSession(cr, uid, context=context)
+ for record_id in ids:
+ on_invoice_paid.fire(session, self._name, record_id)
+ return res
- def _prepare_invoice_refund(self, cr, uid, ids, invoice_vals, date=None, period_id=None, description=None, journal_id=None, context=None):
- invoice = self.browse(cr, uid, invoice_vals['id'], context=context)
- invoice_vals = super(account_invoice, self)._prepare_invoice_refund(cr, uid, ids, invoice_vals, date=date, period_id=period_id,
- description=description, journal_id=journal_id, context=context)
- invoice_vals.update({
- 'sale_ids': [(6,0, [sale.id for sale in invoice.sale_ids])],
- 'shop_id': invoice.shop_id.id,
- })
- return invoice_vals
+
+ # TO REVIEW
+ # _columns={
+ # 'shop_id': fields.many2one('sale.shop', 'Shop', readonly=True, states={'draft': [('readonly', False)]}),
+ # 'do_not_export': fields.boolean(
+ # 'Do not export',
+ # help="This delivery order will not be exported "
+ # "to the external referential."),
+ # }
+ #
+ # def _prepare_invoice_refund(self, cr, uid, ids, invoice_vals, date=None, period_id=None, description=None, journal_id=None, context=None):
+ # invoice = self.browse(cr, uid, invoice_vals['id'], context=context)
+ # invoice_vals = super(account_invoice, self)._prepare_invoice_refund(cr, uid, ids, invoice_vals, date=date, period_id=period_id,
+ # description=description, journal_id=journal_id, context=context)
+ # invoice_vals.update({
+ # 'sale_ids': [(6,0, [sale.id for sale in invoice.sale_ids])],
+ # 'shop_id': invoice.shop_id.id,
+ # })
+ # return invoice_vals
From c74b2ede933f6144aa6b874f00e2fb12d8fa62df Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Wed, 13 Mar 2013 19:48:44 +0100
Subject: [PATCH 07/86] [FIX] styling, license, imports, some fixes
[FIX] remove an old view not installable
---
connector_ecommerce/event.py | 6 +-
connector_ecommerce/invoice.py | 126 +++++++++++++--------------
connector_ecommerce/invoice_view.xml | 12 ---
3 files changed, 63 insertions(+), 81 deletions(-)
diff --git a/connector_ecommerce/event.py b/connector_ecommerce/event.py
index 6f7c8bc0..f75ca21a 100644
--- a/connector_ecommerce/event.py
+++ b/connector_ecommerce/event.py
@@ -34,6 +34,7 @@
* type: 'partial' or 'complete' depending on the picking done
"""
+
on_tracking_number_added = Event()
"""
``on_tracking_number_added`` is fired when a picking has been marked as
@@ -46,14 +47,15 @@
* record_id: id of the record
"""
+
on_invoice_paid = Event()
"""
-``on_invoice_paid`` is fired when an invoice related to an order
- has been paid.
+``on_invoice_paid`` is fired when an invoice has been paid.
Listeners should take the following arguments:
* session: `Session` object
+ * session: `connector.session.ConnectorSession` object
* model_name: name of the model
* record_id: id of the record
"""
diff --git a/connector_ecommerce/invoice.py b/connector_ecommerce/invoice.py
index 17c56262..d096413c 100644
--- a/connector_ecommerce/invoice.py
+++ b/connector_ecommerce/invoice.py
@@ -1,82 +1,74 @@
-# -*- encoding: utf-8 -*-
-###############################################################################
-# #
-# connector_ecommerce for OpenERP #
-# Copyright (C) 2011 Akretion Sébastien BEAU #
-# #
-# 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 . #
-# #
-###############################################################################
-from openerp.osv.orm import Model
-from openerp.osv import fields
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Joel Grand-Guillaume
+# Copyright 2013 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 .
+#
+##############################################################################
+
+from openerp.osv import fields, orm, osv
+from openerp.tools.translate import _
from openerp.addons.connector.session import ConnectorSession
-from .event import on_invoice_validated, on_invoice_paid
+from .event import on_invoice_paid
+
-class account_invoice(Model):
+class account_invoice(orm.Model):
_inherit='account.invoice'
-
+
_columns = {
- 'sale_order_ids': fields.many2many('sale.order', 'sale_order_invoice_rel',
- 'invoice_id', 'order_id', 'Sale Orders', readonly=True,
+ 'sale_order_ids': fields.many2many(
+ '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 _get_related_so_shop(self, invoice):
"""
- As several SO can be linked to several Invoice, we try to get the common
- shop between them all. The goal is further, in the consummer implementation,
- to be able to retieve the right backend to use.
-
- :param invoice is a browse record of account.invoice
- :type browse record
- :return a common sale.shop browse record between all related sale order or
- :raise an ValueError exception if we didn't found exactly one common shop
+ As several sale order can be linked to several invoices, we try
+ to get the common shop between them all. The goal is further, in
+ the consumer implementation, to be able to retrieve the right
+ backend to use.
+
+ An exception is raised if no common shop is found
+
+ :param invoice: browsable record of account.invoice
+ :type invoice: browse_record
+ :returns: a common sale.shop browse record between all related
+ sale orders
+ :raises: osv.except_osv
"""
- shop = set()
+ shops = set()
for so in invoice.sale_order_ids:
- shop.append(so.shop_id)
- if len(shop) != 1:
- raise ValueError("Wrong value for sale_order_ids, an invoice cannot"
- "be related to sale orders that doesn't belong to the same shop, "
- "but must belong to one at least (shop: %s)."%(shop))
- return shop[0]
-
+ shops.add(so.shop_id)
+ if len(shops) != 1:
+ raise osv.except_osv(_("Wrong value for sale_order_ids, "
+ "an invoice cannot be related to sale "
+ "orders that doesn't belong to the "
+ "same shop, but must belong to one at "
+ "least (shops: %s).") %
+ [shop.name for shop in shops])
+ return shops[0].id
+
def confirm_paid(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
- res = super(account_invoice, self).confirm_paid(cr, uid, ids, context)
+ res = super(account_invoice, self).confirm_paid(
+ cr, uid, ids, context=context)
session = ConnectorSession(cr, uid, context=context)
for record_id in ids:
on_invoice_paid.fire(session, self._name, record_id)
return res
-
-
- # TO REVIEW
- # _columns={
- # 'shop_id': fields.many2one('sale.shop', 'Shop', readonly=True, states={'draft': [('readonly', False)]}),
- # 'do_not_export': fields.boolean(
- # 'Do not export',
- # help="This delivery order will not be exported "
- # "to the external referential."),
- # }
- #
- # def _prepare_invoice_refund(self, cr, uid, ids, invoice_vals, date=None, period_id=None, description=None, journal_id=None, context=None):
- # invoice = self.browse(cr, uid, invoice_vals['id'], context=context)
- # invoice_vals = super(account_invoice, self)._prepare_invoice_refund(cr, uid, ids, invoice_vals, date=date, period_id=period_id,
- # description=description, journal_id=journal_id, context=context)
- # invoice_vals.update({
- # 'sale_ids': [(6,0, [sale.id for sale in invoice.sale_ids])],
- # 'shop_id': invoice.shop_id.id,
- # })
- # return invoice_vals
diff --git a/connector_ecommerce/invoice_view.xml b/connector_ecommerce/invoice_view.xml
index 5b6812bc..30816750 100644
--- a/connector_ecommerce/invoice_view.xml
+++ b/connector_ecommerce/invoice_view.xml
@@ -2,17 +2,5 @@
-
- base_sale_multichannel_invoice_form
- account.invoice
-
-
-
-
-
-
-
-
-
From 1ee8efeb71e6b4450a24588725aad7020d50df1f Mon Sep 17 00:00:00 2001
From: davidbeal
Date: Thu, 14 Mar 2013 09:42:18 +0100
Subject: [PATCH 08/86] [FIX] add product_view.xml file
---
connector_ecommerce/__openerp__.py | 1 +
connector_ecommerce/product_view.xml | 28 ++++++++++++++++++++++++++++
2 files changed, 29 insertions(+)
create mode 100644 connector_ecommerce/product_view.xml
diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py
index c5fc44a8..c7ae879d 100644
--- a/connector_ecommerce/__openerp__.py
+++ b/connector_ecommerce/__openerp__.py
@@ -70,6 +70,7 @@
'data': [
'security/ir.model.access.csv',
'sale_view.xml',
+ 'product_view.xml',
'partner_view.xml',
'invoice_view.xml',
'wizard/import_order.xml',
diff --git a/connector_ecommerce/product_view.xml b/connector_ecommerce/product_view.xml
new file mode 100644
index 00000000..dc59df5a
--- /dev/null
+++ b/connector_ecommerce/product_view.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+ product.product
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
From 9e7451a6fc9c0c9815fc5dcf5ad0f8be6bc6c51f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Beau?=
Date: Wed, 13 Mar 2013 19:25:30 +0100
Subject: [PATCH 09/86] [IMP] start adding support of onchange in
connector-ecommerce
[IMP] finish onchange support, add doc string, support tax. The option use external taxe will be not implemented, as re-computing tax in OpenERP is the best option. If you need it, create a independant module for it, fix copyright
[REF] refactor introduce the class SaleOrderOnChange
---
connector_ecommerce/tests/__init__.py | 30 ++++
connector_ecommerce/tests/test_onchange.py | 107 ++++++++++++
connector_ecommerce/unit/__init__.py | 2 +
.../unit/sale_order_onchange.py | 154 ++++++++++++++++++
4 files changed, 293 insertions(+)
create mode 100644 connector_ecommerce/tests/__init__.py
create mode 100644 connector_ecommerce/tests/test_onchange.py
create mode 100644 connector_ecommerce/unit/__init__.py
create mode 100644 connector_ecommerce/unit/sale_order_onchange.py
diff --git a/connector_ecommerce/tests/__init__.py b/connector_ecommerce/tests/__init__.py
new file mode 100644
index 00000000..b1b37af5
--- /dev/null
+++ b/connector_ecommerce/tests/__init__.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Guewen Baconnier
+# Copyright 2012 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 test_onchange
+
+fast_suite = [
+]
+
+checks = [
+ test_onchange,
+]
+
diff --git a/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py
new file mode 100644
index 00000000..93f0a95f
--- /dev/null
+++ b/connector_ecommerce/tests/test_onchange.py
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# connector-ecommerce for OpenERP
+# Copyright (C) 2013-TODAY Akretion .
+# @author Sébastien BEAU
+#
+# 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 unittest2
+import mock
+import magento
+
+from openerp.addons.connector.connector import ConnectorUnit
+from openerp.addons.connector_ecommerce.unit.sale_order_onchange import \
+ SaleOrderOnChange
+from openerp.addons.connector.session import ConnectorSession
+from openerp.addons.connector.connector import Environment
+import openerp.tests.common as common
+
+DB = common.DB
+ADMIN_USER_ID = common.ADMIN_USER_ID
+
+
+class test_onchange(common.TransactionCase):
+ """ Test the imports from a Magento Mock """
+
+ def setUp(self):
+ super(test_onchange, self).setUp()
+ self.session = ConnectorSession(self.cr, self.uid)
+
+ def test_play_onchange(self):
+ product_model = self.registry('product.product')
+ partner_model = self.registry('res.partner')
+ shop_model = self.registry('sale.shop')
+ tax_model = self.registry('account.tax')
+
+
+ backend_record = mock.Mock()
+ env = Environment(backend_record, self.session, 'sale.order')
+
+ partner_id = partner_model.create(self.cr, self.uid, {
+ 'name': 'seb',
+ 'zip': '69100',
+ 'city': 'Villeurbanne',
+ })
+
+ partner_invoice_id = partner_model.create(self.cr, self.uid, {
+ 'name': 'Guewen',
+ 'zip': '1015',
+ 'city': 'Lausanne',
+ 'type': 'invoice',
+ 'parent_id': partner_id,
+ })
+
+ tax_id = tax_model.create(self.cr, self.uid, {
+ 'name': 'My Tax',
+ })
+
+ product_id = product_model.create(self.cr, self.uid, {
+ 'default_code': 'MyCode',
+ 'name': 'My Product',
+ 'weight': 15,
+ 'taxes_id': [(6,0,[tax_id])],
+ })
+
+ shop_id = shop_model.create(self.cr, self.uid, {
+ 'name': 'My shop',
+ })
+
+ order_input = {
+ 'shop_id': shop_id,
+ 'name': 'mag_10000001',
+ 'partner_id': partner_id,
+ 'order_line': [
+ (0,0,{
+ 'product_id': product_id,
+ 'price_unit': 20,
+ 'name': 'My Real Name',
+ 'product_uom_qty': 1,
+ }),
+ ]
+ }
+
+ onchange = SaleOrderOnChange(env)
+ order = onchange.play(order_input)
+
+ self.assertEqual(order['partner_invoice_id'], partner_invoice_id)
+ 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)
+
diff --git a/connector_ecommerce/unit/__init__.py b/connector_ecommerce/unit/__init__.py
new file mode 100644
index 00000000..b9150933
--- /dev/null
+++ b/connector_ecommerce/unit/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+import sale_order_onchange
diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py
new file mode 100644
index 00000000..ee87f71d
--- /dev/null
+++ b/connector_ecommerce/unit/sale_order_onchange.py
@@ -0,0 +1,154 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# connector-ecommerce for OpenERP
+# Copyright (C) 2013-TODAY Akretion .
+# @author Sébastien BEAU
+#
+# 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 .
+#
+###############################################################################
+
+from openerp.addons.connector.connector import ConnectorUnit
+
+class SaleOrderOnChange(ConnectorUnit):
+ # name of the OpenERP model, to be defined in concrete classes
+ _model_name = None
+
+ 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
+ module if they modify the onchange signature
+
+ :param order: a dictionnary of the value of your sale order
+ :type: dict
+
+ :return: a tuple of args and kwargs for the onchange
+ :rtype: tuple
+ """
+ args = [
+ None, # sale order ids not needed
+ order['partner_id'],
+ ]
+ kwargs = {'context': self.session.context}
+ return args, kwargs
+
+ def _play_order_onchange(self, order):
+ """ Play the onchange of the sale order
+
+ :param order: a dictionnary of the value of your sale order
+ :type: dict
+
+ :return: the value of the sale order updated with the onchange result
+ :rtype: dict
+ """
+ sale_model = self.session.pool.get('sale.order')
+
+ #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)
+ vals = res.get('value')
+ for key in vals:
+ if not key in order:
+ order[key] = vals[key]
+
+ return order
+
+ def _get_product_id_onchange_param(self, line, previous_line, order):
+ """ Prepare the arguments for calling the product_id change
+ on sale 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
+ :type: dict
+ :param previous_line: list of dict of the previous line processed
+ :type: list
+ :param order: data of the sale order
+ :type: dict
+
+ :return: a tuple of args and kwargs for the onchange
+ :rtype: tuple
+ """
+ args = [
+ None, # sale order line ids not needed
+ order.get('pricelist_id'),
+ line.get('product_id')
+ ]
+ kwargs ={
+ 'qty': float(line.get('product_uom_qty')),
+ 'uom': line.get('product_uom'),
+ 'qty_uos': float(line.get('product_uos_qty')\
+ or line.get('product_uom_qty')),
+ 'uos': line.get('product_uos'),
+ 'name': line.get('name'),
+ 'partner_id': order.get('partner_id'),
+ 'lang': False,
+ 'update_tax': True,
+ 'date_order': order.get('date_order'),
+ 'packaging': line.get('product_packaging'),
+ 'fiscal_position': order.get('fiscal_position'),
+ 'flag': False,
+ 'context': self.session.context,
+ }
+ return args, kwargs
+
+ def _play_line_onchange(self, line, previous_line, order):
+ """ Play the onchange of the sale order line
+
+ :param line: the sale order line to process
+ :type: dict
+ :param previous_line: list of dict of the previous line processed
+ :type: list
+ :param order: data of the sale order
+ :type: dict
+
+ :return: the value of the sale order updated with the onchange result
+ :rtype: dict
+ """
+ sale_line_model = self.session.pool.get('sale.order.line')
+
+ #Play product_id onchange
+ args, kwargs = self._get_product_id_onchange_param(line,
+ previous_line, order)
+ res = sale_line_model.product_id_change(self.session.cr,
+ self.session.uid, *args, **kwargs)
+ vals = res.get('value')
+ for key in vals:
+ if not key in line:
+ if sale_line_model._columns[key]._type == 'many2many':
+ line[key] = [(6, 0, vals[key])]
+ else:
+ line[key] = vals[key]
+ return line
+
+ def play(self, order):
+ """ Play the onchange of the sale order and it's lines
+
+ :param order: data of the sale order
+ :type: dict
+
+ :return: the value of the sale order updated with the onchange result
+ :rtype: dict
+ """
+ #play onchange on sale order
+ order = self._play_order_onchange(order)
+ #play onchanfe on sale order line
+ order_lines = []
+ for line in order['order_line']:
+ order_lines.append((0, 0,
+ self._play_line_onchange(line[2], order_lines, order)))
+ order['order_line'] = order_lines
+ return order
+
From 2e19c36dae827688ce996ff2f82854911e9f2cd0 Mon Sep 17 00:00:00 2001
From: "@" <@>
Date: Thu, 14 Mar 2013 11:44:57 +0100
Subject: [PATCH 10/86] [REF] code review
---
.../unit/sale_order_onchange.py | 23 +++++++++++--------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py
index ee87f71d..1c8e0b3e 100644
--- a/connector_ecommerce/unit/sale_order_onchange.py
+++ b/connector_ecommerce/unit/sale_order_onchange.py
@@ -59,21 +59,21 @@ def _play_order_onchange(self, order):
args, kwargs = self._get_partner_id_onchange_param(order)
res = sale_model.onchange_partner_id(self.session.cr,
self.session.uid, *args, **kwargs)
- vals = res.get('value')
+ vals = res.get('value', {})
for key in vals:
if not key in order:
order[key] = vals[key]
return order
- def _get_product_id_onchange_param(self, line, previous_line, 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
module if they modify the onchange signature
:param line: the sale order line to process
:type: dict
- :param previous_line: list of dict of the previous line processed
+ :param previous_lines: list of dict of the previous lines processed
:type: list
:param order: data of the sale order
:type: dict
@@ -104,12 +104,12 @@ def _get_product_id_onchange_param(self, line, previous_line, order):
}
return args, kwargs
- def _play_line_onchange(self, line, previous_line, order):
+ def _play_line_onchange(self, line, previous_lines, order):
""" Play the onchange of the sale order line
:param line: the sale order line to process
:type: dict
- :param previous_line: list of dict of the previous line processed
+ :param previous_lines: list of dict of the previous line processed
:type: list
:param order: data of the sale order
:type: dict
@@ -121,10 +121,10 @@ def _play_line_onchange(self, line, previous_line, order):
#Play product_id onchange
args, kwargs = self._get_product_id_onchange_param(line,
- previous_line, order)
+ previous_lines, order)
res = sale_line_model.product_id_change(self.session.cr,
self.session.uid, *args, **kwargs)
- vals = res.get('value')
+ vals = res.get('value', {})
for key in vals:
if not key in line:
if sale_line_model._columns[key]._type == 'many2many':
@@ -146,9 +146,14 @@ def play(self, order):
order = self._play_order_onchange(order)
#play onchanfe on sale order line
order_lines = []
+ # order['order_line'] = [(0, 0, {...}), (0, 0, {...})]
for line in order['order_line']:
- order_lines.append((0, 0,
- self._play_line_onchange(line[2], order_lines, order)))
+ new_line = (0, 0,
+ self._play_line_onchange(line[2],
+ order_lines,
+ order)
+ )
+ order_lines.append(new_line)
order['order_line'] = order_lines
return order
From af288245d6c5859a8f3d1ffa31e70b9e7e08ddda Mon Sep 17 00:00:00 2001
From: unknown
Date: Thu, 14 Mar 2013 12:20:47 +0100
Subject: [PATCH 11/86] [IMP] code review
---
connector_ecommerce/__init__.py | 2 +-
connector_ecommerce/tests/test_onchange.py | 7 ++-
.../unit/sale_order_onchange.py | 53 +++++++++++--------
3 files changed, 34 insertions(+), 28 deletions(-)
diff --git a/connector_ecommerce/__init__.py b/connector_ecommerce/__init__.py
index 0cf0ee35..872e0f16 100644
--- a/connector_ecommerce/__init__.py
+++ b/connector_ecommerce/__init__.py
@@ -31,5 +31,5 @@
import invoice
import payment_method
import event
-
+import unit
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py
index 93f0a95f..1ec83bda 100644
--- a/connector_ecommerce/tests/test_onchange.py
+++ b/connector_ecommerce/tests/test_onchange.py
@@ -23,7 +23,6 @@
import unittest2
import mock
-import magento
from openerp.addons.connector.connector import ConnectorUnit
from openerp.addons.connector_ecommerce.unit.sale_order_onchange import \
@@ -37,7 +36,7 @@
class test_onchange(common.TransactionCase):
- """ Test the imports from a Magento Mock """
+ """ Test the imports from a Magento-like Mock """
def setUp(self):
super(test_onchange, self).setUp()
@@ -75,7 +74,7 @@ def test_play_onchange(self):
'default_code': 'MyCode',
'name': 'My Product',
'weight': 15,
- 'taxes_id': [(6,0,[tax_id])],
+ 'taxes_id': [(6, 0, [tax_id])],
})
shop_id = shop_model.create(self.cr, self.uid, {
@@ -87,7 +86,7 @@ def test_play_onchange(self):
'name': 'mag_10000001',
'partner_id': partner_id,
'order_line': [
- (0,0,{
+ (0, 0, {
'product_id': product_id,
'price_unit': 20,
'name': 'My Real Name',
diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py
index 1c8e0b3e..4e756129 100644
--- a/connector_ecommerce/unit/sale_order_onchange.py
+++ b/connector_ecommerce/unit/sale_order_onchange.py
@@ -23,17 +23,16 @@
from openerp.addons.connector.connector import ConnectorUnit
class SaleOrderOnChange(ConnectorUnit):
- # name of the OpenERP model, to be defined in concrete classes
_model_name = None
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
module if they modify the onchange signature
-
- :param order: a dictionnary of the value of your sale order
+
+ :param order: a dictionary of the value of your sale order
:type: dict
-
+
:return: a tuple of args and kwargs for the onchange
:rtype: tuple
"""
@@ -46,31 +45,33 @@ def _get_partner_id_onchange_param(self, order):
def _play_order_onchange(self, order):
""" Play the onchange of the sale order
-
- :param order: a dictionnary of the value of your sale order
+
+ :param order: a dictionary of the value of your sale order
:type: dict
-
+
:return: the value of the sale order updated with the onchange result
:rtype: dict
"""
sale_model = self.session.pool.get('sale.order')
-
+
#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.session.uid,
+ *args,
+ **kwargs)
vals = res.get('value', {})
for key in vals:
if not key in order:
order[key] = vals[key]
return 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
module if they modify the onchange signature
-
+
:param line: the sale order line to process
:type: dict
:param previous_lines: list of dict of the previous lines processed
@@ -85,12 +86,15 @@ def _get_product_id_onchange_param(self, line, previous_lines, order):
None, # sale order line ids not needed
order.get('pricelist_id'),
line.get('product_id')
- ]
+ ]
+ uos_qty = float(line.get('product_uos_qty', 0))
+ if not uos_qty:
+ uos_qty = float(line.get('product_uom_qty', 0))
+
kwargs ={
- 'qty': float(line.get('product_uom_qty')),
+ 'qty': float(line.get('product_uom_qty', 0)),
'uom': line.get('product_uom'),
- 'qty_uos': float(line.get('product_uos_qty')\
- or line.get('product_uom_qty')),
+ 'qty_uos': uos_qty,
'uos': line.get('product_uos'),
'name': line.get('name'),
'partner_id': order.get('partner_id'),
@@ -101,19 +105,19 @@ def _get_product_id_onchange_param(self, line, previous_lines, order):
'fiscal_position': order.get('fiscal_position'),
'flag': False,
'context': self.session.context,
- }
+ }
return args, kwargs
def _play_line_onchange(self, line, previous_lines, order):
""" Play the onchange of the sale order line
-
+
:param line: the sale 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
:type: dict
-
+
:return: the value of the sale order updated with the onchange result
:rtype: dict
"""
@@ -121,9 +125,12 @@ def _play_line_onchange(self, line, previous_lines, order):
#Play product_id onchange
args, kwargs = self._get_product_id_onchange_param(line,
- previous_lines, order)
+ previous_lines,
+ order)
res = sale_line_model.product_id_change(self.session.cr,
- self.session.uid, *args, **kwargs)
+ self.session.uid,
+ *args,
+ **kwargs)
vals = res.get('value', {})
for key in vals:
if not key in line:
@@ -135,10 +142,10 @@ def _play_line_onchange(self, line, previous_lines, order):
def play(self, order):
""" Play the onchange of the sale order and it's lines
-
+
:param order: data of the sale order
:type: dict
-
+
:return: the value of the sale order updated with the onchange result
:rtype: dict
"""
@@ -154,6 +161,6 @@ def play(self, order):
order)
)
order_lines.append(new_line)
- order['order_line'] = order_lines
+ order['order_line'] = order_lines
return order
From b8b00b37becb31e1251c9f5439926723b443a525 Mon Sep 17 00:00:00 2001
From: Alexandre Fayolle
Date: Fri, 15 Mar 2013 13:57:27 +0100
Subject: [PATCH 12/86] [IMP] play on change on sale.order and sale.order.lines
in new framework, + support adding extra s.o. lines on the fly
add comments on the internals of SaleOrderOnChange.play()
---
connector_ecommerce/sale.py | 20 ++-----
.../unit/sale_order_onchange.py | 60 +++++++++++++------
2 files changed, 47 insertions(+), 33 deletions(-)
diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py
index 13827b3b..f0d163bc 100644
--- a/connector_ecommerce/sale.py
+++ b/connector_ecommerce/sale.py
@@ -699,7 +699,7 @@ def _merge_with_default_values(self, cr, uid, external_session, ressource, vals,
def oe_create(self, cr, uid, external_session, vals, resource, defaults, context):
#depending of the external system the contact address can be optionnal
- vals = self._convert_special_fields(cr, uid, vals, external_session.referential_id.id, context=context)
+ vals = self._convert_special_fields(cr, uid, vals, vals['order_line'], context=context)
if not vals.get('partner_order_id'):
vals['partner_order_id'] = vals['partner_invoice_id']
if not vals.get('partner_shipping_id'):
@@ -800,7 +800,7 @@ def oe_update(self, cr, uid, external_session, existing_rec_id, vals, resource,
" This feature is not supported. Maybe the import try to reimport an existing sale order"%(existing_rec_id,))))
return super(sale_order, self).oe_update(cr, uid, external_session, existing_rec_id, vals, resource, defaults, context=context)
- def _convert_special_fields(self, cr, uid, vals, referential_id, context=None):
+ def _convert_special_fields(self, cr, uid, vals, order_lines, context=None):
"""
Convert the special 'fake' field into an order line
special field are :
@@ -819,8 +819,8 @@ def check_key(keys):
'shipping_amount_tax_included',
'shipping_tax_amount'])
& set(keys)) >= 2
-
- for line in vals['order_line']:
+ vals.setdefault('order_line', [])
+ for line in order_lines:
for field in ['shipping_amount_tax_excluded','shipping_amount_tax_included', 'shipping_tax_amount']:
if field in line[2]:
vals[field] = vals.get(field, 0.0) + line[2][field]
@@ -893,18 +893,6 @@ def _add_order_extra_line(self, cr, uid, vals, option, context):
'price_unit': price_unit,
}
- extra_line = self.pool.get('sale.order.line').play_sale_order_line_onchange(cr, uid, extra_line, vals, vals['order_line'], context=context)
- if context.get('use_external_tax') and option.get('tax_rate_field'):
- tax_rate = vals.pop(option['tax_rate_field'])
- if tax_rate:
- line_tax_id = self.pool.get('account.tax').get_tax_from_rate(cr, uid, tax_rate, context.get('is_tax_included'), context=context)
- if not line_tax_id:
- raise except_osv(_('Error'), _('No tax id found for the rate %s with the tax include = %s')%(tax_rate, context.get('is_tax_included')))
- extra_line['tax_id'] = [(6, 0, [line_tax_id])]
- else:
- extra_line['tax_id'] = False
- if not option.get('tax_rate_field'):
- del extra_line['tax_id']
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])
diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py
index 4e756129..be55a1ec 100644
--- a/connector_ecommerce/unit/sale_order_onchange.py
+++ b/connector_ecommerce/unit/sale_order_onchange.py
@@ -22,7 +22,15 @@
from openerp.addons.connector.connector import ConnectorUnit
-class SaleOrderOnChange(ConnectorUnit):
+class OnChangeManager(ConnectorUnit):
+ def merge_values(self, record, on_change_result):
+ vals = on_change_result.get('value', {})
+ for key in vals:
+ if not key in record:
+ record[key] = vals[key]
+
+
+class SaleOrderOnChange(OnChangeManager):
_model_name = None
def _get_partner_id_onchange_param(self, order):
@@ -43,6 +51,12 @@ 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 _play_order_onchange(self, order):
""" Play the onchange of the sale order
@@ -55,16 +69,18 @@ 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,
*args,
**kwargs)
- vals = res.get('value', {})
- for key in vals:
- if not key in order:
- order[key] = vals[key]
-
+ self.merge_values(order, res)
return order
def _get_product_id_onchange_param(self, line, previous_lines, order):
@@ -131,6 +147,7 @@ def _play_line_onchange(self, line, previous_lines, order):
self.session.uid,
*args,
**kwargs)
+ # TODO refactor this with merge_values
vals = res.get('value', {})
for key in vals:
if not key in line:
@@ -140,7 +157,7 @@ def _play_line_onchange(self, line, previous_lines, order):
line[key] = vals[key]
return line
- def play(self, order):
+ def play(self, order, order_lines):
""" Play the onchange of the sale order and it's lines
:param order: data of the sale order
@@ -152,15 +169,24 @@ def play(self, order):
#play onchange on sale order
order = self._play_order_onchange(order)
#play onchanfe on sale order line
- order_lines = []
- # order['order_line'] = [(0, 0, {...}), (0, 0, {...})]
- for line in order['order_line']:
- new_line = (0, 0,
- self._play_line_onchange(line[2],
- order_lines,
- order)
- )
- order_lines.append(new_line)
- order['order_line'] = order_lines
+ processed_order_lines = []
+ line_lists = [order_lines]
+ if 'order_line' in order and order['order_line'] is not order_lines:
+ # we have both backend-dependent and oerp-native order
+ # lines.
+ # oerp-native lines can have been added to map
+ # shipping fees with an OpenERP Product
+ line_lists.append(order['order_line'])
+ for line_list in line_lists:
+ for idx, line in enumerate(line_list):
+ # line_list format:[(0, 0, {...}), (0, 0, {...})]
+ old_line_data = line[2]
+ new_line_data = self._play_line_onchange(old_line_data,
+ processed_order_lines,
+ order)
+ new_line = (0, 0, new_line_data)
+ processed_order_lines.append(new_line)
+ # in place modification of the sale order line in the list
+ line_list[idx] = new_line
return order
From 80bb6890ca9742bd4f75b7ca97772369b27beb5f Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Mon, 18 Mar 2013 11:52:49 +0100
Subject: [PATCH 13/86] [FIX] wrong arguments in action_done
[IMP] work on stock.picking.out instead of stock.picking
[REM] clean delivery carrier old code
[ADD] a connector hook in the stock.picking.out view
[FIX] action_done is not called on stock.picking.out but only on stock.picking
[CHG] rename base_sale_data.xml to ecommerce_data.xml
[ADD] hook in invoice view for connectors
[ADD] account_invoice.origin_order_id, link to the order which created the invoice
[REF] moved sale.py code to old_stuff.py
[ADD] copy the order id to the invoice it creates
[REM] remove code
[REF] move content of partner.py to old_stuff.py
[REF] move partner_view.xml content to old_xml_stuff.xml
[REF] moved code from product.py to old_stuff.py
[REF] removed views and act_window links to ir.model.data from sale_view.xml
[REF] removed external.referential.category.csv
[REF] remove obsolete access groups
[REF] comment out the sale exception until its reimplementation
[REF] removed the import order wizard
[REF] removed connector.py
[FIX] style
[REF] moved external_referential.py code to old_stuff.py
[REF] remove empty files
[ADD] hook for connectors in sale view
[FIX] do not load removed file
[REF] updated __openerp__ manifest, changed copyright attribution to reflect the facts, changed the license from GPL to AGPL-3
[FIX] reintroduce methods used for the import of magento sale orders
[FIX] connector_ecommerce: replace dependencies on sale_quick_payment by sale_quick_payment
[ADD] connector_ecommerce: add import_rule and days_before_cancel in payment.method, theses fields will be used by the connectors
[IMP] connector_ecommerce: call the onchanges on the sale order to apply the workflow default values
[IMP] connector_ecommerce: activate the options 'Allow different addresses', 'Multiple shop', 'Discount on SO lines'
[FIX] noupdate=1 on the global settings activation
[FIX] missing name in a view
[IMP] add hints in payment method view to help in the choice of the import rules
[ADD] on_product_price_changed Event, fired when the price of a product could have changed
As the price is a fields.function based on the contextual pricelist, we can never be sure
that a price has changed, it depends on the context.
So we search all the base fields used to compute the price, and if one of these has changed,
the event is fired.
[FIX] initialize the context when None
[IMP] reviewed the connector_ecommerce's description in the manifest __openerp__.py
[FIX] remove obsolete sale exception
[ADD] fields cancelled_in_backend and cancellation_resolved to handle the cancellation of the sales orders from a backend
[IMP] add a notification when a user choose to not cancel a sales order cancelled on the backend
[ADD] notification when a sales order is cancelled on the backend
[IMP] ignore the cancellation from the backend should be done by a sales manager only
[IMP] ask for a reason when the sale order is not cancelled despite the cancellation on the backend
[FIX] filter on cancels should exclude the resolved cancels
[ADD] a parent_id field on the sale order, base implementation, the logic needs to be implemented in the connectors due to their own specificities
[ADD] button to open the parent sale order
[ADD] sale exception preventing confirmation of a sale order when it has a parent order cancelled on the backend
[IMP] add the sales manager rights to the connector manager because they usually need these rights
[IMP] fields 'need_cancel' and 'parent_need_cancel'
[FIX] spells cancelled with the US form: canceled
[FIX] typos in views
[FIX] hide the 'keep open' button in canceled state
[ADD] when we write 'canceled_in_backend' in a sales order, try to automatically cancel it
[FIX] filter out already cancelled sales orders from the filter 'to cancel'
[FIX] domain for the invisible attribute of the 'keep open' button, logic was reversed
[IMP] add a note on the related pickings and invoices of an order cancelled from backend
[FIX] cancelation of sales order: quotation states requires to be canceled via the workflow, sales order states with the action_cancel method. Some states can not be canceled.
[ADD] sale exception when an ordered product has a pending connector checkpoint
[ADD] french translation
---
connector_ecommerce/__init__.py | 23 +-
connector_ecommerce/__openerp__.py | 124 +-
connector_ecommerce/account.py | 40 +-
connector_ecommerce/connector.py | 37 -
connector_ecommerce/delivery.py | 30 -
connector_ecommerce/delivery_view.xml | 19 -
...{base_sale_data.xml => ecommerce_data.xml} | 32 +
connector_ecommerce/event.py | 21 +-
connector_ecommerce/external_referential.py | 83 --
.../i18n/base_sale_multichannels.pot | 306 -----
connector_ecommerce/i18n/ca.po | 380 ------
connector_ecommerce/i18n/ca_ES.po | 334 -----
.../i18n/connector_ecommerce.pot | 354 +++++
connector_ecommerce/i18n/es.po | 379 ------
connector_ecommerce/i18n/fr.po | 356 -----
connector_ecommerce/i18n/fr_FR.po | 360 +++++
connector_ecommerce/i18n/pt.po | 379 ------
connector_ecommerce/i18n/sv.po | 327 -----
connector_ecommerce/invoice.py | 29 +-
connector_ecommerce/invoice_view.xml | 14 +
connector_ecommerce/old_stuff.py | 1119 ++++++++++++++++
.../{partner_view.xml => old_xml_stuff.xml} | 7 +-
connector_ecommerce/partner.py | 50 -
connector_ecommerce/payment_method.py | 76 +-
connector_ecommerce/payment_method_view.xml | 39 +-
connector_ecommerce/product.py | 297 +++--
connector_ecommerce/product_view.xml | 3 +-
connector_ecommerce/sale.py | 1187 +++++------------
connector_ecommerce/sale_view.xml | 219 +--
.../security/ir.model.access.csv | 15 -
connector_ecommerce/security/security.xml | 22 +
.../external.referential.category.csv | 2 -
.../settings/sale.exception.csv | 12 -
connector_ecommerce/stock.py | 32 +-
connector_ecommerce/stock_view.xml | 13 +-
.../unit/sale_order_onchange.py | 35 +-
connector_ecommerce/wizard/__init__.py | 22 +-
connector_ecommerce/wizard/import_order.xml | 34 -
...{import_order.py => sale_ignore_cancel.py} | 36 +-
.../wizard/sale_ignore_cancel_view.xml | 43 +
40 files changed, 2700 insertions(+), 4190 deletions(-)
delete mode 100644 connector_ecommerce/connector.py
delete mode 100644 connector_ecommerce/delivery.py
delete mode 100644 connector_ecommerce/delivery_view.xml
rename connector_ecommerce/{base_sale_data.xml => ecommerce_data.xml} (53%)
delete mode 100644 connector_ecommerce/external_referential.py
delete mode 100644 connector_ecommerce/i18n/base_sale_multichannels.pot
delete mode 100644 connector_ecommerce/i18n/ca.po
delete mode 100644 connector_ecommerce/i18n/ca_ES.po
create mode 100644 connector_ecommerce/i18n/connector_ecommerce.pot
delete mode 100644 connector_ecommerce/i18n/es.po
delete mode 100644 connector_ecommerce/i18n/fr.po
create mode 100644 connector_ecommerce/i18n/fr_FR.po
delete mode 100644 connector_ecommerce/i18n/pt.po
delete mode 100644 connector_ecommerce/i18n/sv.po
create mode 100644 connector_ecommerce/old_stuff.py
rename connector_ecommerce/{partner_view.xml => old_xml_stuff.xml} (75%)
delete mode 100644 connector_ecommerce/partner.py
create mode 100644 connector_ecommerce/security/security.xml
delete mode 100644 connector_ecommerce/settings/external.referential.category.csv
delete mode 100644 connector_ecommerce/settings/sale.exception.csv
delete mode 100644 connector_ecommerce/wizard/import_order.xml
rename connector_ecommerce/wizard/{import_order.py => sale_ignore_cancel.py} (52%)
create mode 100644 connector_ecommerce/wizard/sale_ignore_cancel_view.xml
diff --git a/connector_ecommerce/__init__.py b/connector_ecommerce/__init__.py
index 872e0f16..bac99af0 100644
--- a/connector_ecommerce/__init__.py
+++ b/connector_ecommerce/__init__.py
@@ -1,35 +1,30 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2009 Akretion (). All Rights Reserved
-# authors: Raphaël Valyi, Sharoon Thomas
+# Copyright 2013 Camptocamp SA
+# Copyright 2013 Akretion
#
# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# 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 General Public License for more details.
+# GNU Affero General Public License for more details.
#
-# You should have received a copy of the GNU General Public License
+# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
##############################################################################
-import sale
import stock
-import wizard
-import delivery
-import partner
import account
-import external_referential
import product
import invoice
import payment_method
import event
import unit
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+import sale
+import wizard
diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py
index c7ae879d..5690bc63 100644
--- a/connector_ecommerce/__openerp__.py
+++ b/connector_ecommerce/__openerp__.py
@@ -1,86 +1,80 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2009 Akretion (). All Rights Reserved
-# authors: Raphaël Valyi, Sharoon Thomas
-# Copyright (C) 2010-2011 Akretion Sébastien BEAU
+# Copyright 2013 Camptocamp SA
+# Copyright 2013 Akretion
+#
# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# 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 General Public License for more details.
+# GNU Affero General Public License for more details.
#
-# You should have received a copy of the GNU General Public License
+# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
##############################################################################
-
-{
- 'name': 'Connector for E-Commerce',
- 'version': '2.0.0',
- 'category': 'Connector',
- 'description': """
+{'name': 'Connector for E-Commerce',
+ 'version': '2.0.0',
+ 'category': 'Connector',
+ 'author': 'MagentoERPConnect Core Editors',
+ 'website': 'http://www.magentoerpconnect.com',
+ 'license': 'AGPL-3',
+ 'description': """
Connector for E-Commerce
========================
-TODO
-----
+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.
-Review the description
+Data Model
-Old Description
----------------
+ Add structures shared for e-commerce connectors
-This module provide an abstract common minimal base to multi-channels sales.
-Say you want to expose your product catalog to
-* several instances of flashy-sluggish Magento web sites
-* a cutting edge Spree web shop
-* a Neteven online Marketplace
-* EBay
-* Amazon
-* Google Base
-* an external Point Of Sale system
-* ...
-Then this module allows you to:
-* use several external references ids on every OpenERP object matching those all those external referentials
-* per referential instance, use several sale sub platform entities (ex: several Magento websites per instance)
-* per sub platform, use several shops (ex: several Magento web shops per website)
-For each sale shop (matching OpenERP sale.shop object), this module abstract the interfaces to:
-* export the catalog, shop warehouse stock level wise, shop pricelist wise
-* import the catalog
-* import orders
-* export orders/picking status
- """,
- 'author': 'MagentoERPConnect Core Editors',
- 'website': 'http://www.magentoerpconnect.com',
- 'depends': [
- 'sale_automatic_workflow',
- 'sale_exceptions',
- 'connector',
- 'delivery',
- 'base_onchange_player', # TODO remove dependency
- ],
- 'data': [
- 'security/ir.model.access.csv',
- 'sale_view.xml',
- 'product_view.xml',
- 'partner_view.xml',
- 'invoice_view.xml',
- 'wizard/import_order.xml',
- 'delivery_view.xml',
- 'base_sale_data.xml',
- 'settings/sale.exception.csv',
- 'settings/external.referential.category.csv',
- 'stock_view.xml',
- 'payment_method_view.xml',
- 'account_view.xml',
- ],
- 'installable': True,
+.. _`connector`: https://code.launchpad.net/openerp-connector
+.. _`magentoerpconnect`: https://launchpad.net/magentoerpconnect
+.. _`prestashoperpconnect`: https://launchpad.net/prestashoperpconnect
+""",
+ 'depends': [
+ 'connector',
+ 'sale_automatic_workflow',
+ 'sale_exceptions',
+ 'delivery',
+ ],
+ 'data': [
+ 'security/security.xml',
+ 'security/ir.model.access.csv',
+ 'wizard/sale_ignore_cancel_view.xml',
+ 'sale_view.xml',
+ 'product_view.xml',
+ 'invoice_view.xml',
+ 'ecommerce_data.xml',
+ 'stock_view.xml',
+ 'payment_method_view.xml',
+ 'account_view.xml',
+ ],
+ 'installable': True,
}
diff --git a/connector_ecommerce/account.py b/connector_ecommerce/account.py
index affcdacf..97c4d3aa 100644
--- a/connector_ecommerce/account.py
+++ b/connector_ecommerce/account.py
@@ -1,23 +1,23 @@
-# -*- encoding: utf-8 -*-
-#################################################################################
-# #
-# connector_ecommerce for OpenERP #
-# Copyright (C) 2011 Akretion Sébastien BEAU #
-# #
-# 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 . #
-# #
-#################################################################################
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright 2011-2013 Akretion
+# @author Sébastien BEAU
+#
+# 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 .
+#
+##############################################################################
from openerp.osv.orm import Model
from openerp.osv import fields
diff --git a/connector_ecommerce/connector.py b/connector_ecommerce/connector.py
deleted file mode 100644
index 91f1a794..00000000
--- a/connector_ecommerce/connector.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# -*- encoding: utf-8 -*-
-###############################################################################
-# #
-# product_custom_attributes for OpenERP #
-# Copyright (C) 2012 Camptocamp Alexandre Fayolle #
-# Copyright (C) 2012 Akretion Sebastien Beau #
-# #
-# 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 . #
-# #
-###############################################################################
-
-from openerp.addons.connector.connector import AbstractConnector
-
-class BaseConnector(AbstractConnector):
- def _get_import_defaults_res_partner(self, cr, uid, context=None):
- pass
- def _get_import_defaults_res_partner(self, cr, uid, context=None):
- pass
- def _get_import_defaults_external_shop_group(self, cr, uid, context=None):
- pass
-
- def _get_import_defaults_sale_order(self, cr, uid, context=None):
- pass
-
- def _record_one_sale_order(self, cr, uid, res_obj, resource, defaults, context):
- pass
diff --git a/connector_ecommerce/delivery.py b/connector_ecommerce/delivery.py
deleted file mode 100644
index a1e16539..00000000
--- a/connector_ecommerce/delivery.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# -*- encoding: utf-8 -*-
-##############################################################################
-#
-# Author Guewen Baconnier. Copyright 2011 Camptocamp SA
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-from openerp.osv.orm import Model
-from openerp.osv import fields
-
-class delivery_carrier(Model):
- _inherit = "delivery.carrier"
-
- _columns = {
- # TODO to be removed once the job export tracking is there
- 'export_needs_tracking': fields.boolean('Export only shippings with a tracking number'),
- }
diff --git a/connector_ecommerce/delivery_view.xml b/connector_ecommerce/delivery_view.xml
deleted file mode 100644
index 5c09a060..00000000
--- a/connector_ecommerce/delivery_view.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
- delivery.carrier.form.inherit
- delivery.carrier
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/connector_ecommerce/base_sale_data.xml b/connector_ecommerce/ecommerce_data.xml
similarity index 53%
rename from connector_ecommerce/base_sale_data.xml
rename to connector_ecommerce/ecommerce_data.xml
index d749b9ff..803cb71e 100644
--- a/connector_ecommerce/base_sale_data.xml
+++ b/connector_ecommerce/ecommerce_data.xml
@@ -42,5 +42,37 @@
+
+ Parent sales order canceled on the backend.
+ The parent sales order has been canceled on the backend.
+You will not be able to process this sales order until the parent's one is canceled.
+ 30
+ sale.order
+ if order.parent_need_cancel:
+ failed = True
+
+
+
+
+ Sales order canceled on the backend.
+ The sales order has been canceled on the backend.
+ 20
+ sale.order
+ if order.need_cancel:
+ failed = True
+
+
+
+
+ A product needs to be reviewed.
+ A product has been imported from a backend and needs to be reviewed.
+Go to Connectors > Checkpoint and review the new products.
+ 20
+ sale.order.line
+ if object.product_id and object.product_id.has_checkpoint:
+ failed = True
+
+
+
diff --git a/connector_ecommerce/event.py b/connector_ecommerce/event.py
index f75ca21a..7a480284 100644
--- a/connector_ecommerce/event.py
+++ b/connector_ecommerce/event.py
@@ -22,9 +22,10 @@
from openerp.addons.connector.event import Event
-on_picking_done = Event()
+on_picking_out_done = Event()
"""
-``on_picking_done`` is fired when a picking has been marked as done.
+``on_picking_out_done`` is fired when an outgoing picking has been
+marked as done.
Listeners should take the following arguments:
@@ -54,8 +55,22 @@
Listeners should take the following arguments:
- * session: `Session` object
* session: `connector.session.ConnectorSession` object
* model_name: name of the model
* record_id: id of the record
"""
+
+on_product_price_changed = Event()
+"""
+``on_product_price_changed`` is fired when the price of a product is
+changed. Specifically, it is fired when one of the products' fields used
+in the sale pricelists are modified.
+
+There is no guarantee that's the price actually changed,
+because it depends on the pricelists.
+
+ * session: `connector.session.ConnectorSession` object
+ * model_name: name of the model
+ * record_id: id of the record
+
+"""
diff --git a/connector_ecommerce/external_referential.py b/connector_ecommerce/external_referential.py
deleted file mode 100644
index ccda9493..00000000
--- a/connector_ecommerce/external_referential.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# -*- coding: utf-8 -*-
-###############################################################################
-# #
-# connector_ecommerce for OpenERP #
-# Copyright (C) 2011 Akretion Sébastien BEAU #
-# #
-# 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 . #
-# #
-###############################################################################
-from openerp.osv import orm, fields
-
-
-class external_referential(orm.Model):
- _inherit = "external.referential"
-
- _columns = {
- 'last_imported_product_id': fields.integer(
- 'Last Imported Product Id',
- help="Product are imported one by one. "
- "This is the magento id of the last product imported. "
- "If you clear it all product will be imported"),
- # TODO replace by last import date (at website level)
- 'last_imported_partner_id': fields.integer(
- 'Last Imported Partner Id',
- help="Partners are imported one by one. "
- "This is the magento id of the last partner imported. "
- "If you clear it all partners will be imported"),
- 'import_all_attributs': fields.boolean(
- 'Import all attributs',
- help="If the option is uncheck only the attributs "
- "that doesn't exist in OpenERP will be imported "),
- 'import_image_with_product': fields.boolean(
- 'With image',
- help="If the option is check the product's image and "
- "the product will be imported at the same time and"
- "so the step '7-import images' is not needed"),
- 'import_links_with_product': fields.boolean(
- 'With links',
- help="If the option is check the product's links "
- "(Up-Sell, Cross-Sell, Related) and the product will "
- "be imported at the same time and so the step "
- "'8-import links' is not needed"),
- }
-
- def import_customer_groups(self, cr, uid, ids, context=None):
- self.import_resources(cr, uid, ids, 'res.partner.category', context=context)
- return True
-
- def import_product_categories(self, cr, uid, ids, context=None):
- self.import_resources(cr, uid, ids, 'product.category', context=context)
- return True
-
- def import_customers(self, cr, uid, ids, context=None):
- self.import_resources(cr, uid, ids, 'res.partner', context=context)
- return True
-
-# def import_product_attributes_sets(self, cr, uid, ids, context=None):
-# return self.import_resources(cr, uid, ids, 'TODO', context=context)
-#
-# def import_product_attributes_groups(self, cr, uid, ids, context=None):
-# return self.import_resources(cr, uid, ids, 'TODO', context=context)
-#
-# def import_product_attributes(self, cr, uid, ids, context=None):
-# return self.import_resources(cr, uid, ids, 'TODO', context=context)
-
- def import_products(self, cr, uid, ids, context=None):
- self.import_resources(cr, uid, ids, 'product.product', context=context)
- return True
-
- def import_product_links(self, cr, uid, ids, context=None):
- self.import_resources(cr, uid, ids, 'product.link', context=context)
- return True
diff --git a/connector_ecommerce/i18n/base_sale_multichannels.pot b/connector_ecommerce/i18n/base_sale_multichannels.pot
deleted file mode 100644
index a46f0c73..00000000
--- a/connector_ecommerce/i18n/base_sale_multichannels.pot
+++ /dev/null
@@ -1,306 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * connector_ecommerce
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 5.0.6\n"
-"Report-Msgid-Bugs-To: support@openerp.com\n"
-"POT-Creation-Date: 2009-12-20 17:22:08+0000\n"
-"PO-Revision-Date: 2009-12-20 17:22:08+0000\n"
-"Last-Translator: <>\n"
-"Language-Team: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: \n"
-"Plural-Forms: \n"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Partial Delivery"
-msgstr ""
-
-#. module: connector_ecommerce
-#: constraint:ir.model:0
-msgid "The Object name must start with x_ and not contain any special character !"
-msgstr ""
-
-#. module: connector_ecommerce
-#: model:ir.module.module,description:connector_ecommerce.module_meta_information
-msgid "\n"
-"This module provide an abstract common minimal base to multi-channels sales.\n"
-"Say you want to expose your product catalog to\n"
-"* several instances of flashy-sluggish Magento web sites\n"
-"* a cutting edge Spree web shop\n"
-"* a Neteven online Marketplace\n"
-"* EBay\n"
-"* Amazon\n"
-"* Google Base\n"
-"* an external Point Of Sale system\n"
-"* ...\n"
-"Then this module allows you to:\n"
-"* use several external references ids on every OpenERP object matching those all those external referentials\n"
-"* per referential instance, use several sale sub platform entities (ex: several Magento websites per instance)\n"
-"* per sub platform, use several shops (ex: several Magento web shops per website)\n"
-"\n"
-"For each sale shop (matching OpenERP sale.shop object), this module abstract the interfaces to:\n"
-"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
-"* import the catalog\n"
-"* import orders\n"
-"* export orders/picking status\n"
-" "
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,order_policy:0
-msgid "Shipping Policy"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "None"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Shipped Quantities"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:external.shop.group,referential_id:0
-msgid "Referential"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Draft"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_quantity:0
-msgid "The sale order will automatically create the invoice proposition (draft invoice). Ordered and delivered quantities may not be the same. You have to choose if you invoice based on ordered or shipped quantities. If the product is a service, shipped quantities means hours spent on the associated tasks."
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,shop_group_id:0
-msgid "Shop Group"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:product.category,recursive_childen_ids:0
-msgid "All Child Categories"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Update Orders Status"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_policy:0
-msgid "If you don't have enough stock available to deliver all at once, do you accept partial shipments or not?"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:account.journal,external_payment_codes:0
-msgid "Enter the external payment codes, comma separated. They will be used to select the payment journal."
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_policy:0
-msgid "Packing Policy"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Complete Delivery"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_generation_policy:0
-msgid "Invoice Generation Policy"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Ordered Quantities"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,is_tax_included:0
-msgid "Requires sale_tax_include module to be installed"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Catalog"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "External Shop Settings"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Catalog"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice from the Packing"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Order Generation"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:account.journal,external_payment_codes:0
-msgid "External Payment Codes"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice on Order After Delivery"
-msgstr ""
-
-#. module: connector_ecommerce
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:external.shop.group,shop_ids:0
-msgid "Sale Shops"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:external.shop.group,name:0
-msgid "Name"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_quantity:0
-msgid "Invoice on"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,order_policy:0
-msgid "The Shipping Policy is used to synchronise invoice and delivery operations.\n"
-" - The 'Pay before delivery' choice will first generate the invoice and then generate the packing order after the payment of this invoice.\n"
-" - The 'Shipping & Manual Invoice' will create the packing order directly and wait for the user to manually click on the 'Invoice' button to generate the draft invoice.\n"
-" - The 'Invoice on Order After Delivery' choice will generate the draft invoice based on sale order after all packing lists have been finished.\n"
-" - The 'Invoice from the packing' choice is used to create an invoice during the packing process."
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_inventory_export_date:0
-msgid "Last Inventory Export Time"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:external.referential,shop_group_ids:0
-msgid "Sub Entities"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,referential_id:0
-msgid "External Referential"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Payment Before Delivery"
-msgstr ""
-
-#. module: connector_ecommerce
-#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
-msgid "Base Sale MultiChannels"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-#: field:sale.shop,exportable_product_ids:0
-msgid "Exportable Products"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Import Orders"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_generation_policy:0
-msgid "Picking Generation Policy"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_generation_policy:0
-msgid "Should orders create an invoice after import?"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_update_order_export_date:0
-msgid "Last Order Update Time"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_generation_policy:0
-msgid "Should orders create a picking after import?"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Validated"
-msgstr ""
-
-#. module: connector_ecommerce
-#: model:ir.model,name:connector_ecommerce.model_external_shop_group
-msgid "External Referential Shop Group"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Stock Levels Only"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Shipping & Manual Invoice"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Actions"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,exportable_root_category_ids:0
-msgid "Root Category"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,is_tax_included:0
-msgid "Prices Include Tax?"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Shop"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Multi Channels"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Orders"
-msgstr ""
-
diff --git a/connector_ecommerce/i18n/ca.po b/connector_ecommerce/i18n/ca.po
deleted file mode 100644
index 741eb7a9..00000000
--- a/connector_ecommerce/i18n/ca.po
+++ /dev/null
@@ -1,380 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * connector_ecommerce
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 5.0.6\n"
-"Report-Msgid-Bugs-To: support@openerp.com\n"
-"POT-Creation-Date: 2009-12-20 17:22+0000\n"
-"PO-Revision-Date: 2011-02-14 10:04+0000\n"
-"Last-Translator: Jordi Esteve (www.zikzakmedia.com) "
-"\n"
-"Language-Team: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-01-17 05:05+0000\n"
-"X-Generator: Launchpad (build 14676)\n"
-"X-Poedit-Language: Catalan\n"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Partial Delivery"
-msgstr "Enviament parcial"
-
-#. module: connector_ecommerce
-#: constraint:ir.model:0
-msgid ""
-"The Object name must start with x_ and not contain any special character !"
-msgstr ""
-"El nom de l'objecte ha de començar amb x_ i no contenir cap caràcter "
-"especial!"
-
-#. module: connector_ecommerce
-#: model:ir.module.module,description:connector_ecommerce.module_meta_information
-msgid ""
-"\n"
-"This module provide an abstract common minimal base to multi-channels "
-"sales.\n"
-"Say you want to expose your product catalog to\n"
-"* several instances of flashy-sluggish Magento web sites\n"
-"* a cutting edge Spree web shop\n"
-"* a Neteven online Marketplace\n"
-"* EBay\n"
-"* Amazon\n"
-"* Google Base\n"
-"* an external Point Of Sale system\n"
-"* ...\n"
-"Then this module allows you to:\n"
-"* use several external references ids on every OpenERP object matching those "
-"all those external referentials\n"
-"* per referential instance, use several sale sub platform entities (ex: "
-"several Magento websites per instance)\n"
-"* per sub platform, use several shops (ex: several Magento web shops per "
-"website)\n"
-"\n"
-"For each sale shop (matching OpenERP sale.shop object), this module abstract "
-"the interfaces to:\n"
-"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
-"* import the catalog\n"
-"* import orders\n"
-"* export orders/picking status\n"
-" "
-msgstr ""
-"\n"
-"Aquest mòdul proporciona una mínima base d'abstracció comuna a diversos "
-"canals de vendes.\n"
-"Suposem que voleu exposar el vostre catàleg de productes a:\n"
-"* Diverses instàncies de botiga web de Magento\n"
-"* Una botiga web d'última generació Spree\n"
-"* Un mercat Neteven\n"
-"* EBay\n"
-"* Amazon\n"
-"* Google Base\n"
-"* Un sistema punt de venda extern\n"
-"* ...\n"
-"Llavors, aquest mòdul us permet:\n"
-"* L'ús de diverses referències externes a tots els identificadors d'objectes "
-"OpenERP que apunten a totes aquestes referències externes.\n"
-"* Referències per instància, l'ús de diverses sub entitats de vendes (per "
-"exemple diversos llocs web Magento per instància)\n"
-"* Referències per sub entitat, l'ús de diverses botigues (per exemple "
-"diverses botigues web Magento per lloc web)\n"
-"\n"
-"Per a cada botiga de venda (que es correspondrà a l'objecte sale.shop de "
-"OpenERP), aquest mòdul abstreu les interfícies de:\n"
-"* Exportar el catàleg, nivell d'estoc del magatzem de la botiga, tarifa de "
-"preus de la botiga\n"
-"* Importar el catàleg\n"
-"* Importar comandes\n"
-"* Exportar l'estat de les comandes/albarans\n"
-" "
-
-#. module: connector_ecommerce
-#: field:sale.shop,order_policy:0
-msgid "Shipping Policy"
-msgstr "Política de facturació"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "None"
-msgstr "Cap"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Shipped Quantities"
-msgstr "Quantitats enviades"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,referential_id:0
-msgid "Referential"
-msgstr "Referència"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Draft"
-msgstr "Esborrany"
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_quantity:0
-msgid ""
-"The sale order will automatically create the invoice proposition (draft "
-"invoice). Ordered and delivered quantities may not be the same. You have to "
-"choose if you invoice based on ordered or shipped quantities. If the product "
-"is a service, shipped quantities means hours spent on the associated tasks."
-msgstr ""
-"La comanda de venda crearà automàticament la proposta de factura (factura "
-"esborrany). Les quantitats demanades i les quantitats enviades poden no ser "
-"les mateixes. Heu de decidir si factureu basat en quantitats demanades o "
-"enviades. Si el producte és un servei, quantitats enviades significa hores "
-"dedicades a les tasques associades."
-
-#. module: connector_ecommerce
-#: field:sale.shop,shop_group_id:0
-msgid "Shop Group"
-msgstr "Grup botigues"
-
-#. module: connector_ecommerce
-#: field:product.category,recursive_childen_ids:0
-msgid "All Child Categories"
-msgstr "Totes categories filles"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Update Orders Status"
-msgstr "Actualitza estat comandes"
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_policy:0
-msgid ""
-"If you don't have enough stock available to deliver all at once, do you "
-"accept partial shipments or not?"
-msgstr ""
-"Si no disposeu de suficient estoc disponible per a enviar-ho tot a la "
-"vegada, accepteu enviaments parcials?"
-
-#. module: connector_ecommerce
-#: help:account.journal,external_payment_codes:0
-msgid ""
-"Enter the external payment codes, comma separated. They will be used to "
-"select the payment journal."
-msgstr ""
-"Indiqueu els codis de pagament externs, separats per coma. S'utilitzaran per "
-"a seleccionar el diari de pagament."
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_policy:0
-msgid "Packing Policy"
-msgstr "Política d'enviament"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Complete Delivery"
-msgstr "Enviament complet"
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_generation_policy:0
-msgid "Invoice Generation Policy"
-msgstr "Política generació de factures"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Ordered Quantities"
-msgstr "Quantitats ordenades"
-
-#. module: connector_ecommerce
-#: help:sale.shop,is_tax_included:0
-msgid "Requires sale_tax_include module to be installed"
-msgstr "Requereix que el mòdul sale_tax_include sigui instal·lat."
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Catalog"
-msgstr "Catàleg"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "External Shop Settings"
-msgstr "Configuració botiga externa"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Catalog"
-msgstr "Exporta catàleg"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice from the Packing"
-msgstr "Factura des d'albarà"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Order Generation"
-msgstr "Generació comanda"
-
-#. module: connector_ecommerce
-#: field:account.journal,external_payment_codes:0
-msgid "External Payment Codes"
-msgstr "Codis de pagament externs"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice on Order After Delivery"
-msgstr "Factura comanda després de l'enviament"
-
-#. module: connector_ecommerce
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr "XML invàlid per a la definició de la vista!"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,shop_ids:0
-msgid "Sale Shops"
-msgstr "Botigues venda"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,name:0
-msgid "Name"
-msgstr "Nom"
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_quantity:0
-msgid "Invoice on"
-msgstr "Factura les"
-
-#. module: connector_ecommerce
-#: help:sale.shop,order_policy:0
-msgid ""
-"The Shipping Policy is used to synchronise invoice and delivery operations.\n"
-" - The 'Pay before delivery' choice will first generate the invoice and "
-"then generate the packing order after the payment of this invoice.\n"
-" - The 'Shipping & Manual Invoice' will create the packing order directly "
-"and wait for the user to manually click on the 'Invoice' button to generate "
-"the draft invoice.\n"
-" - The 'Invoice on Order After Delivery' choice will generate the draft "
-"invoice based on sale order after all packing lists have been finished.\n"
-" - The 'Invoice from the packing' choice is used to create an invoice "
-"during the packing process."
-msgstr ""
-"La política d'enviament s'utilitza per sincronitzar la factura i les "
-"operacions d'enviament.\n"
-" - L'opció 'Pagament abans de l'enviament' primer genera la factura i "
-"després genera l'albarà al fer efectiu el pagament d'aquesta factura.\n"
-" - L'opció 'Enviament' & Factura manual 'crearà l'albarà directament i "
-"esperarà que l'usuari faci clic manualment al botó' Factura 'per generar la "
-"factura esborrany.\n"
-" - L'opció 'Factura segons comanda després enviament' generarà la factura "
-"esborrany basada en la comanda de venda després que tots els albarans es "
-"processin.\n"
-" - L'opció 'Factura des d'albarà' s'utilitza per a crear una factura des "
-"dels albarans processats."
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_inventory_export_date:0
-msgid "Last Inventory Export Time"
-msgstr "Data última exportació inventari"
-
-#. module: connector_ecommerce
-#: field:external.referential,shop_group_ids:0
-msgid "Sub Entities"
-msgstr "Sub entitats"
-
-#. module: connector_ecommerce
-#: field:sale.shop,referential_id:0
-msgid "External Referential"
-msgstr "Referència externa"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Payment Before Delivery"
-msgstr "Pagament abans de l'enviament"
-
-#. module: connector_ecommerce
-#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
-msgid "Base Sale MultiChannels"
-msgstr "Base vendes multicanal"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-#: field:sale.shop,exportable_product_ids:0
-msgid "Exportable Products"
-msgstr "Productes exportables"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Import Orders"
-msgstr "Importa comandes"
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_generation_policy:0
-msgid "Picking Generation Policy"
-msgstr "Política generació d'albarans"
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_generation_policy:0
-msgid "Should orders create an invoice after import?"
-msgstr "Les comandes haurien de crear una factura després de la importació?"
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_update_order_export_date:0
-msgid "Last Order Update Time"
-msgstr "Data última actualització comandes"
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_generation_policy:0
-msgid "Should orders create a picking after import?"
-msgstr "Les comandes haurien de crear un albarà després de la importació?"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Validated"
-msgstr "Validat"
-
-#. module: connector_ecommerce
-#: model:ir.model,name:connector_ecommerce.model_external_shop_group
-msgid "External Referential Shop Group"
-msgstr "Referència externa grup botigues"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Stock Levels Only"
-msgstr "Exporta només nivells d'estoc"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Shipping & Manual Invoice"
-msgstr "Envia & Factura manual"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Actions"
-msgstr "Accions"
-
-#. module: connector_ecommerce
-#: field:sale.shop,exportable_root_category_ids:0
-msgid "Root Category"
-msgstr "Categoria arrel"
-
-#. module: connector_ecommerce
-#: field:sale.shop,is_tax_included:0
-msgid "Prices Include Tax?"
-msgstr "Preus inclouen impostos?"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Shop"
-msgstr "Botiga venda"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Multi Channels"
-msgstr "Vendes Multi canal"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Orders"
-msgstr "Comandes"
diff --git a/connector_ecommerce/i18n/ca_ES.po b/connector_ecommerce/i18n/ca_ES.po
deleted file mode 100644
index d0830688..00000000
--- a/connector_ecommerce/i18n/ca_ES.po
+++ /dev/null
@@ -1,334 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * connector_ecommerce
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 5.0.6\n"
-"Report-Msgid-Bugs-To: support@openerp.com\n"
-"POT-Creation-Date: 2009-12-20 17:22:08+0000\n"
-"PO-Revision-Date: 2010-03-02 13:08+0100\n"
-"Last-Translator: Jordi Esteve (Zikzakmedia) \n"
-"Language-Team: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Poedit-Language: Catalan\n"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Partial Delivery"
-msgstr "Enviament parcial"
-
-#. module: connector_ecommerce
-#: constraint:ir.model:0
-msgid "The Object name must start with x_ and not contain any special character !"
-msgstr "El nom de l'objecte ha de començar amb x_ i no contenir cap caràcter especial!"
-
-#. module: connector_ecommerce
-#: model:ir.module.module,description:connector_ecommerce.module_meta_information
-msgid ""
-"\n"
-"This module provide an abstract common minimal base to multi-channels sales.\n"
-"Say you want to expose your product catalog to\n"
-"* several instances of flashy-sluggish Magento web sites\n"
-"* a cutting edge Spree web shop\n"
-"* a Neteven online Marketplace\n"
-"* EBay\n"
-"* Amazon\n"
-"* Google Base\n"
-"* an external Point Of Sale system\n"
-"* ...\n"
-"Then this module allows you to:\n"
-"* use several external references ids on every OpenERP object matching those all those external referentials\n"
-"* per referential instance, use several sale sub platform entities (ex: several Magento websites per instance)\n"
-"* per sub platform, use several shops (ex: several Magento web shops per website)\n"
-"\n"
-"For each sale shop (matching OpenERP sale.shop object), this module abstract the interfaces to:\n"
-"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
-"* import the catalog\n"
-"* import orders\n"
-"* export orders/picking status\n"
-" "
-msgstr ""
-"\n"
-"Aquest mòdul proporciona una mínima base d'abstracció comuna a diversos canals de vendes.\n"
-"Suposem que voleu exposar el vostre catàleg de productes a:\n"
-"* Diverses instàncies de botiga web de Magento\n"
-"* Una botiga web d'última generació Spree\n"
-"* Un mercat Neteven\n"
-"* EBay\n"
-"* Amazon\n"
-"* Google Base\n"
-"* Un sistema punt de venda extern\n"
-"* ...\n"
-"Llavors, aquest mòdul us permet:\n"
-"* L'ús de diverses referències externes a tots els identificadors d'objectes OpenERP que apunten a totes aquestes referències externes.\n"
-"* Referències per instància, l'ús de diverses sub entitats de vendes (per exemple diversos llocs web Magento per instància)\n"
-"* Referències per sub entitat, l'ús de diverses botigues (per exemple diverses botigues web Magento per lloc web)\n"
-"\n"
-"Per a cada botiga de venda (que es correspondrà a l'objecte sale.shop de OpenERP), aquest mòdul abstreu les interfícies de:\n"
-"* Exportar el catàleg, nivell d'estoc del magatzem de la botiga, tarifa de preus de la botiga\n"
-"* Importar el catàleg\n"
-"* Importar comandes\n"
-"* Exportar l'estat de les comandes/albarans\n"
-
-#. module: connector_ecommerce
-#: field:sale.shop,order_policy:0
-msgid "Shipping Policy"
-msgstr "Política de facturació"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "None"
-msgstr "Cap"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Shipped Quantities"
-msgstr "Quantitats enviades"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,referential_id:0
-msgid "Referential"
-msgstr "Referència"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Draft"
-msgstr "Esborrany"
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_quantity:0
-msgid "The sale order will automatically create the invoice proposition (draft invoice). Ordered and delivered quantities may not be the same. You have to choose if you invoice based on ordered or shipped quantities. If the product is a service, shipped quantities means hours spent on the associated tasks."
-msgstr "La comanda de venda crearà automàticament la proposta de factura (factura esborrany). Les quantitats demanades i les quantitats enviades poden no ser les mateixes. Heu de decidir si factureu basat en quantitats demanades o enviades. Si el producte és un servei, quantitats enviades significa hores dedicades a les tasques associades."
-
-#. module: connector_ecommerce
-#: field:sale.shop,shop_group_id:0
-msgid "Shop Group"
-msgstr "Grup botigues"
-
-#. module: connector_ecommerce
-#: field:product.category,recursive_childen_ids:0
-msgid "All Child Categories"
-msgstr "Totes categories filles"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Update Orders Status"
-msgstr "Actualitza estat comandes"
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_policy:0
-msgid "If you don't have enough stock available to deliver all at once, do you accept partial shipments or not?"
-msgstr "Si no disposeu de suficient estoc disponible per a enviar-ho tot a la vegada, accepteu enviaments parcials?"
-
-#. module: connector_ecommerce
-#: help:account.journal,external_payment_codes:0
-msgid "Enter the external payment codes, comma separated. They will be used to select the payment journal."
-msgstr "Indiqueu els codis de pagament externs, separats per coma. S'utilitzaran per a seleccionar el diari de pagament."
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_policy:0
-msgid "Packing Policy"
-msgstr "Política d'enviament"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Complete Delivery"
-msgstr "Enviament complet"
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_generation_policy:0
-msgid "Invoice Generation Policy"
-msgstr "Política generació de factures"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Ordered Quantities"
-msgstr "Quantitats ordenades"
-
-#. module: connector_ecommerce
-#: help:sale.shop,is_tax_included:0
-msgid "Requires sale_tax_include module to be installed"
-msgstr "Requereix que el mòdul sale_tax_include sigui instal·lat."
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Catalog"
-msgstr "Catàleg"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "External Shop Settings"
-msgstr "Configuració botiga externa"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Catalog"
-msgstr "Exporta catàleg"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice from the Packing"
-msgstr "Factura des d'albarà"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Order Generation"
-msgstr "Generació comanda"
-
-#. module: connector_ecommerce
-#: field:account.journal,external_payment_codes:0
-msgid "External Payment Codes"
-msgstr "Codis de pagament externs"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice on Order After Delivery"
-msgstr "Factura comanda després de l'enviament"
-
-#. module: connector_ecommerce
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr "XML invàlid per a la definició de la vista!"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,shop_ids:0
-msgid "Sale Shops"
-msgstr "Botigues venda"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,name:0
-msgid "Name"
-msgstr "Nom"
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_quantity:0
-msgid "Invoice on"
-msgstr "Factura les"
-
-#. module: connector_ecommerce
-#: help:sale.shop,order_policy:0
-msgid ""
-"The Shipping Policy is used to synchronise invoice and delivery operations.\n"
-" - The 'Pay before delivery' choice will first generate the invoice and then generate the packing order after the payment of this invoice.\n"
-" - The 'Shipping & Manual Invoice' will create the packing order directly and wait for the user to manually click on the 'Invoice' button to generate the draft invoice.\n"
-" - The 'Invoice on Order After Delivery' choice will generate the draft invoice based on sale order after all packing lists have been finished.\n"
-" - The 'Invoice from the packing' choice is used to create an invoice during the packing process."
-msgstr ""
-"La política d'enviament s'utilitza per sincronitzar la factura i les operacions d'enviament.\n"
-" - L'opció 'Pagament abans de l'enviament' primer genera la factura i després genera l'albarà al fer efectiu el pagament d'aquesta factura.\n"
-" - L'opció 'Enviament' & Factura manual 'crearà l'albarà directament i esperarà que l'usuari faci clic manualment al botó' Factura 'per generar la factura esborrany.\n"
-" - L'opció 'Factura segons comanda després enviament' generarà la factura esborrany basada en la comanda de venda després que tots els albarans es processin.\n"
-" - L'opció 'Factura des d'albarà' s'utilitza per a crear una factura des dels albarans processats."
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_inventory_export_date:0
-msgid "Last Inventory Export Time"
-msgstr "Data última exportació inventari"
-
-#. module: connector_ecommerce
-#: field:external.referential,shop_group_ids:0
-msgid "Sub Entities"
-msgstr "Sub entitats"
-
-#. module: connector_ecommerce
-#: field:sale.shop,referential_id:0
-msgid "External Referential"
-msgstr "Referència externa"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Payment Before Delivery"
-msgstr "Pagament abans de l'enviament"
-
-#. module: connector_ecommerce
-#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
-msgid "Base Sale MultiChannels"
-msgstr "Base vendes multicanal"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-#: field:sale.shop,exportable_product_ids:0
-msgid "Exportable Products"
-msgstr "Productes exportables"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Import Orders"
-msgstr "Importa comandes"
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_generation_policy:0
-msgid "Picking Generation Policy"
-msgstr "Política generació d'albarans"
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_generation_policy:0
-msgid "Should orders create an invoice after import?"
-msgstr "Les comandes haurien de crear una factura després de la importació?"
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_update_order_export_date:0
-msgid "Last Order Update Time"
-msgstr "Data última actualització comandes"
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_generation_policy:0
-msgid "Should orders create a picking after import?"
-msgstr "Les comandes haurien de crear un albarà després de la importació?"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Validated"
-msgstr "Validat"
-
-#. module: connector_ecommerce
-#: model:ir.model,name:connector_ecommerce.model_external_shop_group
-msgid "External Referential Shop Group"
-msgstr "Referència externa grup botigues"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Stock Levels Only"
-msgstr "Exporta només nivells d'estoc"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Shipping & Manual Invoice"
-msgstr "Envia & Factura manual"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Actions"
-msgstr "Accions"
-
-#. module: connector_ecommerce
-#: field:sale.shop,exportable_root_category_ids:0
-msgid "Root Category"
-msgstr "Categoria arrel"
-
-#. module: connector_ecommerce
-#: field:sale.shop,is_tax_included:0
-msgid "Prices Include Tax?"
-msgstr "Preus inclouen impostos?"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Shop"
-msgstr "Botiga venda"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Multi Channels"
-msgstr "Vendes Multi canal"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Orders"
-msgstr "Comandes"
-
diff --git a/connector_ecommerce/i18n/connector_ecommerce.pot b/connector_ecommerce/i18n/connector_ecommerce.pot
new file mode 100644
index 00000000..f2f7538d
--- /dev/null
+++ b/connector_ecommerce/i18n/connector_ecommerce.pot
@@ -0,0 +1,354 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * connector_ecommerce
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-05-01 14:34+0000\n"
+"PO-Revision-Date: 2013-05-01 14:34+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: connector_ecommerce
+#: field:sale.order,cancellation_resolved:0
+msgid "Cancellation from the backend resolved"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_product_has_checkpoint
+msgid "A product has been imported from a backend and needs to be reviewed.\n"
+"Go to Connectors > Checkpoint and review the new products."
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_invoice
+msgid "Invoice"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "Confirm"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Ignore backend's cancellation, Keep Open"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Canceled in backend, to cancel"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Only sales orders canceled in their backend"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_parent_order_need_cancel
+msgid "The parent sales order has been canceled on the backend.\n"
+"You will not be able to process this sales order until the parent's one is canceled."
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "The sales orders using the payment method will always be imported."
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "This sales order has been canceled from the backend.\n"
+" The usual action would be to cancel it in OpenERP along\n"
+" all the documents generated (delivery orders, invoices, ...)."
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:account.tax,group_id:0
+msgid "Choose the tax group. This is needed for example with magento or prestashop"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_stock_picking
+msgid "Picking List"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.actions.act_window,name:connector_ecommerce.action_sale_ignore_cancel
+#: view:sale.ignore.cancel:0
+msgid "Ignore the cancellation on the Backend"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_gift_product_template
+msgid "Gift Certificate"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_ignore_cancel
+msgid "Ignore Sales Order Cancel"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_product
+msgid "Product"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_payment_method
+msgid "Payment Method"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.actions.act_window,name:connector_ecommerce.action_tax_group_form
+#: model:ir.ui.menu,name:connector_ecommerce.menu_action_tax_group_form
+msgid "Tax Groups"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "View Parent Sales Order"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:stock.picking,related_backorder_ids:0
+msgid "Related backorders"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:account.tax.group:0
+msgid "Account Tax Group"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:payment.method,days_before_cancel:0
+msgid "Days before cancel"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "The sales orders using the payment method will never be imported."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.ignore.cancel,reason:0
+msgid "Reason"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_order_need_cancel
+msgid "Sales order canceled on the backend."
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_shop
+msgid "Sales Shop"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:product.category,name:connector_ecommerce.product_categ_services
+msgid "Services"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Other Information"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:product.template,tax_group_id:0
+msgid "Tax group are used with some external system like magento or prestashop"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:product.price.type,pricelist_item_ids:0
+msgid "Pricelist Items"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.order,parent_need_cancel:0
+msgid "A parent sales orders needs cancel"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "Import Rules"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:payment.method,import_rule:0
+msgid "Import Rule"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "However, if for any reason you need to keep it open in OpenERP,\n"
+" write the reason here and it will stay open."
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "The sales orders using the payment method will be imported\n"
+" only when they receive a payment on the E-Commerce backend."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:account.tax.group,tax_ids:0
+msgid "Taxes"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_order_need_cancel
+msgid "The sales order has been canceled on the backend."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.order,need_cancel:0
+msgid "Need to be canceled"
+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."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:account.tax,group_id:0
+#: field:product.template,tax_group_id:0
+msgid "Tax Group"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:account.invoice:0
+msgid "Payments"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_parent_order_need_cancel
+msgid "Parent sales order canceled on the backend."
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.order,need_cancel:0
+msgid "Has been canceled on the backend, need to be canceled."
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_discount_product_template
+msgid "Discount Coupon"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_order
+msgid "Sales Order"
+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."
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_template
+msgid "Product Template"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_stock_picking_out
+msgid "Delivery Orders"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_shipping_product_template
+msgid "Shipping costs"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_cash_on_delivery_product_template
+msgid "Cash on delivery"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.order,canceled_in_backend:0
+msgid "Canceled in backend"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:account.invoice,sale_order_ids:0
+msgid "This is the list of sale orders related to this invoice."
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_tax_group
+msgid "account tax group"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_tax
+msgid "Tax"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:account.invoice:0
+#: view:product.product:0
+#: view:sale.order:0
+#: view:stock.picking.out:0
+msgid "Connectors"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_product_has_checkpoint
+msgid "A product needs to be reviewed."
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.order,parent_id:0
+msgid "A parent sales order is a sales order replaced by this one."
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "Cancel"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.order,parent_id:0
+msgid "Parent Order"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:account.tax.group,name:0
+msgid "Name"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:account.invoice,sale_order_ids:0
+msgid "Sale Orders"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:product.product,has_checkpoint:0
+msgid "Has Checkpoint"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "or"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:stock.picking.out:0
+msgid "Additional Info"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_price_type
+msgid "Price Type"
+msgstr ""
+
diff --git a/connector_ecommerce/i18n/es.po b/connector_ecommerce/i18n/es.po
deleted file mode 100644
index 07cbd78c..00000000
--- a/connector_ecommerce/i18n/es.po
+++ /dev/null
@@ -1,379 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * connector_ecommerce
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 5.0.6\n"
-"Report-Msgid-Bugs-To: support@openerp.com\n"
-"POT-Creation-Date: 2009-12-20 17:22+0000\n"
-"PO-Revision-Date: 2011-02-14 10:04+0000\n"
-"Last-Translator: Jordi Esteve (www.zikzakmedia.com) "
-"\n"
-"Language-Team: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-01-17 05:05+0000\n"
-"X-Generator: Launchpad (build 14676)\n"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Partial Delivery"
-msgstr "Envío parcial"
-
-#. module: connector_ecommerce
-#: constraint:ir.model:0
-msgid ""
-"The Object name must start with x_ and not contain any special character !"
-msgstr ""
-"¡El nombre del objeto debe empezar con x_ y no contener ningún carácter "
-"especial!"
-
-#. module: connector_ecommerce
-#: model:ir.module.module,description:connector_ecommerce.module_meta_information
-msgid ""
-"\n"
-"This module provide an abstract common minimal base to multi-channels "
-"sales.\n"
-"Say you want to expose your product catalog to\n"
-"* several instances of flashy-sluggish Magento web sites\n"
-"* a cutting edge Spree web shop\n"
-"* a Neteven online Marketplace\n"
-"* EBay\n"
-"* Amazon\n"
-"* Google Base\n"
-"* an external Point Of Sale system\n"
-"* ...\n"
-"Then this module allows you to:\n"
-"* use several external references ids on every OpenERP object matching those "
-"all those external referentials\n"
-"* per referential instance, use several sale sub platform entities (ex: "
-"several Magento websites per instance)\n"
-"* per sub platform, use several shops (ex: several Magento web shops per "
-"website)\n"
-"\n"
-"For each sale shop (matching OpenERP sale.shop object), this module abstract "
-"the interfaces to:\n"
-"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
-"* import the catalog\n"
-"* import orders\n"
-"* export orders/picking status\n"
-" "
-msgstr ""
-"\n"
-"Este módulo proporciona una mínima base de abstracción común a varios "
-"canales de ventas.\n"
-"Supongamos que quiere exponer su catálogo de productos en:\n"
-"* Varias instancias de tiendas web de Magento\n"
-"* Una tienda web de última generación Spree\n"
-"* Un mercado Neteven\n"
-"* EBay\n"
-"* Amazon\n"
-"* Google Base\n"
-"* Un sistema punto de venta externo\n"
-"* ...\n"
-"Entonces, este módulo le permite:\n"
-"* El uso de varias referencias externas en todos los identificadores de "
-"objetos OpenERP que mapean todas estas referencias externas.\n"
-"* Referencias por instancia, el uso de varias subentidades de ventas (por "
-"ejemplo varios sitios web Magento por instancia)\n"
-"* Referencias por subentidad, el uso de varias tiendas (por ejemplo varias "
-"tiendas web Magento por sitio web)\n"
-"\n"
-"Para cada tienda de venta (que se corresponda al objeto sale.shop de "
-"OpenERP), este módulo abstrae las interfaces de:\n"
-"* Exportar el catálogo, nivel de stock del almacén de la tienda, tarifa de "
-"precios de la tienda\n"
-"* Importar el catálogo\n"
-"* Importar pedidos\n"
-"* Exportar el estado de pedidos/albaranes\n"
-" "
-
-#. module: connector_ecommerce
-#: field:sale.shop,order_policy:0
-msgid "Shipping Policy"
-msgstr "Política de facturación"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "None"
-msgstr "Ninguno/a"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Shipped Quantities"
-msgstr "Cantidades enviadas"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,referential_id:0
-msgid "Referential"
-msgstr "Referencia"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Draft"
-msgstr "Borrador"
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_quantity:0
-msgid ""
-"The sale order will automatically create the invoice proposition (draft "
-"invoice). Ordered and delivered quantities may not be the same. You have to "
-"choose if you invoice based on ordered or shipped quantities. If the product "
-"is a service, shipped quantities means hours spent on the associated tasks."
-msgstr ""
-"El pedido de venta creará automáticamente la propuesta de factura (factura "
-"borrador). Las cantidades pedidas y las cantidades enviadas pueden no ser "
-"las mismas. Tiene que decidir si factura basado en cantidades pedidas o "
-"enviadas. Si el producto es un servicio, cantidades enviadas significa horas "
-"dedicadas a las tareas asociadas."
-
-#. module: connector_ecommerce
-#: field:sale.shop,shop_group_id:0
-msgid "Shop Group"
-msgstr "Grupo tiendas"
-
-#. module: connector_ecommerce
-#: field:product.category,recursive_childen_ids:0
-msgid "All Child Categories"
-msgstr "Todas categorías hijas"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Update Orders Status"
-msgstr "Actualizar estado pedidos"
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_policy:0
-msgid ""
-"If you don't have enough stock available to deliver all at once, do you "
-"accept partial shipments or not?"
-msgstr ""
-"Si no dispone de suficiente stock disponible para enviarlo todo a la vez, "
-"¿acepta envíos parciales?"
-
-#. module: connector_ecommerce
-#: help:account.journal,external_payment_codes:0
-msgid ""
-"Enter the external payment codes, comma separated. They will be used to "
-"select the payment journal."
-msgstr ""
-"Indique los códigos de pago externos, separados por coma. Serán utilizados "
-"para seleccionar el diario de pago."
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_policy:0
-msgid "Packing Policy"
-msgstr "Política de envío"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Complete Delivery"
-msgstr "Envío completo"
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_generation_policy:0
-msgid "Invoice Generation Policy"
-msgstr "Política generación de facturas"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Ordered Quantities"
-msgstr "Cantidades ordenadas"
-
-#. module: connector_ecommerce
-#: help:sale.shop,is_tax_included:0
-msgid "Requires sale_tax_include module to be installed"
-msgstr "Requiere que el módulo sale_tax_include sea instalado."
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Catalog"
-msgstr "Catálogo"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "External Shop Settings"
-msgstr "Configuración tienda externa"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Catalog"
-msgstr "Exportar catálogo"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice from the Packing"
-msgstr "Factura desde albarán"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Order Generation"
-msgstr "Generación pedido"
-
-#. module: connector_ecommerce
-#: field:account.journal,external_payment_codes:0
-msgid "External Payment Codes"
-msgstr "Códigos de pago externos"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice on Order After Delivery"
-msgstr "Facturar pedido después del envío"
-
-#. module: connector_ecommerce
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr "¡XML inválido para la definición de la vista!"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,shop_ids:0
-msgid "Sale Shops"
-msgstr "Tiendas venta"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,name:0
-msgid "Name"
-msgstr "Nombre"
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_quantity:0
-msgid "Invoice on"
-msgstr "Facturar las"
-
-#. module: connector_ecommerce
-#: help:sale.shop,order_policy:0
-msgid ""
-"The Shipping Policy is used to synchronise invoice and delivery operations.\n"
-" - The 'Pay before delivery' choice will first generate the invoice and "
-"then generate the packing order after the payment of this invoice.\n"
-" - The 'Shipping & Manual Invoice' will create the packing order directly "
-"and wait for the user to manually click on the 'Invoice' button to generate "
-"the draft invoice.\n"
-" - The 'Invoice on Order After Delivery' choice will generate the draft "
-"invoice based on sale order after all packing lists have been finished.\n"
-" - The 'Invoice from the packing' choice is used to create an invoice "
-"during the packing process."
-msgstr ""
-"La política de envío se utiliza para sincronizar la factura y las "
-"operaciones de envío.\n"
-" - La opción 'Pago antes del envío' primero genera la factura y luego "
-"genera el albarán después del pago de esta factura.\n"
-" - La opción 'Envío '& Factura manual' creará el albarán directamente y "
-"esperará a que el usuario haga clic manualmente en el botón 'Factura' para "
-"generar la factura borrador.\n"
-" - La opción 'Factura según pedido después envío' generará la factura "
-"borrador basada en el pedido de venta después de que todos los albaranes se "
-"hayan procesado.\n"
-" - La opción 'Factura desde albarán' se utiliza para crear una factura "
-"durante el proceso de los albaranes."
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_inventory_export_date:0
-msgid "Last Inventory Export Time"
-msgstr "Fecha última exportación inventario"
-
-#. module: connector_ecommerce
-#: field:external.referential,shop_group_ids:0
-msgid "Sub Entities"
-msgstr "Sub entidades"
-
-#. module: connector_ecommerce
-#: field:sale.shop,referential_id:0
-msgid "External Referential"
-msgstr "Referencia externa"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Payment Before Delivery"
-msgstr "Pago antes del envío"
-
-#. module: connector_ecommerce
-#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
-msgid "Base Sale MultiChannels"
-msgstr "Base ventas multicanal"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-#: field:sale.shop,exportable_product_ids:0
-msgid "Exportable Products"
-msgstr "Productos exportables"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Import Orders"
-msgstr "Importar pedidos"
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_generation_policy:0
-msgid "Picking Generation Policy"
-msgstr "Política generación de albaranes"
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_generation_policy:0
-msgid "Should orders create an invoice after import?"
-msgstr "¿Los pedidos deberían crear una factura después de la importación?"
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_update_order_export_date:0
-msgid "Last Order Update Time"
-msgstr "Fecha última actualización pedidos"
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_generation_policy:0
-msgid "Should orders create a picking after import?"
-msgstr "¿Los pedidos deberían crear un albarán después de la importación?"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Validated"
-msgstr "Validado"
-
-#. module: connector_ecommerce
-#: model:ir.model,name:connector_ecommerce.model_external_shop_group
-msgid "External Referential Shop Group"
-msgstr "Referencia externa grupo tiendas"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Stock Levels Only"
-msgstr "Exportar sólo niveles de stock"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Shipping & Manual Invoice"
-msgstr "Enviar & Factura manual"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Actions"
-msgstr "Accions"
-
-#. module: connector_ecommerce
-#: field:sale.shop,exportable_root_category_ids:0
-msgid "Root Category"
-msgstr "Categoría raíz"
-
-#. module: connector_ecommerce
-#: field:sale.shop,is_tax_included:0
-msgid "Prices Include Tax?"
-msgstr "¿Precios incluyen impuestos?"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Shop"
-msgstr "Tienda venta"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Multi Channels"
-msgstr "Ventas Multi canal"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Orders"
-msgstr "Pedidos"
diff --git a/connector_ecommerce/i18n/fr.po b/connector_ecommerce/i18n/fr.po
deleted file mode 100644
index 793cdcda..00000000
--- a/connector_ecommerce/i18n/fr.po
+++ /dev/null
@@ -1,356 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * connector_ecommerce
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 6.1beta\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-12-20 17:22+0000\n"
-"PO-Revision-Date: 2011-12-05 12:42+0000\n"
-"Last-Translator: OpenERP Administrators \n"
-"Language-Team: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-01-17 05:05+0000\n"
-"X-Generator: Launchpad (build 14676)\n"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Partial Delivery"
-msgstr "Livraison Partielle"
-
-#. module: connector_ecommerce
-#: constraint:ir.model:0
-msgid ""
-"The Object name must start with x_ and not contain any special character !"
-msgstr ""
-
-#. module: connector_ecommerce
-#: model:ir.module.module,description:connector_ecommerce.module_meta_information
-msgid ""
-"\n"
-"This module provide an abstract common minimal base to multi-channels "
-"sales.\n"
-"Say you want to expose your product catalog to\n"
-"* several instances of flashy-sluggish Magento web sites\n"
-"* a cutting edge Spree web shop\n"
-"* a Neteven online Marketplace\n"
-"* EBay\n"
-"* Amazon\n"
-"* Google Base\n"
-"* an external Point Of Sale system\n"
-"* ...\n"
-"Then this module allows you to:\n"
-"* use several external references ids on every OpenERP object matching those "
-"all those external referentials\n"
-"* per referential instance, use several sale sub platform entities (ex: "
-"several Magento websites per instance)\n"
-"* per sub platform, use several shops (ex: several Magento web shops per "
-"website)\n"
-"\n"
-"For each sale shop (matching OpenERP sale.shop object), this module abstract "
-"the interfaces to:\n"
-"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
-"* import the catalog\n"
-"* import orders\n"
-"* export orders/picking status\n"
-" "
-msgstr ""
-"\n"
-"Ce module fourni une couche d'abstracion minimale pour les ventes en multi-"
-"canaux.\n"
-"Vous voulez exposer votre catalogue produits sur\n"
-"* plusieurs instances de sites web magento\n"
-"* une boutique en ligne Spree d'avant garde\n"
-"* un marché en ligne Neteven\n"
-"* EBay\n"
-"* Amazon\n"
-"* Google Base\n"
-"* un système de point de vente externe\n"
-"* ...\n"
-"Ce module vous permet donc:\n"
-"* d'utiliser plusieurs identifiants externes dans tout les objets OpenERP "
-"correspondant entre eux use several external references ids on every OpenERP "
-"object matching those all those external referentials\n"
-"* par instance référentielle, d'utiliser plusieurs entités de sous "
-"plateforme de vente (ex: plusieurs sites web Magento par instance)\n"
-"* par sous plateforme, d'utiliser plusieurs boutiques (ex: plusieurs "
-"boutiques en ligne Magento par site web)\n"
-"\n"
-"Pour chaque boutique de vente (correspondant aux objets OpenERP sale.shop), "
-"ce module extrait les interfaces pour:\n"
-"* exporter le catalogue, le niveau de stock du magasin, les listes de prix "
-"du magasin\n"
-"* importer le catalogue\n"
-"* importer les commandes\n"
-"* exporter les commandes/status picking\n"
-" "
-
-#. module: connector_ecommerce
-#: field:sale.shop,order_policy:0
-msgid "Shipping Policy"
-msgstr "Politique d'expédition"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "None"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Shipped Quantities"
-msgstr "Quantités Expédiées"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,referential_id:0
-msgid "Referential"
-msgstr "Référentiel"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Draft"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_quantity:0
-msgid ""
-"The sale order will automatically create the invoice proposition (draft "
-"invoice). Ordered and delivered quantities may not be the same. You have to "
-"choose if you invoice based on ordered or shipped quantities. If the product "
-"is a service, shipped quantities means hours spent on the associated tasks."
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,shop_group_id:0
-msgid "Shop Group"
-msgstr "Groupe de Magasin"
-
-#. module: connector_ecommerce
-#: field:product.category,recursive_childen_ids:0
-msgid "All Child Categories"
-msgstr "Toute les Catégories Enfant"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Update Orders Status"
-msgstr "Mettre à Jour les Status des Commmandes"
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_policy:0
-msgid ""
-"If you don't have enough stock available to deliver all at once, do you "
-"accept partial shipments or not?"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:account.journal,external_payment_codes:0
-msgid ""
-"Enter the external payment codes, comma separated. They will be used to "
-"select the payment journal."
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_policy:0
-msgid "Packing Policy"
-msgstr "Politique d'Emballage"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Complete Delivery"
-msgstr "Livraison Complète"
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_generation_policy:0
-msgid "Invoice Generation Policy"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Ordered Quantities"
-msgstr "Quantités Commandées"
-
-#. module: connector_ecommerce
-#: help:sale.shop,is_tax_included:0
-msgid "Requires sale_tax_include module to be installed"
-msgstr "Requière le module sale_tax_include pour pouvoir être installé"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Catalog"
-msgstr "Catalogue"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "External Shop Settings"
-msgstr "Paramètres du Magasin Externe"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Catalog"
-msgstr "Exporter le Catalogue"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice from the Packing"
-msgstr "Facture de l'emballage"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Order Generation"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:account.journal,external_payment_codes:0
-msgid "External Payment Codes"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice on Order After Delivery"
-msgstr "Facture sur Commande Après Livraison"
-
-#. module: connector_ecommerce
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:external.shop.group,shop_ids:0
-msgid "Sale Shops"
-msgstr "Magasins de Vente"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,name:0
-msgid "Name"
-msgstr "Nom"
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_quantity:0
-msgid "Invoice on"
-msgstr "Facture sur"
-
-#. module: connector_ecommerce
-#: help:sale.shop,order_policy:0
-msgid ""
-"The Shipping Policy is used to synchronise invoice and delivery operations.\n"
-" - The 'Pay before delivery' choice will first generate the invoice and "
-"then generate the packing order after the payment of this invoice.\n"
-" - The 'Shipping & Manual Invoice' will create the packing order directly "
-"and wait for the user to manually click on the 'Invoice' button to generate "
-"the draft invoice.\n"
-" - The 'Invoice on Order After Delivery' choice will generate the draft "
-"invoice based on sale order after all packing lists have been finished.\n"
-" - The 'Invoice from the packing' choice is used to create an invoice "
-"during the packing process."
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_inventory_export_date:0
-msgid "Last Inventory Export Time"
-msgstr "Date du Dernier Export d'Inventaire"
-
-#. module: connector_ecommerce
-#: field:external.referential,shop_group_ids:0
-msgid "Sub Entities"
-msgstr "Sous Entité"
-
-#. module: connector_ecommerce
-#: field:sale.shop,referential_id:0
-msgid "External Referential"
-msgstr "Référentiel Externe"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Payment Before Delivery"
-msgstr "Paiement Avant Livraison"
-
-#. module: connector_ecommerce
-#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
-msgid "Base Sale MultiChannels"
-msgstr "Ventes en Multi Canaux"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-#: field:sale.shop,exportable_product_ids:0
-msgid "Exportable Products"
-msgstr "Produits Exportables"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Import Orders"
-msgstr "Import des Commandes"
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_generation_policy:0
-msgid "Picking Generation Policy"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_generation_policy:0
-msgid "Should orders create an invoice after import?"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_update_order_export_date:0
-msgid "Last Order Update Time"
-msgstr "Date de la dernière mise à jour des commandes"
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_generation_policy:0
-msgid "Should orders create a picking after import?"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Validated"
-msgstr ""
-
-#. module: connector_ecommerce
-#: model:ir.model,name:connector_ecommerce.model_external_shop_group
-msgid "External Referential Shop Group"
-msgstr "Référence Externe du Groupe de Magasin"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Stock Levels Only"
-msgstr "Export des niveaux de Stock Seulement"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Shipping & Manual Invoice"
-msgstr "Expédition et Facture Manuelle"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Actions"
-msgstr "Actions"
-
-#. module: connector_ecommerce
-#: field:sale.shop,exportable_root_category_ids:0
-msgid "Root Category"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,is_tax_included:0
-msgid "Prices Include Tax?"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Shop"
-msgstr "Magasin de Vente"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Multi Channels"
-msgstr "Vente Multi Canaux"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Orders"
-msgstr "Commandes"
diff --git a/connector_ecommerce/i18n/fr_FR.po b/connector_ecommerce/i18n/fr_FR.po
new file mode 100644
index 00000000..b26c268f
--- /dev/null
+++ b/connector_ecommerce/i18n/fr_FR.po
@@ -0,0 +1,360 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * connector_ecommerce
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-05-01 14:17+0000\n"
+"PO-Revision-Date: 2013-05-01 14:17+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: connector_ecommerce
+#: field:sale.order,cancellation_resolved:0
+msgid "Cancellation from the backend resolved"
+msgstr "Annulation depuis le backend résolue"
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_product_has_checkpoint
+msgid "A product has been imported from a backend and needs to be reviewed.\n"
+"Go to Connectors > Checkpoint and review the new products."
+msgstr "Un article a été importé depuis un backend et nécessite un contrôle.\n"
+"Aller dans Connecteurs > Points de contrôle et vérifier les nouveaux articles."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_invoice
+msgid "Invoice"
+msgstr "Facture"
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "Confirm"
+msgstr "Confirmer"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Ignore backend's cancellation, Keep Open"
+msgstr "Ignorer l'annulation du backend, laisser ouvert."
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Canceled in backend, to cancel"
+msgstr "Annulé dans le backend, à annuler"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Only sales orders canceled in their backend"
+msgstr "Uniquement les commandes annulées dans leur backend"
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_parent_order_need_cancel
+msgid "The parent sales order has been canceled on the backend.\n"
+"You will not be able to process this sales order until the parent's one is canceled."
+msgstr "The commande parente a été annulée sur son backend.\n"
+"Impossible de confirmer ce devis tant que la commande parente n'est pas annulée."
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "The sales orders using the payment method will always be imported."
+msgstr "Les commandes utilisant cette méthode de paiement seront toujours importées."
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "This sales order has been canceled from the backend.\n"
+" The usual action would be to cancel it in OpenERP along\n"
+" all the documents generated (delivery orders, invoices, ...)."
+msgstr "Cette commande a été annulée sur son backend.\n"
+" L'action standard est d'annuler la commande dans OpenERP ainsi\n"
+" que tous les documents qu'elle a générés (bons de livraison, factures, ...)."
+
+#. module: connector_ecommerce
+#: help:account.tax,group_id:0
+msgid "Choose the tax group. This is needed for example with magento or prestashop"
+msgstr "Choisir le groupe de taxes. Utilisé pour Magento ou Prestashop."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_stock_picking
+msgid "Picking List"
+msgstr "Liste de colisage"
+
+#. module: connector_ecommerce
+#: model:ir.actions.act_window,name:connector_ecommerce.action_sale_ignore_cancel
+#: view:sale.ignore.cancel:0
+msgid "Ignore the cancellation on the Backend"
+msgstr "Ignorer l'annulation du backend."
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_gift_product_template
+msgid "Gift Certificate"
+msgstr "Coupon Cadeau"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_ignore_cancel
+msgid "Ignore Sales Order Cancel"
+msgstr "Ignorer les annulations de commandes"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_product
+msgid "Product"
+msgstr "Produit"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_payment_method
+msgid "Payment Method"
+msgstr "Méthode de paiement"
+
+#. module: connector_ecommerce
+#: model:ir.actions.act_window,name:connector_ecommerce.action_tax_group_form
+#: model:ir.ui.menu,name:connector_ecommerce.menu_action_tax_group_form
+msgid "Tax Groups"
+msgstr "Groupes de taxes"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "View Parent Sales Order"
+msgstr "Voir la commande parente"
+
+#. module: connector_ecommerce
+#: field:stock.picking,related_backorder_ids:0
+msgid "Related backorders"
+msgstr "Reliquat lié"
+
+#. module: connector_ecommerce
+#: view:account.tax.group:0
+msgid "Account Tax Group"
+msgstr "Groupe de taxes"
+
+#. module: connector_ecommerce
+#: field:payment.method,days_before_cancel:0
+msgid "Days before cancel"
+msgstr "Jours avant annulation"
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "The sales orders using the payment method will never be imported."
+msgstr "Les commandes utilisant cette méthode de paiement ne seront jamais importées."
+
+#. module: connector_ecommerce
+#: field:sale.ignore.cancel,reason:0
+msgid "Reason"
+msgstr "Raison"
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_order_need_cancel
+msgid "Sales order canceled on the backend."
+msgstr "Commandes annulées sur leur backend."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_shop
+msgid "Sales Shop"
+msgstr "Magasins"
+
+#. module: connector_ecommerce
+#: model:product.category,name:connector_ecommerce.product_categ_services
+msgid "Services"
+msgstr "Services"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Other Information"
+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"
+msgstr "Les groupes de taxes sont utilisés avec des systèmes externes comme Magento ou Prestashop."
+
+#. module: connector_ecommerce
+#: field:product.price.type,pricelist_item_ids:0
+msgid "Pricelist Items"
+msgstr "Lignes de liste de prix"
+
+#. module: connector_ecommerce
+#: field:sale.order,parent_need_cancel:0
+msgid "A parent sales orders needs cancel"
+msgstr "Une commande parente doit être annulée"
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "Import Rules"
+msgstr "Règles d'import"
+
+#. module: connector_ecommerce
+#: field:payment.method,import_rule:0
+msgid "Import Rule"
+msgstr "Règle d'import"
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "However, if for any reason you need to keep it open in OpenERP,\n"
+" write the reason here and it will stay open."
+msgstr "Cependant, si pour une raison donnée vous devez la laisser ouverte dans OpenERP,\n"
+" écrivez la raison ici et confirmez.."
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "The sales orders using the payment method will be imported\n"
+" only when they receive a payment on the E-Commerce backend."
+msgstr "Les commandes utilisant cette méthode de paiement seront importées\n"
+" uniquement quand elles recevront un paiement sur leur backend e-commerce."
+
+#. module: connector_ecommerce
+#: field:account.tax.group,tax_ids:0
+msgid "Taxes"
+msgstr "Taxes"
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_order_need_cancel
+msgid "The sales order has been canceled on the backend."
+msgstr "Les commandes ont été annulées sur leur backend."
+
+#. module: connector_ecommerce
+#: field:sale.order,need_cancel:0
+msgid "Need to be canceled"
+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 canceled."
+msgstr "Une commande parente a été annulée sur le backend et doit être annulée."
+
+#. module: connector_ecommerce
+#: field:account.tax,group_id:0
+#: field:product.template,tax_group_id:0
+msgid "Tax Group"
+msgstr "Groupe de taxes"
+
+#. module: connector_ecommerce
+#: view:account.invoice:0
+msgid "Payments"
+msgstr "Paiements"
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_parent_order_need_cancel
+msgid "Parent sales order canceled on the backend."
+msgstr "Commande parente annulée sur le backend."
+
+#. module: connector_ecommerce
+#: help:sale.order,need_cancel:0
+msgid "Has been canceled on the backend, need to be canceled."
+msgstr "A été annulée sur le backend, doit être annulée."
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_discount_product_template
+msgid "Discount Coupon"
+msgstr "Bon de réduction"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_order
+msgid "Sales Order"
+msgstr "Bon de commande"
+
+#. 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."
+msgstr "Après \"n\" jours, si la règle d'import n'est pas satisfaite, l'import de la commande sera annulé."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_template
+msgid "Product Template"
+msgstr "Template d'article"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_stock_picking_out
+msgid "Delivery Orders"
+msgstr "Bons de livraison"
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_shipping_product_template
+msgid "Shipping costs"
+msgstr "Coûts de livraison"
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_cash_on_delivery_product_template
+msgid "Cash on delivery"
+msgstr "Livraison contre remboursement"
+
+#. module: connector_ecommerce
+#: field:sale.order,canceled_in_backend:0
+msgid "Canceled in backend"
+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."
+msgstr "Liste des commandes liées à cette facture."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_tax_group
+msgid "account tax group"
+msgstr "Groupe de taxes"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_tax
+msgid "Tax"
+msgstr "Taxe"
+
+#. module: connector_ecommerce
+#: view:account.invoice:0
+#: view:product.product:0
+#: view:sale.order:0
+#: view:stock.picking.out:0
+msgid "Connectors"
+msgstr "Connecteurs"
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_product_has_checkpoint
+msgid "A product needs to be reviewed."
+msgstr "Un article doit être contrôlé."
+
+#. module: connector_ecommerce
+#: help:sale.order,parent_id:0
+msgid "A parent sales order is a sales order replaced by this one."
+msgstr "Une commande parente est une commande remplacée par celle-ci."
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "Cancel"
+msgstr "Annuler"
+
+#. module: connector_ecommerce
+#: field:sale.order,parent_id:0
+msgid "Parent Order"
+msgstr "Commande parente"
+
+#. module: connector_ecommerce
+#: field:account.tax.group,name:0
+msgid "Name"
+msgstr "Nom"
+
+#. module: connector_ecommerce
+#: field:account.invoice,sale_order_ids:0
+msgid "Sale Orders"
+msgstr "Bons de commande"
+
+#. module: connector_ecommerce
+#: field:product.product,has_checkpoint:0
+msgid "Has Checkpoint"
+msgstr "A un point de contrôle"
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "or"
+msgstr "ou"
+
+#. module: connector_ecommerce
+#: view:stock.picking.out:0
+msgid "Additional Info"
+msgstr "Informations additionnelles"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_price_type
+msgid "Price Type"
+msgstr "Type de prix"
+
diff --git a/connector_ecommerce/i18n/pt.po b/connector_ecommerce/i18n/pt.po
deleted file mode 100644
index 34c89660..00000000
--- a/connector_ecommerce/i18n/pt.po
+++ /dev/null
@@ -1,379 +0,0 @@
-# Portuguese translation for openobject-addons
-# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
-# This file is distributed under the same license as the openobject-addons package.
-# FIRST AUTHOR , 2011.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: openobject-addons\n"
-"Report-Msgid-Bugs-To: FULL NAME \n"
-"POT-Creation-Date: 2009-12-20 17:22+0000\n"
-"PO-Revision-Date: 2011-02-14 10:04+0000\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: Portuguese \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-01-17 05:05+0000\n"
-"X-Generator: Launchpad (build 14676)\n"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Partial Delivery"
-msgstr "Entrega Parcial"
-
-#. module: connector_ecommerce
-#: constraint:ir.model:0
-msgid ""
-"The Object name must start with x_ and not contain any special character !"
-msgstr ""
-"O nome do Objecto deve começar com x_ e não pode conter nenhum caracter "
-"especial !"
-
-#. module: connector_ecommerce
-#: model:ir.module.module,description:connector_ecommerce.module_meta_information
-msgid ""
-"\n"
-"This module provide an abstract common minimal base to multi-channels "
-"sales.\n"
-"Say you want to expose your product catalog to\n"
-"* several instances of flashy-sluggish Magento web sites\n"
-"* a cutting edge Spree web shop\n"
-"* a Neteven online Marketplace\n"
-"* EBay\n"
-"* Amazon\n"
-"* Google Base\n"
-"* an external Point Of Sale system\n"
-"* ...\n"
-"Then this module allows you to:\n"
-"* use several external references ids on every OpenERP object matching those "
-"all those external referentials\n"
-"* per referential instance, use several sale sub platform entities (ex: "
-"several Magento websites per instance)\n"
-"* per sub platform, use several shops (ex: several Magento web shops per "
-"website)\n"
-"\n"
-"For each sale shop (matching OpenERP sale.shop object), this module abstract "
-"the interfaces to:\n"
-"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
-"* import the catalog\n"
-"* import orders\n"
-"* export orders/picking status\n"
-" "
-msgstr ""
-"\n"
-"Este módulo fornece uma base comum mínima abstrata para vendas multi-"
-"canais.\n"
-"Digamos que queira expor o seu catálogo de produto para\n"
-"* várias instâncias de wev sites Magento flashy-sluggish\n"
-"* Uma loja online Spree de ponta\n"
-"* Uma Mercado Local online de Neteven\n"
-"* EBay\n"
-"* Amazon\n"
-"* Google Base\n"
-"* um sistema externo de Ponto de Venda\n"
-"* ...\n"
-"Então, este módulo permite-lhe fazer:\n"
-"* utilizar vários id externos de referência em cada objecto OpenERP "
-"correspondente a todas as referências externas\n"
-"* por referência de instância utilizar várias entradas de sub-plantaformas "
-"de vendas (ex: várias páginas web Magento por instância)\n"
-"* por sub-plantaforma, utilizar várias lojas (ec: várias lojas web Magento "
-"por página web)\n"
-"\n"
-"Para cada loja de venda (sale.shop.object correspondente OpenERP), este "
-"módulo abstrata as interfaces para:\n"
-"* exportar o catálogo,nível sensato de stock no armazém da loja, lista de "
-"preço justo da loja \n"
-"* importar o catálogo\n"
-"* importar ordens\n"
-"* exportar ordens/estado da recolha\n"
-" "
-
-#. module: connector_ecommerce
-#: field:sale.shop,order_policy:0
-msgid "Shipping Policy"
-msgstr "Política de Expedição"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "None"
-msgstr "Nenhum"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Shipped Quantities"
-msgstr "Quantidades Enviadas"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,referential_id:0
-msgid "Referential"
-msgstr "Referencial"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Draft"
-msgstr "Rascunho"
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_quantity:0
-msgid ""
-"The sale order will automatically create the invoice proposition (draft "
-"invoice). Ordered and delivered quantities may not be the same. You have to "
-"choose if you invoice based on ordered or shipped quantities. If the product "
-"is a service, shipped quantities means hours spent on the associated tasks."
-msgstr ""
-"A ordem de venda vai automáticamente criar uma proposta de factura (factura "
-"de rascunho). Quantidades entregues e ordenadas podem não ser a mesma. Vai "
-"ter que escolher se a sua factura é baseada em ordenada ou quantidades "
-"enviadas. Se o produto é um serviço, quantidades enviadas significa horas "
-"gastas nas tarefas associadas."
-
-#. module: connector_ecommerce
-#: field:sale.shop,shop_group_id:0
-msgid "Shop Group"
-msgstr "Grupo de Loja"
-
-#. module: connector_ecommerce
-#: field:product.category,recursive_childen_ids:0
-msgid "All Child Categories"
-msgstr "Todas as Categorias Descendentes"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Update Orders Status"
-msgstr "Estado das Ordens Actualizadas"
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_policy:0
-msgid ""
-"If you don't have enough stock available to deliver all at once, do you "
-"accept partial shipments or not?"
-msgstr ""
-"Se não tiver stock sufeciente desponível para entregar de uma vez, aceita "
-"transferência parciais ou não?"
-
-#. module: connector_ecommerce
-#: help:account.journal,external_payment_codes:0
-msgid ""
-"Enter the external payment codes, comma separated. They will be used to "
-"select the payment journal."
-msgstr ""
-"Entrar com os códigos de pagamento externo, vírgula separada. Eles serão "
-"utilizados para selecionar o diário de pagamento."
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_policy:0
-msgid "Packing Policy"
-msgstr "Política de Embalagem"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Complete Delivery"
-msgstr "Entrega completa"
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_generation_policy:0
-msgid "Invoice Generation Policy"
-msgstr "Politica de Geração de Factura"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Ordered Quantities"
-msgstr "Quantidades Ordenadas"
-
-#. module: connector_ecommerce
-#: help:sale.shop,is_tax_included:0
-msgid "Requires sale_tax_include module to be installed"
-msgstr "Requere que o módulo sale_tax_include seja instalado"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Catalog"
-msgstr "Catálogo"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "External Shop Settings"
-msgstr "Definições da Loja Externa"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Catalog"
-msgstr "Exportar Catálogo"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice from the Packing"
-msgstr "Factura de Embalagem"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Order Generation"
-msgstr "Ordem de Geração"
-
-#. module: connector_ecommerce
-#: field:account.journal,external_payment_codes:0
-msgid "External Payment Codes"
-msgstr "Códigos de Pagamento Externo"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice on Order After Delivery"
-msgstr "Ordem Facturada Antes da Entrega"
-
-#. module: connector_ecommerce
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr "XML Inválido para a Arquitectura de Vista!"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,shop_ids:0
-msgid "Sale Shops"
-msgstr "Lojas de Vendas"
-
-#. module: connector_ecommerce
-#: field:external.shop.group,name:0
-msgid "Name"
-msgstr "Nome"
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_quantity:0
-msgid "Invoice on"
-msgstr "Facturado em"
-
-#. module: connector_ecommerce
-#: help:sale.shop,order_policy:0
-msgid ""
-"The Shipping Policy is used to synchronise invoice and delivery operations.\n"
-" - The 'Pay before delivery' choice will first generate the invoice and "
-"then generate the packing order after the payment of this invoice.\n"
-" - The 'Shipping & Manual Invoice' will create the packing order directly "
-"and wait for the user to manually click on the 'Invoice' button to generate "
-"the draft invoice.\n"
-" - The 'Invoice on Order After Delivery' choice will generate the draft "
-"invoice based on sale order after all packing lists have been finished.\n"
-" - The 'Invoice from the packing' choice is used to create an invoice "
-"during the packing process."
-msgstr ""
-"A Políca de Entrega é utilizada para sincronizar a factura e as operações de "
-"entrega.\n"
-" - A escolha 'Pagar antes de entregar' vai gerar a factura e em seguida "
-"gerar uma ordem de embalagem depois do pagamento desta factura.\n"
-" - O 'Envio & Factura Manual' vai criar directamente a ordem de embalagem "
-"e esperar para que o utilizador clique manualmente no botão 'factura' para "
-"gerar uma factura rascunho.\n"
-" - A escolha 'Factura em Ordem Antes da Entrega' vai gerar uma factura "
-"rascunho baseada na ordem de venda depois de todas as listas de embalagem "
-"tenham terminado.\n"
-" - A escolha 'Factura a partir da embalagem' é utilizada para criar uma "
-"factura durante o processo de embalagem."
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_inventory_export_date:0
-msgid "Last Inventory Export Time"
-msgstr "Último Inventário de Exportação de Tempo"
-
-#. module: connector_ecommerce
-#: field:external.referential,shop_group_ids:0
-msgid "Sub Entities"
-msgstr "Sub Movimentos"
-
-#. module: connector_ecommerce
-#: field:sale.shop,referential_id:0
-msgid "External Referential"
-msgstr "Referencial Externa"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Payment Before Delivery"
-msgstr "Pagamento Antes da Entrega"
-
-#. module: connector_ecommerce
-#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
-msgid "Base Sale MultiChannels"
-msgstr "Venda Base de Multi-Canais"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-#: field:sale.shop,exportable_product_ids:0
-msgid "Exportable Products"
-msgstr "Produtos Exportados"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Import Orders"
-msgstr "Importar Ordem"
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_generation_policy:0
-msgid "Picking Generation Policy"
-msgstr "Política de Recolha de Geração"
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_generation_policy:0
-msgid "Should orders create an invoice after import?"
-msgstr "As ordens devem criar uma factura depois da importação?"
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_update_order_export_date:0
-msgid "Last Order Update Time"
-msgstr "Última Actualização da Ordem Tempo"
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_generation_policy:0
-msgid "Should orders create a picking after import?"
-msgstr "As ordens devem criar uma recolha depois da importação?"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Validated"
-msgstr "Validado"
-
-#. module: connector_ecommerce
-#: model:ir.model,name:connector_ecommerce.model_external_shop_group
-msgid "External Referential Shop Group"
-msgstr "Referencia Externa Grupo de Loja"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Stock Levels Only"
-msgstr "Exportar Somente os Níveis de Stock"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Shipping & Manual Invoice"
-msgstr "Expedição e Factura Manual"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Actions"
-msgstr "Acção"
-
-#. module: connector_ecommerce
-#: field:sale.shop,exportable_root_category_ids:0
-msgid "Root Category"
-msgstr "Categoria Raíz"
-
-#. module: connector_ecommerce
-#: field:sale.shop,is_tax_included:0
-msgid "Prices Include Tax?"
-msgstr "Preços Incluem Impostos?"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Shop"
-msgstr "Loja de Venda"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Multi Channels"
-msgstr "Venda Multi Canais"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Orders"
-msgstr "Ordem"
diff --git a/connector_ecommerce/i18n/sv.po b/connector_ecommerce/i18n/sv.po
deleted file mode 100644
index 6efbea0e..00000000
--- a/connector_ecommerce/i18n/sv.po
+++ /dev/null
@@ -1,327 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * connector_ecommerce
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 5.0.14\n"
-"Report-Msgid-Bugs-To: support@openerp.com\n"
-"POT-Creation-Date: 2009-12-20 17:22+0000\n"
-"PO-Revision-Date: 2011-02-14 11:51+0000\n"
-"Last-Translator: Olivier Dony (OpenERP) \n"
-"Language-Team: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-01-17 05:05+0000\n"
-"X-Generator: Launchpad (build 14676)\n"
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Partial Delivery"
-msgstr ""
-
-#. module: connector_ecommerce
-#: constraint:ir.model:0
-msgid ""
-"The Object name must start with x_ and not contain any special character !"
-msgstr ""
-
-#. module: connector_ecommerce
-#: model:ir.module.module,description:connector_ecommerce.module_meta_information
-msgid ""
-"\n"
-"This module provide an abstract common minimal base to multi-channels "
-"sales.\n"
-"Say you want to expose your product catalog to\n"
-"* several instances of flashy-sluggish Magento web sites\n"
-"* a cutting edge Spree web shop\n"
-"* a Neteven online Marketplace\n"
-"* EBay\n"
-"* Amazon\n"
-"* Google Base\n"
-"* an external Point Of Sale system\n"
-"* ...\n"
-"Then this module allows you to:\n"
-"* use several external references ids on every OpenERP object matching those "
-"all those external referentials\n"
-"* per referential instance, use several sale sub platform entities (ex: "
-"several Magento websites per instance)\n"
-"* per sub platform, use several shops (ex: several Magento web shops per "
-"website)\n"
-"\n"
-"For each sale shop (matching OpenERP sale.shop object), this module abstract "
-"the interfaces to:\n"
-"* export the catalog, shop warehouse stock level wise, shop pricelist wise\n"
-"* import the catalog\n"
-"* import orders\n"
-"* export orders/picking status\n"
-" "
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,order_policy:0
-msgid "Shipping Policy"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "None"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Shipped Quantities"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:external.shop.group,referential_id:0
-msgid "Referential"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Draft"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_quantity:0
-msgid ""
-"The sale order will automatically create the invoice proposition (draft "
-"invoice). Ordered and delivered quantities may not be the same. You have to "
-"choose if you invoice based on ordered or shipped quantities. If the product "
-"is a service, shipped quantities means hours spent on the associated tasks."
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,shop_group_id:0
-msgid "Shop Group"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:product.category,recursive_childen_ids:0
-msgid "All Child Categories"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Update Orders Status"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_policy:0
-msgid ""
-"If you don't have enough stock available to deliver all at once, do you "
-"accept partial shipments or not?"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:account.journal,external_payment_codes:0
-msgid ""
-"Enter the external payment codes, comma separated. They will be used to "
-"select the payment journal."
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_policy:0
-msgid "Packing Policy"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,picking_policy:0
-msgid "Complete Delivery"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_generation_policy:0
-msgid "Invoice Generation Policy"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_quantity:0
-msgid "Ordered Quantities"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,is_tax_included:0
-msgid "Requires sale_tax_include module to be installed"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Catalog"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "External Shop Settings"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Catalog"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice from the Packing"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Order Generation"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:account.journal,external_payment_codes:0
-msgid "External Payment Codes"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Invoice on Order After Delivery"
-msgstr ""
-
-#. module: connector_ecommerce
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:external.shop.group,shop_ids:0
-msgid "Sale Shops"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:external.shop.group,name:0
-msgid "Name"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,invoice_quantity:0
-msgid "Invoice on"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,order_policy:0
-msgid ""
-"The Shipping Policy is used to synchronise invoice and delivery operations.\n"
-" - The 'Pay before delivery' choice will first generate the invoice and "
-"then generate the packing order after the payment of this invoice.\n"
-" - The 'Shipping & Manual Invoice' will create the packing order directly "
-"and wait for the user to manually click on the 'Invoice' button to generate "
-"the draft invoice.\n"
-" - The 'Invoice on Order After Delivery' choice will generate the draft "
-"invoice based on sale order after all packing lists have been finished.\n"
-" - The 'Invoice from the packing' choice is used to create an invoice "
-"during the packing process."
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_inventory_export_date:0
-msgid "Last Inventory Export Time"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:external.referential,shop_group_ids:0
-msgid "Sub Entities"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,referential_id:0
-msgid "External Referential"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Payment Before Delivery"
-msgstr ""
-
-#. module: connector_ecommerce
-#: model:ir.module.module,shortdesc:connector_ecommerce.module_meta_information
-msgid "Base Sale MultiChannels"
-msgstr "Base Sale MultiChannels"
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-#: field:sale.shop,exportable_product_ids:0
-msgid "Exportable Products"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Import Orders"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,picking_generation_policy:0
-msgid "Picking Generation Policy"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,invoice_generation_policy:0
-msgid "Should orders create an invoice after import?"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,last_update_order_export_date:0
-msgid "Last Order Update Time"
-msgstr ""
-
-#. module: connector_ecommerce
-#: help:sale.shop,picking_generation_policy:0
-msgid "Should orders create a picking after import?"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,invoice_generation_policy:0
-#: selection:sale.shop,picking_generation_policy:0
-msgid "Validated"
-msgstr ""
-
-#. module: connector_ecommerce
-#: model:ir.model,name:connector_ecommerce.model_external_shop_group
-msgid "External Referential Shop Group"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Export Stock Levels Only"
-msgstr ""
-
-#. module: connector_ecommerce
-#: selection:sale.shop,order_policy:0
-msgid "Shipping & Manual Invoice"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Actions"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,exportable_root_category_ids:0
-msgid "Root Category"
-msgstr ""
-
-#. module: connector_ecommerce
-#: field:sale.shop,is_tax_included:0
-msgid "Prices Include Tax?"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Shop"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Sale Multi Channels"
-msgstr ""
-
-#. module: connector_ecommerce
-#: view:sale.shop:0
-msgid "Orders"
-msgstr ""
diff --git a/connector_ecommerce/invoice.py b/connector_ecommerce/invoice.py
index d096413c..f7a1690a 100644
--- a/connector_ecommerce/invoice.py
+++ b/connector_ecommerce/invoice.py
@@ -29,7 +29,7 @@ class account_invoice(orm.Model):
_inherit='account.invoice'
_columns = {
- 'sale_order_ids': fields.many2many(
+ 'sale_order_ids': fields.many2many( # TODO duplicate with 'sale_ids', replace
'sale.order',
'sale_order_invoice_rel',
'invoice_id',
@@ -38,33 +38,6 @@ class account_invoice(orm.Model):
help="This is the list of sale orders related to this invoice."),
}
- def _get_related_so_shop(self, invoice):
- """
- As several sale order can be linked to several invoices, we try
- to get the common shop between them all. The goal is further, in
- the consumer implementation, to be able to retrieve the right
- backend to use.
-
- An exception is raised if no common shop is found
-
- :param invoice: browsable record of account.invoice
- :type invoice: browse_record
- :returns: a common sale.shop browse record between all related
- sale orders
- :raises: osv.except_osv
- """
- shops = set()
- for so in invoice.sale_order_ids:
- shops.add(so.shop_id)
- if len(shops) != 1:
- raise osv.except_osv(_("Wrong value for sale_order_ids, "
- "an invoice cannot be related to sale "
- "orders that doesn't belong to the "
- "same shop, but must belong to one at "
- "least (shops: %s).") %
- [shop.name for shop in shops])
- return shops[0].id
-
def confirm_paid(self, cr, uid, ids, context=None):
res = super(account_invoice, self).confirm_paid(
cr, uid, ids, context=context)
diff --git a/connector_ecommerce/invoice_view.xml b/connector_ecommerce/invoice_view.xml
index 30816750..5a899fe6 100644
--- a/connector_ecommerce/invoice_view.xml
+++ b/connector_ecommerce/invoice_view.xml
@@ -2,5 +2,19 @@
+
+ account.invoice.connector.form
+ account.invoice
+
+
+
+
+
+
+
+
+
+
diff --git a/connector_ecommerce/old_stuff.py b/connector_ecommerce/old_stuff.py
new file mode 100644
index 00000000..7fe067d4
--- /dev/null
+++ b/connector_ecommerce/old_stuff.py
@@ -0,0 +1,1119 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2009 Akretion (). All Rights Reserved
+# authors: Raphaël Valyi, Sharoon Thomas
+# Copyright (C) 2010-2013 Akretion Sébastien BEAU
+# Copyright 2011-2013 Camptocamp SA
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+# moved from sale.py ##################
+
+from openerp.osv.orm import Model
+from openerp.osv import fields
+from openerp.osv.osv import except_osv
+from openerp import pooler
+from sets import Set as set
+from openerp import netsvc
+from openerp.tools.translate import _
+import time
+import openerp.addons.decimal_precision as dp
+from datetime import datetime, timedelta
+from dateutil.relativedelta import relativedelta
+from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
+from openerp.addons.connector.external_osv import ExternalSession
+from openerp.addons.connector.decorator import open_report
+from openerp.addons.connector.decorator import catch_error_in_report
+
+import logging
+_logger = logging.getLogger(__name__)
+
+
+
+class external_shop_group(Model):
+ _name = 'external.shop.group'
+ _description = 'External Referential Shop Group'
+
+ _columns = {
+ 'name': fields.char('Name', size=64, required=True),
+ 'referential_id': fields.many2one('external.referential', 'Referential', select=True,
+ ondelete='cascade'),
+ 'shop_ids': fields.one2many('sale.shop', 'shop_group_id', 'Sale Shops'),
+ }
+
+ # xxx move to BaseConnector _get_import_defaults_external_shop_group
+ def _get_default_import_values(self, cr, uid, external_session, **kwargs):
+ return {'referential_id' : external_session.referential_id.id}
+
+
+class external_referential(Model):
+ _inherit = 'external.referential'
+
+ _columns = {
+ 'shop_group_ids': fields.one2many('external.shop.group', 'referential_id', 'Sub Entities'),
+ }
+
+
+
+class ExternalShippingCreateError(Exception):
+ """
+ This error has to be raised when we tried to create a stock.picking on
+ the external referential and the external referential has failed
+ to create it. It must be raised only when we are SURE that the
+ external referential will never be able to create it!
+ """
+ pass
+
+
+
+class sale_shop(Model):
+ _inherit = "sale.shop"
+
+ def _get_exportable_category_ids(self, cr, uid, ids, name, args, context=None):
+ res = {}
+ for shop in self.browse(cr, uid, ids, context=context):
+ res[shop.id] = set()
+ for category in shop.exportable_root_category_ids:
+ res[shop.id] = res[shop.id].union(set(self.pool.get('product.category')._get_recursive_children_ids(cr, uid, [category.id], "", [], context)[category.id]))
+ res[shop.id] = list(res[shop.id])
+ return res
+
+ def _get_exportable_product_ids(self, cr, uid, ids, name, args, context=None):
+ res = {}
+ for shop in self.read(cr, uid, ids, ['exportable_category_ids'], context=context):
+ all_categories = shop['exportable_category_ids']
+
+ # If product_m2mcategories module is installed search in main category
+ # and extra categories. If not, only in main category
+ cr.execute('select * from ir_module_module where name=%s and state=%s',
+ ('product_m2mcategories','installed'))
+ if cr.fetchone():
+ res[shop['id']] = self.pool.get("product.product").search(cr, uid, ['|',
+ ('categ_id', 'in', all_categories),('categ_ids', 'in', all_categories)])
+ else:
+ res[shop['id']] = self.pool.get("product.product").search(cr, uid,
+ [('categ_id', 'in', all_categories)])
+ return res
+
+ def _get_referential_id(self, cr, uid, ids, name, args, context=None):
+ res = {}
+ for shop in self.browse(cr, uid, ids, context=context):
+ if shop.shop_group_id:
+ res[shop.id] = shop.shop_group_id.referential_id.id
+ else:
+ res[shop.id] = shop.referential_integer_id
+ return res
+
+ def _get_shop_from_shop_group(self, cr, uid, ids, context=None):
+ return self.pool.get('sale.shop').search(cr, uid, [('shop_group_id', 'in', ids)], context=context)
+
+ def _set_referential_id(self, cr, uid, id, name, value, arg, context=None):
+ shop = self.browse(cr, uid, id, context=context)
+ if shop.shop_group_id:
+ raise except_osv(_("User Error"), _("You can not change the referential of this shop, please change the referential of the shop group!"))
+ else:
+ self.write(cr, uid, id, {'referential_integer_id': value}, context=context)
+ return True
+
+ def _get_shop_ids(self, cr, uid, ids, context=None):
+ shop_ids=[]
+ for group in self.pool.get('external.shop.group').browse(cr, uid, ids, context=context):
+ shop_ids += [shop.id for shop in group.shop_ids]
+ return shop_ids
+
+ def _get_stock_field_id(self, cr, uid, context=None):
+ if self.pool.get('ir.module.module').search(cr, uid, [
+ ['name', '=', 'stock_available_immediately'],
+ ['state', 'in', ['installed', 'to upgrade']],
+ ], context=context):
+ stock_field = 'immediately_usable_qty'
+ else:
+ stock_field = 'virtual_available'
+
+ field_ids = self.pool.get('ir.model.fields').search(
+ cr, uid,
+ [('model', '=', 'product.product'),
+ ('name', '=', stock_field)],
+ context=context)
+ return field_ids[0]
+
+ #Depending of the e-commerce solution use you can have one or more root category
+ #If you need only one the value will be stored in the exportable_root_category_ids fields
+ def _get_rootcategory(self, cr, uid, ids, name, value, context=None):
+ res = {}
+ for shop in self.browse(cr, uid, ids, context):
+ res[shop.id] = shop.exportable_root_category_ids and shop.exportable_root_category_ids[0].id or False
+ return res
+
+ def _set_rootcategory(self, cr, uid, id, name, value, fnct_inv_arg, context=None):
+ return self.write(cr, uid, id, {'exportable_root_category_ids': [(6,0,[value])]}, context=context)
+
+ def _get_referential_type_name(self, cr, uid, ids, field_name, arg, context=None):
+ result = {}
+ for shop in self.browse(cr, uid, ids):
+ if shop.referential_id:
+ result[shop.id] = shop.referential_id.type_id.name
+ else:
+ result[shop.id] = False
+ return result
+
+ _columns = {
+ 'exportable_category_ids': fields.function(_get_exportable_category_ids, type='many2many', relation="product.category", string='Exportable Categories'),
+ 'exportable_root_category_ids': fields.many2many('product.category', 'shop_category_rel', 'categ_id', 'shop_id', 'Exportable Root Categories'),
+ 'exportable_root_category_id':fields.function(_get_rootcategory, fnct_inv = _set_rootcategory, type="many2one", relation="product.category", string="Root Category"),
+ 'exportable_product_ids': fields.function(_get_exportable_product_ids, type='many2many', relation="product.product", string='Exportable Products'),
+ 'shop_group_id': fields.many2one('external.shop.group', 'Shop Group', ondelete='cascade'),
+ # to remove?
+ 'last_inventory_export_date': fields.datetime('Last Inventory Export Time'),
+ # to remove
+ 'last_images_export_date': fields.datetime('Last Images Export Time'),
+ # to remove
+ 'last_update_order_export_date' : fields.datetime('Last Order Update Time'),
+ # to remove
+ 'last_products_export_date' : fields.datetime('Last Product Export Time'),
+ # to remove
+ 'last_special_products_export_date' : fields.datetime('Last Special Product Export Time'),
+ # to remove
+ 'last_category_export_date' : fields.datetime('Last Category Export Time'),
+ 'referential_id': fields.function(
+ _get_referential_id,
+ fnct_inv=_set_referential_id,
+ type='many2one',
+ relation='external.referential',
+ string='External Referential',
+ store={
+ 'sale.shop': (
+ lambda self, cr, uid, ids, c=None: ids,
+ ['referential_integer_id', 'shop_group_id'],
+ 10),
+ 'external.shop.group': (
+ _get_shop_from_shop_group,
+ ['referential_id'],
+ 20),
+ }),
+ # wat?
+ 'referential_integer_id': fields.integer('Referential Integer ID'),
+ 'is_tax_included': fields.boolean(
+ 'Prices Include Tax',
+ help="Does the external system work with Taxes Inclusive prices ?"),
+ 'sale_journal': fields.many2one('account.journal', 'Sale Journal'),
+ 'order_prefix': fields.char('Order Prefix', size=64),
+ 'default_payment_method_id': fields.many2one('payment.method', 'Payment Method'),
+ 'default_language': fields.many2one('res.lang', 'Default Language'),
+ 'default_fiscal_position': fields.many2one('account.fiscal.position', 'Default Fiscal Position'),
+ 'default_customer_account': fields.many2one('account.account', 'Default Customer Account'),
+ 'default_customer_lang': fields.many2one('res.lang', 'Default Customer Language'),
+ 'auto_import': fields.boolean('Automatic Import'),
+ # 'address_id':fields.many2one('res.partner.address', 'Address'),
+ # TODO migrate from address to partner?
+ 'partner_id':fields.many2one('res.partner', 'Partner'),
+ 'website': fields.char('Website', size=64),
+ 'image':fields.binary('Image', filters='*.png,*.jpg,*.gif'),
+ # to remove? (always computed by openerp)
+ 'use_external_tax': fields.boolean(
+ 'Use External Taxes',
+ help="If activated, the external taxes will be applied.\n"
+ "If not activated, OpenERP will compute them "
+ "according to default values and fiscal positions."),
+ 'import_orders_from_date': fields.datetime('Only created after'),
+ # to remove? always check
+ 'check_total_amount': fields.boolean('Check Total Amount', help="The total amount computed by OpenERP should match with the external amount, if not the sale order can not be confirmed."),
+ # to remove
+ 'type_name': fields.function(_get_referential_type_name, type='char', string='Referential type',
+ store={
+ 'sale.shop': (lambda self, cr, uid, ids, c={}: ids, ['referential_id', 'shop_group_id'],10)}),
+ 'product_stock_field_id': fields.many2one(
+ 'ir.model.fields',
+ string='Stock Field',
+ domain="[('model', 'in', ['product.product', 'product.template']),"
+ " ('ttype', '=', 'float')]",
+ help="Choose the field of the product which will be used for "
+ "stock inventory updates.\nIf empty, Quantity Available "
+ "is used"),
+ }
+
+ _defaults = {
+ # FIXME, WTF with that default value
+ 'payment_default_id': 1, #required field that would cause trouble if not set when importing
+ 'auto_import': True,
+ 'use_external_tax': True,
+ 'product_stock_field_id': _get_stock_field_id,
+ }
+
+ def init_context_before_exporting_resource(self, cr, uid, external_session, object_id, resource_name, context=None):
+ context = super(sale_shop, self).init_context_before_exporting_resource(cr, uid, external_session, object_id, resource_name, context=context)
+ context['pricelist'] = external_session.sync_from_object.get_pricelist(context=context)
+ return context
+
+ def get_pricelist(self, cr, uid, id, context=None):
+ if isinstance(id, list):
+ id=id[0]
+ shop = self.browse(cr, uid, id, context=context)
+ if shop.pricelist_id:
+ return shop.pricelist_id.id
+ else:
+ return self.pool.get('product.pricelist').search(cr, uid, [('type', '=', 'sale'), ('active', '=', True)], context=context)[0]
+
+ def export_catalog(self, cr, uid, ids, context=None):
+ if context is None: context={}
+ self.export_resources(cr, uid, ids, 'product.category', context=context)
+ # In various e-commerce system product can depend of other products
+ # So the simple product (with no dependency) are exported in priority
+ # Then the special product (with dependency) are exported at the end
+ context['export_product'] = 'simple'
+ self.export_resources(cr, uid, ids, 'product.product', context=context)
+ context['export_product'] = 'special'
+ self.export_resources(cr, uid, ids, 'product.product', context=context)
+ #Export Images
+ self.export_resources(cr, uid, ids, 'product.images', context=context)
+
+ #TODO export link
+ #TODO update the last date
+ #I don't know where it's the best to update it here or in the export functions
+ #take care about concurent write with different cursor
+
+
+ return True
+
+ def export_inventory(self, cr, uid, ids, context=None):
+ if context is None:
+ context = {}
+ for shop in self.browse(cr, uid, ids):
+ external_session = ExternalSession(shop.referential_id, shop)
+ self._export_inventory(cr, uid, external_session, ids, context=context)
+ return True
+
+ def _get_product_ids_for_stock_to_export(self, cr, uid, shop, context=None):
+ return [product.id for product in shop.exportable_product_ids]
+
+ def _export_inventory(self, cr, uid, external_session, ids, context=None):
+ shop = external_session.sync_from_object
+ stock_move_obj = self.pool.get('stock.move')
+ for shop in self.browse(cr, uid, ids):
+ external_session = ExternalSession(shop.referential_id, shop)
+
+ product_ids = self._get_product_ids_for_stock_to_export(cr, uid, shop, context=context)
+
+ if shop.last_inventory_export_date:
+ # we do not exclude canceled moves because it means
+ # some stock levels could have increased since last export
+ recent_move_ids = stock_move_obj.search(
+ cr, uid,
+ [('write_date', '>', shop.last_inventory_export_date),
+ ('product_id', 'in', product_ids),
+ ('product_id.type', '!=', 'service'),
+ ('state', '!=', 'draft')],
+ context=context)
+ else:
+ recent_move_ids = stock_move_obj.search(
+ cr, uid,
+ [('product_id', 'in', product_ids)],
+ context=context)
+
+ recent_moves = stock_move_obj.browse(
+ cr, uid, recent_move_ids, context=context)
+
+ product_ids = [move.product_id.id
+ for move
+ in recent_moves
+ if move.product_id.state != 'obsolete']
+ product_ids = list(set(product_ids))
+ external_session.logger.info('Export Stock for %s products' %len(product_ids))
+ self.pool.get('product.product').export_inventory(
+ cr, uid, external_session, product_ids, context=context)
+ shop.write({'last_inventory_export_date':
+ time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
+ return True
+
+ def import_catalog(self, cr, uid, ids, context):
+ #TODO import categories, then products
+ raise except_osv(_("Not Implemented"), _("Not Implemented in abstract base module!"))
+
+ def import_orders(self, cr, uid, ids, context=None):
+ self.import_resources(cr, uid, ids, 'sale.order', context=context)
+ return True
+
+ def check_need_to_update(self, cr, uid, ids, context=None):
+ """ This function will update the order status in OpenERP for
+ the order which are in the state 'need to update' """
+ for shop in self.browse(cr, uid, ids, context=context):
+ external_session = ExternalSession(shop.referential_id, shop)
+ so_obj = self.pool.get('sale.order')
+ orders_to_update = so_obj.search(cr, uid,
+ [('need_to_update', '=', True),
+ ('shop_id', '=', shop.id)],
+ context=context)
+ so_obj._check_need_to_update(cr, uid, external_session, orders_to_update, context=context)
+ return False
+
+ def _update_order_query(self, cr, uid, shop, context=None):
+ req = """
+ SELECT ir_model_data.res_id, ir_model_data.name
+ FROM sale_order
+ INNER JOIN ir_model_data ON sale_order.id = ir_model_data.res_id
+ WHERE ir_model_data.model='sale.order' AND sale_order.shop_id=%s
+ AND ir_model_data.referential_id NOTNULL
+ """
+ params = (shop.id,)
+ if shop.last_update_order_export_date:
+ req += "AND sale_order.update_state_date > %s"
+ params = (shop.id, shop.last_update_order_export_date)
+ return req, params
+
+ def update_orders(self, cr, uid, ids, context=None):
+ if context is None:
+ context = {}
+ for shop in self.browse(cr, uid, ids):
+ external_session = ExternalSession(shop.referential_id, shop)
+ #get all orders, which the state is not draft and the date of modification is superior to the last update, to exports
+ cr.execute(*self._update_order_query(cr, uid, shop, context=context))
+ results = cr.fetchall()
+ for result in results:
+ ids = self.pool.get('sale.order').search(cr, uid, [('id', '=', result[0])])
+ if ids:
+ id = ids[0]
+ order = self.pool.get('sale.order').browse(cr, uid, id, context)
+ order_ext_id = result[1].split('sale_order/')[1]
+ res = self.update_shop_orders(cr, uid, external_session, order, order_ext_id, context)
+ if res:
+ external_session.logger.info(_("Successfully updated order with OpenERP id %s and ext id %s in external sale system") % (id, order_ext_id))
+ self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_update_order_export_date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
+ return False
+
+ def export_shop_partners(self, cr, uid, ids, context=None):
+ if context is None: context={}
+ self.export_resources(cr, uid, ids, 'res.partner', context=context)
+ return True
+
+ def update_shop_orders(self, cr, uid, external_session, order, ext_id, context):
+ raise except_osv(_("Not Implemented"), _("Not Implemented in abstract base module!"))
+
+ def _export_shipping_query(self, cr, uid, shop, context=None):
+ query = """
+ SELECT stock_picking.id AS picking_id,
+ sale_order.id AS order_id,
+ count(pickings.id) AS picking_number
+ FROM stock_picking
+ LEFT JOIN sale_order
+ ON sale_order.id = stock_picking.sale_id
+ LEFT JOIN stock_picking as pickings
+ ON (sale_order.id = pickings.sale_id
+ AND pickings.type='out'
+ AND pickings.state!='cancel')
+ LEFT JOIN ir_model_data
+ ON stock_picking.id = ir_model_data.res_id
+ AND ir_model_data.model = 'stock.picking'
+ LEFT JOIN delivery_carrier
+ ON delivery_carrier.id = stock_picking.carrier_id
+ WHERE sale_order.shop_id = %(shop_id)s
+ AND ir_model_data.res_id ISNULL
+ AND stock_picking.state = 'done'
+ AND stock_picking.type = 'out'
+ AND NOT stock_picking.do_not_export
+ AND (NOT delivery_carrier.export_needs_tracking
+ OR stock_picking.carrier_tracking_ref IS NOT NULL)
+ GROUP BY stock_picking.id,
+ sale_order.id,
+ delivery_carrier.export_needs_tracking,
+ stock_picking.carrier_tracking_ref,
+ stock_picking.backorder_id
+ ORDER BY sale_order.id ASC,
+ COALESCE(stock_picking.backorder_id, NULL, 0) ASC"""
+ params = {'shop_id': shop.id}
+ return query, params
+
+ def export_shipping(self, cr, uid, ids, context):
+ picking_obj = self.pool.get('stock.picking')
+ for shop in self.browse(cr, uid, ids):
+ cr.execute(*self._export_shipping_query(
+ cr, uid, shop, context=context))
+ results = cr.dictfetchall()
+ if not results:
+ _logger.info("There is no shipping to export for the shop '%s' to the external referential", shop.name)
+ continue
+ context['conn_obj'] = shop.referential_id.external_connection()
+
+
+ picking_cr = pooler.get_db(cr.dbname).cursor()
+ try:
+ for result in results:
+ picking_id = result['picking_id']
+
+ if result["picking_number"] == 1:
+ picking_type = 'complete'
+ else:
+ picking_type = 'partial'
+
+ ext_shipping_id = False
+ try:
+ ext_shipping_id = picking_obj.create_ext_shipping(
+ picking_cr, uid, picking_id, picking_type,
+ shop.referential_id.id, context)
+ except ExternalShippingCreateError, e:
+ # when the creation has failed on the external
+ # referential and we know that we can never
+ # create it, we flag it as do_not_export
+ # ExternalShippingCreateError raising has to be
+ # correctly handled by create_ext_shipping()
+ picking_obj.write(
+ picking_cr, uid,
+ picking_id,
+ {'do_not_export': True},
+ context=context)
+
+ if ext_shipping_id:
+ picking_obj.create_external_id_vals(
+ picking_cr,
+ uid,
+ picking_id,
+ ext_shipping_id,
+ shop.referential_id.id,
+ context=context)
+ _logger.info("Successfully creating shipping with OpenERP id %s and ext id %s in external sale system", result["picking_id"], ext_shipping_id)
+ picking_cr.commit()
+ finally:
+ picking_cr.close()
+ return True
+
+ def export_invoices(self, cr, uid, ids, context=None):
+ invoice_obj = self.pool.get('account.invoice')
+ for shop in self.browse(cr, uid, ids, context=None):
+ external_session = ExternalSession(shop.referential_id, shop)
+ invoice_ids = self.get_invoice_to_export(cr, uid, shop.id, context=context)
+ if not invoice_ids:
+ external_session.logger.info("There is no invoice to export for the shop '%s' to the external referential" % (shop.name,))
+ for invoice_id in invoice_ids:
+ self.pool.get('account.invoice')._export_one_resource(cr, uid, external_session, invoice_id, context=context)
+ return True
+
+ def get_invoice_to_export(self, cr, uid, shop_id, context=None):
+ shop = self.browse(cr, uid, shop_id, context=context)
+ cr.execute(*self._export_invoice_query(cr, uid, shop, context=context))
+ results = cr.dictfetchall()
+ return [res['invoice_id'] for res in results]
+
+ def _export_invoice_query(self, cr, uid, shop, context=None):
+ query = """
+ SELECT account_invoice.id AS invoice_id
+ FROM account_invoice
+ LEFT JOIN ir_model_data
+ ON account_invoice.id = ir_model_data.res_id
+ AND ir_model_data.model = 'account.invoice'
+ AND referential_id = %(referential_id)s
+ WHERE shop_id = %(shop_id)s
+ AND ir_model_data.res_id ISNULL
+ AND account_invoice.state in ('paid', 'open')
+ AND NOT account_invoice.do_not_export
+ """
+ params = {'shop_id': shop.id, 'referential_id': shop.referential_id.id}
+ return query, params
+
+sale_shop()
+
+
+class sale_order(Model):
+ _inherit = "sale.order"
+
+ _columns = {
+ # to remove? will the orders be created as draft when they
+ # wait a payment or are they not imported at all? (the job
+ # retries at intervals)
+ 'need_to_update': fields.boolean('Need To Update'),
+ 'ext_total_amount': fields.float(
+ 'Origin External Amount',
+ digits_compute=dp.get_precision('Sale Price'),
+ readonly=True),
+ 'ext_total_amount_tax': fields.float(
+ 'Origin External Tax Amount',
+ digits_compute=dp.get_precision('Sale Price'),
+ readonly=True),
+ 'referential_id': fields.related(
+ 'shop_id',
+ 'referential_id',
+ type='many2one',
+ relation='external.referential',
+ string='External Referential'),
+ 'update_state_date': fields.datetime('Update State Date'),
+ # FIXME WTF are these 3 fields
+ 'shipping_tax_amount': fields.dummy(string = 'Shipping Taxe Amount'),
+ 'shipping_amount_tax_excluded': fields.dummy(string = 'Shipping Price Tax Exclude'),
+ 'shipping_amount_tax_included': fields.dummy(string = 'Shipping Price Tax Include'),
+ }
+
+ _defaults = {
+ 'need_to_update': False,
+ }
+
+ def write(self, cr, uid, ids, vals, context=None):
+ if 'state' in vals:
+ vals['update_state_date'] = datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT)
+ return super(sale_order, self).write(cr, uid, ids, vals, context=context)
+
+ # xxx move to BaseConnector _get_import_defaults_sale_order
+ def _get_default_import_values(self, cr, uid, external_session, mapping_id=None, defaults=None, context=None):
+ shop = False
+ if external_session.sync_from_object._name == 'sale.shop':
+ shop = external_session.sync_from_object
+ elif context.get('sale_shop_id'):
+ shop = self.pool.get('sale.shop').browse(cr, uid, context['sale_shop_id'], context=context)
+ if shop:
+ if defaults is None: defaults = {}
+ defaults.update({
+ 'pricelist_id': shop.get_pricelist(context=context),
+ 'shop_id': shop.id,
+ 'fiscal_position': shop.default_fiscal_position.id,
+ 'payment_method_id': shop.default_payment_method_id.id,
+ 'company_id': shop.company_id.id,
+ })
+ #TODO we should avoid passing this parameter in the context
+ #for now we new it for importing order from wizard correctly
+ #refactor for V7
+ context.update({
+ 'use_external_tax': shop.use_external_tax,
+ 'is_tax_included': shop.is_tax_included,
+ })
+ return defaults
+
+ @open_report
+ def _import_resources(self, cr, uid, external_session, defaults=None, method="search_then_read", context=None):
+ if context is None: context={}
+ shop = external_session.sync_from_object
+ if shop:
+ context.update({
+ 'use_external_tax': shop.use_external_tax,
+ 'is_tax_included': shop.is_tax_included,
+ })
+ return super(sale_order, self)._import_resources(cr, uid, external_session, defaults=defaults, method=method, context=context)
+
+
+ def check_if_order_exist(self, cr, uid, external_session, resource, order_mapping=None, defaults=None, context=None):
+ mapping_name = False
+ for line in order_mapping['mapping_lines']:
+ if line['internal_field'] == 'name':
+ mapping_name = line
+ if mapping_name:
+ local_mapping = {1: {'mapping_lines': [mapping_name]}}
+ vals = self._transform_one_resource(cr, uid, external_session,
+ 'from_external_to_openerp', resource,
+ mapping=local_mapping,
+ mapping_id=1,
+ defaults=defaults,
+ context=context)
+ if vals.get('name'):
+ exist_id = self.search(cr, uid, [['name', '=', vals['name']]], context=context)
+ if exist_id:
+ external_session.logger.info("Sale Order %s already exist in OpenERP,"
+ "no need to import it again"%vals['name'])
+ return True
+
+ return False
+
+ # xxx a deplacer dans BaseConnector sale_order
+ @catch_error_in_report
+ def _record_one_external_resource(self, cr, uid, external_session, resource, defaults=None,
+ mapping=None, mapping_id=None, context=None):
+ mapping, mapping_id = self._init_mapping(cr, uid, external_session.referential_id.id,
+ mapping=mapping, mapping_id=mapping_id, context=context)
+ exist_id = self.check_if_order_exist(cr, uid, external_session, resource,
+ order_mapping=mapping[mapping_id], defaults=defaults, context=context)
+ if exist_id:
+ return {}
+ else:
+ return super(sale_order, self)._record_one_external_resource(cr, uid, external_session, resource,
+ defaults=defaults, mapping=mapping, mapping_id=mapping_id, context=context)
+
+ def _check_need_to_update(self, cr, uid, external_session, ids, context=None):
+ """
+ For each order, check in external system if it has been paid since last
+ check. If so, it will launch the defined flow based on the
+ payment type (validate order, invoice, ...)
+ """
+ for order in self.browse(cr, uid, ids, context=context):
+ self._check_need_to_update_single(cr, uid, external_session, order, context=context)
+ return True
+
+ def _check_need_to_update_single(self, cr, uid, external_session, order, context=None):
+ """Not implemented in this abstract module"""
+ return True
+
+ def _get_params_onchange_partner_id(self, cr, uid, vals, context=None):
+ args = [
+ 'None',
+ vals.get('partner_id'),
+ ]
+ return args, {}
+
+ #I will probably extract this code in order to put it in a "glue" module
+ def _get_params_onchange_address_id(self, cr, uid, vals, context=None):
+ args = [
+ None,
+ vals.get('partner_invoice_id'),
+ vals.get('partner_shipping_id'),
+ vals.get('partner_id'),
+ ]
+ kwargs = {
+ 'shop_id': vals.get('shop_id'),
+ }
+ return args, kwargs
+
+ def play_sale_order_onchange(self, cr, uid, vals, defaults=None, context=None):
+ ir_module_obj= self.pool.get('ir.module.module')
+ if ir_module_obj.search(cr, uid, [
+ ['name', '=', 'account_fiscal_position_rule_sale'],
+ ['state', 'in', ['installed', 'to upgrade']],
+ ], context=context):
+ vals = self.call_onchange(cr, uid, 'onchange_partner_id', vals, defaults, context=context)
+ vals = self.call_onchange(cr, uid, 'onchange_address_id', vals, defaults, context=context)
+ else:
+ vals = self.call_onchange(cr, uid, 'onchange_partner_id', vals, defaults, context=context)
+
+
+ return vals
+
+ def _merge_with_default_values(self, cr, uid, external_session, ressource, vals, sub_mapping_list, defaults=None, context=None):
+ if vals.get('name'):
+ shop = external_session.sync_from_object
+ if shop.order_prefix:
+ vals['name'] = '%s%s' %(shop.order_prefix, vals['name'])
+ if context is None: context ={}
+ if vals.get('payment_method_id'):
+ payment_method = self.pool.get('payment.method').browse(cr, uid, vals['payment_method_id'], context=context)
+ workflow_process = payment_method.workflow_process_id
+ if workflow_process:
+ vals['order_policy'] = workflow_process.order_policy
+ vals['picking_policy'] = workflow_process.picking_policy
+ vals['invoice_quantity'] = workflow_process.invoice_quantity
+ # update vals with order onchange in order to compute taxes
+ vals = self.play_sale_order_onchange(cr, uid, vals, defaults=defaults, context=context)
+ return super(sale_order, self)._merge_with_default_values(cr, uid, external_session, ressource, vals, sub_mapping_list, defaults=defaults, context=context)
+
+ def oe_create(self, cr, uid, external_session, vals, resource, defaults, context):
+ #depending of the external system the contact address can be optionnal
+ vals = self._convert_special_fields(cr, uid, vals, vals['order_line'], context=context)
+ if not vals.get('partner_order_id'):
+ vals['partner_order_id'] = vals['partner_invoice_id']
+ if not vals.get('partner_shipping_id'):
+ vals['partner_shipping_id'] = vals['partner_invoice_id']
+ order_id = super(sale_order, self).oe_create(cr, uid, external_session, vals, resource, defaults, context)
+ self.paid_and_update(cr, uid, external_session, order_id, resource, context=context)
+ return order_id
+
+ def paid_and_update(self, cr, uid, external_session, order_id, resource, context=None):
+ wf_service = netsvc.LocalService("workflow")
+ paid = self.create_external_payment(cr, uid, external_session, order_id, resource, context)
+ order = self.browse(cr, uid, order_id, context=context)
+ validate_order = order.workflow_process_id.validate_order
+ if validate_order == 'always' or validate_order == 'if_paid' and paid:
+ try:
+ wf_service.trg_validate(uid, 'sale.order', order.id, 'order_confirm', cr)
+ except:
+ raise
+ #What we should do?? creating the order but not validating it???
+ #Maybe setting a special flag can be a good solution? with a retry method?
+ return True
+
+ elif validate_order == 'if_paid' and order.payment_method_id.automatic_update:
+ days_before_order_cancel = order.workflow_process_id.days_before_order_cancel or 30
+ order_date = datetime.strptime(order.date_order, DEFAULT_SERVER_DATE_FORMAT)
+ order_cancel_date = order_date + relativedelta(days=days_before_order_cancel)
+ if order.state == 'draft' and order_cancel_date < datetime.now():
+ wf_service.trg_validate(uid, 'sale.order', order.id, 'cancel', cr)
+ self.write(cr, uid, order.id, {'need_to_update': False})
+ self.log(cr, uid, order.id, ("order %s canceled in OpenERP because older than % days"
+ "and still not confirmed") % (order.id, days_before_order_cancel))
+ #TODO eventually call a trigger to cancel the order in the external system too
+ external_session.logger.info(("order %s canceled in OpenERP because older than % days and "
+ "still not confirmed") %(order.id, days_before_order_cancel))
+ else:
+ self.write(cr, uid, order_id, {'need_to_update': True}, context=context)
+ return False
+
+ def create_external_payment(self, cr, uid, external_session, order_id, resource, context):
+ """
+ Fonction that will create a payment from the external resource
+ """
+ vals = self._get_payment_information(cr, uid, external_session, order_id, resource, context=context)
+ if vals.get('paid'):
+ if not vals.get('journal_id'):
+ external_session.logger.warning(_("Not journal found for payment method %s. Can not create payment")%vals['payment_method'])
+ vals['paid'] = False
+ else:
+ self.pay_sale_order(cr, uid, order_id, vals['journal_id'], vals['amount'], vals['date'], context=context)
+ return vals.get('paid')
+
+ def _get_payment_information(self, cr, uid, external_session, order_id, resource, context=None):
+ """
+ Function that will return the information in order to create the payment
+ """
+ vals = {}
+ sale = self.browse(cr, uid, order_id, context=context)
+ vals['payment_method'] = sale.payment_method_id.name
+ vals['journal_id'] = sale.payment_method_id.journal_id and sale.payment_method_id.journal_id.id
+ vals['date'] = sale.date_order
+ return vals
+
+ def _prepare_invoice(self, cr, uid, order, lines, context=None):
+ """Prepare the dict of values to create the new invoice for a
+ sale order. This method may be overridden to implement custom
+ invoice generation (making sure to call super() to establish
+ a clean extension chain).
+
+ :param browse_record order: sale.order record to invoice
+ :param list(int) lines: list of invoice line IDs that must be
+ attached to the invoice
+ :return: dict of value to create() the invoice
+ """
+ vals = super(sale_order, self)._prepare_invoice(cr, uid, order, lines, context=context)
+ if order.shop_id.sale_journal:
+ vals['journal_id'] = order.shop_id.sale_journal.id
+ vals['shop_id'] = order.shop_id.id
+ return vals
+
+ def _prepare_order_picking(self, cr, uid, order, context=None):
+ vals = super(sale_order, self)._prepare_order_picking(cr, uid, order, context=context)
+ vals['shop_id'] = order.shop_id.id
+ return vals
+
+ def oe_update(self, cr, uid, external_session, existing_rec_id, vals, resource, defaults, context=None):
+ '''Not implemented in this abstract module, if it's not implemented in your module it will raise an error'''
+ # Explication :
+ # sometime customer can do ugly thing like renamming a sale_order and try to reimported it,
+ # sometime openerp run two scheduler at the same time, or the customer launch two openerp at the same time
+ # or the external system give us again an already imported order
+ # As the update of an existing order (this is not the update of the status but the update of the line, the address...)
+ # is not supported by connector_ecommerce and also not in magentoerpconnect.
+ # It's better to don't allow this feature to avoid hidding a problem.
+ # It's better to have the order not imported and to know it than having order with duplicated line.
+ if not (context and context.get('oe_update_supported', False)):
+ #TODO found a clean solution to raise the except_osv error in the try except of the function import_with_try
+ raise except_osv(_("Not Implemented"), _(("The order with the id %s try to be updated from the external system."
+ " This feature is not supported. Maybe the import try to reimport an existing sale order"%(existing_rec_id,))))
+ return super(sale_order, self).oe_update(cr, uid, external_session, existing_rec_id, vals, resource, defaults, context=context)
+
+
+
+
+class sale_order_line(Model):
+ _inherit='sale.order.line'
+
+ _columns = {
+ 'ext_product_ref': fields.char('Product Ext Ref',
+ help="This is the original external product reference", size=256),
+ # FIXME WTF are these 3 fields
+ 'shipping_tax_amount': fields.dummy(string = 'Shipping Taxe Amount'),
+ 'shipping_amount_tax_excluded': fields.dummy(string = 'Shipping Price Tax Exclude'),
+ 'shipping_amount_tax_included': fields.dummy(string = 'Shipping Price Tax Include'),
+ 'ext_ref_line': fields.char('Ext. Ref Line', size=64,
+ help='Unique order line id delivered by external application'),
+ }
+
+ def _get_params_product_id_change(self, cr, uid, line, parent_data, previous_lines, context=None):
+ args = [
+ None,
+ parent_data.get('pricelist_id'),
+ line.get('product_id')
+ ]
+ kwargs ={
+ 'qty': float(line.get('product_uom_qty')),
+ 'uom': line.get('product_uom'),
+ 'qty_uos': float(line.get('product_uos_qty') or line.get('product_uom_qty')),
+ 'uos': line.get('product_uos'),
+ 'name': line.get('name'),
+ 'partner_id': parent_data.get('partner_id'),
+ 'lang': False,
+ 'update_tax': True,
+ 'date_order': parent_data.get('date_order'),
+ 'packaging': line.get('product_packaging'),
+ 'fiscal_position': parent_data.get('fiscal_position'),
+ 'flag': False,
+ 'context': context,
+ }
+ return args, kwargs
+
+ # XXX what is the added value of those 'play' onchanges?
+ def play_sale_order_line_onchange(self, cr, uid, line, parent_data, previous_lines, defaults=None, context=None):
+ original_line = line.copy()
+ if not context.get('use_external_tax') and 'tax_id' in line:
+ del line['tax_id']
+ line = self.call_onchange(cr, uid, 'product_id_change', line, defaults=defaults, parent_data=parent_data, previous_lines=previous_lines, context=context)
+ #TODO all m2m should be mapped correctly
+ if context.get('use_external_tax'):
+ #if we use the external tax and the onchange have added a taxe,
+ #them we remove it.
+ #Indeed we have to make the difference between a real tax_id
+ #imported and a default value set by the onchange
+ if not 'tax_id' in original_line and 'tax_id' in line:
+ del line['tax_id']
+ elif line.get('tax_id'):
+ line['tax_id'] = [(6, 0, line['tax_id'])]
+ return line
+
+ def _transform_one_resource(self, cr, uid, external_session, convertion_type, resource, mapping, mapping_id,
+ mapping_line_filter_ids=None, parent_data=None, previous_result=None, defaults=None, context=None):
+ if context is None: context={}
+ line = super(sale_order_line, self)._transform_one_resource(cr, uid, external_session, convertion_type, resource,
+ mapping, mapping_id, mapping_line_filter_ids=mapping_line_filter_ids, parent_data=parent_data,
+ previous_result=previous_result, defaults=defaults, context=context)
+
+ if context.get('is_tax_included') and 'price_unit_tax_included' in line:
+ line['price_unit'] = line['price_unit_tax_included']
+ elif 'price_unit_tax_excluded' in line:
+ line['price_unit'] = line['price_unit_tax_excluded']
+
+ line = self.play_sale_order_line_onchange(cr, uid, line, parent_data, previous_result,
+ defaults, context=context)
+ if context.get('use_external_tax'):
+ if not 'tax_id' in line and line.get('tax_rate'):
+ line_tax_id = self.pool.get('account.tax').get_tax_from_rate(cr, uid, line['tax_rate'], context.get('is_tax_included', False), context=context)
+ if not line_tax_id:
+ raise except_osv(_('Error'), _('No tax id found for the rate %s with the tax include = %s')%(line['tax_rate'], context.get('is_tax_included')))
+ line['tax_id'] = [(6, 0, [line_tax_id])]
+ else:
+ line['tax_id'] = False
+ return line
+
+
+# moved from partner.py ###############
+
+from openerp.osv import orm, fields
+
+
+class res_partner(orm.Model):
+ _inherit = 'res.partner'
+
+ _columns = {
+ 'shop_ids': fields.many2many(
+ 'sale.shop',
+ 'sale_shop_res_partner_rel',
+ 'shop_id',
+ 'partner_id',
+ string='Present in Shops',
+ readonly=True,
+ help="List of shops in which this customer exists."),
+ }
+
+ # xxx move to BaseConnector _get_import_defaults_res_partner
+ def _get_default_import_values(self, cr, uid, external_session, mapping_id=None, defaults=None, context=None):
+ if external_session.sync_from_object._name == 'sale.shop':
+ shop = external_session.sync_from_object
+ if not defaults: defaults = {}
+ defaults.update({
+ 'lang': shop.default_customer_lang.code,
+ 'property_account_position': shop.default_fiscal_position.id,
+ 'property_account_receivable': shop.default_customer_account,
+ 'shop_ids': [(4, shop.id)],
+ })
+ return defaults
+
+
+# moved from product.py #################
+
+
+
+from openerp.osv.orm import Model
+from openerp.osv import fields
+
+from openerp.addons.connector.decorator import only_for_referential
+from openerp.addons.connector.decorator import commit_now
+
+class product_product(Model):
+ _inherit='product.product'
+
+ def _check_if_export(self, cr, uid, external_session, product, context=None):
+ if context.get('export_product') == 'simple':
+ return True
+ return False
+
+ @only_for_referential(ref_categ ='Multichannel Sale')
+ def _get_last_exported_date(self, cr, uid, external_session, context=None):
+ shop = external_session.sync_from_object
+ if context.get('export_product') == 'simple':
+ return shop.last_products_export_date
+ elif context.get('export_product') == 'special':
+ return shop.last_special_products_export_date
+ return False
+
+ @only_for_referential(ref_categ ='Multichannel Sale')
+ @commit_now
+ def _set_last_exported_date(self, cr, uid, external_session, date, context=None):
+ shop = external_session.sync_from_object
+ if context.get('export_product') == 'simple':
+ return self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_products_export_date': date}, context=context)
+ elif context.get('export_product') == 'special':
+ return self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_special_products_export_date': date}, context=context)
+
+ @only_for_referential(ref_categ ='Multichannel Sale')
+ def get_ids_and_update_date(self, cr, uid, external_session, ids=None, last_exported_date=None, context=None):
+ res = (), {} # list of ids, dict of ids to date_changed
+ shop = external_session.sync_from_object
+ if shop.exportable_product_ids:
+ product_ids = [product.id for product in shop.exportable_product_ids if self._check_if_export(cr, uid, external_session, product, context=context)]
+ if ids:
+ product_ids = set(ids).intersection(set(product_ids))
+ if product_ids:
+ res = super(product_product, self).get_ids_and_update_date(cr, uid, external_session,
+ ids=product_ids,
+ last_exported_date=last_exported_date,
+ context=context)
+ return res
+
+
+ def _get_categories_ids_for_shop(self, cr, uid, product_id, shop_id, context=None):
+ shop_categ_ids = self.pool.get('sale.shop').read(cr, uid, shop_id,
+ ['exportable_category_ids'],
+ context=context)['exportable_category_ids']
+ product = self.read(cr, uid, product_id, ['categ_ids', 'categ_id'], context=context)
+ product_categ_ids = product['categ_ids']
+ if product['categ_id'][0] not in product_categ_ids:
+ product_categ_ids.append(product['categ_id'][0])
+ res = []
+ for categ in product_categ_ids:
+ if categ in shop_categ_ids:
+ res.append(categ)
+ return res
+
+ def _get_categories_ids_for_shop(self, cr, uid, product_id, shop_id, context=None):
+ shop_obj = self.pool.get('sale.shop')
+ shop_values = shop_obj.read(cr, uid, shop_id,
+ ['exportable_category_ids'],
+ context=context)
+ shop_categ_ids = set(shop_values['exportable_category_ids'])
+ product = self.read(cr, uid, product_id, ['categ_ids', 'categ_id'], context=context)
+ product_categ_ids = set(product['categ_ids'])
+ product_categ_ids.add(product['categ_id'][0])
+ return list(prod_categ_ids & shop_categ_ids)
+
+ def _get_or_create_ext_category_ids_for_shop(self, cr, uid, external_session, product_id, context=None):
+ res = []
+ categ_obj = self.pool.get('product.category')
+ for oe_categ_id in self._get_categories_ids_for_shop(cr, uid, product_id, external_session.sync_from_object.id, context=context):
+ res.append(categ_obj.get_or_create_extid(cr, uid, external_session, oe_categ_id, context=context))
+ return res
+
+
+class product_category(Model):
+ _inherit = "product.category"
+
+ def collect_children(self, category, children=None):
+ if children is None:
+ children = []
+
+ for child in category.child_id:
+ children.append(child.id)
+ self.collect_children(child, children)
+
+ return children
+
+ def _get_recursive_children_ids(self, cr, uid, ids, name, args, context=None):
+ res = {}
+ for category in self.browse(cr, uid, ids):
+ res[category.id] = self.collect_children(category, [category.id])
+ return res
+
+ _columns = {
+ 'recursive_children_ids': fields.function(_get_recursive_children_ids, method=True, type='one2many', relation="product.category", string='All Child Categories'),
+ }
+
+ @only_for_referential(ref_categ ='Multichannel Sale')
+ def _get_last_exported_date(self, cr, uid, external_session, context=None):
+ shop = external_session.sync_from_object
+ return shop.last_category_export_date
+
+ @only_for_referential(ref_categ ='Multichannel Sale')
+ @commit_now
+ def _set_last_exported_date(self, cr, uid, external_session, date, context=None):
+ shop = external_session.sync_from_object
+ return self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_category_export_date': date}, context=context)
+
+ def get_ids_and_update_date(self, cr, uid, external_session, ids=None, last_exported_date=None, context=None):
+ shop = external_session.sync_from_object
+ if shop.exportable_category_ids:
+ res = super(product_category, self).get_ids_and_update_date(cr, uid, external_session,
+ ids=[categ.id for categ in shop.exportable_category_ids],
+ last_exported_date=last_exported_date,
+ context=context)
+ else:
+ res = (), {} # list of ids, dict of ids to date_changed
+ return res
+
+
+# moved from external_referential.py #########
+
+
+from openerp.osv import orm, fields
+
+
+class external_referential(orm.Model):
+ _inherit = "external.referential"
+
+ _columns = {
+ 'last_imported_product_id': fields.integer(
+ 'Last Imported Product Id',
+ help="Product are imported one by one. "
+ "This is the magento id of the last product imported. "
+ "If you clear it all product will be imported"),
+ # TODO replace by last import date (at website level)
+ 'last_imported_partner_id': fields.integer(
+ 'Last Imported Partner Id',
+ help="Partners are imported one by one. "
+ "This is the magento id of the last partner imported. "
+ "If you clear it all partners will be imported"),
+ 'import_all_attributs': fields.boolean(
+ 'Import all attributs',
+ help="If the option is uncheck only the attributs "
+ "that doesn't exist in OpenERP will be imported "),
+ 'import_image_with_product': fields.boolean(
+ 'With image',
+ help="If the option is check the product's image and "
+ "the product will be imported at the same time and"
+ "so the step '7-import images' is not needed"),
+ 'import_links_with_product': fields.boolean(
+ 'With links',
+ help="If the option is check the product's links "
+ "(Up-Sell, Cross-Sell, Related) and the product will "
+ "be imported at the same time and so the step "
+ "'8-import links' is not needed"),
+ }
+
+ def import_customer_groups(self, cr, uid, ids, context=None):
+ self.import_resources(cr, uid, ids, 'res.partner.category', context=context)
+ return True
+
+ def import_product_categories(self, cr, uid, ids, context=None):
+ self.import_resources(cr, uid, ids, 'product.category', context=context)
+ return True
+
+ def import_customers(self, cr, uid, ids, context=None):
+ self.import_resources(cr, uid, ids, 'res.partner', context=context)
+ return True
+
+# def import_product_attributes_sets(self, cr, uid, ids, context=None):
+# return self.import_resources(cr, uid, ids, 'TODO', context=context)
+#
+# def import_product_attributes_groups(self, cr, uid, ids, context=None):
+# return self.import_resources(cr, uid, ids, 'TODO', context=context)
+#
+# def import_product_attributes(self, cr, uid, ids, context=None):
+# return self.import_resources(cr, uid, ids, 'TODO', context=context)
+
+ def import_products(self, cr, uid, ids, context=None):
+ self.import_resources(cr, uid, ids, 'product.product', context=context)
+ return True
+
+ def import_product_links(self, cr, uid, ids, context=None):
+ self.import_resources(cr, uid, ids, 'product.link', context=context)
+ return True
diff --git a/connector_ecommerce/partner_view.xml b/connector_ecommerce/old_xml_stuff.xml
similarity index 75%
rename from connector_ecommerce/partner_view.xml
rename to connector_ecommerce/old_xml_stuff.xml
index e52390b5..decc57e0 100644
--- a/connector_ecommerce/partner_view.xml
+++ b/connector_ecommerce/old_xml_stuff.xml
@@ -1,11 +1,5 @@
-
-
@@ -26,3 +20,4 @@
+
diff --git a/connector_ecommerce/partner.py b/connector_ecommerce/partner.py
deleted file mode 100644
index 48fca23f..00000000
--- a/connector_ecommerce/partner.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# -*- encoding: utf-8 -*-
-#################################################################################
-# #
-# connector_ecommerce for OpenERP #
-# Copyright (C) 2011 Akretion Sébastien BEAU #
-# #
-# 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 . #
-# #
-#################################################################################
-
-from openerp.osv import orm, fields
-
-
-class res_partner(orm.Model):
- _inherit = 'res.partner'
-
- _columns = {
- 'shop_ids': fields.many2many(
- 'sale.shop',
- 'sale_shop_res_partner_rel',
- 'shop_id',
- 'partner_id',
- string='Present in Shops',
- readonly=True,
- help="List of shops in which this customer exists."),
- }
-
- # xxx move to BaseConnector _get_import_defaults_res_partner
- def _get_default_import_values(self, cr, uid, external_session, mapping_id=None, defaults=None, context=None):
- if external_session.sync_from_object._name == 'sale.shop':
- shop = external_session.sync_from_object
- if not defaults: defaults = {}
- defaults.update({
- 'lang': shop.default_customer_lang.code,
- 'property_account_position': shop.default_fiscal_position.id,
- 'property_account_receivable': shop.default_customer_account,
- 'shop_ids': [(4, shop.id)],
- })
- return defaults
diff --git a/connector_ecommerce/payment_method.py b/connector_ecommerce/payment_method.py
index 6f4c2021..555e7beb 100644
--- a/connector_ecommerce/payment_method.py
+++ b/connector_ecommerce/payment_method.py
@@ -1,38 +1,51 @@
# -*- coding: utf-8 -*-
-#################################################################################
-# #
-# connector_ecommerce for OpenERP #
-# Copyright (C) 2011 Akretion Sébastien BEAU #
-# #
-# 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 . #
-# #
-#################################################################################
-
+##############################################################################
+#
+# Copyright 2011-2013 Akretion
+# @author Sébastien BEAU
+#
+# 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 .
+#
+##############################################################################
from openerp.osv import orm, fields
-
class payment_method(orm.Model):
_inherit = "payment.method"
+ def _get_import_rules(self, cr, uid, context=None):
+ return [('always', 'Always'),
+ ('never', 'Never'),
+ ('paid', 'Paid'),
+ ]
+
_columns = {
- 'automatic_update': fields.boolean(
- 'Automatic Update',
- help="If the order is not paid, OpenERP will call the "
- "external system before each order import in order to know "
- "if this order is paid"),
+ # 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):
@@ -42,13 +55,14 @@ def get_or_create_payment_method(self, cr, uid, payment_method, context=None):
:rtype: int
:return: id of required payment method
"""
-
pay_method_obj = self.pool.get('payment.method')
- method_ids = pay_method_obj.search(cr, uid, [['name', '=ilike', payment_method]],
- context=context)
+ method_ids = pay_method_obj.search(cr, uid,
+ [('name', '=ilike', payment_method)],
+ context=context)
if method_ids:
method_id = method_ids[0]
else:
- method_id = pay_method_obj.create(cr, uid, {'name' : payment_method}, context=context)
-
+ method_id = pay_method_obj.create(cr, uid,
+ {'name': payment_method},
+ context=context)
return method_id
diff --git a/connector_ecommerce/payment_method_view.xml b/connector_ecommerce/payment_method_view.xml
index fd22077a..788b3bd3 100644
--- a/connector_ecommerce/payment_method_view.xml
+++ b/connector_ecommerce/payment_method_view.xml
@@ -1,6 +1,6 @@
@@ -10,25 +10,40 @@
- sale_automatic_workflow.payment_method.view_form
+ payment.method.connector_ecommerce.formpayment.method
-
-
+
-
-
-
+
+
+
+
+
+
+
+
+ The sales orders using the payment method will never be imported.
+
+
+ The sales orders using the payment method will always be imported.
+
+
+ The sales orders using the payment method will be imported
+ only when they receive a payment on the E-Commerce backend.
+
+
+
+
- sale_automatic_workflow.payment_method.view_tree
+ payment.method.connector_ecommerce.treepayment.method
-
-
+
-
-
+
+
diff --git a/connector_ecommerce/product.py b/connector_ecommerce/product.py
index dc4e5419..9d68dceb 100644
--- a/connector_ecommerce/product.py
+++ b/connector_ecommerce/product.py
@@ -1,170 +1,175 @@
- # -*- encoding: utf-8 -*-
-###############################################################################
-# #
-# connector_ecommerce for OpenERP #
-# Copyright (C) 2011 Akretion Sébastien BEAU #
-# #
-# 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 . #
-# #
-###############################################################################
-
-
-from openerp.osv.orm import Model
-from openerp.osv import fields
-
-from openerp.addons.connector.decorator import only_for_referential
-from openerp.addons.connector.decorator import commit_now
-
-class product_product(Model):
- _inherit='product.product'
-
- def _check_if_export(self, cr, uid, external_session, product, context=None):
- if context.get('export_product') == 'simple':
- return True
- return False
-
- @only_for_referential(ref_categ ='Multichannel Sale')
- def _get_last_exported_date(self, cr, uid, external_session, context=None):
- shop = external_session.sync_from_object
- if context.get('export_product') == 'simple':
- return shop.last_products_export_date
- elif context.get('export_product') == 'special':
- return shop.last_special_products_export_date
- return False
-
- @only_for_referential(ref_categ ='Multichannel Sale')
- @commit_now
- def _set_last_exported_date(self, cr, uid, external_session, date, context=None):
- shop = external_session.sync_from_object
- if context.get('export_product') == 'simple':
- return self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_products_export_date': date}, context=context)
- elif context.get('export_product') == 'special':
- return self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_special_products_export_date': date}, context=context)
-
- @only_for_referential(ref_categ ='Multichannel Sale')
- def get_ids_and_update_date(self, cr, uid, external_session, ids=None, last_exported_date=None, context=None):
- res = (), {} # list of ids, dict of ids to date_changed
- shop = external_session.sync_from_object
- if shop.exportable_product_ids:
- product_ids = [product.id for product in shop.exportable_product_ids if self._check_if_export(cr, uid, external_session, product, context=context)]
- if ids:
- product_ids = set(ids).intersection(set(product_ids))
- if product_ids:
- res = super(product_product, self).get_ids_and_update_date(cr, uid, external_session,
- ids=product_ids,
- last_exported_date=last_exported_date,
- context=context)
- return res
-
-
- def _get_categories_ids_for_shop(self, cr, uid, product_id, shop_id, context=None):
- shop_categ_ids = self.pool.get('sale.shop').read(cr, uid, shop_id,
- ['exportable_category_ids'],
- context=context)['exportable_category_ids']
- product = self.read(cr, uid, product_id, ['categ_ids', 'categ_id'], context=context)
- product_categ_ids = product['categ_ids']
- if product['categ_id'][0] not in product_categ_ids:
- product_categ_ids.append(product['categ_id'][0])
- res = []
- for categ in product_categ_ids:
- if categ in shop_categ_ids:
- res.append(categ)
- return res
-
- def _get_categories_ids_for_shop(self, cr, uid, product_id, shop_id, context=None):
- shop_obj = self.pool.get('sale.shop')
- shop_values = shop_obj.read(cr, uid, shop_id,
- ['exportable_category_ids'],
- context=context)
- shop_categ_ids = set(shop_values['exportable_category_ids'])
- product = self.read(cr, uid, product_id, ['categ_ids', 'categ_id'], context=context)
- product_categ_ids = set(product['categ_ids'])
- product_categ_ids.add(product['categ_id'][0])
- return list(prod_categ_ids & shop_categ_ids)
-
- def _get_or_create_ext_category_ids_for_shop(self, cr, uid, external_session, product_id, context=None):
- res = []
- categ_obj = self.pool.get('product.category')
- for oe_categ_id in self._get_categories_ids_for_shop(cr, uid, product_id, external_session.sync_from_object.id, context=context):
- res.append(categ_obj.get_or_create_extid(cr, uid, external_session, oe_categ_id, context=context))
- return res
-
-
-
-class product_template(Model):
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Sébastien BEAU
+# Copyright 2011-2013 Akretion
+#
+# 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 .
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+from openerp.addons.connector.session import ConnectorSession
+from .event import on_product_price_changed
+
+
+class product_template(orm.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):
- result[product.id] = product.taxes_id and product.taxes_id[0].group_id.id
+ 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,
+ 'tax_group_id': fields.function(
+ _get_tax_group_id,
string='Tax Group',
type='many2one',
relation='account.tax.group',
store=False,
- help=('Tax group are use with some external',
- ' system like magento or prestashop')),
+ help='Tax group are used with some external '
+ 'system like magento or prestashop'),
}
+ def _price_changed(self, cr, uid, ids, vals, context=None):
+ """ Fire the ``on_product_price_changed`` on all the variants of
+ the template if the price if 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.
+
+ 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)
+ # 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
+ # variant has been changed
+ tmpl_fields = [field for field in vals if field in self._columns]
+ 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)
+ # 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:
+ on_product_price_changed.fire(session,
+ product_obj._name,
+ prod_id)
+
+ def write(self, cr, uid, ids, vals, context=None):
+ result = super(product_template, self).write(cr, uid, ids,
+ vals, context=context)
+ self._price_changed(cr, uid, ids, vals, context=context)
+ return result
+
+
+class product_product(orm.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
-class product_category(Model):
- _inherit = "product.category"
+ _columns = {
+ 'has_checkpoint': fields.function(_get_checkpoint,
+ type='boolean',
+ readonly=True,
+ string='Has Checkpoint'),
+ }
- def collect_children(self, category, children=None):
- if children is None:
- children = []
+ def _price_changed(self, cr, uid, ids, vals, context=None):
+ """ Fire the ``on_product_price_changed`` if the price
+ if 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.
+
+ 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)
+ if any(field in price_fields for field in vals):
+ session = ConnectorSession(cr, uid, context=context)
+ for prod_id in 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 = {}
+ 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)
+ return result
- for child in category.child_id:
- children.append(child.id)
- self.collect_children(child, children)
+ def create(self, cr, uid, vals, context=None):
+ product_ids = super(product_product, self).create(
+ cr, uid, vals, context=None)
+ self._price_changed(cr, uid, [product_ids], vals, context=context)
+ return product_ids
- return children
- def _get_recursive_children_ids(self, cr, uid, ids, name, args, context=None):
- res = {}
- for category in self.browse(cr, uid, ids):
- res[category.id] = self.collect_children(category, [category.id])
- return res
+class product_price_type(orm.Model):
+ _inherit = 'product.price.type'
_columns = {
- 'recursive_children_ids': fields.function(_get_recursive_children_ids, method=True, type='one2many', relation="product.category", string='All Child Categories'),
+ 'pricelist_item_ids': fields.one2many(
+ 'product.pricelist.item', 'base',
+ string='Pricelist Items',
+ readonly=True)
}
- @only_for_referential(ref_categ ='Multichannel Sale')
- def _get_last_exported_date(self, cr, uid, external_session, context=None):
- shop = external_session.sync_from_object
- return shop.last_category_export_date
-
- @only_for_referential(ref_categ ='Multichannel Sale')
- @commit_now
- def _set_last_exported_date(self, cr, uid, external_session, date, context=None):
- shop = external_session.sync_from_object
- return self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_category_export_date': date}, context=context)
-
- def get_ids_and_update_date(self, cr, uid, external_session, ids=None, last_exported_date=None, context=None):
- shop = external_session.sync_from_object
- if shop.exportable_category_ids:
- res = super(product_category, self).get_ids_and_update_date(cr, uid, external_session,
- ids=[categ.id for categ in shop.exportable_category_ids],
- last_exported_date=last_exported_date,
- context=context)
- else:
- res = (), {} # list of ids, dict of ids to date_changed
- return res
-
+ def sale_price_fields(self, cr, uid, context=None):
+ """ 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,
+ [('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]
diff --git a/connector_ecommerce/product_view.xml b/connector_ecommerce/product_view.xml
index dc59df5a..fa54e2b8 100644
--- a/connector_ecommerce/product_view.xml
+++ b/connector_ecommerce/product_view.xml
@@ -10,6 +10,7 @@
+ product.product.formproduct.product
@@ -25,4 +26,4 @@
-
\ No newline at end of file
+
diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py
index f0d163bc..d7f1394a 100644
--- a/connector_ecommerce/sale.py
+++ b/connector_ecommerce/sale.py
@@ -1,827 +1,316 @@
-# -*- encoding: utf-8 -*-
-#########################################################################
-# #
-# Copyright (C) 2009 Raphaël Valyi #
-# Copyright (C) 2010-2011 Akretion Sébastien BEAU #
-# #
-# Copyright (C) 2011-2012 Camptocamp Guewen Baconnier #
-# Copyright (C) 2011 by Openlabs Technologies & Consulting (P) Limited #
-# #
-#This program is free software: you can redistribute it and/or modify #
-#it under the terms of the GNU 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 General Public License for more details. #
-# #
-#You should have received a copy of the GNU General Public License #
-#along with this program. If not, see . #
-#########################################################################
-
-from openerp.osv.orm import Model
-from openerp.osv import fields
-from openerp.osv.osv import except_osv
-from openerp import pooler
-from sets import Set as set
-from openerp import netsvc
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Guewen Baconnier
+# Copyright 2011-2013 Camptocamp SA
+# Author: Sébastien Beau
+# Copyright 2010-2013 Akretion
+#
+# 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 .
+#
+##############################################################################
+
+from openerp.osv import orm, fields, osv
from openerp.tools.translate import _
-import time
-import openerp.addons.decimal_precision as dp
-from datetime import datetime, timedelta
-from dateutil.relativedelta import relativedelta
-from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
-from openerp.addons.connector.external_osv import ExternalSession
-from openerp.addons.connector.decorator import open_report
-from openerp.addons.connector.decorator import catch_error_in_report
+from openerp import netsvc
-import logging
-_logger = logging.getLogger(__name__)
+class sale_shop(orm.Model):
+ _inherit = 'sale.shop'
-class external_shop_group(Model):
- _name = 'external.shop.group'
- _description = 'External Referential Shop Group'
+ def _get_payment_default(self, cr, uid, context=None):
+ """ Return a arbitrary account.payment.term record for the sale.shop
- _columns = {
- 'name': fields.char('Name', size=64, required=True),
- 'referential_id': fields.many2one('external.referential', 'Referential', select=True,
- ondelete='cascade'),
- 'shop_ids': fields.one2many('sale.shop', 'shop_group_id', 'Sale Shops'),
+ ``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,
}
- # xxx move to BaseConnector _get_import_defaults_external_shop_group
- def _get_default_import_values(self, cr, uid, external_session, **kwargs):
- return {'referential_id' : external_session.referential_id.id}
+class sale_order(orm.Model):
+ """ Add a cancellation mecanism in the sales orders
-class external_referential(Model):
- _inherit = 'external.referential'
+ When a sale order is canceled in a backend, the connectors can flag
+ the 'canceled_in_backend' flag. It will:
- _columns = {
- 'shop_group_ids': fields.one2many('external.shop.group', 'referential_id', 'Sub Entities'),
- }
+ * try to automatically cancel the sales order
+ * block the confirmation of the sales orders using a 'sales exception'
+ When a sales order is canceled or the user used the button to force
+ 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
+ link with the parent to be defined by each connector), it will be
+ blocked until the cancellation of the sale order is resolved.
-class ExternalShippingCreateError(Exception):
- """
- This error has to be raised when we tried to create a stock.picking on
- the external referential and the external referential has failed
- to create it. It must be raised only when we are SURE that the
- external referential will never be able to create it!
- """
- pass
-
-
-class sale_shop(Model):
- _inherit = "sale.shop"
-
- def _get_exportable_category_ids(self, cr, uid, ids, name, args, context=None):
- res = {}
- for shop in self.browse(cr, uid, ids, context=context):
- res[shop.id] = set()
- for category in shop.exportable_root_category_ids:
- res[shop.id] = res[shop.id].union(set(self.pool.get('product.category')._get_recursive_children_ids(cr, uid, [category.id], "", [], context)[category.id]))
- res[shop.id] = list(res[shop.id])
- return res
-
- def _get_exportable_product_ids(self, cr, uid, ids, name, args, context=None):
- res = {}
- for shop in self.read(cr, uid, ids, ['exportable_category_ids'], context=context):
- all_categories = shop['exportable_category_ids']
-
- # If product_m2mcategories module is installed search in main category
- # and extra categories. If not, only in main category
- cr.execute('select * from ir_module_module where name=%s and state=%s',
- ('product_m2mcategories','installed'))
- if cr.fetchone():
- res[shop['id']] = self.pool.get("product.product").search(cr, uid, ['|',
- ('categ_id', 'in', all_categories),('categ_ids', 'in', all_categories)])
- else:
- res[shop['id']] = self.pool.get("product.product").search(cr, uid,
- [('categ_id', 'in', all_categories)])
- return res
-
- def _get_referential_id(self, cr, uid, ids, name, args, context=None):
- res = {}
- for shop in self.browse(cr, uid, ids, context=context):
- if shop.shop_group_id:
- res[shop.id] = shop.shop_group_id.referential_id.id
- else:
- res[shop.id] = shop.referential_integer_id
- return res
+ This is used by, for instance, the magento connector, when one
+ modifies a sales order, Magento cancels it and create a new one with
+ the first one as parent.
+ """
+ _inherit = 'sale.order'
- def _get_shop_from_shop_group(self, cr, uid, ids, context=None):
- return self.pool.get('sale.shop').search(cr, uid, [('shop_group_id', 'in', ids)], context=context)
+ def _get_parent_id(self, cr, uid, ids, name, arg, context=None):
+ return self.get_parent_id(cr, uid, ids, context=context)
- def _set_referential_id(self, cr, uid, id, name, value, arg, context=None):
- shop = self.browse(cr, uid, id, context=context)
- if shop.shop_group_id:
- raise except_osv(_("User Error"), _("You can not change the referential of this shop, please change the referential of the shop group!"))
- else:
- self.write(cr, uid, id, {'referential_integer_id': value}, context=context)
- return True
+ def get_parent_id(self, cr, uid, ids, context=None):
+ """ Need to be inherited in the connectors to implement the
+ parent logic.
- def _get_shop_ids(self, cr, uid, ids, context=None):
- shop_ids=[]
- for group in self.pool.get('external.shop.group').browse(cr, uid, ids, context=context):
- shop_ids += [shop.id for shop in group.shop_ids]
- return shop_ids
-
- def _get_stock_field_id(self, cr, uid, context=None):
- if self.pool.get('ir.module.module').search(cr, uid, [
- ['name', '=', 'stock_available_immediately'],
- ['state', 'in', ['installed', 'to upgrade']],
- ], context=context):
- stock_field = 'immediately_usable_qty'
- else:
- stock_field = 'virtual_available'
-
- field_ids = self.pool.get('ir.model.fields').search(
- cr, uid,
- [('model', '=', 'product.product'),
- ('name', '=', stock_field)],
- context=context)
- return field_ids[0]
-
- #Depending of the e-commerce solution use you can have one or more root category
- #If you need only one the value will be stored in the exportable_root_category_ids fields
- def _get_rootcategory(self, cr, uid, ids, name, value, context=None):
- res = {}
- for shop in self.browse(cr, uid, ids, context):
- res[shop.id] = shop.exportable_root_category_ids and shop.exportable_root_category_ids[0].id or False
- return res
-
- def _set_rootcategory(self, cr, uid, id, name, value, fnct_inv_arg, context=None):
- return self.write(cr, uid, id, {'exportable_root_category_ids': [(6,0,[value])]}, context=context)
-
- def _get_referential_type_name(self, cr, uid, ids, field_name, arg, context=None):
+ 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 shop in self.browse(cr, uid, ids):
- if shop.referential_id:
- result[shop.id] = shop.referential_id.type_id.name
- else:
- result[shop.id] = False
+ for order in self.browse(cr, uid, ids, context=context):
+ result[order.id] = self._need_cancel(cr, uid, order,
+ context=context)
return result
- _columns = {
- 'exportable_category_ids': fields.function(_get_exportable_category_ids, type='many2many', relation="product.category", string='Exportable Categories'),
- 'exportable_root_category_ids': fields.many2many('product.category', 'shop_category_rel', 'categ_id', 'shop_id', 'Exportable Root Categories'),
- 'exportable_root_category_id':fields.function(_get_rootcategory, fnct_inv = _set_rootcategory, type="many2one", relation="product.category", string="Root Category"),
- 'exportable_product_ids': fields.function(_get_exportable_product_ids, type='many2many', relation="product.product", string='Exportable Products'),
- 'shop_group_id': fields.many2one('external.shop.group', 'Shop Group', ondelete='cascade'),
- # to remove?
- 'last_inventory_export_date': fields.datetime('Last Inventory Export Time'),
- # to remove
- 'last_images_export_date': fields.datetime('Last Images Export Time'),
- # to remove
- 'last_update_order_export_date' : fields.datetime('Last Order Update Time'),
- # to remove
- 'last_products_export_date' : fields.datetime('Last Product Export Time'),
- # to remove
- 'last_special_products_export_date' : fields.datetime('Last Special Product Export Time'),
- # to remove
- 'last_category_export_date' : fields.datetime('Last Category Export Time'),
- 'referential_id': fields.function(
- _get_referential_id,
- fnct_inv=_set_referential_id,
- type='many2one',
- relation='external.referential',
- string='External Referential',
- store={
- 'sale.shop': (
- lambda self, cr, uid, ids, c=None: ids,
- ['referential_integer_id', 'shop_group_id'],
- 10),
- 'external.shop.group': (
- _get_shop_from_shop_group,
- ['referential_id'],
- 20),
- }),
- # wat?
- 'referential_integer_id': fields.integer('Referential Integer ID'),
- 'is_tax_included': fields.boolean(
- 'Prices Include Tax',
- help="Does the external system work with Taxes Inclusive prices ?"),
- 'sale_journal': fields.many2one('account.journal', 'Sale Journal'),
- 'order_prefix': fields.char('Order Prefix', size=64),
- 'default_payment_method_id': fields.many2one('payment.method', 'Payment Method'),
- 'default_language': fields.many2one('res.lang', 'Default Language'),
- 'default_fiscal_position': fields.many2one('account.fiscal.position', 'Default Fiscal Position'),
- 'default_customer_account': fields.many2one('account.account', 'Default Customer Account'),
- 'default_customer_lang': fields.many2one('res.lang', 'Default Customer Language'),
- 'auto_import': fields.boolean('Automatic Import'),
- # 'address_id':fields.many2one('res.partner.address', 'Address'),
- # TODO migrate from address to partner?
- 'partner_id':fields.many2one('res.partner', 'Partner'),
- 'website': fields.char('Website', size=64),
- 'image':fields.binary('Image', filters='*.png,*.jpg,*.gif'),
- # to remove? (always computed by openerp)
- 'use_external_tax': fields.boolean(
- 'Use External Taxes',
- help="If activated, the external taxes will be applied.\n"
- "If not activated, OpenERP will compute them "
- "according to default values and fiscal positions."),
- 'import_orders_from_date': fields.datetime('Only created after'),
- # to remove? always check
- 'check_total_amount': fields.boolean('Check Total Amount', help="The total amount computed by OpenERP should match with the external amount, if not the sale order can not be confirmed."),
- # to remove
- 'type_name': fields.function(_get_referential_type_name, type='char', string='Referential type',
- store={
- 'sale.shop': (lambda self, cr, uid, ids, c={}: ids, ['referential_id', 'shop_group_id'],10)}),
- 'product_stock_field_id': fields.many2one(
- 'ir.model.fields',
- string='Stock Field',
- domain="[('model', 'in', ['product.product', 'product.template']),"
- " ('ttype', '=', 'float')]",
- help="Choose the field of the product which will be used for "
- "stock inventory updates.\nIf empty, Quantity Available "
- "is used"),
- }
+ 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
- _defaults = {
- # FIXME, WTF with that default value
- 'payment_default_id': 1, #required field that would cause trouble if not set when importing
- 'auto_import': True,
- 'use_external_tax': True,
- 'product_stock_field_id': _get_stock_field_id,
+ _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 init_context_before_exporting_resource(self, cr, uid, external_session, object_id, resource_name, context=None):
- context = super(sale_shop, self).init_context_before_exporting_resource(cr, uid, external_session, object_id, resource_name, context=context)
- context['pricelist'] = external_session.sync_from_object.get_pricelist(context=context)
- return context
-
- def get_pricelist(self, cr, uid, id, context=None):
- if isinstance(id, list):
- id=id[0]
- shop = self.browse(cr, uid, id, context=context)
- if shop.pricelist_id:
- return shop.pricelist_id.id
- else:
- return self.pool.get('product.pricelist').search(cr, uid, [('type', '=', 'sale'), ('active', '=', True)], context=context)[0]
-
- def export_catalog(self, cr, uid, ids, context=None):
- if context is None: context={}
- self.export_resources(cr, uid, ids, 'product.category', context=context)
- # In various e-commerce system product can depend of other products
- # So the simple product (with no dependency) are exported in priority
- # Then the special product (with dependency) are exported at the end
- context['export_product'] = 'simple'
- self.export_resources(cr, uid, ids, 'product.product', context=context)
- context['export_product'] = 'special'
- self.export_resources(cr, uid, ids, 'product.product', context=context)
- #Export Images
- self.export_resources(cr, uid, ids, 'product.images', context=context)
-
- #TODO export link
- #TODO update the last date
- #I don't know where it's the best to update it here or in the export functions
- #take care about concurent write with different cursor
-
+ def _need_cancel(self, cr, uid, order, context=None):
+ """ 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
- return True
-
- def export_inventory(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
- for shop in self.browse(cr, uid, ids):
- external_session = ExternalSession(shop.referential_id, shop)
- self._export_inventory(cr, uid, external_session, ids, context=context)
- return True
-
- def _get_product_ids_for_stock_to_export(self, cr, uid, shop, context=None):
- return [product.id for product in shop.exportable_product_ids]
-
- def _export_inventory(self, cr, uid, external_session, ids, context=None):
- shop = external_session.sync_from_object
- stock_move_obj = self.pool.get('stock.move')
- for shop in self.browse(cr, uid, ids):
- external_session = ExternalSession(shop.referential_id, shop)
-
- product_ids = self._get_product_ids_for_stock_to_export(cr, uid, shop, context=context)
-
- if shop.last_inventory_export_date:
- # we do not exclude canceled moves because it means
- # some stock levels could have increased since last export
- recent_move_ids = stock_move_obj.search(
- cr, uid,
- [('write_date', '>', shop.last_inventory_export_date),
- ('product_id', 'in', product_ids),
- ('product_id.type', '!=', 'service'),
- ('state', '!=', 'draft')],
- context=context)
+ def _parent_need_cancel(self, cr, uid, order, context=None):
+ """ 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:
- recent_move_ids = stock_move_obj.search(
- cr, uid,
- [('product_id', 'in', product_ids)],
- context=context)
-
- recent_moves = stock_move_obj.browse(
- cr, uid, recent_move_ids, context=context)
-
- product_ids = [move.product_id.id
- for move
- in recent_moves
- if move.product_id.state != 'obsolete']
- product_ids = list(set(product_ids))
- external_session.logger.info('Export Stock for %s products' %len(product_ids))
- self.pool.get('product.product').export_inventory(
- cr, uid, external_session, product_ids, context=context)
- shop.write({'last_inventory_export_date':
- time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
- return True
+ return False
+ if not order.parent_id:
+ return False
+ return need_cancel(order.parent_id)
- def import_catalog(self, cr, uid, ids, context):
- #TODO import categories, then products
- raise except_osv(_("Not Implemented"), _("Not Implemented in abstract base module!"))
+ def _try_auto_cancel(self, cr, uid, ids, context=None):
+ """ Try to automatically cancel a sales order canceled
+ in a backend.
- def import_orders(self, cr, uid, ids, context=None):
- self.import_resources(cr, uid, ids, 'sale.order', context=context)
- return True
-
- def check_need_to_update(self, cr, uid, ids, context=None):
- """ This function will update the order status in OpenERP for
- the order which are in the state 'need to update' """
- for shop in self.browse(cr, uid, ids, context=context):
- external_session = ExternalSession(shop.referential_id, shop)
- so_obj = self.pool.get('sale.order')
- orders_to_update = so_obj.search(cr, uid,
- [('need_to_update', '=', True),
- ('shop_id', '=', shop.id)],
- context=context)
- so_obj._check_need_to_update(cr, uid, external_session, orders_to_update, context=context)
- return False
-
- def _update_order_query(self, cr, uid, shop, context=None):
- req = """
- SELECT ir_model_data.res_id, ir_model_data.name
- FROM sale_order
- INNER JOIN ir_model_data ON sale_order.id = ir_model_data.res_id
- WHERE ir_model_data.model='sale.order' AND sale_order.shop_id=%s
- AND ir_model_data.referential_id NOTNULL
+ If it can't cancel it, does nothing.
"""
- params = (shop.id,)
- if shop.last_update_order_export_date:
- req += "AND sale_order.update_state_date > %s"
- params = (shop.id, shop.last_update_order_export_date)
- return req, params
-
- def update_orders(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
- for shop in self.browse(cr, uid, ids):
- external_session = ExternalSession(shop.referential_id, shop)
- #get all orders, which the state is not draft and the date of modification is superior to the last update, to exports
- cr.execute(*self._update_order_query(cr, uid, shop, context=context))
- results = cr.fetchall()
- for result in results:
- ids = self.pool.get('sale.order').search(cr, uid, [('id', '=', result[0])])
- if ids:
- id = ids[0]
- order = self.pool.get('sale.order').browse(cr, uid, id, context)
- order_ext_id = result[1].split('sale_order/')[1]
- res = self.update_shop_orders(cr, uid, external_session, order, order_ext_id, context)
- if res:
- external_session.logger.info(_("Successfully updated order with OpenERP id %s and ext id %s in external sale system") % (id, order_ext_id))
- self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_update_order_export_date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
- return False
-
- def export_shop_partners(self, cr, uid, ids, context=None):
- if context is None: context={}
- self.export_resources(cr, uid, ids, 'res.partner', context=context)
- return True
-
- def update_shop_orders(self, cr, uid, external_session, order, ext_id, context):
- raise except_osv(_("Not Implemented"), _("Not Implemented in abstract base module!"))
-
- def _export_shipping_query(self, cr, uid, shop, context=None):
- query = """
- SELECT stock_picking.id AS picking_id,
- sale_order.id AS order_id,
- count(pickings.id) AS picking_number
- FROM stock_picking
- LEFT JOIN sale_order
- ON sale_order.id = stock_picking.sale_id
- LEFT JOIN stock_picking as pickings
- ON (sale_order.id = pickings.sale_id
- AND pickings.type='out'
- AND pickings.state!='cancel')
- LEFT JOIN ir_model_data
- ON stock_picking.id = ir_model_data.res_id
- AND ir_model_data.model = 'stock.picking'
- LEFT JOIN delivery_carrier
- ON delivery_carrier.id = stock_picking.carrier_id
- WHERE sale_order.shop_id = %(shop_id)s
- AND ir_model_data.res_id ISNULL
- AND stock_picking.state = 'done'
- AND stock_picking.type = 'out'
- AND NOT stock_picking.do_not_export
- AND (NOT delivery_carrier.export_needs_tracking
- OR stock_picking.carrier_tracking_ref IS NOT NULL)
- GROUP BY stock_picking.id,
- sale_order.id,
- delivery_carrier.export_needs_tracking,
- stock_picking.carrier_tracking_ref,
- stock_picking.backorder_id
- ORDER BY sale_order.id ASC,
- COALESCE(stock_picking.backorder_id, NULL, 0) ASC"""
- params = {'shop_id': shop.id}
- return query, params
-
- def export_shipping(self, cr, uid, ids, context):
- picking_obj = self.pool.get('stock.picking')
- for shop in self.browse(cr, uid, ids):
- cr.execute(*self._export_shipping_query(
- cr, uid, shop, context=context))
- results = cr.dictfetchall()
- if not results:
- _logger.info("There is no shipping to export for the shop '%s' to the external referential", shop.name)
+ wkf_states = ('draft', 'sent')
+ action_states = ('manual', 'progress')
+ wf_service = netsvc.LocalService("workflow")
+ resolution_msg = _("
Resolution:
"
+ "
Cancel the linked invoices, delivery "
+ "orders, automatic payments.
"
+ "
Cancel the sales order manually.
"
+ "
")
+ for order_id in ids:
+ state = self.read(cr, uid, order_id,
+ ['state'], context=context)['state']
+ if state == 'cancel':
continue
- context['conn_obj'] = shop.referential_id.external_connection()
-
-
- picking_cr = pooler.get_db(cr.dbname).cursor()
- try:
- for result in results:
- picking_id = result['picking_id']
-
- if result["picking_number"] == 1:
- picking_type = 'complete'
+ elif state == 'done':
+ message = _("The sales order cannot be automatically "
+ "canceled because it is already done.")
+ elif state in wkf_states + action_states:
+ try:
+ # respect the same cancellation methods than
+ # 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)
+ elif state in action_states:
+ self.action_cancel(cr, uid, order_id, context=context)
else:
- picking_type = 'partial'
-
- ext_shipping_id = False
- try:
- ext_shipping_id = picking_obj.create_ext_shipping(
- picking_cr, uid, picking_id, picking_type,
- shop.referential_id.id, context)
- except ExternalShippingCreateError, e:
- # when the creation has failed on the external
- # referential and we know that we can never
- # create it, we flag it as do_not_export
- # ExternalShippingCreateError raising has to be
- # correctly handled by create_ext_shipping()
- picking_obj.write(
- picking_cr, uid,
- picking_id,
- {'do_not_export': True},
- context=context)
-
- if ext_shipping_id:
- picking_obj.create_external_id_vals(
- picking_cr,
- uid,
- picking_id,
- ext_shipping_id,
- shop.referential_id.id,
- context=context)
- _logger.info("Successfully creating shipping with OpenERP id %s and ext id %s in external sale system", result["picking_id"], ext_shipping_id)
- picking_cr.commit()
- finally:
- picking_cr.close()
- return True
-
- def export_invoices(self, cr, uid, ids, context=None):
- invoice_obj = self.pool.get('account.invoice')
- for shop in self.browse(cr, uid, ids, context=None):
- external_session = ExternalSession(shop.referential_id, shop)
- invoice_ids = self.get_invoice_to_export(cr, uid, shop.id, context=context)
- if not invoice_ids:
- external_session.logger.info("There is no invoice to export for the shop '%s' to the external referential" % (shop.name,))
- for invoice_id in invoice_ids:
- self.pool.get('account.invoice')._export_one_resource(cr, uid, external_session, invoice_id, context=context)
- return True
-
- def get_invoice_to_export(self, cr, uid, shop_id, context=None):
- shop = self.browse(cr, uid, shop_id, context=context)
- cr.execute(*self._export_invoice_query(cr, uid, shop, context=context))
- results = cr.dictfetchall()
- return [res['invoice_id'] for res in results]
-
- def _export_invoice_query(self, cr, uid, shop, context=None):
- query = """
- SELECT account_invoice.id AS invoice_id
- FROM account_invoice
- LEFT JOIN ir_model_data
- ON account_invoice.id = ir_model_data.res_id
- AND ir_model_data.model = 'account.invoice'
- AND referential_id = %(referential_id)s
- WHERE shop_id = %(shop_id)s
- AND ir_model_data.res_id ISNULL
- AND account_invoice.state in ('paid', 'open')
- AND NOT account_invoice.do_not_export
- """
- params = {'shop_id': shop.id, 'referential_id': shop.referential_id.id}
- return query, params
-
-sale_shop()
-
-
-class sale_order(Model):
- _inherit = "sale.order"
+ raise ValueError('%s should not fall here.' % state)
+ except osv.except_osv:
+ # the 'cancellation_resolved' flag will stay to False
+ message = _("The sales order could not be automatically "
+ "canceled.") + resolution_msg
+ else:
+ message = _("The sales order has been automatically "
+ "canceled.")
+ else:
+ # shipping_except, invoice_except, ...
+ # can not be canceled from the view, so assume that it
+ # should not be canceled here neiter, exception to
+ # 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)
+
+ def _log_canceled_in_backend(self, cr, uid, ids, context=None):
+ 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):
+ 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)
+ if order.invoice_ids:
+ picking_obj = self.pool.get('account.invoice')
+ picking_obj.message_post(cr, uid, order.invoice_ids,
+ body=message, context=context)
+
+ def create(self, cr, uid, values, context=None):
+ order_id = super(sale_order, self).create(cr, uid, values,
+ context=context)
+ 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
- _columns = {
- # to remove? will the orders be created as draft when they
- # wait a payment or are they not imported at all? (the job
- # retries at intervals)
- 'need_to_update': fields.boolean('Need To Update'),
- 'ext_total_amount': fields.float(
- 'Origin External Amount',
- digits_compute=dp.get_precision('Sale Price'),
- readonly=True),
- 'ext_total_amount_tax': fields.float(
- 'Origin External Tax Amount',
- digits_compute=dp.get_precision('Sale Price'),
- readonly=True),
- 'referential_id': fields.related(
- 'shop_id',
- 'referential_id',
- type='many2one',
- relation='external.referential',
- string='External Referential'),
- 'update_state_date': fields.datetime('Update State Date'),
- # FIXME WTF are these 3 fields
- 'shipping_tax_amount': fields.dummy(string = 'Shipping Taxe Amount'),
- 'shipping_amount_tax_excluded': fields.dummy(string = 'Shipping Price Tax Exclude'),
- 'shipping_amount_tax_included': fields.dummy(string = 'Shipping Price Tax Include'),
- }
+ def write(self, cr, uid, ids, values, context=None):
+ result = super(sale_order, self).write(cr, uid, ids, values,
+ context=context)
+ 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)
+ return result
- _defaults = {
- 'need_to_update': False,
- }
+ 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:
+ # 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
- def write(self, cr, uid, ids, vals, context=None):
- if 'state' in vals:
- vals['update_state_date'] = datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT)
- return super(sale_order, self).write(cr, uid, ids, vals, context=context)
-
- # xxx move to BaseConnector _get_import_defaults_sale_order
- def _get_default_import_values(self, cr, uid, external_session, mapping_id=None, defaults=None, context=None):
- shop = False
- if external_session.sync_from_object._name == 'sale.shop':
- shop = external_session.sync_from_object
- elif context.get('sale_shop_id'):
- shop = self.pool.get('sale.shop').browse(cr, uid, context['sale_shop_id'], context=context)
- if shop:
- if defaults is None: defaults = {}
- defaults.update({
- 'pricelist_id': shop.get_pricelist(context=context),
- 'shop_id': shop.id,
- 'fiscal_position': shop.default_fiscal_position.id,
- 'payment_method_id': shop.default_payment_method_id.id,
- 'company_id': shop.company_id.id,
- })
- #TODO we should avoid passing this parameter in the context
- #for now we new it for importing order from wizard correctly
- #refactor for V7
- context.update({
- 'use_external_tax': shop.use_external_tax,
- 'is_tax_included': shop.is_tax_included,
- })
- return defaults
-
- @open_report
- def _import_resources(self, cr, uid, external_session, defaults=None, method="search_then_read", context=None):
- if context is None: context={}
- shop = external_session.sync_from_object
- if shop:
- context.update({
- 'use_external_tax': shop.use_external_tax,
- 'is_tax_included': shop.is_tax_included,
- })
- return super(sale_order, self)._import_resources(cr, uid, external_session, defaults=defaults, method=method, context=context)
-
-
- def check_if_order_exist(self, cr, uid, external_session, resource, order_mapping=None, defaults=None, context=None):
- mapping_name = False
- for line in order_mapping['mapping_lines']:
- if line['internal_field'] == 'name':
- mapping_name = line
- if mapping_name:
- local_mapping = {1: {'mapping_lines': [mapping_name]}}
- vals = self._transform_one_resource(cr, uid, external_session,
- 'from_external_to_openerp', resource,
- mapping=local_mapping,
- mapping_id=1,
- defaults=defaults,
- context=context)
- if vals.get('name'):
- exist_id = self.search(cr, uid, [['name', '=', vals['name']]], context=context)
- if exist_id:
- external_session.logger.info("Sale Order %s already exist in OpenERP,"
- "no need to import it again"%vals['name'])
- return True
-
- return False
-
- # xxx a deplacer dans BaseConnector sale_order
- @catch_error_in_report
- def _record_one_external_resource(self, cr, uid, external_session, resource, defaults=None,
- mapping=None, mapping_id=None, context=None):
- mapping, mapping_id = self._init_mapping(cr, uid, external_session.referential_id.id,
- mapping=mapping, mapping_id=mapping_id, context=context)
- exist_id = self.check_if_order_exist(cr, uid, external_session, resource,
- order_mapping=mapping[mapping_id], defaults=defaults, context=context)
- if exist_id:
- return {}
- else:
- return super(sale_order, self)._record_one_external_resource(cr, uid, external_session, resource,
- defaults=defaults, mapping=mapping, mapping_id=mapping_id, context=context)
+ def ignore_cancellation(self, cr, uid, ids, reason, context=None):
+ """ Manually set the cancellation from the backend as resolved.
- def _check_need_to_update(self, cr, uid, external_session, ids, context=None):
+ The user can choose to keep the sale order active for some reason,
+ so it just push a button to keep it alive.
"""
- For each order, check in external system if it has been paid since last
- check. If so, it will launch the defined flow based on the
- payment type (validate order, invoice, ...)
- """
- for order in self.browse(cr, uid, ids, context=context):
- self._check_need_to_update_single(cr, uid, external_session, order, context=context)
- return True
-
- def _check_need_to_update_single(self, cr, uid, external_session, order, context=None):
- """Not implemented in this abstract module"""
+ 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)
return True
- def _get_params_onchange_partner_id(self, cr, uid, vals, context=None):
- args = [
- 'None',
- vals.get('partner_id'),
- ]
- return args, {}
-
- #I will probably extract this code in order to put it in a "glue" module
- def _get_params_onchange_address_id(self, cr, uid, vals, context=None):
- args = [
- None,
- vals.get('partner_invoice_id'),
- vals.get('partner_shipping_id'),
- vals.get('partner_id'),
- ]
- kwargs = {
- 'shop_id': vals.get('shop_id'),
- }
- return args, kwargs
-
- def play_sale_order_onchange(self, cr, uid, vals, defaults=None, context=None):
- ir_module_obj= self.pool.get('ir.module.module')
- if ir_module_obj.search(cr, uid, [
- ['name', '=', 'account_fiscal_position_rule_sale'],
- ['state', 'in', ['installed', 'to upgrade']],
- ], context=context):
- vals = self.call_onchange(cr, uid, 'onchange_partner_id', vals, defaults, context=context)
- vals = self.call_onchange(cr, uid, 'onchange_address_id', vals, defaults, context=context)
- else:
- vals = self.call_onchange(cr, uid, 'onchange_partner_id', vals, defaults, context=context)
-
-
- return vals
-
- def _merge_with_default_values(self, cr, uid, external_session, ressource, vals, sub_mapping_list, defaults=None, context=None):
- if vals.get('name'):
- shop = external_session.sync_from_object
- if shop.order_prefix:
- vals['name'] = '%s%s' %(shop.order_prefix, vals['name'])
- if context is None: context ={}
- if vals.get('payment_method_id'):
- payment_method = self.pool.get('payment.method').browse(cr, uid, vals['payment_method_id'], context=context)
- workflow_process = payment_method.workflow_process_id
- if workflow_process:
- vals['order_policy'] = workflow_process.order_policy
- vals['picking_policy'] = workflow_process.picking_policy
- vals['invoice_quantity'] = workflow_process.invoice_quantity
- # update vals with order onchange in order to compute taxes
- vals = self.play_sale_order_onchange(cr, uid, vals, defaults=defaults, context=context)
- return super(sale_order, self)._merge_with_default_values(cr, uid, external_session, ressource, vals, sub_mapping_list, defaults=defaults, context=context)
-
- def oe_create(self, cr, uid, external_session, vals, resource, defaults, context):
- #depending of the external system the contact address can be optionnal
- vals = self._convert_special_fields(cr, uid, vals, vals['order_line'], context=context)
- if not vals.get('partner_order_id'):
- vals['partner_order_id'] = vals['partner_invoice_id']
- if not vals.get('partner_shipping_id'):
- vals['partner_shipping_id'] = vals['partner_invoice_id']
- order_id = super(sale_order, self).oe_create(cr, uid, external_session, vals, resource, defaults, context)
- self.paid_and_update(cr, uid, external_session, order_id, resource, context=context)
- return order_id
-
- def paid_and_update(self, cr, uid, external_session, order_id, resource, context=None):
- wf_service = netsvc.LocalService("workflow")
- paid = self.create_external_payment(cr, uid, external_session, order_id, resource, context)
- order = self.browse(cr, uid, order_id, context=context)
- validate_order = order.workflow_process_id.validate_order
- if validate_order == 'always' or validate_order == 'if_paid' and paid:
- try:
- wf_service.trg_validate(uid, 'sale.order', order.id, 'order_confirm', cr)
- except:
- raise
- #What we should do?? creating the order but not validating it???
- #Maybe setting a special flag can be a good solution? with a retry method?
- return True
-
- elif validate_order == 'if_paid' and order.payment_method_id.automatic_update:
- days_before_order_cancel = order.workflow_process_id.days_before_order_cancel or 30
- order_date = datetime.strptime(order.date_order, DEFAULT_SERVER_DATE_FORMAT)
- order_cancel_date = order_date + relativedelta(days=days_before_order_cancel)
- if order.state == 'draft' and order_cancel_date < datetime.now():
- wf_service.trg_validate(uid, 'sale.order', order.id, 'cancel', cr)
- self.write(cr, uid, order.id, {'need_to_update': False})
- self.log(cr, uid, order.id, ("order %s canceled in OpenERP because older than % days"
- "and still not confirmed") % (order.id, days_before_order_cancel))
- #TODO eventually call a trigger to cancel the order in the external system too
- external_session.logger.info(("order %s canceled in OpenERP because older than % days and "
- "still not confirmed") %(order.id, days_before_order_cancel))
- else:
- self.write(cr, uid, order_id, {'need_to_update': True}, context=context)
- return False
-
- def create_external_payment(self, cr, uid, external_session, order_id, resource, context):
- """
- Fonction that will create a payment from the external resource
- """
- vals = self._get_payment_information(cr, uid, external_session, order_id, resource, context=context)
- if vals.get('paid'):
- if not vals.get('journal_id'):
- external_session.logger.warning(_("Not journal found for payment method %s. Can not create payment")%vals['payment_method'])
- vals['paid'] = False
- else:
- self.pay_sale_order(cr, uid, order_id, vals['journal_id'], vals['amount'], vals['date'], context=context)
- return vals.get('paid')
+ def action_view_parent(self, cr, uid, ids, context=None):
+ """ Return an action to display the parent sale order """
+ if isinstance(ids, (list, tuple)):
+ assert len(ids) == 1
+ ids = ids[0]
- def _get_payment_information(self, cr, uid, external_session, order_id, resource, context=None):
- """
- Function that will return the information in order to create the payment
- """
- vals = {}
- sale = self.browse(cr, uid, order_id, context=context)
- vals['payment_method'] = sale.payment_method_id.name
- vals['journal_id'] = sale.payment_method_id.journal_id and sale.payment_method_id.journal_id.id
- vals['date'] = sale.date_order
- return vals
+ mod_obj = self.pool.get('ir.model.data')
+ act_obj = self.pool.get('ir.actions.act_window')
- def _prepare_invoice(self, cr, uid, order, lines, context=None):
- """Prepare the dict of values to create the new invoice for a
- sale order. This method may be overridden to implement custom
- invoice generation (making sure to call super() to establish
- a clean extension chain).
+ parent = self.browse(cr, uid, ids, context=context).parent_id
+ if not parent:
+ return
- :param browse_record order: sale.order record to invoice
- :param list(int) lines: list of invoice line IDs that must be
- attached to the invoice
- :return: dict of value to create() the invoice
- """
- vals = super(sale_order, self)._prepare_invoice(cr, uid, order, lines, context=context)
- if order.shop_id.sale_journal:
- vals['journal_id'] = order.shop_id.sale_journal.id
- vals['shop_id'] = order.shop_id.id
- return vals
+ view_xmlid = ('sale', 'view_order_form')
+ if parent.state in ('draft', 'sent', 'cancel'):
+ action_xmlid = ('sale', 'action_quotations')
+ else:
+ action_xmlid = ('sale', 'action_orders')
- def _prepare_order_picking(self, cr, uid, order, context=None):
- vals = super(sale_order, self)._prepare_order_picking(cr, uid, order, context=context)
- vals['shop_id'] = order.shop_id.id
- return vals
+ 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]
- def oe_update(self, cr, uid, external_session, existing_rec_id, vals, resource, defaults, context=None):
- '''Not implemented in this abstract module, if it's not implemented in your module it will raise an error'''
- # Explication :
- # sometime customer can do ugly thing like renamming a sale_order and try to reimported it,
- # sometime openerp run two scheduler at the same time, or the customer launch two openerp at the same time
- # or the external system give us again an already imported order
- # As the update of an existing order (this is not the update of the status but the update of the line, the address...)
- # is not supported by connector_ecommerce and also not in magentoerpconnect.
- # It's better to don't allow this feature to avoid hidding a problem.
- # It's better to have the order not imported and to know it than having order with duplicated line.
- if not (context and context.get('oe_update_supported', False)):
- #TODO found a clean solution to raise the except_osv error in the try except of the function import_with_try
- raise except_osv(_("Not Implemented"), _(("The order with the id %s try to be updated from the external system."
- " This feature is not supported. Maybe the import try to reimport an existing sale order"%(existing_rec_id,))))
- return super(sale_order, self).oe_update(cr, uid, external_session, existing_rec_id, vals, resource, defaults, context=context)
+ ref = mod_obj.get_object_reference(cr, uid, *view_xmlid)
+ action['views'] = [(ref[1] if ref else False, 'form')]
+ action['res_id'] = parent.id
+ return action
+ # XXX the 3 next methods seems very specific to magento
def _convert_special_fields(self, cr, uid, vals, order_lines, context=None):
- """
- Convert the special 'fake' field into an order line
- special field are :
+ """ 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 dict vals : values of the sale order to create
- :param int referential_id : external referential id
+ :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
"""
+ shipping_fields = ['shipping_amount_tax_excluded',
+ 'shipping_amount_tax_included',
+ 'shipping_tax_amount']
+
def check_key(keys):
- return len(set([
- 'shipping_amount_tax_excluded',
- 'shipping_amount_tax_included',
- 'shipping_tax_amount'])
- & set(keys)) >= 2
+ return len(set(shipping_fields) & set(keys)) >= 2
+
vals.setdefault('order_line', [])
for line in order_lines:
- for field in ['shipping_amount_tax_excluded','shipping_amount_tax_included', 'shipping_tax_amount']:
+ for field in shipping_fields:
if field in line[2]:
vals[field] = vals.get(field, 0.0) + line[2][field]
del line[2][field]
@@ -831,151 +320,79 @@ def check_key(keys):
vals['shipping_amount_tax_excluded'] = vals['shipping_amount_tax_included'] - vals['shipping_tax_amount']
elif not 'shipping_tax_amount' in vals:
vals['shipping_tax_amount'] = vals['shipping_amount_tax_included'] - vals['shipping_amount_tax_excluded']
- vals['shipping_tax_rate'] = vals['shipping_amount_tax_excluded'] and \
- vals['shipping_tax_amount'] / vals['shipping_amount_tax_excluded'] or 0
+ if vals['shipping_amount_tax_excluded']:
+ vals['shipping_tax_rate'] = vals['shipping_tax_amount'] / vals['shipping_amount_tax_excluded']
+ 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)
+ vals = self._add_order_extra_line(cr, uid, vals,
+ option, context=context)
return vals
-
def _get_special_fields(self, cr, uid, context=None):
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'),
+ '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'),
+ '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'),
},
{
- 'price_unit_tax_excluded' : 'gift_certificates_amount', #gift certificate doesn't have any tax
- 'price_unit_tax_included' : 'gift_certificates_amount',
- 'product_ref' : ('connector_ecommerce', 'product_product_gift'),
+ #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,
},
]
- def _add_order_extra_line(self, cr, uid, vals, option, context):
- """ 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...
+ def _add_order_extra_line(self, cr, uid, vals, option, context=None):
+ """ 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: dictionnary of option for the special field to process
+ :param option: dictionary of options for the special field to process
"""
- if context is None: context={}
+ if context is None:
+ context = {}
sign = option.get('sign', 1)
- if context.get('is_tax_included') and vals.get(option['price_unit_tax_included']):
+ 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:
- for key in ['price_unit_tax_excluded', 'price_unit_tax_included', 'tax_rate_field']:
+ 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 not price, we have nothing to import
+ return vals # if there is no price, we have nothing to import
model_data_obj = self.pool.get('ir.model.data')
- model, product_id = model_data_obj.get_object_reference(cr, uid, *option['product_ref'])
- product = self.pool.get('product.product').browse(cr, uid, product_id, context)
+ 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 = {
- 'product_id': product.id,
- 'name': product.name,
- 'product_uom': product.uom_id.id,
- 'product_uom_qty': 1,
- 'price_unit': price_unit,
- }
+ extra_line = {'product_id': product.id,
+ 'name': product.name,
+ 'product_uom': product.uom_id.id,
+ 'product_uom_qty': 1,
+ 'price_unit': price_unit}
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])
+ extra_line['name'] = "%s [%s]" % (extra_line['name'],
+ vals[ext_code_field])
vals['order_line'].append((0, 0, extra_line))
return vals
-
-class sale_order_line(Model):
- _inherit='sale.order.line'
-
- _columns = {
- 'ext_product_ref': fields.char('Product Ext Ref',
- help="This is the original external product reference", size=256),
- # FIXME WTF are these 3 fields
- 'shipping_tax_amount': fields.dummy(string = 'Shipping Taxe Amount'),
- 'shipping_amount_tax_excluded': fields.dummy(string = 'Shipping Price Tax Exclude'),
- 'shipping_amount_tax_included': fields.dummy(string = 'Shipping Price Tax Include'),
- 'ext_ref_line': fields.char('Ext. Ref Line', size=64,
- help='Unique order line id delivered by external application'),
- }
-
- def _get_params_product_id_change(self, cr, uid, line, parent_data, previous_lines, context=None):
- args = [
- None,
- parent_data.get('pricelist_id'),
- line.get('product_id')
- ]
- kwargs ={
- 'qty': float(line.get('product_uom_qty')),
- 'uom': line.get('product_uom'),
- 'qty_uos': float(line.get('product_uos_qty') or line.get('product_uom_qty')),
- 'uos': line.get('product_uos'),
- 'name': line.get('name'),
- 'partner_id': parent_data.get('partner_id'),
- 'lang': False,
- 'update_tax': True,
- 'date_order': parent_data.get('date_order'),
- 'packaging': line.get('product_packaging'),
- 'fiscal_position': parent_data.get('fiscal_position'),
- 'flag': False,
- 'context': context,
- }
- return args, kwargs
-
- # XXX what is the added value of those 'play' onchanges?
- def play_sale_order_line_onchange(self, cr, uid, line, parent_data, previous_lines, defaults=None, context=None):
- original_line = line.copy()
- if not context.get('use_external_tax') and 'tax_id' in line:
- del line['tax_id']
- line = self.call_onchange(cr, uid, 'product_id_change', line, defaults=defaults, parent_data=parent_data, previous_lines=previous_lines, context=context)
- #TODO all m2m should be mapped correctly
- if context.get('use_external_tax'):
- #if we use the external tax and the onchange have added a taxe,
- #them we remove it.
- #Indeed we have to make the difference between a real tax_id
- #imported and a default value set by the onchange
- if not 'tax_id' in original_line and 'tax_id' in line:
- del line['tax_id']
- elif line.get('tax_id'):
- line['tax_id'] = [(6, 0, line['tax_id'])]
- return line
-
- def _transform_one_resource(self, cr, uid, external_session, convertion_type, resource, mapping, mapping_id,
- mapping_line_filter_ids=None, parent_data=None, previous_result=None, defaults=None, context=None):
- if context is None: context={}
- line = super(sale_order_line, self)._transform_one_resource(cr, uid, external_session, convertion_type, resource,
- mapping, mapping_id, mapping_line_filter_ids=mapping_line_filter_ids, parent_data=parent_data,
- previous_result=previous_result, defaults=defaults, context=context)
-
- if context.get('is_tax_included') and 'price_unit_tax_included' in line:
- line['price_unit'] = line['price_unit_tax_included']
- elif 'price_unit_tax_excluded' in line:
- line['price_unit'] = line['price_unit_tax_excluded']
-
- line = self.play_sale_order_line_onchange(cr, uid, line, parent_data, previous_result,
- defaults, context=context)
- if context.get('use_external_tax'):
- if not 'tax_id' in line and line.get('tax_rate'):
- line_tax_id = self.pool.get('account.tax').get_tax_from_rate(cr, uid, line['tax_rate'], context.get('is_tax_included', False), context=context)
- if not line_tax_id:
- raise except_osv(_('Error'), _('No tax id found for the rate %s with the tax include = %s')%(line['tax_rate'], context.get('is_tax_included')))
- line['tax_id'] = [(6, 0, [line_tax_id])]
- else:
- line['tax_id'] = False
- return line
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/connector_ecommerce/sale_view.xml b/connector_ecommerce/sale_view.xml
index 05e76e0b..2361f072 100644
--- a/connector_ecommerce/sale_view.xml
+++ b/connector_ecommerce/sale_view.xml
@@ -2,199 +2,62 @@
-
- connector_ecommerce_view_shop_form
- sale.shop
-
+
+ sale.order.connector.form
+ sale.order
+
-
-
-
-
-
-
-
+
+
+
+
+
-
- base_sale_multichannel_view_order_tree
+
+ sale_order.view_formsale.order
-
+
-
-
-
-
-
+
+
+
+
+
+
+
- base_sale_multichannel.view_sales_order_filter
+ sale.order.searchsale.order
-
-
-
-
-
-
+
+
+
+
-
- base_sale_multichannel_view_order_form
- sale.order
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- base_sale_multichannel_view_order_tree
- sale.order.line
-
-
-
-
-
-
-
-
-
-
-
- base_sale_multichannel_view_order_form
- sale.order.line
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- base.sale.external.shop.group.form
- external.shop.group
-
-
-
-
-
-
- base.sale.external.shop.group.tree
- external.shop.group
-
-
-
-
-
-
-
-
-
-
- External referential shop groups
- external.shop.group
- form
- tree,form
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/connector_ecommerce/security/ir.model.access.csv b/connector_ecommerce/security/ir.model.access.csv
index a1170aff..baefbbae 100755
--- a/connector_ecommerce/security/ir.model.access.csv
+++ b/connector_ecommerce/security/ir.model.access.csv
@@ -1,18 +1,3 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
-"access_connector_ecommerce_external_shop_group_manager","connector_ecommerce_external_shop_group","model_external_shop_group","base.group_sale_manager",1,1,1,1
-"access_connector_external_referential","connector_external_referential","connector.model_external_referential","base.group_sale_manager",1,1,1,1
-"access_connector_external_referential_type","connector_external_referential_type","connector.model_external_referential_type","base.group_sale_manager",1,1,1,1
-"access_connector_external_referential_version","connector_external_referential_version","connector.model_external_referential_version","base.group_sale_manager",1,1,1,1
-"access_connector_external_mapping_template","connector_external_mapping_template","connector.model_external_mapping_template","base.group_sale_manager",1,1,1,1
-"access_connector_external_mappinglines_template","connector_external_mappinglines_template","connector.model_external_mappinglines_template","base.group_sale_manager",1,1,1,1
-"access_connector_external_referential","connector_external_referential","connector.model_external_referential","base.group_sale_manager",1,1,1,1
-"access_connector_external_mapping_line","connector_external_mapping_line","connector.model_external_mapping_line","base.group_sale_manager",1,1,1,1
-"access_connector_external_mapping","connector_external_mapping","connector.model_external_mapping","base.group_sale_manager",1,1,1,1
-"access_connector_external_report","connector_external_report","connector.model_external_report","base.group_sale_manager",1,1,1,1
-"access_connector_external_report_history","connector_external_report_history","connector.model_external_report_history","base.group_sale_manager",1,1,1,1
-"access_connector_external_report_line","connector_external_report_line","connector.model_external_report_line","base.group_sale_manager",1,1,1,1
-"access_sale_sale_shop","sale_sale_shop","sale.model_sale_shop","base.group_sale_manager",1,1,1,1
-"access_connector_ecommerce_ir_model_data","connector_ecommerce_ir_model_data","base.model_ir_model_data","base.group_sale_manager",1,1,1,1
-"access_connector_ecommerce_external_shop_group","connector_ecommerce_external_shop_group","model_external_shop_group","base.group_user",1,0,0,0
"access_account_tax_group_user","Read-only access to account.tax.group","model_account_tax_group","base.group_user",1,0,0,0
"access_account_tax_group_account_manager","RW access to account.tax.group","model_account_tax_group","account.group_account_manager",1,1,1,1
diff --git a/connector_ecommerce/security/security.xml b/connector_ecommerce/security/security.xml
new file mode 100644
index 00000000..169f7d9b
--- /dev/null
+++ b/connector_ecommerce/security/security.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/connector_ecommerce/settings/external.referential.category.csv b/connector_ecommerce/settings/external.referential.category.csv
deleted file mode 100644
index fb399328..00000000
--- a/connector_ecommerce/settings/external.referential.category.csv
+++ /dev/null
@@ -1,2 +0,0 @@
-"id","name"
-"multichannels","Multichannel Sale"
diff --git a/connector_ecommerce/settings/sale.exception.csv b/connector_ecommerce/settings/sale.exception.csv
deleted file mode 100644
index 58491b7b..00000000
--- a/connector_ecommerce/settings/sale.exception.csv
+++ /dev/null
@@ -1,12 +0,0 @@
-id,name,description,sequence,model,code
-excep_wrong_total_amount,Total Amount differs from external system,"The amount computed doesn't match with the external amount because the taxes have not been configured properly (maybe some fiscal positions have changed the final price).
-Please fix it manually and check your taxes rules.
-
-NB : This check have being applied because you have checked the option \check total amount\"" on the shop of this sale order""",30,sale.order,"if order.shop_id.check_total_amount and abs(order.amount_total - order.ext_total_amount) >= 0.01:
- failed = True"
-excep_wrong_total_amount_tax,Total Tax Amount differs from external system,"The tax amount computed doesn't match with the external tax amount because the taxes have not been configured properly (maybe some fiscal positions have changed the final price).
-Please fix it manually and check your taxes rules.
-
-NB : This check have being applied because you have checked the option \check total amount\"" on the shop of this sale order""",30,sale.order,"#By default we allow a cent of difference for the taxe, feel free to customise it in your own module
-if order.shop_id.check_total_amount and abs(order.amount_tax - order.ext_total_amount_tax) > 0.01:
- failed = True"
diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py
index 7fc944ea..778dd491 100644
--- a/connector_ecommerce/stock.py
+++ b/connector_ecommerce/stock.py
@@ -22,8 +22,7 @@
from openerp.osv import orm, fields
from openerp.addons.connector.session import ConnectorSession
-from .event import on_picking_done, on_tracking_number_added
-
+from .event import on_picking_out_done, on_tracking_number_added
class stock_picking(orm.Model):
_inherit = 'stock.picking'
@@ -35,26 +34,33 @@ class stock_picking(orm.Model):
}
def action_done(self, cr, uid, ids, context=None):
- res = super(stock_picking, self).action_done(
- self, cr, uid, ids, context=context)
+ res = super(stock_picking, self).action_done(cr, uid,
+ ids, context=context)
session = ConnectorSession(cr, uid, context=context)
# Look if it exists a backorder, in that case call for partial
- picking_vals = self.read(cr, uid, ids,
- ['id', 'related_backorder_ids'],
+ picking_records = self.read(cr, uid, ids,
+ ['id', 'related_backorder_ids', 'type'],
context=context)
- for record_id, related_backorder_ids in picking_vals:
- if related_backorder_ids:
- picking_type = 'partial'
+ for picking_vals in picking_records:
+ if picking_vals['type'] != 'out':
+ continue
+ if picking_vals['related_backorder_ids']:
+ picking_method = 'partial'
else:
- picking_type = 'complete'
- on_picking_done.fire(session, self._name, record_id, picking_type)
+ picking_method = 'complete'
+ on_picking_out_done.fire(session, self._name,
+ picking_vals['id'], picking_method)
return res
+
+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, self).write(cr, uid, ids,
- vals, context=context)
+ res = super(stock_picking_out, 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 0701f37a..cc102b30 100644
--- a/connector_ecommerce/stock_view.xml
+++ b/connector_ecommerce/stock_view.xml
@@ -1,13 +1,16 @@
-
- stock.picking.out.form.ext
- stock.picking
+
+ stock.picking.out.connector.form
+ stock.picking.out
-
-
+
+
+
+
diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py
index be55a1ec..fa5323b6 100644
--- a/connector_ecommerce/unit/sale_order_onchange.py
+++ b/connector_ecommerce/unit/sale_order_onchange.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-###############################################################################
+##############################################################################
#
# connector-ecommerce for OpenERP
# Copyright (C) 2013-TODAY Akretion .
@@ -18,10 +18,11 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-###############################################################################
+##############################################################################
from openerp.addons.connector.connector import ConnectorUnit
+
class OnChangeManager(ConnectorUnit):
def merge_values(self, record, on_change_result):
vals = on_change_result.get('value', {})
@@ -57,6 +58,18 @@ def _get_shop_id_onchange_param(self, order):
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}
+ return args, kwargs
+
def _play_order_onchange(self, order):
""" Play the onchange of the sale order
@@ -75,12 +88,29 @@ def _play_order_onchange(self, order):
*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,
*args,
**kwargs)
self.merge_values(order, res)
+
+ # 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)
+
+ # 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
def _get_product_id_onchange_param(self, line, previous_lines, order):
@@ -189,4 +219,3 @@ def play(self, order, order_lines):
# in place modification of the sale order line in the list
line_list[idx] = new_line
return order
-
diff --git a/connector_ecommerce/wizard/__init__.py b/connector_ecommerce/wizard/__init__.py
index 6a92c0ab..f5c43f15 100644
--- a/connector_ecommerce/wizard/__init__.py
+++ b/connector_ecommerce/wizard/__init__.py
@@ -1,23 +1,3 @@
# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Base_sale_multichannels module for OpenERP
-# Copyright (C) 2010 Sébastien BEAU
-#
-# 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 import_order
+import sale_ignore_cancel
diff --git a/connector_ecommerce/wizard/import_order.xml b/connector_ecommerce/wizard/import_order.xml
deleted file mode 100644
index b5b53763..00000000
--- a/connector_ecommerce/wizard/import_order.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
- sale.order.import.wizard.view
- sale.order.import.wizard
-
-
-
-
-
-
- Import Order
- ir.actions.act_window
- sale.order.import.wizard
- form
- form
- new
- {}
-
-
-
- client_action_multi
- sale.shop
- Import Order
-
-
-
-
-
diff --git a/connector_ecommerce/wizard/import_order.py b/connector_ecommerce/wizard/sale_ignore_cancel.py
similarity index 52%
rename from connector_ecommerce/wizard/import_order.py
rename to connector_ecommerce/wizard/sale_ignore_cancel.py
index 6f347781..aa57c9dd 100644
--- a/connector_ecommerce/wizard/import_order.py
+++ b/connector_ecommerce/wizard/sale_ignore_cancel.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Base_sale_multichannels module for OpenERP
-# Copyright (C) 2010 Sébastien BEAU
+# Author: Guewen Baconnier
+# Copyright 2013 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,24 +19,28 @@
#
##############################################################################
+from openerp.osv import orm, fields
-from osv import fields,osv
-from tools.translate import _
-from openerp.addons.connector.external_osv import ExternalSession
-class sale_order_import_wizard(osv.osv_memory):
- _name = 'sale.order.import.wizard'
- _description = 'sale order import wizard'
+class sale_ignore_cancel(orm.TransientModel):
+ _name = 'sale.ignore.cancel'
+ _description = 'Ignore Sales Order Cancel'
_columns = {
- 'order_number': fields.char('Order Number', size=64),
- }
+ 'reason': fields.html('Reason', required=True),
+ }
- def import_order(self, cr, uid, ids, context=None):
+ def confirm_ignore_cancel(self, cr, uid, ids, context=None):
if context is None:
- context={}
- shop = self.pool.get('sale.shop').browse(cr, uid, context['active_id'], context=context)
- external_session = ExternalSession(shop.referential_id, shop)
- wizard = self.browse(cr, uid, ids[0], context=context)
- self.pool.get('sale.order')._import_one_resource(cr, uid, external_session, wizard.order_number, context=context)
+ 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)
return {'type': 'ir.actions.act_window_close'}
diff --git a/connector_ecommerce/wizard/sale_ignore_cancel_view.xml b/connector_ecommerce/wizard/sale_ignore_cancel_view.xml
new file mode 100644
index 00000000..2688c491
--- /dev/null
+++ b/connector_ecommerce/wizard/sale_ignore_cancel_view.xml
@@ -0,0 +1,43 @@
+
+
+
+
+ Sale Ignore Cancel
+ sale.ignore.cancel
+
+
+
+
+
+
+ Ignore the cancellation on the Backend
+ ir.actions.act_window
+ sale.ignore.cancel
+ form
+ form
+
+ new
+
+
+
From fdcf3af57cb57fe0ee4fdf5caceeb362148c7638 Mon Sep 17 00:00:00 2001
From: Brendan Clune
Date: Fri, 14 Jun 2013 15:04:00 +0200
Subject: [PATCH 14/86] [ADD] 'Authorized' import rules to be able to import
sales orders authorized by a payment institute but not paid yet.
---
connector_ecommerce/payment_method.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/connector_ecommerce/payment_method.py b/connector_ecommerce/payment_method.py
index 555e7beb..a1e5173f 100644
--- a/connector_ecommerce/payment_method.py
+++ b/connector_ecommerce/payment_method.py
@@ -29,6 +29,7 @@ def _get_import_rules(self, cr, uid, context=None):
return [('always', 'Always'),
('never', 'Never'),
('paid', 'Paid'),
+ ('authorized', 'Authorized'),
]
_columns = {
From 1e51403ad99dede41764f9a74308f32e8ba50228 Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Tue, 25 Jun 2013 17:04:52 +0200
Subject: [PATCH 15/86] [REF] started to use ConnectorUnit classes to add extra
lines in sale orders (shipping, ...), need a refactoring of the Mapper
though. WIP
---
connector_ecommerce/sale.py | 71 +++++++++++++++++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py
index d7f1394a..b9dcf15f 100644
--- a/connector_ecommerce/sale.py
+++ b/connector_ecommerce/sale.py
@@ -24,6 +24,7 @@
from openerp.osv import orm, fields, osv
from openerp.tools.translate import _
from openerp import netsvc
+from openerp.addons.connector.connector import ConnectorUnit
class sale_shop(orm.Model):
@@ -396,3 +397,73 @@ def _add_order_extra_line(self, cr, uid, vals, option, context=None):
vals[ext_code_field])
vals['order_line'].append((0, 0, extra_line))
return vals
+
+
+class ExtraOrderLineBuilder(ConnectorUnit):
+ """ Base class to build a sale order line for a sale order
+
+ Used when extra order lines have to be added in a sale order
+ but we only know some parameters (product, price, ...), for instance,
+ a line for the shipping costs or the gift coupons.
+
+ It can be subclassed to customize the way the lines are created.
+ """
+ _model_name = None
+
+ def __init__(self, environment):
+ super(ExtraOrderLineCreator, self).__init__(environment)
+ self.product_ref = None # tuple (module, xmlid)
+ self.price_unit = None
+ self.quantity = 1
+ self.sign = 1
+
+ def get_line(self):
+ assert self.product_ref
+ assert self.price_unit is not None
+ line = {}
+
+ 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, *self.product_ref)
+ product = product_obj.browse(cr, uid, product_id, context=context)
+
+ return {'product_id': product.id,
+ 'name': product.name,
+ 'product_uom': product.uom_id.id,
+ 'product_uom_qty': self.quantity,
+ 'price_unit': self.price_unit * self.sign}
+
+
+class ShippingLineBuilder(ExtraOrderLineBuilder):
+ _model_name = None
+
+ def __init__(self, environment):
+ super(ShippingLineBuilder, self).__init__(environment)
+ self.product_ref = ('connector_ecommerce', 'product_product_shipping')
+
+
+class CashOnDeliveryLineBuilder(ExtraOrderLineBuilder):
+ _model_name = None
+
+ def __init__(self, environment):
+ super(CashOnDeliveryLineBuilder, self).__init__(environment)
+ self.product_ref = ('connector_ecommerce',
+ 'product_product_cash_on_delivery')
+
+
+class GiftOrderLineBuilder(ExtraOrderLineBuilder):
+ _model_name = None
+
+ def __init__(self, environment):
+ super(GiftOrderLineBuilder, self).__init__(environment)
+ self.product_ref = ('connector_ecommerce',
+ 'product_product_gift')
+ self.sign = -1
+ self.gift_code = None
+
+ def get_line(self):
+ line = super(GiftOrderLineBuilder, self).get_line()
+ if self.gift_code:
+ line['name'] = "%s [%s]" % (line['name'], self.gift_code)
+ return line
From 43f31dcb278e8a5a8146629ff4e6b137aeabee22 Mon Sep 17 00:00:00 2001
From: Arthur Vuillard
Date: Thu, 27 Jun 2013 16:17:50 +0200
Subject: [PATCH 16/86] Fix a bug : remove special fields before database
storage (avoid to try to store non existing fields in db)
---
connector_ecommerce/sale.py | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py
index b9dcf15f..e1e6f56f 100644
--- a/connector_ecommerce/sale.py
+++ b/connector_ecommerce/sale.py
@@ -372,13 +372,7 @@ def _add_order_extra_line(self, cr, uid, vals, option, context=None):
elif vals.get(option['price_unit_tax_excluded']):
price_unit = vals.pop(option['price_unit_tax_excluded']) * sign
else:
- 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
-
+ 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(
From c230e777dc0dfe189eeb557bb51bc37693776ffc Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Fri, 5 Jul 2013 11:40:28 +0200
Subject: [PATCH 17/86] [DEL] remove old stuff
---
connector_ecommerce/old_stuff.py | 1119 -------------------------
connector_ecommerce/old_xml_stuff.xml | 23 -
2 files changed, 1142 deletions(-)
delete mode 100644 connector_ecommerce/old_stuff.py
delete mode 100644 connector_ecommerce/old_xml_stuff.xml
diff --git a/connector_ecommerce/old_stuff.py b/connector_ecommerce/old_stuff.py
deleted file mode 100644
index 7fe067d4..00000000
--- a/connector_ecommerce/old_stuff.py
+++ /dev/null
@@ -1,1119 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2009 Akretion (). All Rights Reserved
-# authors: Raphaël Valyi, Sharoon Thomas
-# Copyright (C) 2010-2013 Akretion Sébastien BEAU
-# Copyright 2011-2013 Camptocamp SA
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-# moved from sale.py ##################
-
-from openerp.osv.orm import Model
-from openerp.osv import fields
-from openerp.osv.osv import except_osv
-from openerp import pooler
-from sets import Set as set
-from openerp import netsvc
-from openerp.tools.translate import _
-import time
-import openerp.addons.decimal_precision as dp
-from datetime import datetime, timedelta
-from dateutil.relativedelta import relativedelta
-from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
-from openerp.addons.connector.external_osv import ExternalSession
-from openerp.addons.connector.decorator import open_report
-from openerp.addons.connector.decorator import catch_error_in_report
-
-import logging
-_logger = logging.getLogger(__name__)
-
-
-
-class external_shop_group(Model):
- _name = 'external.shop.group'
- _description = 'External Referential Shop Group'
-
- _columns = {
- 'name': fields.char('Name', size=64, required=True),
- 'referential_id': fields.many2one('external.referential', 'Referential', select=True,
- ondelete='cascade'),
- 'shop_ids': fields.one2many('sale.shop', 'shop_group_id', 'Sale Shops'),
- }
-
- # xxx move to BaseConnector _get_import_defaults_external_shop_group
- def _get_default_import_values(self, cr, uid, external_session, **kwargs):
- return {'referential_id' : external_session.referential_id.id}
-
-
-class external_referential(Model):
- _inherit = 'external.referential'
-
- _columns = {
- 'shop_group_ids': fields.one2many('external.shop.group', 'referential_id', 'Sub Entities'),
- }
-
-
-
-class ExternalShippingCreateError(Exception):
- """
- This error has to be raised when we tried to create a stock.picking on
- the external referential and the external referential has failed
- to create it. It must be raised only when we are SURE that the
- external referential will never be able to create it!
- """
- pass
-
-
-
-class sale_shop(Model):
- _inherit = "sale.shop"
-
- def _get_exportable_category_ids(self, cr, uid, ids, name, args, context=None):
- res = {}
- for shop in self.browse(cr, uid, ids, context=context):
- res[shop.id] = set()
- for category in shop.exportable_root_category_ids:
- res[shop.id] = res[shop.id].union(set(self.pool.get('product.category')._get_recursive_children_ids(cr, uid, [category.id], "", [], context)[category.id]))
- res[shop.id] = list(res[shop.id])
- return res
-
- def _get_exportable_product_ids(self, cr, uid, ids, name, args, context=None):
- res = {}
- for shop in self.read(cr, uid, ids, ['exportable_category_ids'], context=context):
- all_categories = shop['exportable_category_ids']
-
- # If product_m2mcategories module is installed search in main category
- # and extra categories. If not, only in main category
- cr.execute('select * from ir_module_module where name=%s and state=%s',
- ('product_m2mcategories','installed'))
- if cr.fetchone():
- res[shop['id']] = self.pool.get("product.product").search(cr, uid, ['|',
- ('categ_id', 'in', all_categories),('categ_ids', 'in', all_categories)])
- else:
- res[shop['id']] = self.pool.get("product.product").search(cr, uid,
- [('categ_id', 'in', all_categories)])
- return res
-
- def _get_referential_id(self, cr, uid, ids, name, args, context=None):
- res = {}
- for shop in self.browse(cr, uid, ids, context=context):
- if shop.shop_group_id:
- res[shop.id] = shop.shop_group_id.referential_id.id
- else:
- res[shop.id] = shop.referential_integer_id
- return res
-
- def _get_shop_from_shop_group(self, cr, uid, ids, context=None):
- return self.pool.get('sale.shop').search(cr, uid, [('shop_group_id', 'in', ids)], context=context)
-
- def _set_referential_id(self, cr, uid, id, name, value, arg, context=None):
- shop = self.browse(cr, uid, id, context=context)
- if shop.shop_group_id:
- raise except_osv(_("User Error"), _("You can not change the referential of this shop, please change the referential of the shop group!"))
- else:
- self.write(cr, uid, id, {'referential_integer_id': value}, context=context)
- return True
-
- def _get_shop_ids(self, cr, uid, ids, context=None):
- shop_ids=[]
- for group in self.pool.get('external.shop.group').browse(cr, uid, ids, context=context):
- shop_ids += [shop.id for shop in group.shop_ids]
- return shop_ids
-
- def _get_stock_field_id(self, cr, uid, context=None):
- if self.pool.get('ir.module.module').search(cr, uid, [
- ['name', '=', 'stock_available_immediately'],
- ['state', 'in', ['installed', 'to upgrade']],
- ], context=context):
- stock_field = 'immediately_usable_qty'
- else:
- stock_field = 'virtual_available'
-
- field_ids = self.pool.get('ir.model.fields').search(
- cr, uid,
- [('model', '=', 'product.product'),
- ('name', '=', stock_field)],
- context=context)
- return field_ids[0]
-
- #Depending of the e-commerce solution use you can have one or more root category
- #If you need only one the value will be stored in the exportable_root_category_ids fields
- def _get_rootcategory(self, cr, uid, ids, name, value, context=None):
- res = {}
- for shop in self.browse(cr, uid, ids, context):
- res[shop.id] = shop.exportable_root_category_ids and shop.exportable_root_category_ids[0].id or False
- return res
-
- def _set_rootcategory(self, cr, uid, id, name, value, fnct_inv_arg, context=None):
- return self.write(cr, uid, id, {'exportable_root_category_ids': [(6,0,[value])]}, context=context)
-
- def _get_referential_type_name(self, cr, uid, ids, field_name, arg, context=None):
- result = {}
- for shop in self.browse(cr, uid, ids):
- if shop.referential_id:
- result[shop.id] = shop.referential_id.type_id.name
- else:
- result[shop.id] = False
- return result
-
- _columns = {
- 'exportable_category_ids': fields.function(_get_exportable_category_ids, type='many2many', relation="product.category", string='Exportable Categories'),
- 'exportable_root_category_ids': fields.many2many('product.category', 'shop_category_rel', 'categ_id', 'shop_id', 'Exportable Root Categories'),
- 'exportable_root_category_id':fields.function(_get_rootcategory, fnct_inv = _set_rootcategory, type="many2one", relation="product.category", string="Root Category"),
- 'exportable_product_ids': fields.function(_get_exportable_product_ids, type='many2many', relation="product.product", string='Exportable Products'),
- 'shop_group_id': fields.many2one('external.shop.group', 'Shop Group', ondelete='cascade'),
- # to remove?
- 'last_inventory_export_date': fields.datetime('Last Inventory Export Time'),
- # to remove
- 'last_images_export_date': fields.datetime('Last Images Export Time'),
- # to remove
- 'last_update_order_export_date' : fields.datetime('Last Order Update Time'),
- # to remove
- 'last_products_export_date' : fields.datetime('Last Product Export Time'),
- # to remove
- 'last_special_products_export_date' : fields.datetime('Last Special Product Export Time'),
- # to remove
- 'last_category_export_date' : fields.datetime('Last Category Export Time'),
- 'referential_id': fields.function(
- _get_referential_id,
- fnct_inv=_set_referential_id,
- type='many2one',
- relation='external.referential',
- string='External Referential',
- store={
- 'sale.shop': (
- lambda self, cr, uid, ids, c=None: ids,
- ['referential_integer_id', 'shop_group_id'],
- 10),
- 'external.shop.group': (
- _get_shop_from_shop_group,
- ['referential_id'],
- 20),
- }),
- # wat?
- 'referential_integer_id': fields.integer('Referential Integer ID'),
- 'is_tax_included': fields.boolean(
- 'Prices Include Tax',
- help="Does the external system work with Taxes Inclusive prices ?"),
- 'sale_journal': fields.many2one('account.journal', 'Sale Journal'),
- 'order_prefix': fields.char('Order Prefix', size=64),
- 'default_payment_method_id': fields.many2one('payment.method', 'Payment Method'),
- 'default_language': fields.many2one('res.lang', 'Default Language'),
- 'default_fiscal_position': fields.many2one('account.fiscal.position', 'Default Fiscal Position'),
- 'default_customer_account': fields.many2one('account.account', 'Default Customer Account'),
- 'default_customer_lang': fields.many2one('res.lang', 'Default Customer Language'),
- 'auto_import': fields.boolean('Automatic Import'),
- # 'address_id':fields.many2one('res.partner.address', 'Address'),
- # TODO migrate from address to partner?
- 'partner_id':fields.many2one('res.partner', 'Partner'),
- 'website': fields.char('Website', size=64),
- 'image':fields.binary('Image', filters='*.png,*.jpg,*.gif'),
- # to remove? (always computed by openerp)
- 'use_external_tax': fields.boolean(
- 'Use External Taxes',
- help="If activated, the external taxes will be applied.\n"
- "If not activated, OpenERP will compute them "
- "according to default values and fiscal positions."),
- 'import_orders_from_date': fields.datetime('Only created after'),
- # to remove? always check
- 'check_total_amount': fields.boolean('Check Total Amount', help="The total amount computed by OpenERP should match with the external amount, if not the sale order can not be confirmed."),
- # to remove
- 'type_name': fields.function(_get_referential_type_name, type='char', string='Referential type',
- store={
- 'sale.shop': (lambda self, cr, uid, ids, c={}: ids, ['referential_id', 'shop_group_id'],10)}),
- 'product_stock_field_id': fields.many2one(
- 'ir.model.fields',
- string='Stock Field',
- domain="[('model', 'in', ['product.product', 'product.template']),"
- " ('ttype', '=', 'float')]",
- help="Choose the field of the product which will be used for "
- "stock inventory updates.\nIf empty, Quantity Available "
- "is used"),
- }
-
- _defaults = {
- # FIXME, WTF with that default value
- 'payment_default_id': 1, #required field that would cause trouble if not set when importing
- 'auto_import': True,
- 'use_external_tax': True,
- 'product_stock_field_id': _get_stock_field_id,
- }
-
- def init_context_before_exporting_resource(self, cr, uid, external_session, object_id, resource_name, context=None):
- context = super(sale_shop, self).init_context_before_exporting_resource(cr, uid, external_session, object_id, resource_name, context=context)
- context['pricelist'] = external_session.sync_from_object.get_pricelist(context=context)
- return context
-
- def get_pricelist(self, cr, uid, id, context=None):
- if isinstance(id, list):
- id=id[0]
- shop = self.browse(cr, uid, id, context=context)
- if shop.pricelist_id:
- return shop.pricelist_id.id
- else:
- return self.pool.get('product.pricelist').search(cr, uid, [('type', '=', 'sale'), ('active', '=', True)], context=context)[0]
-
- def export_catalog(self, cr, uid, ids, context=None):
- if context is None: context={}
- self.export_resources(cr, uid, ids, 'product.category', context=context)
- # In various e-commerce system product can depend of other products
- # So the simple product (with no dependency) are exported in priority
- # Then the special product (with dependency) are exported at the end
- context['export_product'] = 'simple'
- self.export_resources(cr, uid, ids, 'product.product', context=context)
- context['export_product'] = 'special'
- self.export_resources(cr, uid, ids, 'product.product', context=context)
- #Export Images
- self.export_resources(cr, uid, ids, 'product.images', context=context)
-
- #TODO export link
- #TODO update the last date
- #I don't know where it's the best to update it here or in the export functions
- #take care about concurent write with different cursor
-
-
- return True
-
- def export_inventory(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
- for shop in self.browse(cr, uid, ids):
- external_session = ExternalSession(shop.referential_id, shop)
- self._export_inventory(cr, uid, external_session, ids, context=context)
- return True
-
- def _get_product_ids_for_stock_to_export(self, cr, uid, shop, context=None):
- return [product.id for product in shop.exportable_product_ids]
-
- def _export_inventory(self, cr, uid, external_session, ids, context=None):
- shop = external_session.sync_from_object
- stock_move_obj = self.pool.get('stock.move')
- for shop in self.browse(cr, uid, ids):
- external_session = ExternalSession(shop.referential_id, shop)
-
- product_ids = self._get_product_ids_for_stock_to_export(cr, uid, shop, context=context)
-
- if shop.last_inventory_export_date:
- # we do not exclude canceled moves because it means
- # some stock levels could have increased since last export
- recent_move_ids = stock_move_obj.search(
- cr, uid,
- [('write_date', '>', shop.last_inventory_export_date),
- ('product_id', 'in', product_ids),
- ('product_id.type', '!=', 'service'),
- ('state', '!=', 'draft')],
- context=context)
- else:
- recent_move_ids = stock_move_obj.search(
- cr, uid,
- [('product_id', 'in', product_ids)],
- context=context)
-
- recent_moves = stock_move_obj.browse(
- cr, uid, recent_move_ids, context=context)
-
- product_ids = [move.product_id.id
- for move
- in recent_moves
- if move.product_id.state != 'obsolete']
- product_ids = list(set(product_ids))
- external_session.logger.info('Export Stock for %s products' %len(product_ids))
- self.pool.get('product.product').export_inventory(
- cr, uid, external_session, product_ids, context=context)
- shop.write({'last_inventory_export_date':
- time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
- return True
-
- def import_catalog(self, cr, uid, ids, context):
- #TODO import categories, then products
- raise except_osv(_("Not Implemented"), _("Not Implemented in abstract base module!"))
-
- def import_orders(self, cr, uid, ids, context=None):
- self.import_resources(cr, uid, ids, 'sale.order', context=context)
- return True
-
- def check_need_to_update(self, cr, uid, ids, context=None):
- """ This function will update the order status in OpenERP for
- the order which are in the state 'need to update' """
- for shop in self.browse(cr, uid, ids, context=context):
- external_session = ExternalSession(shop.referential_id, shop)
- so_obj = self.pool.get('sale.order')
- orders_to_update = so_obj.search(cr, uid,
- [('need_to_update', '=', True),
- ('shop_id', '=', shop.id)],
- context=context)
- so_obj._check_need_to_update(cr, uid, external_session, orders_to_update, context=context)
- return False
-
- def _update_order_query(self, cr, uid, shop, context=None):
- req = """
- SELECT ir_model_data.res_id, ir_model_data.name
- FROM sale_order
- INNER JOIN ir_model_data ON sale_order.id = ir_model_data.res_id
- WHERE ir_model_data.model='sale.order' AND sale_order.shop_id=%s
- AND ir_model_data.referential_id NOTNULL
- """
- params = (shop.id,)
- if shop.last_update_order_export_date:
- req += "AND sale_order.update_state_date > %s"
- params = (shop.id, shop.last_update_order_export_date)
- return req, params
-
- def update_orders(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
- for shop in self.browse(cr, uid, ids):
- external_session = ExternalSession(shop.referential_id, shop)
- #get all orders, which the state is not draft and the date of modification is superior to the last update, to exports
- cr.execute(*self._update_order_query(cr, uid, shop, context=context))
- results = cr.fetchall()
- for result in results:
- ids = self.pool.get('sale.order').search(cr, uid, [('id', '=', result[0])])
- if ids:
- id = ids[0]
- order = self.pool.get('sale.order').browse(cr, uid, id, context)
- order_ext_id = result[1].split('sale_order/')[1]
- res = self.update_shop_orders(cr, uid, external_session, order, order_ext_id, context)
- if res:
- external_session.logger.info(_("Successfully updated order with OpenERP id %s and ext id %s in external sale system") % (id, order_ext_id))
- self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_update_order_export_date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
- return False
-
- def export_shop_partners(self, cr, uid, ids, context=None):
- if context is None: context={}
- self.export_resources(cr, uid, ids, 'res.partner', context=context)
- return True
-
- def update_shop_orders(self, cr, uid, external_session, order, ext_id, context):
- raise except_osv(_("Not Implemented"), _("Not Implemented in abstract base module!"))
-
- def _export_shipping_query(self, cr, uid, shop, context=None):
- query = """
- SELECT stock_picking.id AS picking_id,
- sale_order.id AS order_id,
- count(pickings.id) AS picking_number
- FROM stock_picking
- LEFT JOIN sale_order
- ON sale_order.id = stock_picking.sale_id
- LEFT JOIN stock_picking as pickings
- ON (sale_order.id = pickings.sale_id
- AND pickings.type='out'
- AND pickings.state!='cancel')
- LEFT JOIN ir_model_data
- ON stock_picking.id = ir_model_data.res_id
- AND ir_model_data.model = 'stock.picking'
- LEFT JOIN delivery_carrier
- ON delivery_carrier.id = stock_picking.carrier_id
- WHERE sale_order.shop_id = %(shop_id)s
- AND ir_model_data.res_id ISNULL
- AND stock_picking.state = 'done'
- AND stock_picking.type = 'out'
- AND NOT stock_picking.do_not_export
- AND (NOT delivery_carrier.export_needs_tracking
- OR stock_picking.carrier_tracking_ref IS NOT NULL)
- GROUP BY stock_picking.id,
- sale_order.id,
- delivery_carrier.export_needs_tracking,
- stock_picking.carrier_tracking_ref,
- stock_picking.backorder_id
- ORDER BY sale_order.id ASC,
- COALESCE(stock_picking.backorder_id, NULL, 0) ASC"""
- params = {'shop_id': shop.id}
- return query, params
-
- def export_shipping(self, cr, uid, ids, context):
- picking_obj = self.pool.get('stock.picking')
- for shop in self.browse(cr, uid, ids):
- cr.execute(*self._export_shipping_query(
- cr, uid, shop, context=context))
- results = cr.dictfetchall()
- if not results:
- _logger.info("There is no shipping to export for the shop '%s' to the external referential", shop.name)
- continue
- context['conn_obj'] = shop.referential_id.external_connection()
-
-
- picking_cr = pooler.get_db(cr.dbname).cursor()
- try:
- for result in results:
- picking_id = result['picking_id']
-
- if result["picking_number"] == 1:
- picking_type = 'complete'
- else:
- picking_type = 'partial'
-
- ext_shipping_id = False
- try:
- ext_shipping_id = picking_obj.create_ext_shipping(
- picking_cr, uid, picking_id, picking_type,
- shop.referential_id.id, context)
- except ExternalShippingCreateError, e:
- # when the creation has failed on the external
- # referential and we know that we can never
- # create it, we flag it as do_not_export
- # ExternalShippingCreateError raising has to be
- # correctly handled by create_ext_shipping()
- picking_obj.write(
- picking_cr, uid,
- picking_id,
- {'do_not_export': True},
- context=context)
-
- if ext_shipping_id:
- picking_obj.create_external_id_vals(
- picking_cr,
- uid,
- picking_id,
- ext_shipping_id,
- shop.referential_id.id,
- context=context)
- _logger.info("Successfully creating shipping with OpenERP id %s and ext id %s in external sale system", result["picking_id"], ext_shipping_id)
- picking_cr.commit()
- finally:
- picking_cr.close()
- return True
-
- def export_invoices(self, cr, uid, ids, context=None):
- invoice_obj = self.pool.get('account.invoice')
- for shop in self.browse(cr, uid, ids, context=None):
- external_session = ExternalSession(shop.referential_id, shop)
- invoice_ids = self.get_invoice_to_export(cr, uid, shop.id, context=context)
- if not invoice_ids:
- external_session.logger.info("There is no invoice to export for the shop '%s' to the external referential" % (shop.name,))
- for invoice_id in invoice_ids:
- self.pool.get('account.invoice')._export_one_resource(cr, uid, external_session, invoice_id, context=context)
- return True
-
- def get_invoice_to_export(self, cr, uid, shop_id, context=None):
- shop = self.browse(cr, uid, shop_id, context=context)
- cr.execute(*self._export_invoice_query(cr, uid, shop, context=context))
- results = cr.dictfetchall()
- return [res['invoice_id'] for res in results]
-
- def _export_invoice_query(self, cr, uid, shop, context=None):
- query = """
- SELECT account_invoice.id AS invoice_id
- FROM account_invoice
- LEFT JOIN ir_model_data
- ON account_invoice.id = ir_model_data.res_id
- AND ir_model_data.model = 'account.invoice'
- AND referential_id = %(referential_id)s
- WHERE shop_id = %(shop_id)s
- AND ir_model_data.res_id ISNULL
- AND account_invoice.state in ('paid', 'open')
- AND NOT account_invoice.do_not_export
- """
- params = {'shop_id': shop.id, 'referential_id': shop.referential_id.id}
- return query, params
-
-sale_shop()
-
-
-class sale_order(Model):
- _inherit = "sale.order"
-
- _columns = {
- # to remove? will the orders be created as draft when they
- # wait a payment or are they not imported at all? (the job
- # retries at intervals)
- 'need_to_update': fields.boolean('Need To Update'),
- 'ext_total_amount': fields.float(
- 'Origin External Amount',
- digits_compute=dp.get_precision('Sale Price'),
- readonly=True),
- 'ext_total_amount_tax': fields.float(
- 'Origin External Tax Amount',
- digits_compute=dp.get_precision('Sale Price'),
- readonly=True),
- 'referential_id': fields.related(
- 'shop_id',
- 'referential_id',
- type='many2one',
- relation='external.referential',
- string='External Referential'),
- 'update_state_date': fields.datetime('Update State Date'),
- # FIXME WTF are these 3 fields
- 'shipping_tax_amount': fields.dummy(string = 'Shipping Taxe Amount'),
- 'shipping_amount_tax_excluded': fields.dummy(string = 'Shipping Price Tax Exclude'),
- 'shipping_amount_tax_included': fields.dummy(string = 'Shipping Price Tax Include'),
- }
-
- _defaults = {
- 'need_to_update': False,
- }
-
- def write(self, cr, uid, ids, vals, context=None):
- if 'state' in vals:
- vals['update_state_date'] = datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT)
- return super(sale_order, self).write(cr, uid, ids, vals, context=context)
-
- # xxx move to BaseConnector _get_import_defaults_sale_order
- def _get_default_import_values(self, cr, uid, external_session, mapping_id=None, defaults=None, context=None):
- shop = False
- if external_session.sync_from_object._name == 'sale.shop':
- shop = external_session.sync_from_object
- elif context.get('sale_shop_id'):
- shop = self.pool.get('sale.shop').browse(cr, uid, context['sale_shop_id'], context=context)
- if shop:
- if defaults is None: defaults = {}
- defaults.update({
- 'pricelist_id': shop.get_pricelist(context=context),
- 'shop_id': shop.id,
- 'fiscal_position': shop.default_fiscal_position.id,
- 'payment_method_id': shop.default_payment_method_id.id,
- 'company_id': shop.company_id.id,
- })
- #TODO we should avoid passing this parameter in the context
- #for now we new it for importing order from wizard correctly
- #refactor for V7
- context.update({
- 'use_external_tax': shop.use_external_tax,
- 'is_tax_included': shop.is_tax_included,
- })
- return defaults
-
- @open_report
- def _import_resources(self, cr, uid, external_session, defaults=None, method="search_then_read", context=None):
- if context is None: context={}
- shop = external_session.sync_from_object
- if shop:
- context.update({
- 'use_external_tax': shop.use_external_tax,
- 'is_tax_included': shop.is_tax_included,
- })
- return super(sale_order, self)._import_resources(cr, uid, external_session, defaults=defaults, method=method, context=context)
-
-
- def check_if_order_exist(self, cr, uid, external_session, resource, order_mapping=None, defaults=None, context=None):
- mapping_name = False
- for line in order_mapping['mapping_lines']:
- if line['internal_field'] == 'name':
- mapping_name = line
- if mapping_name:
- local_mapping = {1: {'mapping_lines': [mapping_name]}}
- vals = self._transform_one_resource(cr, uid, external_session,
- 'from_external_to_openerp', resource,
- mapping=local_mapping,
- mapping_id=1,
- defaults=defaults,
- context=context)
- if vals.get('name'):
- exist_id = self.search(cr, uid, [['name', '=', vals['name']]], context=context)
- if exist_id:
- external_session.logger.info("Sale Order %s already exist in OpenERP,"
- "no need to import it again"%vals['name'])
- return True
-
- return False
-
- # xxx a deplacer dans BaseConnector sale_order
- @catch_error_in_report
- def _record_one_external_resource(self, cr, uid, external_session, resource, defaults=None,
- mapping=None, mapping_id=None, context=None):
- mapping, mapping_id = self._init_mapping(cr, uid, external_session.referential_id.id,
- mapping=mapping, mapping_id=mapping_id, context=context)
- exist_id = self.check_if_order_exist(cr, uid, external_session, resource,
- order_mapping=mapping[mapping_id], defaults=defaults, context=context)
- if exist_id:
- return {}
- else:
- return super(sale_order, self)._record_one_external_resource(cr, uid, external_session, resource,
- defaults=defaults, mapping=mapping, mapping_id=mapping_id, context=context)
-
- def _check_need_to_update(self, cr, uid, external_session, ids, context=None):
- """
- For each order, check in external system if it has been paid since last
- check. If so, it will launch the defined flow based on the
- payment type (validate order, invoice, ...)
- """
- for order in self.browse(cr, uid, ids, context=context):
- self._check_need_to_update_single(cr, uid, external_session, order, context=context)
- return True
-
- def _check_need_to_update_single(self, cr, uid, external_session, order, context=None):
- """Not implemented in this abstract module"""
- return True
-
- def _get_params_onchange_partner_id(self, cr, uid, vals, context=None):
- args = [
- 'None',
- vals.get('partner_id'),
- ]
- return args, {}
-
- #I will probably extract this code in order to put it in a "glue" module
- def _get_params_onchange_address_id(self, cr, uid, vals, context=None):
- args = [
- None,
- vals.get('partner_invoice_id'),
- vals.get('partner_shipping_id'),
- vals.get('partner_id'),
- ]
- kwargs = {
- 'shop_id': vals.get('shop_id'),
- }
- return args, kwargs
-
- def play_sale_order_onchange(self, cr, uid, vals, defaults=None, context=None):
- ir_module_obj= self.pool.get('ir.module.module')
- if ir_module_obj.search(cr, uid, [
- ['name', '=', 'account_fiscal_position_rule_sale'],
- ['state', 'in', ['installed', 'to upgrade']],
- ], context=context):
- vals = self.call_onchange(cr, uid, 'onchange_partner_id', vals, defaults, context=context)
- vals = self.call_onchange(cr, uid, 'onchange_address_id', vals, defaults, context=context)
- else:
- vals = self.call_onchange(cr, uid, 'onchange_partner_id', vals, defaults, context=context)
-
-
- return vals
-
- def _merge_with_default_values(self, cr, uid, external_session, ressource, vals, sub_mapping_list, defaults=None, context=None):
- if vals.get('name'):
- shop = external_session.sync_from_object
- if shop.order_prefix:
- vals['name'] = '%s%s' %(shop.order_prefix, vals['name'])
- if context is None: context ={}
- if vals.get('payment_method_id'):
- payment_method = self.pool.get('payment.method').browse(cr, uid, vals['payment_method_id'], context=context)
- workflow_process = payment_method.workflow_process_id
- if workflow_process:
- vals['order_policy'] = workflow_process.order_policy
- vals['picking_policy'] = workflow_process.picking_policy
- vals['invoice_quantity'] = workflow_process.invoice_quantity
- # update vals with order onchange in order to compute taxes
- vals = self.play_sale_order_onchange(cr, uid, vals, defaults=defaults, context=context)
- return super(sale_order, self)._merge_with_default_values(cr, uid, external_session, ressource, vals, sub_mapping_list, defaults=defaults, context=context)
-
- def oe_create(self, cr, uid, external_session, vals, resource, defaults, context):
- #depending of the external system the contact address can be optionnal
- vals = self._convert_special_fields(cr, uid, vals, vals['order_line'], context=context)
- if not vals.get('partner_order_id'):
- vals['partner_order_id'] = vals['partner_invoice_id']
- if not vals.get('partner_shipping_id'):
- vals['partner_shipping_id'] = vals['partner_invoice_id']
- order_id = super(sale_order, self).oe_create(cr, uid, external_session, vals, resource, defaults, context)
- self.paid_and_update(cr, uid, external_session, order_id, resource, context=context)
- return order_id
-
- def paid_and_update(self, cr, uid, external_session, order_id, resource, context=None):
- wf_service = netsvc.LocalService("workflow")
- paid = self.create_external_payment(cr, uid, external_session, order_id, resource, context)
- order = self.browse(cr, uid, order_id, context=context)
- validate_order = order.workflow_process_id.validate_order
- if validate_order == 'always' or validate_order == 'if_paid' and paid:
- try:
- wf_service.trg_validate(uid, 'sale.order', order.id, 'order_confirm', cr)
- except:
- raise
- #What we should do?? creating the order but not validating it???
- #Maybe setting a special flag can be a good solution? with a retry method?
- return True
-
- elif validate_order == 'if_paid' and order.payment_method_id.automatic_update:
- days_before_order_cancel = order.workflow_process_id.days_before_order_cancel or 30
- order_date = datetime.strptime(order.date_order, DEFAULT_SERVER_DATE_FORMAT)
- order_cancel_date = order_date + relativedelta(days=days_before_order_cancel)
- if order.state == 'draft' and order_cancel_date < datetime.now():
- wf_service.trg_validate(uid, 'sale.order', order.id, 'cancel', cr)
- self.write(cr, uid, order.id, {'need_to_update': False})
- self.log(cr, uid, order.id, ("order %s canceled in OpenERP because older than % days"
- "and still not confirmed") % (order.id, days_before_order_cancel))
- #TODO eventually call a trigger to cancel the order in the external system too
- external_session.logger.info(("order %s canceled in OpenERP because older than % days and "
- "still not confirmed") %(order.id, days_before_order_cancel))
- else:
- self.write(cr, uid, order_id, {'need_to_update': True}, context=context)
- return False
-
- def create_external_payment(self, cr, uid, external_session, order_id, resource, context):
- """
- Fonction that will create a payment from the external resource
- """
- vals = self._get_payment_information(cr, uid, external_session, order_id, resource, context=context)
- if vals.get('paid'):
- if not vals.get('journal_id'):
- external_session.logger.warning(_("Not journal found for payment method %s. Can not create payment")%vals['payment_method'])
- vals['paid'] = False
- else:
- self.pay_sale_order(cr, uid, order_id, vals['journal_id'], vals['amount'], vals['date'], context=context)
- return vals.get('paid')
-
- def _get_payment_information(self, cr, uid, external_session, order_id, resource, context=None):
- """
- Function that will return the information in order to create the payment
- """
- vals = {}
- sale = self.browse(cr, uid, order_id, context=context)
- vals['payment_method'] = sale.payment_method_id.name
- vals['journal_id'] = sale.payment_method_id.journal_id and sale.payment_method_id.journal_id.id
- vals['date'] = sale.date_order
- return vals
-
- def _prepare_invoice(self, cr, uid, order, lines, context=None):
- """Prepare the dict of values to create the new invoice for a
- sale order. This method may be overridden to implement custom
- invoice generation (making sure to call super() to establish
- a clean extension chain).
-
- :param browse_record order: sale.order record to invoice
- :param list(int) lines: list of invoice line IDs that must be
- attached to the invoice
- :return: dict of value to create() the invoice
- """
- vals = super(sale_order, self)._prepare_invoice(cr, uid, order, lines, context=context)
- if order.shop_id.sale_journal:
- vals['journal_id'] = order.shop_id.sale_journal.id
- vals['shop_id'] = order.shop_id.id
- return vals
-
- def _prepare_order_picking(self, cr, uid, order, context=None):
- vals = super(sale_order, self)._prepare_order_picking(cr, uid, order, context=context)
- vals['shop_id'] = order.shop_id.id
- return vals
-
- def oe_update(self, cr, uid, external_session, existing_rec_id, vals, resource, defaults, context=None):
- '''Not implemented in this abstract module, if it's not implemented in your module it will raise an error'''
- # Explication :
- # sometime customer can do ugly thing like renamming a sale_order and try to reimported it,
- # sometime openerp run two scheduler at the same time, or the customer launch two openerp at the same time
- # or the external system give us again an already imported order
- # As the update of an existing order (this is not the update of the status but the update of the line, the address...)
- # is not supported by connector_ecommerce and also not in magentoerpconnect.
- # It's better to don't allow this feature to avoid hidding a problem.
- # It's better to have the order not imported and to know it than having order with duplicated line.
- if not (context and context.get('oe_update_supported', False)):
- #TODO found a clean solution to raise the except_osv error in the try except of the function import_with_try
- raise except_osv(_("Not Implemented"), _(("The order with the id %s try to be updated from the external system."
- " This feature is not supported. Maybe the import try to reimport an existing sale order"%(existing_rec_id,))))
- return super(sale_order, self).oe_update(cr, uid, external_session, existing_rec_id, vals, resource, defaults, context=context)
-
-
-
-
-class sale_order_line(Model):
- _inherit='sale.order.line'
-
- _columns = {
- 'ext_product_ref': fields.char('Product Ext Ref',
- help="This is the original external product reference", size=256),
- # FIXME WTF are these 3 fields
- 'shipping_tax_amount': fields.dummy(string = 'Shipping Taxe Amount'),
- 'shipping_amount_tax_excluded': fields.dummy(string = 'Shipping Price Tax Exclude'),
- 'shipping_amount_tax_included': fields.dummy(string = 'Shipping Price Tax Include'),
- 'ext_ref_line': fields.char('Ext. Ref Line', size=64,
- help='Unique order line id delivered by external application'),
- }
-
- def _get_params_product_id_change(self, cr, uid, line, parent_data, previous_lines, context=None):
- args = [
- None,
- parent_data.get('pricelist_id'),
- line.get('product_id')
- ]
- kwargs ={
- 'qty': float(line.get('product_uom_qty')),
- 'uom': line.get('product_uom'),
- 'qty_uos': float(line.get('product_uos_qty') or line.get('product_uom_qty')),
- 'uos': line.get('product_uos'),
- 'name': line.get('name'),
- 'partner_id': parent_data.get('partner_id'),
- 'lang': False,
- 'update_tax': True,
- 'date_order': parent_data.get('date_order'),
- 'packaging': line.get('product_packaging'),
- 'fiscal_position': parent_data.get('fiscal_position'),
- 'flag': False,
- 'context': context,
- }
- return args, kwargs
-
- # XXX what is the added value of those 'play' onchanges?
- def play_sale_order_line_onchange(self, cr, uid, line, parent_data, previous_lines, defaults=None, context=None):
- original_line = line.copy()
- if not context.get('use_external_tax') and 'tax_id' in line:
- del line['tax_id']
- line = self.call_onchange(cr, uid, 'product_id_change', line, defaults=defaults, parent_data=parent_data, previous_lines=previous_lines, context=context)
- #TODO all m2m should be mapped correctly
- if context.get('use_external_tax'):
- #if we use the external tax and the onchange have added a taxe,
- #them we remove it.
- #Indeed we have to make the difference between a real tax_id
- #imported and a default value set by the onchange
- if not 'tax_id' in original_line and 'tax_id' in line:
- del line['tax_id']
- elif line.get('tax_id'):
- line['tax_id'] = [(6, 0, line['tax_id'])]
- return line
-
- def _transform_one_resource(self, cr, uid, external_session, convertion_type, resource, mapping, mapping_id,
- mapping_line_filter_ids=None, parent_data=None, previous_result=None, defaults=None, context=None):
- if context is None: context={}
- line = super(sale_order_line, self)._transform_one_resource(cr, uid, external_session, convertion_type, resource,
- mapping, mapping_id, mapping_line_filter_ids=mapping_line_filter_ids, parent_data=parent_data,
- previous_result=previous_result, defaults=defaults, context=context)
-
- if context.get('is_tax_included') and 'price_unit_tax_included' in line:
- line['price_unit'] = line['price_unit_tax_included']
- elif 'price_unit_tax_excluded' in line:
- line['price_unit'] = line['price_unit_tax_excluded']
-
- line = self.play_sale_order_line_onchange(cr, uid, line, parent_data, previous_result,
- defaults, context=context)
- if context.get('use_external_tax'):
- if not 'tax_id' in line and line.get('tax_rate'):
- line_tax_id = self.pool.get('account.tax').get_tax_from_rate(cr, uid, line['tax_rate'], context.get('is_tax_included', False), context=context)
- if not line_tax_id:
- raise except_osv(_('Error'), _('No tax id found for the rate %s with the tax include = %s')%(line['tax_rate'], context.get('is_tax_included')))
- line['tax_id'] = [(6, 0, [line_tax_id])]
- else:
- line['tax_id'] = False
- return line
-
-
-# moved from partner.py ###############
-
-from openerp.osv import orm, fields
-
-
-class res_partner(orm.Model):
- _inherit = 'res.partner'
-
- _columns = {
- 'shop_ids': fields.many2many(
- 'sale.shop',
- 'sale_shop_res_partner_rel',
- 'shop_id',
- 'partner_id',
- string='Present in Shops',
- readonly=True,
- help="List of shops in which this customer exists."),
- }
-
- # xxx move to BaseConnector _get_import_defaults_res_partner
- def _get_default_import_values(self, cr, uid, external_session, mapping_id=None, defaults=None, context=None):
- if external_session.sync_from_object._name == 'sale.shop':
- shop = external_session.sync_from_object
- if not defaults: defaults = {}
- defaults.update({
- 'lang': shop.default_customer_lang.code,
- 'property_account_position': shop.default_fiscal_position.id,
- 'property_account_receivable': shop.default_customer_account,
- 'shop_ids': [(4, shop.id)],
- })
- return defaults
-
-
-# moved from product.py #################
-
-
-
-from openerp.osv.orm import Model
-from openerp.osv import fields
-
-from openerp.addons.connector.decorator import only_for_referential
-from openerp.addons.connector.decorator import commit_now
-
-class product_product(Model):
- _inherit='product.product'
-
- def _check_if_export(self, cr, uid, external_session, product, context=None):
- if context.get('export_product') == 'simple':
- return True
- return False
-
- @only_for_referential(ref_categ ='Multichannel Sale')
- def _get_last_exported_date(self, cr, uid, external_session, context=None):
- shop = external_session.sync_from_object
- if context.get('export_product') == 'simple':
- return shop.last_products_export_date
- elif context.get('export_product') == 'special':
- return shop.last_special_products_export_date
- return False
-
- @only_for_referential(ref_categ ='Multichannel Sale')
- @commit_now
- def _set_last_exported_date(self, cr, uid, external_session, date, context=None):
- shop = external_session.sync_from_object
- if context.get('export_product') == 'simple':
- return self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_products_export_date': date}, context=context)
- elif context.get('export_product') == 'special':
- return self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_special_products_export_date': date}, context=context)
-
- @only_for_referential(ref_categ ='Multichannel Sale')
- def get_ids_and_update_date(self, cr, uid, external_session, ids=None, last_exported_date=None, context=None):
- res = (), {} # list of ids, dict of ids to date_changed
- shop = external_session.sync_from_object
- if shop.exportable_product_ids:
- product_ids = [product.id for product in shop.exportable_product_ids if self._check_if_export(cr, uid, external_session, product, context=context)]
- if ids:
- product_ids = set(ids).intersection(set(product_ids))
- if product_ids:
- res = super(product_product, self).get_ids_and_update_date(cr, uid, external_session,
- ids=product_ids,
- last_exported_date=last_exported_date,
- context=context)
- return res
-
-
- def _get_categories_ids_for_shop(self, cr, uid, product_id, shop_id, context=None):
- shop_categ_ids = self.pool.get('sale.shop').read(cr, uid, shop_id,
- ['exportable_category_ids'],
- context=context)['exportable_category_ids']
- product = self.read(cr, uid, product_id, ['categ_ids', 'categ_id'], context=context)
- product_categ_ids = product['categ_ids']
- if product['categ_id'][0] not in product_categ_ids:
- product_categ_ids.append(product['categ_id'][0])
- res = []
- for categ in product_categ_ids:
- if categ in shop_categ_ids:
- res.append(categ)
- return res
-
- def _get_categories_ids_for_shop(self, cr, uid, product_id, shop_id, context=None):
- shop_obj = self.pool.get('sale.shop')
- shop_values = shop_obj.read(cr, uid, shop_id,
- ['exportable_category_ids'],
- context=context)
- shop_categ_ids = set(shop_values['exportable_category_ids'])
- product = self.read(cr, uid, product_id, ['categ_ids', 'categ_id'], context=context)
- product_categ_ids = set(product['categ_ids'])
- product_categ_ids.add(product['categ_id'][0])
- return list(prod_categ_ids & shop_categ_ids)
-
- def _get_or_create_ext_category_ids_for_shop(self, cr, uid, external_session, product_id, context=None):
- res = []
- categ_obj = self.pool.get('product.category')
- for oe_categ_id in self._get_categories_ids_for_shop(cr, uid, product_id, external_session.sync_from_object.id, context=context):
- res.append(categ_obj.get_or_create_extid(cr, uid, external_session, oe_categ_id, context=context))
- return res
-
-
-class product_category(Model):
- _inherit = "product.category"
-
- def collect_children(self, category, children=None):
- if children is None:
- children = []
-
- for child in category.child_id:
- children.append(child.id)
- self.collect_children(child, children)
-
- return children
-
- def _get_recursive_children_ids(self, cr, uid, ids, name, args, context=None):
- res = {}
- for category in self.browse(cr, uid, ids):
- res[category.id] = self.collect_children(category, [category.id])
- return res
-
- _columns = {
- 'recursive_children_ids': fields.function(_get_recursive_children_ids, method=True, type='one2many', relation="product.category", string='All Child Categories'),
- }
-
- @only_for_referential(ref_categ ='Multichannel Sale')
- def _get_last_exported_date(self, cr, uid, external_session, context=None):
- shop = external_session.sync_from_object
- return shop.last_category_export_date
-
- @only_for_referential(ref_categ ='Multichannel Sale')
- @commit_now
- def _set_last_exported_date(self, cr, uid, external_session, date, context=None):
- shop = external_session.sync_from_object
- return self.pool.get('sale.shop').write(cr, uid, shop.id, {'last_category_export_date': date}, context=context)
-
- def get_ids_and_update_date(self, cr, uid, external_session, ids=None, last_exported_date=None, context=None):
- shop = external_session.sync_from_object
- if shop.exportable_category_ids:
- res = super(product_category, self).get_ids_and_update_date(cr, uid, external_session,
- ids=[categ.id for categ in shop.exportable_category_ids],
- last_exported_date=last_exported_date,
- context=context)
- else:
- res = (), {} # list of ids, dict of ids to date_changed
- return res
-
-
-# moved from external_referential.py #########
-
-
-from openerp.osv import orm, fields
-
-
-class external_referential(orm.Model):
- _inherit = "external.referential"
-
- _columns = {
- 'last_imported_product_id': fields.integer(
- 'Last Imported Product Id',
- help="Product are imported one by one. "
- "This is the magento id of the last product imported. "
- "If you clear it all product will be imported"),
- # TODO replace by last import date (at website level)
- 'last_imported_partner_id': fields.integer(
- 'Last Imported Partner Id',
- help="Partners are imported one by one. "
- "This is the magento id of the last partner imported. "
- "If you clear it all partners will be imported"),
- 'import_all_attributs': fields.boolean(
- 'Import all attributs',
- help="If the option is uncheck only the attributs "
- "that doesn't exist in OpenERP will be imported "),
- 'import_image_with_product': fields.boolean(
- 'With image',
- help="If the option is check the product's image and "
- "the product will be imported at the same time and"
- "so the step '7-import images' is not needed"),
- 'import_links_with_product': fields.boolean(
- 'With links',
- help="If the option is check the product's links "
- "(Up-Sell, Cross-Sell, Related) and the product will "
- "be imported at the same time and so the step "
- "'8-import links' is not needed"),
- }
-
- def import_customer_groups(self, cr, uid, ids, context=None):
- self.import_resources(cr, uid, ids, 'res.partner.category', context=context)
- return True
-
- def import_product_categories(self, cr, uid, ids, context=None):
- self.import_resources(cr, uid, ids, 'product.category', context=context)
- return True
-
- def import_customers(self, cr, uid, ids, context=None):
- self.import_resources(cr, uid, ids, 'res.partner', context=context)
- return True
-
-# def import_product_attributes_sets(self, cr, uid, ids, context=None):
-# return self.import_resources(cr, uid, ids, 'TODO', context=context)
-#
-# def import_product_attributes_groups(self, cr, uid, ids, context=None):
-# return self.import_resources(cr, uid, ids, 'TODO', context=context)
-#
-# def import_product_attributes(self, cr, uid, ids, context=None):
-# return self.import_resources(cr, uid, ids, 'TODO', context=context)
-
- def import_products(self, cr, uid, ids, context=None):
- self.import_resources(cr, uid, ids, 'product.product', context=context)
- return True
-
- def import_product_links(self, cr, uid, ids, context=None):
- self.import_resources(cr, uid, ids, 'product.link', context=context)
- return True
diff --git a/connector_ecommerce/old_xml_stuff.xml b/connector_ecommerce/old_xml_stuff.xml
deleted file mode 100644
index decc57e0..00000000
--- a/connector_ecommerce/old_xml_stuff.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
- shop_ids.partner.form
- res.partner
-
-
-
-
-
-
-
-
-
-
-
-
-
-
From 902e5e9f020e2920c0152befecc10045a69bd9e3 Mon Sep 17 00:00:00 2001
From: Mathieu VATEL
Date: Mon, 15 Jul 2013 15:31:08 +0200
Subject: [PATCH 18/86] [IMP] - make possible to inherit the method
_add_order_extra_line (done for prestashoperpconnect in a first place to be
able to add or not the tax on delivery lines)
---
connector_ecommerce/sale.py | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py
index e1e6f56f..f382ba3b 100644
--- a/connector_ecommerce/sale.py
+++ b/connector_ecommerce/sale.py
@@ -355,6 +355,16 @@ def _get_special_fields(self, cr, uid, context=None):
},
]
+ def _get_order_extra_line_vals(self, cr, uid,
+ vals, option, product, price_unit, context=None):
+ return {
+ 'product_id': product.id,
+ 'name': product.name,
+ 'product_uom': product.uom_id.id,
+ 'product_uom_qty': 1,
+ 'price_unit': price_unit
+ }
+
def _add_order_extra_line(self, cr, uid, vals, option, context=None):
""" Add or substract amount on order as a separate line item
with single quantity for each type of amounts like: shipping,
@@ -379,11 +389,8 @@ def _add_order_extra_line(self, cr, uid, vals, option, context=None):
cr, uid, *option['product_ref'])
product = product_obj.browse(cr, uid, product_id, context=context)
- extra_line = {'product_id': product.id,
- 'name': product.name,
- 'product_uom': product.uom_id.id,
- 'product_uom_qty': 1,
- 'price_unit': price_unit}
+ 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):
From 58ff4c27b87500da13cf350c666a9429dbb36a2a Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Mon, 15 Jul 2013 16:29:14 +0200
Subject: [PATCH 19/86] [FIX] indentation according to pep8
---
connector_ecommerce/sale.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py
index f382ba3b..796e8bf8 100644
--- a/connector_ecommerce/sale.py
+++ b/connector_ecommerce/sale.py
@@ -355,8 +355,8 @@ def _get_special_fields(self, cr, uid, context=None):
},
]
- def _get_order_extra_line_vals(self, cr, uid,
- vals, option, product, price_unit, context=None):
+ def _get_order_extra_line_vals(self, cr, uid, vals, option, product,
+ price_unit, context=None):
return {
'product_id': product.id,
'name': product.name,
@@ -386,11 +386,11 @@ def _add_order_extra_line(self, cr, uid, vals, option, context=None):
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'])
+ 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)
+ 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):
From c542c2f068e230f1528dd9b2085b98f8aa87e820 Mon Sep 17 00:00:00 2001
From: Allison Miller
Date: Mon, 5 Aug 2013 08:18:10 -0400
Subject: [PATCH 20/86] Added "invoice validated" event and called upon
"on_invoice_validate".
---
connector_ecommerce/event.py | 11 +++++++++++
connector_ecommerce/invoice.py | 11 +++++++++--
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/connector_ecommerce/event.py b/connector_ecommerce/event.py
index 7a480284..5941d8b8 100644
--- a/connector_ecommerce/event.py
+++ b/connector_ecommerce/event.py
@@ -60,6 +60,17 @@
* record_id: id of the record
"""
+on_invoice_validated = Event()
+"""
+``on_invoice_validated`` is fired when an invoice has been validated.
+
+Listeners should take the following arguments:
+
+ * session: `connector.session.ConnectorSession` object
+ * model_name: name of the model
+ * record_id: id of the record
+"""
+
on_product_price_changed = Event()
"""
``on_product_price_changed`` is fired when the price of a product is
diff --git a/connector_ecommerce/invoice.py b/connector_ecommerce/invoice.py
index f7a1690a..abc3276e 100644
--- a/connector_ecommerce/invoice.py
+++ b/connector_ecommerce/invoice.py
@@ -22,8 +22,7 @@
from openerp.osv import fields, orm, osv
from openerp.tools.translate import _
from openerp.addons.connector.session import ConnectorSession
-from .event import on_invoice_paid
-
+from .event import on_invoice_paid, on_invoice_validated
class account_invoice(orm.Model):
_inherit='account.invoice'
@@ -45,3 +44,11 @@ def confirm_paid(self, cr, uid, ids, context=None):
for record_id in 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:
+ on_invoice_validated.fire(session, self._name, record_id)
+ return res
From 62cd2e57fe4a10f9c619b847c07faaddae749ba1 Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Mon, 5 Aug 2013 22:18:29 +0200
Subject: [PATCH 21/86] [FIX] the onchange test had a TypeError, now it fails
for some reason
[ADD] a test which check if on_invoice_validated is correctly fired
[ADD] test the fire of 'on_invoice_paid'
[FIX] formatting of the onchange test
[FIX] fix the failing test: the payment_method_id and workflow_payment_id are not mandatory in a sale order
[FIX] fr_FR.po files not loaded, should be named fr.po
[FIX] context not propagated
[ADD] docstring
[CHG] rename ExtraOrderLineBuilder to SpecialOrderLineBuilder
[FIX] use session
[ADD] deprecation warning
[IMP] allow to use a product id or a product browse_record in lines builders
[FIX] Sales Orders onchanges: allow to have lines with other commands than (0, 0, {values}).
[FIX] simplify last change
[FIX] in lines builders, product_ref is not mandatory if we provide a product, renames 'product_id' to 'product', keeping ambiguity as we can have an int or browse_record.
[IMP] propagate the 'shop_id' in the context if it exists so the fiscal position rules (from openerp-fiscal-rules' project) can apply automatically
[FIX] 'int' object is not iterable error
[FIX] 'int' object is not iterable error, again
---
connector_ecommerce/i18n/{fr_FR.po => fr.po} | 98 ++++++++++++-------
connector_ecommerce/invoice.py | 1 +
connector_ecommerce/product.py | 6 +-
connector_ecommerce/sale.py | 45 ++++++---
connector_ecommerce/tests/__init__.py | 2 +
.../tests/test_invoice_event.py | 97 ++++++++++++++++++
connector_ecommerce/tests/test_onchange.py | 66 +++++--------
.../unit/sale_order_onchange.py | 48 ++++-----
8 files changed, 257 insertions(+), 106 deletions(-)
rename connector_ecommerce/i18n/{fr_FR.po => fr.po} (82%)
create mode 100644 connector_ecommerce/tests/test_invoice_event.py
diff --git a/connector_ecommerce/i18n/fr_FR.po b/connector_ecommerce/i18n/fr.po
similarity index 82%
rename from connector_ecommerce/i18n/fr_FR.po
rename to connector_ecommerce/i18n/fr.po
index b26c268f..be4be82e 100644
--- a/connector_ecommerce/i18n/fr_FR.po
+++ b/connector_ecommerce/i18n/fr.po
@@ -6,14 +6,15 @@ msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-05-01 14:17+0000\n"
-"PO-Revision-Date: 2013-05-01 14:17+0000\n"
-"Last-Translator: <>\n"
+"POT-Creation-Date: 2013-05-01 14:34+0000\n"
+"PO-Revision-Date: 2014-01-14 09:42+0000\n"
+"Last-Translator: Guewen Baconnier @ Camptocamp \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: \n"
-"Plural-Forms: \n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-01-15 07:02+0000\n"
+"X-Generator: Launchpad (build 16890)\n"
#. module: connector_ecommerce
#: field:sale.order,cancellation_resolved:0
@@ -22,10 +23,13 @@ msgstr "Annulation depuis le backend résolue"
#. module: connector_ecommerce
#: model:sale.exception,description:connector_ecommerce.excep_product_has_checkpoint
-msgid "A product has been imported from a backend and needs to be reviewed.\n"
+msgid ""
+"A product has been imported from a backend and needs to be reviewed.\n"
"Go to Connectors > Checkpoint and review the new products."
-msgstr "Un article a été importé depuis un backend et nécessite un contrôle.\n"
-"Aller dans Connecteurs > Points de contrôle et vérifier les nouveaux articles."
+msgstr ""
+"Un article a été importé depuis un backend et nécessite un contrôle.\n"
+"Aller dans Connecteurs > Points de contrôle et vérifier les nouveaux "
+"articles."
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_account_invoice
@@ -54,28 +58,39 @@ msgstr "Uniquement les commandes annulées dans leur backend"
#. module: connector_ecommerce
#: model:sale.exception,description:connector_ecommerce.excep_parent_order_need_cancel
-msgid "The parent sales order has been canceled on the backend.\n"
-"You will not be able to process this sales order until the parent's one is canceled."
-msgstr "The commande parente a été annulée sur son backend.\n"
-"Impossible de confirmer ce devis tant que la commande parente n'est pas annulée."
+msgid ""
+"The parent sales order has been canceled on the backend.\n"
+"You will not be able to process this sales order until the parent's one is "
+"canceled."
+msgstr ""
+"The commande parente a été annulée sur son backend.\n"
+"Impossible de confirmer ce devis tant que la commande parente n'est pas "
+"annulée."
#. module: connector_ecommerce
#: view:payment.method:0
msgid "The sales orders using the payment method will always be imported."
-msgstr "Les commandes utilisant cette méthode de paiement seront toujours importées."
+msgstr ""
+"Les commandes utilisant cette méthode de paiement seront toujours importées."
#. module: connector_ecommerce
#: view:sale.ignore.cancel:0
-msgid "This sales order has been canceled from the backend.\n"
+msgid ""
+"This sales order has been canceled from the backend.\n"
" The usual action would be to cancel it in OpenERP along\n"
-" all the documents generated (delivery orders, invoices, ...)."
-msgstr "Cette commande a été annulée sur son backend.\n"
-" L'action standard est d'annuler la commande dans OpenERP ainsi\n"
-" que tous les documents qu'elle a générés (bons de livraison, factures, ...)."
+" all the documents generated (delivery orders, invoices, "
+"...)."
+msgstr ""
+"Cette commande a été annulée sur son backend.\n"
+" L'action standard est d'annuler la commande dans OpenERP "
+"ainsi\n"
+" que tous les documents qu'elle a générés (bons de "
+"livraison, factures, ...)."
#. module: connector_ecommerce
#: help:account.tax,group_id:0
-msgid "Choose the tax group. This is needed for example with magento or prestashop"
+msgid ""
+"Choose the tax group. This is needed for example with magento or prestashop"
msgstr "Choisir le groupe de taxes. Utilisé pour Magento ou Prestashop."
#. module: connector_ecommerce
@@ -138,7 +153,8 @@ msgstr "Jours avant annulation"
#. module: connector_ecommerce
#: view:payment.method:0
msgid "The sales orders using the payment method will never be imported."
-msgstr "Les commandes utilisant cette méthode de paiement ne seront jamais importées."
+msgstr ""
+"Les commandes utilisant cette méthode de paiement ne seront jamais importées."
#. module: connector_ecommerce
#: field:sale.ignore.cancel,reason:0
@@ -167,8 +183,11 @@ 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"
-msgstr "Les groupes de taxes sont utilisés avec des systèmes externes comme Magento ou Prestashop."
+msgid ""
+"Tax group 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."
#. module: connector_ecommerce
#: field:product.price.type,pricelist_item_ids:0
@@ -192,17 +211,24 @@ msgstr "Règle d'import"
#. module: connector_ecommerce
#: view:sale.ignore.cancel:0
-msgid "However, if for any reason you need to keep it open in OpenERP,\n"
+msgid ""
+"However, if for any reason you need to keep it open in OpenERP,\n"
" write the reason here and it will stay open."
-msgstr "Cependant, si pour une raison donnée vous devez la laisser ouverte dans OpenERP,\n"
+msgstr ""
+"Cependant, si pour une raison donnée vous devez la laisser ouverte dans "
+"OpenERP,\n"
" écrivez la raison ici et confirmez.."
#. module: connector_ecommerce
#: view:payment.method:0
-msgid "The sales orders using the payment method will be imported\n"
-" only when they receive a payment on the E-Commerce backend."
-msgstr "Les commandes utilisant cette méthode de paiement seront importées\n"
-" uniquement quand elles recevront un paiement sur leur backend e-commerce."
+msgid ""
+"The sales orders using the payment method will be imported\n"
+" only when they receive a payment on the E-"
+"Commerce backend."
+msgstr ""
+"Les commandes utilisant cette méthode de paiement seront importées\n"
+" uniquement quand elles recevront un paiement "
+"sur leur backend e-commerce."
#. module: connector_ecommerce
#: field:account.tax.group,tax_ids:0
@@ -221,8 +247,11 @@ 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 canceled."
-msgstr "Une commande parente a été annulée sur le backend et doit être annulée."
+msgid ""
+"A parent sales orders 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."
#. module: connector_ecommerce
#: field:account.tax,group_id:0
@@ -257,8 +286,12 @@ msgstr "Bon de commande"
#. 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."
-msgstr "Après \"n\" jours, si la règle d'import n'est pas satisfaite, l'import de la commande sera annulé."
+msgid ""
+"After 'n' days, if the 'Import Rule' is not fulfilled, the import of the "
+"sale 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é."
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_product_template
@@ -357,4 +390,3 @@ msgstr "Informations additionnelles"
#: model:ir.model,name:connector_ecommerce.model_product_price_type
msgid "Price Type"
msgstr "Type de prix"
-
diff --git a/connector_ecommerce/invoice.py b/connector_ecommerce/invoice.py
index abc3276e..2e1cb70a 100644
--- a/connector_ecommerce/invoice.py
+++ b/connector_ecommerce/invoice.py
@@ -24,6 +24,7 @@
from openerp.addons.connector.session import ConnectorSession
from .event import on_invoice_paid, on_invoice_validated
+
class account_invoice(orm.Model):
_inherit='account.invoice'
diff --git a/connector_ecommerce/product.py b/connector_ecommerce/product.py
index 9d68dceb..2460b35e 100644
--- a/connector_ecommerce/product.py
+++ b/connector_ecommerce/product.py
@@ -82,6 +82,8 @@ def _price_changed(self, cr, uid, ids, vals, context=None):
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)
@@ -134,6 +136,8 @@ def _price_changed(self, cr, uid, ids, vals, context=None):
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(
@@ -143,7 +147,7 @@ def write(self, cr, uid, ids, vals, context=None):
def create(self, cr, uid, vals, context=None):
product_ids = super(product_product, self).create(
- cr, uid, vals, context=None)
+ cr, uid, vals, context=context)
self._price_changed(cr, uid, [product_ids], vals, context=context)
return product_ids
diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py
index 796e8bf8..af40b034 100644
--- a/connector_ecommerce/sale.py
+++ b/connector_ecommerce/sale.py
@@ -21,11 +21,15 @@
#
##############################################################################
+import logging
+
from openerp.osv import orm, fields, osv
from openerp.tools.translate import _
from openerp import netsvc
from openerp.addons.connector.connector import ConnectorUnit
+_logger = logging.getLogger(__name__)
+
class sale_shop(orm.Model):
_inherit = 'sale.shop'
@@ -302,6 +306,9 @@ def _convert_special_fields(self, cr, uid, vals, order_lines, context=None):
: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']
@@ -400,7 +407,7 @@ def _add_order_extra_line(self, cr, uid, vals, option, context=None):
return vals
-class ExtraOrderLineBuilder(ConnectorUnit):
+class SpecialOrderLineBuilder(ConnectorUnit):
""" Base class to build a sale order line for a sale order
Used when extra order lines have to be added in a sale order
@@ -408,27 +415,40 @@ class ExtraOrderLineBuilder(ConnectorUnit):
a line for the shipping costs or the gift coupons.
It can be subclassed to customize the way the lines are created.
+
+ Usage::
+
+ builder = self.get_connector_for_unit(ShippingLineBuilder,
+ model='sale.order.line')
+ builder.price_unit = 100
+ builder.get_line()
+
"""
_model_name = None
def __init__(self, environment):
- super(ExtraOrderLineCreator, self).__init__(environment)
+ super(SpecialOrderLineBuilder, self).__init__(environment)
+ self.product = None # id or browse_record
+ # when no product_id, fallback to a product_ref
self.product_ref = None # tuple (module, xmlid)
self.price_unit = None
self.quantity = 1
self.sign = 1
def get_line(self):
- assert self.product_ref
+ assert self.product_ref or self.product
assert self.price_unit is not None
line = {}
+ session = self.session
- 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, *self.product_ref)
- product = product_obj.browse(cr, uid, product_id, context=context)
+ 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)
+ if not isinstance(product_id, orm.browse_record):
+ product = session.browse('product.product', product_id)
return {'product_id': product.id,
'name': product.name,
'product_uom': product.uom_id.id,
@@ -436,7 +456,8 @@ def get_line(self):
'price_unit': self.price_unit * self.sign}
-class ShippingLineBuilder(ExtraOrderLineBuilder):
+class ShippingLineBuilder(SpecialOrderLineBuilder):
+ """ Return values for a Shipping line """
_model_name = None
def __init__(self, environment):
@@ -444,7 +465,8 @@ def __init__(self, environment):
self.product_ref = ('connector_ecommerce', 'product_product_shipping')
-class CashOnDeliveryLineBuilder(ExtraOrderLineBuilder):
+class CashOnDeliveryLineBuilder(SpecialOrderLineBuilder):
+ """ Return values for a Cash on Delivery line """
_model_name = None
def __init__(self, environment):
@@ -453,7 +475,8 @@ def __init__(self, environment):
'product_product_cash_on_delivery')
-class GiftOrderLineBuilder(ExtraOrderLineBuilder):
+class GiftOrderLineBuilder(SpecialOrderLineBuilder):
+ """ Return values for a Gift line """
_model_name = None
def __init__(self, environment):
diff --git a/connector_ecommerce/tests/__init__.py b/connector_ecommerce/tests/__init__.py
index b1b37af5..fbfe23ee 100644
--- a/connector_ecommerce/tests/__init__.py
+++ b/connector_ecommerce/tests/__init__.py
@@ -20,11 +20,13 @@
##############################################################################
import test_onchange
+import test_invoice_event
fast_suite = [
]
checks = [
test_onchange,
+ test_invoice_event,
]
diff --git a/connector_ecommerce/tests/test_invoice_event.py b/connector_ecommerce/tests/test_invoice_event.py
new file mode 100644
index 00000000..2d8945a8
--- /dev/null
+++ b/connector_ecommerce/tests/test_invoice_event.py
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Author: Guewen Baconnier
+# Copyright 2013 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 unittest2
+import mock
+from functools import partial
+
+import openerp.tests.common as common
+from openerp import netsvc
+
+
+class test_invoice_event(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,
+ 'type': 'out_invoice',
+ 'invoice_line': [(0, 0, {'name': "LCD Screen",
+ 'product_id': product_id,
+ 'quantity': 5,
+ 'price_unit': 200})],
+ }
+ onchange_res = self.invoice_model.onchange_partner_id(
+ cr, uid, [], '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)
+
+ 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.assertEqual(self.invoice.state, 'open')
+ event_mock.fire.assert_called_with(mock.ANY,
+ 'account.invoice',
+ self.invoice.id)
+
+ 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.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]
+ 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,
+ 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',
+ self.invoice.id)
diff --git a/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py
index 1ec83bda..9f08aa45 100644
--- a/connector_ecommerce/tests/test_onchange.py
+++ b/connector_ecommerce/tests/test_onchange.py
@@ -20,13 +20,11 @@
#
###############################################################################
-
import unittest2
import mock
-from openerp.addons.connector.connector import ConnectorUnit
-from openerp.addons.connector_ecommerce.unit.sale_order_onchange import \
- SaleOrderOnChange
+from openerp.addons.connector_ecommerce.unit.sale_order_onchange import (
+ SaleOrderOnChange)
from openerp.addons.connector.session import ConnectorSession
from openerp.addons.connector.connector import Environment
import openerp.tests.common as common
@@ -36,50 +34,40 @@
class test_onchange(common.TransactionCase):
- """ Test the imports from a Magento-like Mock """
+ """ Test if the onchanges are applied correctly on a sale order"""
def setUp(self):
super(test_onchange, self).setUp()
self.session = ConnectorSession(self.cr, self.uid)
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
backend_record = mock.Mock()
env = Environment(backend_record, self.session, 'sale.order')
- partner_id = partner_model.create(self.cr, self.uid, {
- 'name': 'seb',
- 'zip': '69100',
- 'city': 'Villeurbanne',
- })
-
- partner_invoice_id = partner_model.create(self.cr, self.uid, {
- 'name': 'Guewen',
- 'zip': '1015',
- 'city': 'Lausanne',
- 'type': 'invoice',
- 'parent_id': partner_id,
- })
-
- tax_id = tax_model.create(self.cr, self.uid, {
- 'name': 'My Tax',
- })
-
- product_id = product_model.create(self.cr, self.uid, {
- 'default_code': 'MyCode',
- 'name': 'My Product',
- 'weight': 15,
- 'taxes_id': [(6, 0, [tax_id])],
- })
-
- shop_id = shop_model.create(self.cr, self.uid, {
- 'name': 'My shop',
- })
+ 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])]})
+ shop_id = shop_model.create(cr, uid, {'name': 'My shop'})
order_input = {
'shop_id': shop_id,
@@ -94,13 +82,13 @@ def test_play_onchange(self):
}),
]
}
-
+
onchange = SaleOrderOnChange(env)
- order = onchange.play(order_input)
-
+ order = onchange.play(order_input,
+ order_input['order_line'])
+
self.assertEqual(order['partner_invoice_id'], partner_invoice_id)
- line = order['order_line'][0][2]
+ 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)
-
diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py
index fa5323b6..79066d79 100644
--- a/connector_ecommerce/unit/sale_order_onchange.py
+++ b/connector_ecommerce/unit/sale_order_onchange.py
@@ -96,20 +96,22 @@ def _play_order_onchange(self, order):
**kwargs)
self.merge_values(order, res)
- # 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)
+ 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)
- # 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)
+ 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
@@ -197,7 +199,8 @@ def play(self, order, order_lines):
:rtype: dict
"""
#play onchange on sale order
- order = self._play_order_onchange(order)
+ with self.session.change_context(dict(shop_id=order.get('shop_id'))):
+ order = self._play_order_onchange(order)
#play onchanfe on sale order line
processed_order_lines = []
line_lists = [order_lines]
@@ -208,14 +211,15 @@ def play(self, order, order_lines):
# shipping fees with an OpenERP Product
line_lists.append(order['order_line'])
for line_list in line_lists:
- for idx, line in enumerate(line_list):
+ for idx, command_line in enumerate(line_list):
# line_list format:[(0, 0, {...}), (0, 0, {...})]
- old_line_data = line[2]
- new_line_data = self._play_line_onchange(old_line_data,
- processed_order_lines,
- order)
- new_line = (0, 0, new_line_data)
- processed_order_lines.append(new_line)
- # in place modification of the sale order line in the list
- line_list[idx] = new_line
+ if command_line[0] in (0, 1): # create or update values
+ # keeps command number and ID (or 0)
+ old_line_data = command_line[2]
+ new_line_data = self._play_line_onchange(
+ old_line_data, processed_order_lines, order)
+ new_line = (command_line[0], command_line[1], new_line_data)
+ processed_order_lines.append(new_line)
+ # in place modification of the sale order line in the list
+ line_list[idx] = new_line
return order
From 68cd0c129cf4b4a89aa81ebf0ba9bcd1cfb8e5d5 Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Wed, 15 Jan 2014 10:14:23 +0100
Subject: [PATCH 22/86] [BUMP] release 2.1.0
---
connector_ecommerce/__openerp__.py | 10 +-
connector_ecommerce/i18n/de.po | 393 +++++++++++++++++++++++++++++
connector_ecommerce/i18n/fr.po | 4 +-
3 files changed, 400 insertions(+), 7 deletions(-)
create mode 100644 connector_ecommerce/i18n/de.po
diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py
index 5690bc63..7c6670c2 100644
--- a/connector_ecommerce/__openerp__.py
+++ b/connector_ecommerce/__openerp__.py
@@ -20,10 +20,10 @@
##############################################################################
{'name': 'Connector for E-Commerce',
- 'version': '2.0.0',
+ 'version': '2.1.0',
'category': 'Connector',
- 'author': 'MagentoERPConnect Core Editors',
- 'website': 'http://www.magentoerpconnect.com',
+ 'author': 'Connector Core Editors',
+ 'website': 'http://openerp-connector.com',
'license': 'AGPL-3',
'description': """
Connector for E-Commerce
@@ -54,8 +54,8 @@
Add structures shared for e-commerce connectors
-.. _`connector`: https://code.launchpad.net/openerp-connector
-.. _`magentoerpconnect`: https://launchpad.net/magentoerpconnect
+ .. _`connector`: http://openerp-connector.com
+.. _`magentoerpconnect`: http://openerp-magento-connector.com
.. _`prestashoperpconnect`: https://launchpad.net/prestashoperpconnect
""",
'depends': [
diff --git a/connector_ecommerce/i18n/de.po b/connector_ecommerce/i18n/de.po
new file mode 100644
index 00000000..5bc384eb
--- /dev/null
+++ b/connector_ecommerce/i18n/de.po
@@ -0,0 +1,393 @@
+# German translation for openerp-connector-ecommerce
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the openerp-connector-ecommerce package.
+# FIRST AUTHOR , 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openerp-connector-ecommerce\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2013-05-01 14:34+0000\n"
+"PO-Revision-Date: 2014-01-24 09:54+0000\n"
+"Last-Translator: Jan-Philipp Fischer \n"
+"Language-Team: German \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-01-25 06:55+0000\n"
+"X-Generator: Launchpad (build 16914)\n"
+
+#. module: connector_ecommerce
+#: field:sale.order,cancellation_resolved:0
+msgid "Cancellation from the backend resolved"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_product_has_checkpoint
+msgid ""
+"A product has been imported from a backend and needs to be reviewed.\n"
+"Go to Connectors > Checkpoint and review the new products."
+msgstr ""
+"Ein Produkt wurde aus einem Backend importiert und benötigt eine "
+"überprüfung.\n"
+"Gehen Sie zu Connectors->Checkpunkte und überprüfen Sie das neue Produkt."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_invoice
+msgid "Invoice"
+msgstr "Rechnung"
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "Confirm"
+msgstr "Bestätigen"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Ignore backend's cancellation, Keep Open"
+msgstr "Ignoriere abbruch im Backend und lasse offen"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Canceled in backend, to cancel"
+msgstr "Abbebrochen im Backend, abzubrechen"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Only sales orders canceled in their backend"
+msgstr "Nur VK-Aufträge können im Backend abgebrochen werden"
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_parent_order_need_cancel
+msgid ""
+"The parent sales order has been canceled on the backend.\n"
+"You will not be able to process this sales order until the parent's one is "
+"canceled."
+msgstr ""
+"Der übergeordnete VK-Auftrag wurde im Backend abgebrochen.\n"
+"Sie werden nicht in der Lage sein, diesen VK-Auftrag fortzusetzen, \n"
+"solange der übergeordnete VK-Auftrag abgebrochen ist."
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "The sales orders using the payment method will always be imported."
+msgstr ""
+"Die VK-Aufträge welche diese Zahlungsmethode verwenden,\r\n"
+"werden immer importiert."
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid ""
+"This sales order has been canceled from the backend.\n"
+" The usual action would be to cancel it in OpenERP along\n"
+" all the documents generated (delivery orders, invoices, "
+"...)."
+msgstr ""
+"Dieser VK-Auftrag wurde vom Backend abgebrochen.\n"
+"Die übliche Aktion wäre das Abbrechen von allen OpenERP\n"
+"Belegen (Lieferaufträge, Rechnungen, ...)."
+
+#. module: connector_ecommerce
+#: help:account.tax,group_id:0
+msgid ""
+"Choose the tax group. This is needed for example with magento or prestashop"
+msgstr ""
+"Wählen Sie die Steuergruppe. Dies wird z. B. für Magento oder Prestashop "
+"benötigt."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_stock_picking
+msgid "Picking List"
+msgstr "Entnahmeliste"
+
+#. module: connector_ecommerce
+#: model:ir.actions.act_window,name:connector_ecommerce.action_sale_ignore_cancel
+#: view:sale.ignore.cancel:0
+msgid "Ignore the cancellation on the Backend"
+msgstr "Ignoriere den Abbruch im Backend."
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_gift_product_template
+msgid "Gift Certificate"
+msgstr "Geschenkzertifikat"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_ignore_cancel
+msgid "Ignore Sales Order Cancel"
+msgstr "Ignoriere VK-Auftrag-Abbruch"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_product
+msgid "Product"
+msgstr "Produkt"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_payment_method
+msgid "Payment Method"
+msgstr "Zahlungsmethode"
+
+#. module: connector_ecommerce
+#: model:ir.actions.act_window,name:connector_ecommerce.action_tax_group_form
+#: model:ir.ui.menu,name:connector_ecommerce.menu_action_tax_group_form
+msgid "Tax Groups"
+msgstr "Steuergruppen"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "View Parent Sales Order"
+msgstr "Zeige übergeordnete VK-Aufträge"
+
+#. module: connector_ecommerce
+#: field:stock.picking,related_backorder_ids:0
+msgid "Related backorders"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:account.tax.group:0
+msgid "Account Tax Group"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:payment.method,days_before_cancel:0
+msgid "Days before cancel"
+msgstr "Tage bevor Abbruch"
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "The sales orders using the payment method will never be imported."
+msgstr "Dei VK-Aufträge mit dieser Zahlungsmethode werden nie importiert."
+
+#. module: connector_ecommerce
+#: field:sale.ignore.cancel,reason:0
+msgid "Reason"
+msgstr "Grund"
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_order_need_cancel
+msgid "Sales order canceled on the backend."
+msgstr "VK-Auftrag im Backend abgebrochen."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_shop
+msgid "Sales Shop"
+msgstr "Verkaufsshop"
+
+#. module: connector_ecommerce
+#: model:product.category,name:connector_ecommerce.product_categ_services
+msgid "Services"
+msgstr "Dienstleistungen"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Other Information"
+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"
+msgstr ""
+"Steuergruppen werden für einige externe Systeme wie Magento oder Prestashop "
+"genutzt."
+
+#. module: connector_ecommerce
+#: field:product.price.type,pricelist_item_ids:0
+msgid "Pricelist Items"
+msgstr "Preislistenartikel"
+
+#. module: connector_ecommerce
+#: field:sale.order,parent_need_cancel:0
+msgid "A parent sales orders needs cancel"
+msgstr "Eine übergeordnete"
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "Import Rules"
+msgstr "Importregeln"
+
+#. module: connector_ecommerce
+#: field:payment.method,import_rule:0
+msgid "Import Rule"
+msgstr "Importregeln"
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid ""
+"However, if for any reason you need to keep it open in OpenERP,\n"
+" write the reason here and it will stay open."
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid ""
+"The sales orders using the payment method will be imported\n"
+" only when they receive a payment on the E-"
+"Commerce backend."
+msgstr ""
+"Die VK-Aufträge welche diese Zahlungsmethode benutzen werden nur "
+"importiert,\n"
+"wenn eine Zahlung auf dem E-Commerce Backend vorliegt."
+
+#. module: connector_ecommerce
+#: field:account.tax.group,tax_ids:0
+msgid "Taxes"
+msgstr "Steuern"
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_order_need_cancel
+msgid "The sales order has been canceled on the backend."
+msgstr "Der VK-Auftrag wurde im Backend abgebrochen"
+
+#. module: connector_ecommerce
+#: field:sale.order,need_cancel:0
+msgid "Need to be canceled"
+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."
+msgstr ""
+"Ein übergeordneter VK-Auftrag wurde im Backend abgebrochen und muss "
+"abgebrochen werden."
+
+#. module: connector_ecommerce
+#: field:account.tax,group_id:0
+#: field:product.template,tax_group_id:0
+msgid "Tax Group"
+msgstr "Steuergruppe"
+
+#. module: connector_ecommerce
+#: view:account.invoice:0
+msgid "Payments"
+msgstr "Zahlungen"
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_parent_order_need_cancel
+msgid "Parent sales order canceled on the backend."
+msgstr "Übergeordneter VK-Auftrag im Backend abgebrochen."
+
+#. module: connector_ecommerce
+#: help:sale.order,need_cancel:0
+msgid "Has been canceled on the backend, need to be canceled."
+msgstr "Wurde im Backend abgebrochen, muss abgebrochen werden."
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_discount_product_template
+msgid "Discount Coupon"
+msgstr "Rabattcode"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_order
+msgid "Sales Order"
+msgstr "VK-Auftrag"
+
+#. 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."
+msgstr ""
+"Nach 'n' Tagen, wenn die 'Import Regel' nicht erfüllt ist, wird der Import "
+"abgebrochen."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_template
+msgid "Product Template"
+msgstr "Produkt Vorlage"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_stock_picking_out
+msgid "Delivery Orders"
+msgstr "Auslieferungsaufträge"
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_shipping_product_template
+msgid "Shipping costs"
+msgstr "Lieferkosten"
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_cash_on_delivery_product_template
+msgid "Cash on delivery"
+msgstr "Nachname (Zahlung)"
+
+#. module: connector_ecommerce
+#: field:sale.order,canceled_in_backend:0
+msgid "Canceled in backend"
+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."
+msgstr ""
+"Dies ist die Liste der VK-Aufträge welche mit dieser Rechnung in beziehung "
+"stehen."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_tax_group
+msgid "account tax group"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_tax
+msgid "Tax"
+msgstr "Steuern"
+
+#. module: connector_ecommerce
+#: view:account.invoice:0
+#: view:product.product:0
+#: view:sale.order:0
+#: view:stock.picking.out:0
+msgid "Connectors"
+msgstr "Connector"
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_product_has_checkpoint
+msgid "A product needs to be reviewed."
+msgstr "Ein Produkt muss überprüft werden"
+
+#. module: connector_ecommerce
+#: help:sale.order,parent_id:0
+msgid "A parent sales order is a sales order replaced by this one."
+msgstr "Ein übergeordneter VK-Auftrag wurde durch diesen ersetzt."
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "Cancel"
+msgstr "Abbrechen"
+
+#. module: connector_ecommerce
+#: field:sale.order,parent_id:0
+msgid "Parent Order"
+msgstr "Übergeordneter VK-Auftrag"
+
+#. module: connector_ecommerce
+#: field:account.tax.group,name:0
+msgid "Name"
+msgstr "Name"
+
+#. module: connector_ecommerce
+#: field:account.invoice,sale_order_ids:0
+msgid "Sale Orders"
+msgstr "VK-Aufträge"
+
+#. module: connector_ecommerce
+#: field:product.product,has_checkpoint:0
+msgid "Has Checkpoint"
+msgstr "Hat Überprüfungspunkt"
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "or"
+msgstr "oder"
+
+#. module: connector_ecommerce
+#: view:stock.picking.out:0
+msgid "Additional Info"
+msgstr "Zusätzliche Information"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_price_type
+msgid "Price Type"
+msgstr "Preistyp"
diff --git a/connector_ecommerce/i18n/fr.po b/connector_ecommerce/i18n/fr.po
index be4be82e..a57cab73 100644
--- a/connector_ecommerce/i18n/fr.po
+++ b/connector_ecommerce/i18n/fr.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-15 07:02+0000\n"
-"X-Generator: Launchpad (build 16890)\n"
+"X-Launchpad-Export-Date: 2014-01-23 06:04+0000\n"
+"X-Generator: Launchpad (build 16901)\n"
#. module: connector_ecommerce
#: field:sale.order,cancellation_resolved:0
From c2db2b23dbebc2b9d175d9c8d4922c9b2f5fe53c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=A9al?=
Date: Tue, 4 Feb 2014 16:10:03 +0100
Subject: [PATCH 23/86] [IMP] move product_normal_form_view in
connector_base_product
---
connector_ecommerce/__openerp__.py | 1 +
connector_ecommerce/i18n/nl.po | 394 +++++++++++++++++++++++++++
connector_ecommerce/product_view.xml | 29 --
3 files changed, 395 insertions(+), 29 deletions(-)
create mode 100644 connector_ecommerce/i18n/nl.po
delete mode 100644 connector_ecommerce/product_view.xml
diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py
index 7c6670c2..23737a24 100644
--- a/connector_ecommerce/__openerp__.py
+++ b/connector_ecommerce/__openerp__.py
@@ -63,6 +63,7 @@
'sale_automatic_workflow',
'sale_exceptions',
'delivery',
+ 'connector_base_product',
],
'data': [
'security/security.xml',
diff --git a/connector_ecommerce/i18n/nl.po b/connector_ecommerce/i18n/nl.po
new file mode 100644
index 00000000..742580e1
--- /dev/null
+++ b/connector_ecommerce/i18n/nl.po
@@ -0,0 +1,394 @@
+# Dutch translation for openerp-connector-ecommerce
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the openerp-connector-ecommerce package.
+# FIRST AUTHOR , 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openerp-connector-ecommerce\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2013-05-01 14:34+0000\n"
+"PO-Revision-Date: 2014-02-12 08:22+0000\n"
+"Last-Translator: Erwin van der Ploeg (BAS Solutions) \n"
+"Language-Team: Dutch \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-02-13 06:55+0000\n"
+"X-Generator: Launchpad (build 16916)\n"
+
+#. module: connector_ecommerce
+#: field:sale.order,cancellation_resolved:0
+msgid "Cancellation from the backend resolved"
+msgstr "Annulering in de backend opgelost."
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_product_has_checkpoint
+msgid ""
+"A product has been imported from a backend and needs to be reviewed.\n"
+"Go to Connectors > Checkpoint and review the new products."
+msgstr ""
+"Een product is geïmporteerd vanuit de backend en moet worden gecontroleerd.\n"
+"Ga naar Connectors > Controlepunt en controleer de nieuwe producten."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_invoice
+msgid "Invoice"
+msgstr "Factuur"
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "Confirm"
+msgstr "Bevestigen"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Ignore backend's cancellation, Keep Open"
+msgstr "Negeer annulering van de backend. Open houden."
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Canceled in backend, to cancel"
+msgstr "Geannuleerd in backen, te annuleren"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Only sales orders canceled in their backend"
+msgstr "Alleen verkooporders welke zijn geannuleerd in de backend."
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_parent_order_need_cancel
+msgid ""
+"The parent sales order has been canceled on the backend.\n"
+"You will not be able to process this sales order until the parent's one is "
+"canceled."
+msgstr ""
+"De bovenliggende verkooporder is geannuleerd in de backend.\n"
+"U kunt deze verkooporder niet verder verwerken totdat de bovenliggende is "
+"geannuleerd."
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "The sales orders using the payment method will always be imported."
+msgstr "De verkooporder met deze betaalwijze zal altijd worden geïmporteerd."
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid ""
+"This sales order has been canceled from the backend.\n"
+" The usual action would be to cancel it in OpenERP along\n"
+" all the documents generated (delivery orders, invoices, "
+"...)."
+msgstr ""
+"Deze verkooporder is geannuleerd in de backend.\n"
+" De normale actie is om deze order ook in OpenERP te "
+"annuleren,\n"
+" tezamen met de overige documenten, zoals uitgaande "
+"levering en factuur."
+
+#. module: connector_ecommerce
+#: help:account.tax,group_id:0
+msgid ""
+"Choose the tax group. This is needed for example with magento or prestashop"
+msgstr ""
+"Kies een BTW groep. Dit is nodig voor de koppeling met Magento of Prestashop"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_stock_picking
+msgid "Picking List"
+msgstr "Verzamellijst"
+
+#. module: connector_ecommerce
+#: model:ir.actions.act_window,name:connector_ecommerce.action_sale_ignore_cancel
+#: view:sale.ignore.cancel:0
+msgid "Ignore the cancellation on the Backend"
+msgstr "Annuleren vanuit de backend negeren"
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_gift_product_template
+msgid "Gift Certificate"
+msgstr "Waardebon"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_ignore_cancel
+msgid "Ignore Sales Order Cancel"
+msgstr "Negeer annuleren verkooporder"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_product
+msgid "Product"
+msgstr "Product"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_payment_method
+msgid "Payment Method"
+msgstr "Betaalwijze"
+
+#. module: connector_ecommerce
+#: model:ir.actions.act_window,name:connector_ecommerce.action_tax_group_form
+#: model:ir.ui.menu,name:connector_ecommerce.menu_action_tax_group_form
+msgid "Tax Groups"
+msgstr "BTW Groepen"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "View Parent Sales Order"
+msgstr "Bekijk bovenliggende verkooporder"
+
+#. module: connector_ecommerce
+#: field:stock.picking,related_backorder_ids:0
+msgid "Related backorders"
+msgstr "Relateerde backorders"
+
+#. module: connector_ecommerce
+#: view:account.tax.group:0
+msgid "Account Tax Group"
+msgstr "BTW groep"
+
+#. module: connector_ecommerce
+#: field:payment.method,days_before_cancel:0
+msgid "Days before cancel"
+msgstr "Dagen voor annuleren"
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "The sales orders using the payment method will never be imported."
+msgstr "De verkooporder met deze betaalwijze zal nooit worden geïmporteerd."
+
+#. module: connector_ecommerce
+#: field:sale.ignore.cancel,reason:0
+msgid "Reason"
+msgstr "Reden"
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_order_need_cancel
+msgid "Sales order canceled on the backend."
+msgstr "Verkooporder is geannuleerd in de backend"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_shop
+msgid "Sales Shop"
+msgstr "Verkooppunt"
+
+#. module: connector_ecommerce
+#: model:product.category,name:connector_ecommerce.product_categ_services
+msgid "Services"
+msgstr "Diensten"
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Other Information"
+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"
+msgstr ""
+"BTW groepen worden gebruikt met sommige externe systemen, zoals Magento of "
+"Prestashop."
+
+#. module: connector_ecommerce
+#: field:product.price.type,pricelist_item_ids:0
+msgid "Pricelist Items"
+msgstr "Prijslijst items"
+
+#. module: connector_ecommerce
+#: field:sale.order,parent_need_cancel:0
+msgid "A parent sales orders needs cancel"
+msgstr "Een bovenliggende verkooporder dient te worden geannuleerd"
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "Import Rules"
+msgstr "Import regels"
+
+#. module: connector_ecommerce
+#: field:payment.method,import_rule:0
+msgid "Import Rule"
+msgstr "Import regel"
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid ""
+"However, if for any reason you need to keep it open in OpenERP,\n"
+" write the reason here and it will stay open."
+msgstr ""
+"Indien u, voor welke reden dan ook, deze open wilt houden in OpenERP,\n"
+" schrijf dan hier de reden en hij blijft open."
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid ""
+"The sales orders using the payment method will be imported\n"
+" only when they receive a payment on the E-"
+"Commerce backend."
+msgstr ""
+"De verkooporder met deze betaalwijze wordt geïmporteerd\n"
+" alleen als een betaling is ontvangen in de e-"
+"commerce backend."
+
+#. module: connector_ecommerce
+#: field:account.tax.group,tax_ids:0
+msgid "Taxes"
+msgstr "BTW"
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_order_need_cancel
+msgid "The sales order has been canceled on the backend."
+msgstr "De verkooporder is geannuleerd in de backend."
+
+#. module: connector_ecommerce
+#: field:sale.order,need_cancel:0
+msgid "Need to be canceled"
+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 "
+"canceled."
+msgstr ""
+"Een bovenliggende verkooporder is geannuleerd in de backend en dient te "
+"worden geannuleerd."
+
+#. module: connector_ecommerce
+#: field:account.tax,group_id:0
+#: field:product.template,tax_group_id:0
+msgid "Tax Group"
+msgstr "BTW Groep"
+
+#. module: connector_ecommerce
+#: view:account.invoice:0
+msgid "Payments"
+msgstr "Betalingen"
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_parent_order_need_cancel
+msgid "Parent sales order canceled on the backend."
+msgstr "Bovenliggende verkooporder is geannuleerd in de backend."
+
+#. module: connector_ecommerce
+#: help:sale.order,need_cancel:0
+msgid "Has been canceled on the backend, need to be canceled."
+msgstr "Is geannuleerd in de backend en dient geannuleerd te worden."
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_discount_product_template
+msgid "Discount Coupon"
+msgstr "Kortingsbon"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_order
+msgid "Sales Order"
+msgstr "Verkooporder"
+
+#. 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."
+msgstr ""
+"Als na 'n' dagen niet aan de 'import regel' is voldaan, wordt de import van "
+"de verkooporder geannuleerd."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_template
+msgid "Product Template"
+msgstr "Productsjabloon"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_stock_picking_out
+msgid "Delivery Orders"
+msgstr "Uitgaande leveringen"
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_shipping_product_template
+msgid "Shipping costs"
+msgstr "Afleverkosten"
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_cash_on_delivery_product_template
+msgid "Cash on delivery"
+msgstr "Contant bij afleveren"
+
+#. module: connector_ecommerce
+#: field:sale.order,canceled_in_backend:0
+msgid "Canceled in backend"
+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."
+msgstr ""
+"Dit is een lijst met alle verkooporders gerelateerd aan deze factuur."
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_tax_group
+msgid "account tax group"
+msgstr "BTW groep"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_tax
+msgid "Tax"
+msgstr "BTW"
+
+#. module: connector_ecommerce
+#: view:account.invoice:0
+#: view:product.product:0
+#: view:sale.order:0
+#: view:stock.picking.out:0
+msgid "Connectors"
+msgstr "Connectors"
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_product_has_checkpoint
+msgid "A product needs to be reviewed."
+msgstr "Een product dient te worden gecontroleerd"
+
+#. module: connector_ecommerce
+#: help:sale.order,parent_id:0
+msgid "A parent sales order is a sales order replaced by this one."
+msgstr ""
+"Een bovenliggende verkooporder is een verkooporder welke is vervangen door "
+"deze order."
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "Cancel"
+msgstr "Annuleren"
+
+#. module: connector_ecommerce
+#: field:sale.order,parent_id:0
+msgid "Parent Order"
+msgstr "Bovenliggende order"
+
+#. module: connector_ecommerce
+#: field:account.tax.group,name:0
+msgid "Name"
+msgstr "Naam"
+
+#. module: connector_ecommerce
+#: field:account.invoice,sale_order_ids:0
+msgid "Sale Orders"
+msgstr "Verkooporders"
+
+#. module: connector_ecommerce
+#: field:product.product,has_checkpoint:0
+msgid "Has Checkpoint"
+msgstr "Heeft controlepunt"
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "or"
+msgstr "of"
+
+#. module: connector_ecommerce
+#: view:stock.picking.out:0
+msgid "Additional Info"
+msgstr "Aanvullende informatie"
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_price_type
+msgid "Price Type"
+msgstr "Soort prijs"
diff --git a/connector_ecommerce/product_view.xml b/connector_ecommerce/product_view.xml
deleted file mode 100644
index fa54e2b8..00000000
--- a/connector_ecommerce/product_view.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
- product.product.form
- product.product
-
-
-
-
-
-
-
-
-
-
-
-
-
-
From 0ed66ba4f84601a81683ab1f1e9c1a0b8157e5b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=A9al?=
Date: Fri, 14 Feb 2014 11:26:50 +0100
Subject: [PATCH 24/86] [FIX] product_view.xml in __openerp__.py
---
connector_ecommerce/__openerp__.py | 1 -
connector_ecommerce/i18n/es.po | 369 +++++++++++++++++++++++++++++
2 files changed, 369 insertions(+), 1 deletion(-)
create mode 100644 connector_ecommerce/i18n/es.po
diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py
index 23737a24..d999777e 100644
--- a/connector_ecommerce/__openerp__.py
+++ b/connector_ecommerce/__openerp__.py
@@ -70,7 +70,6 @@
'security/ir.model.access.csv',
'wizard/sale_ignore_cancel_view.xml',
'sale_view.xml',
- 'product_view.xml',
'invoice_view.xml',
'ecommerce_data.xml',
'stock_view.xml',
diff --git a/connector_ecommerce/i18n/es.po b/connector_ecommerce/i18n/es.po
new file mode 100644
index 00000000..f436e7e4
--- /dev/null
+++ b/connector_ecommerce/i18n/es.po
@@ -0,0 +1,369 @@
+# Spanish translation for openerp-connector-ecommerce
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the openerp-connector-ecommerce package.
+# FIRST AUTHOR , 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openerp-connector-ecommerce\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2013-05-01 14:34+0000\n"
+"PO-Revision-Date: 2014-02-21 10:42+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Spanish \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-02-22 07:51+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
+
+#. module: connector_ecommerce
+#: field:sale.order,cancellation_resolved:0
+msgid "Cancellation from the backend resolved"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_product_has_checkpoint
+msgid ""
+"A product has been imported from a backend and needs to be reviewed.\n"
+"Go to Connectors > Checkpoint and review the new products."
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_invoice
+msgid "Invoice"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "Confirm"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Ignore backend's cancellation, Keep Open"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Canceled in backend, to cancel"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Only sales orders canceled in their backend"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_parent_order_need_cancel
+msgid ""
+"The parent sales order has been canceled on the backend.\n"
+"You will not be able to process this sales order until the parent's one is "
+"canceled."
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "The sales orders using the payment method will always be imported."
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid ""
+"This sales order has been canceled from the backend.\n"
+" The usual action would be to cancel it in OpenERP along\n"
+" all the documents generated (delivery orders, invoices, "
+"...)."
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:account.tax,group_id:0
+msgid ""
+"Choose the tax group. This is needed for example with magento or prestashop"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_stock_picking
+msgid "Picking List"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.actions.act_window,name:connector_ecommerce.action_sale_ignore_cancel
+#: view:sale.ignore.cancel:0
+msgid "Ignore the cancellation on the Backend"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_gift_product_template
+msgid "Gift Certificate"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_ignore_cancel
+msgid "Ignore Sales Order Cancel"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_product
+msgid "Product"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_payment_method
+msgid "Payment Method"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.actions.act_window,name:connector_ecommerce.action_tax_group_form
+#: model:ir.ui.menu,name:connector_ecommerce.menu_action_tax_group_form
+msgid "Tax Groups"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "View Parent Sales Order"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:stock.picking,related_backorder_ids:0
+msgid "Related backorders"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:account.tax.group:0
+msgid "Account Tax Group"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:payment.method,days_before_cancel:0
+msgid "Days before cancel"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "The sales orders using the payment method will never be imported."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.ignore.cancel,reason:0
+msgid "Reason"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_order_need_cancel
+msgid "Sales order canceled on the backend."
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_shop
+msgid "Sales Shop"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:product.category,name:connector_ecommerce.product_categ_services
+msgid "Services"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.order:0
+msgid "Other Information"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:product.template,tax_group_id:0
+msgid ""
+"Tax group are used with some external system like magento or prestashop"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:product.price.type,pricelist_item_ids:0
+msgid "Pricelist Items"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.order,parent_need_cancel:0
+msgid "A parent sales orders needs cancel"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid "Import Rules"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:payment.method,import_rule:0
+msgid "Import Rule"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid ""
+"However, if for any reason you need to keep it open in OpenERP,\n"
+" write the reason here and it will stay open."
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:payment.method:0
+msgid ""
+"The sales orders using the payment method will be imported\n"
+" only when they receive a payment on the E-"
+"Commerce backend."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:account.tax.group,tax_ids:0
+msgid "Taxes"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,description:connector_ecommerce.excep_order_need_cancel
+msgid "The sales order has been canceled on the backend."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.order,need_cancel:0
+msgid "Need to be canceled"
+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."
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:account.tax,group_id:0
+#: field:product.template,tax_group_id:0
+msgid "Tax Group"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:account.invoice:0
+msgid "Payments"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_parent_order_need_cancel
+msgid "Parent sales order canceled on the backend."
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.order,need_cancel:0
+msgid "Has been canceled on the backend, need to be canceled."
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_discount_product_template
+msgid "Discount Coupon"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_sale_order
+msgid "Sales Order"
+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."
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_template
+msgid "Product Template"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_stock_picking_out
+msgid "Delivery Orders"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_shipping_product_template
+msgid "Shipping costs"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:product.template,name:connector_ecommerce.product_product_cash_on_delivery_product_template
+msgid "Cash on delivery"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.order,canceled_in_backend:0
+msgid "Canceled in backend"
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:account.invoice,sale_order_ids:0
+msgid "This is the list of sale orders related to this invoice."
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_tax_group
+msgid "account tax group"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_account_tax
+msgid "Tax"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:account.invoice:0
+#: view:product.product:0
+#: view:sale.order:0
+#: view:stock.picking.out:0
+msgid "Connectors"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:sale.exception,name:connector_ecommerce.excep_product_has_checkpoint
+msgid "A product needs to be reviewed."
+msgstr ""
+
+#. module: connector_ecommerce
+#: help:sale.order,parent_id:0
+msgid "A parent sales order is a sales order replaced by this one."
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "Cancel"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:sale.order,parent_id:0
+msgid "Parent Order"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:account.tax.group,name:0
+msgid "Name"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:account.invoice,sale_order_ids:0
+msgid "Sale Orders"
+msgstr ""
+
+#. module: connector_ecommerce
+#: field:product.product,has_checkpoint:0
+msgid "Has Checkpoint"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:sale.ignore.cancel:0
+msgid "or"
+msgstr ""
+
+#. module: connector_ecommerce
+#: view:stock.picking.out:0
+msgid "Additional Info"
+msgstr ""
+
+#. module: connector_ecommerce
+#: model:ir.model,name:connector_ecommerce.model_product_price_type
+msgid "Price Type"
+msgstr ""
From e90ebcf9ae186a639305cc5da5009c4ff9eb94d0 Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Mon, 31 Mar 2014 13:44:46 +0200
Subject: [PATCH 25/86] The special sales orders lines can have a sequence and
have low priority by default so they are likely to appear at the bottom,
shipping line being the last one
---
connector_ecommerce/sale.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py
index af40b034..5c55a3d5 100644
--- a/connector_ecommerce/sale.py
+++ b/connector_ecommerce/sale.py
@@ -434,6 +434,7 @@ def __init__(self, environment):
self.price_unit = None
self.quantity = 1
self.sign = 1
+ self.sequence = 90
def get_line(self):
assert self.product_ref or self.product
@@ -453,7 +454,8 @@ def get_line(self):
'name': product.name,
'product_uom': product.uom_id.id,
'product_uom_qty': self.quantity,
- 'price_unit': self.price_unit * self.sign}
+ 'price_unit': self.price_unit * self.sign,
+ 'sequence': self.sequence}
class ShippingLineBuilder(SpecialOrderLineBuilder):
@@ -463,6 +465,7 @@ class ShippingLineBuilder(SpecialOrderLineBuilder):
def __init__(self, environment):
super(ShippingLineBuilder, self).__init__(environment)
self.product_ref = ('connector_ecommerce', 'product_product_shipping')
+ self.sequence = 99
class CashOnDeliveryLineBuilder(SpecialOrderLineBuilder):
@@ -473,6 +476,7 @@ def __init__(self, environment):
super(CashOnDeliveryLineBuilder, self).__init__(environment)
self.product_ref = ('connector_ecommerce',
'product_product_cash_on_delivery')
+ self.sequence = 98
class GiftOrderLineBuilder(SpecialOrderLineBuilder):
@@ -485,6 +489,7 @@ def __init__(self, environment):
'product_product_gift')
self.sign = -1
self.gift_code = None
+ self.sequence = 97
def get_line(self):
line = super(GiftOrderLineBuilder, self).get_line()
From 7ea1fb267a910239b8337d0d91d6fc2577e09d5a Mon Sep 17 00:00:00 2001
From: Romain Deheele
Date: Mon, 7 Apr 2014 11:23:16 +0200
Subject: [PATCH 26/86] [FIX] related_backorder_ids shoud not be linked with a
new copy
---
connector_ecommerce/stock.py | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py
index 778dd491..03140207 100644
--- a/connector_ecommerce/stock.py
+++ b/connector_ecommerce/stock.py
@@ -24,6 +24,7 @@
from openerp.addons.connector.session import ConnectorSession
from .event import on_picking_out_done, on_tracking_number_added
+
class stock_picking(orm.Model):
_inherit = 'stock.picking'
@@ -39,8 +40,8 @@ def action_done(self, cr, uid, ids, context=None):
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)
+ ['id', 'related_backorder_ids', 'type'],
+ context=context)
for picking_vals in picking_records:
if picking_vals['type'] != 'out':
continue
@@ -52,6 +53,13 @@ def action_done(self, cr, uid, ids, context=None):
picking_vals['id'], picking_method)
return res
+ def copy(self, cr, uid, id, default=None, context=None):
+ context = context or {}
+ default = default and default.copy() or {}
+ default['related_backorder_ids'] = False
+ return super(stock_picking, self).copy(cr, uid,
+ id, default, context=context)
+
class stock_picking_out(orm.Model):
_inherit = 'stock.picking.out'
From 4e956be27391bb2b3ad726c40e0cabc53f99dfe3 Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Wed, 9 Apr 2014 16:22:51 +0200
Subject: [PATCH 27/86] rise the sequence of the special lines to reduce
chances to be reached in case of orders with many lines, leave some space if
people want to insert custom special lines in between
The default special's sequence is 980, for the same reason than before
do not build a new dict when default is an empty dict, not necessary to build a context dict (not used)
add read accesses on the sales users so they can confirm a sales order
---
connector_ecommerce/sale.py | 8 ++++----
connector_ecommerce/security/ir.model.access.csv | 1 +
connector_ecommerce/stock.py | 6 ++++--
3 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py
index 5c55a3d5..29a9a9b6 100644
--- a/connector_ecommerce/sale.py
+++ b/connector_ecommerce/sale.py
@@ -434,7 +434,7 @@ def __init__(self, environment):
self.price_unit = None
self.quantity = 1
self.sign = 1
- self.sequence = 90
+ self.sequence = 980
def get_line(self):
assert self.product_ref or self.product
@@ -465,7 +465,7 @@ class ShippingLineBuilder(SpecialOrderLineBuilder):
def __init__(self, environment):
super(ShippingLineBuilder, self).__init__(environment)
self.product_ref = ('connector_ecommerce', 'product_product_shipping')
- self.sequence = 99
+ self.sequence = 999
class CashOnDeliveryLineBuilder(SpecialOrderLineBuilder):
@@ -476,7 +476,7 @@ def __init__(self, environment):
super(CashOnDeliveryLineBuilder, self).__init__(environment)
self.product_ref = ('connector_ecommerce',
'product_product_cash_on_delivery')
- self.sequence = 98
+ self.sequence = 995
class GiftOrderLineBuilder(SpecialOrderLineBuilder):
@@ -489,7 +489,7 @@ def __init__(self, environment):
'product_product_gift')
self.sign = -1
self.gift_code = None
- self.sequence = 97
+ self.sequence = 990
def get_line(self):
line = super(GiftOrderLineBuilder, self).get_line()
diff --git a/connector_ecommerce/security/ir.model.access.csv b/connector_ecommerce/security/ir.model.access.csv
index baefbbae..e972b444 100755
--- a/connector_ecommerce/security/ir.model.access.csv
+++ b/connector_ecommerce/security/ir.model.access.csv
@@ -1,3 +1,4 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_account_tax_group_user","Read-only access to account.tax.group","model_account_tax_group","base.group_user",1,0,0,0
"access_account_tax_group_account_manager","RW access to account.tax.group","model_account_tax_group","account.group_account_manager",1,1,1,1
+access_connector_checkpoint_sale_user,connector checkpoint sales user,connector.model_connector_checkpoint,base.group_sale_salesman,1,0,0,0
diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py
index 03140207..121633f0 100644
--- a/connector_ecommerce/stock.py
+++ b/connector_ecommerce/stock.py
@@ -54,8 +54,10 @@ def action_done(self, cr, uid, ids, context=None):
return res
def copy(self, cr, uid, id, default=None, context=None):
- context = context or {}
- default = default and default.copy() or {}
+ 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)
From c79a86ddcae53c2a17a0908ce9a3f278f64ae406 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=A9al?=
Date: Fri, 25 Apr 2014 12:26:02 +0200
Subject: [PATCH 28/86] [IMP] allow to override payment rules
---
connector_ecommerce/payment_method.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/connector_ecommerce/payment_method.py b/connector_ecommerce/payment_method.py
index a1e5173f..164f189a 100644
--- a/connector_ecommerce/payment_method.py
+++ b/connector_ecommerce/payment_method.py
@@ -32,6 +32,9 @@ def _get_import_rules(self, cr, uid, context=None):
('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,...)
@@ -39,7 +42,7 @@ def _get_import_rules(self, cr, uid, context=None):
'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,
+ 'import_rule': fields.selection(__get_import_rules,
string="Import Rule",
required=True)
}
From b7b8f0ff542364aed10db398842ace196f950ede Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Mon, 26 May 2014 13:14:55 +0200
Subject: [PATCH 29/86] Bump to version 2.2.0
---
connector_ecommerce/__openerp__.py | 2 +-
connector_ecommerce/i18n/de.po | 4 +-
connector_ecommerce/i18n/es.po | 179 +++++++++++++++++++----------
connector_ecommerce/i18n/fr.po | 4 +-
connector_ecommerce/i18n/nl.po | 4 +-
5 files changed, 127 insertions(+), 66 deletions(-)
diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py
index d999777e..a3f6ea84 100644
--- a/connector_ecommerce/__openerp__.py
+++ b/connector_ecommerce/__openerp__.py
@@ -20,7 +20,7 @@
##############################################################################
{'name': 'Connector for E-Commerce',
- 'version': '2.1.0',
+ 'version': '2.2.0',
'category': 'Connector',
'author': 'Connector Core Editors',
'website': 'http://openerp-connector.com',
diff --git a/connector_ecommerce/i18n/de.po b/connector_ecommerce/i18n/de.po
index 5bc384eb..40d89a8c 100644
--- a/connector_ecommerce/i18n/de.po
+++ b/connector_ecommerce/i18n/de.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-25 06:55+0000\n"
-"X-Generator: Launchpad (build 16914)\n"
+"X-Launchpad-Export-Date: 2014-05-27 06:09+0000\n"
+"X-Generator: Launchpad (build 17017)\n"
#. module: connector_ecommerce
#: field:sale.order,cancellation_resolved:0
diff --git a/connector_ecommerce/i18n/es.po b/connector_ecommerce/i18n/es.po
index f436e7e4..6a476ce3 100644
--- a/connector_ecommerce/i18n/es.po
+++ b/connector_ecommerce/i18n/es.po
@@ -1,26 +1,27 @@
# Spanish translation for openerp-connector-ecommerce
# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
# This file is distributed under the same license as the openerp-connector-ecommerce package.
-# FIRST AUTHOR , 2014.
+# Alberto Garcia , 2014.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-connector-ecommerce\n"
-"Report-Msgid-Bugs-To: FULL NAME \n"
+"Report-Msgid-Bugs-To: Alberto Garcia \n"
"POT-Creation-Date: 2013-05-01 14:34+0000\n"
-"PO-Revision-Date: 2014-02-21 10:42+0000\n"
-"Last-Translator: FULL NAME \n"
+"PO-Revision-Date: 2014-06-06 00:02+0000\n"
+"Last-Translator: Alberto Garcia (Factor Libre) "
+"\n"
"Language-Team: Spanish \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-02-22 07:51+0000\n"
-"X-Generator: Launchpad (build 16926)\n"
+"X-Launchpad-Export-Date: 2014-06-06 06:38+0000\n"
+"X-Generator: Launchpad (build 17031)\n"
#. module: connector_ecommerce
#: field:sale.order,cancellation_resolved:0
msgid "Cancellation from the backend resolved"
-msgstr ""
+msgstr "Cancelelación resuelta desde el área de administración"
#. module: connector_ecommerce
#: model:sale.exception,description:connector_ecommerce.excep_product_has_checkpoint
@@ -28,31 +29,34 @@ msgid ""
"A product has been imported from a backend and needs to be reviewed.\n"
"Go to Connectors > Checkpoint and review the new products."
msgstr ""
+"Un producto ha sido importado de un área de administración y debe ser "
+"revisado.\n"
+"Vaya a Conectores > Punto de Control y revise los nuevos productos."
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_account_invoice
msgid "Invoice"
-msgstr ""
+msgstr "Factura"
#. module: connector_ecommerce
#: view:sale.ignore.cancel:0
msgid "Confirm"
-msgstr ""
+msgstr "Confirmar"
#. module: connector_ecommerce
#: view:sale.order:0
msgid "Ignore backend's cancellation, Keep Open"
-msgstr ""
+msgstr "Ignorar cancelaciones del área de administración, Mantener Abierto"
#. module: connector_ecommerce
#: view:sale.order:0
msgid "Canceled in backend, to cancel"
-msgstr ""
+msgstr "Cancelado en el área de administración, a cancelar"
#. module: connector_ecommerce
#: view:sale.order:0
msgid "Only sales orders canceled in their backend"
-msgstr ""
+msgstr "Solo las órdenes de venta canceladas en sus áreas de administración"
#. module: connector_ecommerce
#: model:sale.exception,description:connector_ecommerce.excep_parent_order_need_cancel
@@ -61,11 +65,14 @@ msgid ""
"You will not be able to process this sales order until the parent's one is "
"canceled."
msgstr ""
+"El pedido de venta padre ha sido cancelado en el área de administración.\n"
+"No podrá procesar este pedido de venta hasta que el padre sea cancelado."
#. module: connector_ecommerce
#: view:payment.method:0
msgid "The sales orders using the payment method will always be imported."
msgstr ""
+"Los pedidos de venta que usan el método de pago serán siempre importados."
#. module: connector_ecommerce
#: view:sale.ignore.cancel:0
@@ -75,125 +82,133 @@ msgid ""
" all the documents generated (delivery orders, invoices, "
"...)."
msgstr ""
+"Este pedido de venta ha sido cancelado desde el área de administración.\n"
+" La acción habitual sería cancelarlo en OpenERP junto "
+"con\n"
+" todos los documentos generados (ordenes de entrega, "
+"facturas, ...)."
#. module: connector_ecommerce
#: help:account.tax,group_id:0
msgid ""
"Choose the tax group. This is needed for example with magento or prestashop"
msgstr ""
+"Elija el grupo fiscal. Esto es necesario por ejemplo con Magento o Prestashop"
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_stock_picking
msgid "Picking List"
-msgstr ""
+msgstr "Albarán"
#. module: connector_ecommerce
#: model:ir.actions.act_window,name:connector_ecommerce.action_sale_ignore_cancel
#: view:sale.ignore.cancel:0
msgid "Ignore the cancellation on the Backend"
-msgstr ""
+msgstr "Ignorar la cancelación en el Área de Administración"
#. module: connector_ecommerce
#: model:product.template,name:connector_ecommerce.product_product_gift_product_template
msgid "Gift Certificate"
-msgstr ""
+msgstr "Certificado de Regalo"
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_sale_ignore_cancel
msgid "Ignore Sales Order Cancel"
-msgstr ""
+msgstr "Ignorar Órdenes de Venta Canceladas"
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_product_product
msgid "Product"
-msgstr ""
+msgstr "Producto"
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_payment_method
msgid "Payment Method"
-msgstr ""
+msgstr "Método de Pago"
#. module: connector_ecommerce
#: model:ir.actions.act_window,name:connector_ecommerce.action_tax_group_form
#: model:ir.ui.menu,name:connector_ecommerce.menu_action_tax_group_form
msgid "Tax Groups"
-msgstr ""
+msgstr "Gupo Fiscal"
#. module: connector_ecommerce
#: view:sale.order:0
msgid "View Parent Sales Order"
-msgstr ""
+msgstr "Ver Pedido de Venta Padre"
#. module: connector_ecommerce
#: field:stock.picking,related_backorder_ids:0
msgid "Related backorders"
-msgstr ""
+msgstr "Pedidos pendientes relacionados"
#. module: connector_ecommerce
#: view:account.tax.group:0
msgid "Account Tax Group"
-msgstr ""
+msgstr "Grupo de Cuenta Fiscal"
#. module: connector_ecommerce
#: field:payment.method,days_before_cancel:0
msgid "Days before cancel"
-msgstr ""
+msgstr "Días antes de cancelar"
#. module: connector_ecommerce
#: view:payment.method:0
msgid "The sales orders using the payment method will never be imported."
msgstr ""
+"Los pedidos de venta que usan el método de pago nunca serán importados."
#. module: connector_ecommerce
#: field:sale.ignore.cancel,reason:0
msgid "Reason"
-msgstr ""
+msgstr "Razón"
#. module: connector_ecommerce
#: model:sale.exception,name:connector_ecommerce.excep_order_need_cancel
msgid "Sales order canceled on the backend."
-msgstr ""
+msgstr "Pedido de venta cancelado en el área de administración."
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_sale_shop
msgid "Sales Shop"
-msgstr ""
+msgstr "Tienda ventas"
#. module: connector_ecommerce
#: model:product.category,name:connector_ecommerce.product_categ_services
msgid "Services"
-msgstr ""
+msgstr "Servicios"
#. module: connector_ecommerce
#: view:sale.order:0
msgid "Other Information"
-msgstr ""
+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"
msgstr ""
+"El grupo fiscal se usa con algún sistema externo como magento do prestashop"
#. module: connector_ecommerce
#: field:product.price.type,pricelist_item_ids:0
msgid "Pricelist Items"
-msgstr ""
+msgstr "Listado de Precios de Artículos"
#. module: connector_ecommerce
#: field:sale.order,parent_need_cancel:0
msgid "A parent sales orders needs cancel"
-msgstr ""
+msgstr "Una orden de venta padre debe cancelar"
#. module: connector_ecommerce
#: view:payment.method:0
msgid "Import Rules"
-msgstr ""
+msgstr "Importar Reglas"
#. module: connector_ecommerce
#: field:payment.method,import_rule:0
msgid "Import Rule"
-msgstr ""
+msgstr "Importar Regla"
#. module: connector_ecommerce
#: view:sale.ignore.cancel:0
@@ -201,6 +216,8 @@ msgid ""
"However, if for any reason you need to keep it open in OpenERP,\n"
" write the reason here and it will stay open."
msgstr ""
+"Sin embargo. si por alguna razón necesita mantenerlo abierto en OpenERP,\n"
+"\t\t\t\t\tescriba la razón aquí y se mantendrá abierto."
#. module: connector_ecommerce
#: view:payment.method:0
@@ -209,21 +226,24 @@ msgid ""
" only when they receive a payment on the E-"
"Commerce backend."
msgstr ""
+"Los pedidos de venta que usan el método de pago serán importados\n"
+" solo cuando recivan un pago en el area de "
+"administración del comercio electrónico."
#. module: connector_ecommerce
#: field:account.tax.group,tax_ids:0
msgid "Taxes"
-msgstr ""
+msgstr "Impuestos"
#. module: connector_ecommerce
#: model:sale.exception,description:connector_ecommerce.excep_order_need_cancel
msgid "The sales order has been canceled on the backend."
-msgstr ""
+msgstr "El pedido de venta ha sido cancelado en el área de administración."
#. module: connector_ecommerce
#: field:sale.order,need_cancel:0
msgid "Need to be canceled"
-msgstr ""
+msgstr "Debe ser cancelado"
#. module: connector_ecommerce
#: help:sale.order,parent_need_cancel:0
@@ -231,37 +251,39 @@ msgid ""
"A parent sales orders 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 "
+"debe ser cancelada."
#. module: connector_ecommerce
#: field:account.tax,group_id:0
#: field:product.template,tax_group_id:0
msgid "Tax Group"
-msgstr ""
+msgstr "Tax Group"
#. module: connector_ecommerce
#: view:account.invoice:0
msgid "Payments"
-msgstr ""
+msgstr "Pagos"
#. module: connector_ecommerce
#: model:sale.exception,name:connector_ecommerce.excep_parent_order_need_cancel
msgid "Parent sales order canceled on the backend."
-msgstr ""
+msgstr "Órdenes de venta padres canceladas en el área de administración."
#. module: connector_ecommerce
#: help:sale.order,need_cancel:0
msgid "Has been canceled on the backend, need to be canceled."
-msgstr ""
+msgstr "Ha sido cancelado en el área de administración, debe ser cancelado."
#. module: connector_ecommerce
#: model:product.template,name:connector_ecommerce.product_product_discount_product_template
msgid "Discount Coupon"
-msgstr ""
+msgstr "Cupón de Descuento"
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_sale_order
msgid "Sales Order"
-msgstr ""
+msgstr "Pedidos de venta"
#. module: connector_ecommerce
#: help:payment.method,days_before_cancel:0
@@ -269,46 +291,48 @@ msgid ""
"After 'n' days, if the 'Import Rule' is not fulfilled, the import of the "
"sale 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."
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_product_template
msgid "Product Template"
-msgstr ""
+msgstr "Plantilla de producto"
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_stock_picking_out
msgid "Delivery Orders"
-msgstr ""
+msgstr "Albaranes de salida"
#. module: connector_ecommerce
#: model:product.template,name:connector_ecommerce.product_product_shipping_product_template
msgid "Shipping costs"
-msgstr ""
+msgstr "Gastos de envio"
#. module: connector_ecommerce
#: model:product.template,name:connector_ecommerce.product_product_cash_on_delivery_product_template
msgid "Cash on delivery"
-msgstr ""
+msgstr "Contra reembolso"
#. module: connector_ecommerce
#: field:sale.order,canceled_in_backend:0
msgid "Canceled in backend"
-msgstr ""
+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."
-msgstr ""
+msgstr "Esta es la lista de pedidos de venta relacionados con esta factura."
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_account_tax_group
msgid "account tax group"
-msgstr ""
+msgstr "cuenta de grupo fiscal"
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_account_tax
msgid "Tax"
-msgstr ""
+msgstr "Impuesto"
#. module: connector_ecommerce
#: view:account.invoice:0
@@ -316,54 +340,91 @@ msgstr ""
#: view:sale.order:0
#: view:stock.picking.out:0
msgid "Connectors"
-msgstr ""
+msgstr "Conectores"
#. module: connector_ecommerce
#: model:sale.exception,name:connector_ecommerce.excep_product_has_checkpoint
msgid "A product needs to be reviewed."
-msgstr ""
+msgstr "Un nuevo producto debe ser revisado."
#. module: connector_ecommerce
#: help:sale.order,parent_id:0
msgid "A parent sales order is a sales order replaced by this one."
msgstr ""
+"Una orden de venta padre is una orden de venta reeplazada por esta otra."
#. module: connector_ecommerce
#: view:sale.ignore.cancel:0
msgid "Cancel"
-msgstr ""
+msgstr "Cancelar"
#. module: connector_ecommerce
#: field:sale.order,parent_id:0
msgid "Parent Order"
-msgstr ""
+msgstr "Orden Padre"
#. module: connector_ecommerce
#: field:account.tax.group,name:0
msgid "Name"
-msgstr ""
+msgstr "Nombre"
#. module: connector_ecommerce
#: field:account.invoice,sale_order_ids:0
msgid "Sale Orders"
-msgstr ""
+msgstr "Pedido de Venta"
#. module: connector_ecommerce
#: field:product.product,has_checkpoint:0
msgid "Has Checkpoint"
-msgstr ""
+msgstr "Tiene Punto de Control"
#. module: connector_ecommerce
#: view:sale.ignore.cancel:0
msgid "or"
-msgstr ""
+msgstr "o"
#. module: connector_ecommerce
#: view:stock.picking.out:0
msgid "Additional Info"
-msgstr ""
+msgstr "Info Adicional"
#. module: connector_ecommerce
#: model:ir.model,name:connector_ecommerce.model_product_price_type
msgid "Price Type"
-msgstr ""
+msgstr "Tipo precio"
+
+#~ msgid ""
+#~ "
Resolution:
Cancel the linked invoices, delivery orders, automatic "
+#~ "payments.
Cancel the sales order manually.
"
+#~ msgstr ""
+#~ "
Resolución:
Cancelar las facturas vinculadas, órdenes de entraga, "
+#~ "pagos automáticos.
Cancelar las órdenes de venta "
+#~ "manualmente.
"
+
+#~ msgid ""
+#~ "Despite the cancellation of the sales order on the backend, it should stay "
+#~ "open.
Reason: %s"
+#~ msgstr ""
+#~ "Apesar de la cancelación de la orden de vente en el área de administración. "
+#~ "debería permanecer abierto.
Razón: %s"
+
+#~ msgid ""
+#~ "The sales order cannot be automatically canceled because it is already done."
+#~ msgstr ""
+#~ "El pedido de venta no pudesn ser cancelado automáticamente porque ya está "
+#~ "'hecho'."
+
+#~ msgid "The sales order could not be automatically canceled for this status."
+#~ msgstr ""
+#~ "El pedido de venta podría no ser cancelado automáticamente por este estado."
+
+#~ msgid "The sales order could not be automatically canceled."
+#~ msgstr "El pedido de vente podría no ser cancelado automáticamente."
+
+#~ msgid "The sales order has been automatically canceled."
+#~ msgstr "El pedido de venta ha sido cancelado automáticamente."
+
+#~ msgid "Warning: the origin sales order %s has been canceled on the backend."
+#~ msgstr ""
+#~ "Aviso: el pedido de venta original %s ha sido cancelado en el área de "
+#~ "administración."
diff --git a/connector_ecommerce/i18n/fr.po b/connector_ecommerce/i18n/fr.po
index a57cab73..19357ee2 100644
--- a/connector_ecommerce/i18n/fr.po
+++ b/connector_ecommerce/i18n/fr.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-23 06:04+0000\n"
-"X-Generator: Launchpad (build 16901)\n"
+"X-Launchpad-Export-Date: 2014-05-27 06:09+0000\n"
+"X-Generator: Launchpad (build 17017)\n"
#. module: connector_ecommerce
#: field:sale.order,cancellation_resolved:0
diff --git a/connector_ecommerce/i18n/nl.po b/connector_ecommerce/i18n/nl.po
index 742580e1..67153249 100644
--- a/connector_ecommerce/i18n/nl.po
+++ b/connector_ecommerce/i18n/nl.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-02-13 06:55+0000\n"
-"X-Generator: Launchpad (build 16916)\n"
+"X-Launchpad-Export-Date: 2014-05-27 06:09+0000\n"
+"X-Generator: Launchpad (build 17017)\n"
#. module: connector_ecommerce
#: field:sale.order,cancellation_resolved:0
From 067ae886a8c8f314fdc0aa7736d3f0de2e91df4e Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Mon, 7 Jul 2014 11:55:58 +0200
Subject: [PATCH 30/86] set modules to not installable
Move connector_ecommerce in the root folder and set installable
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.
sale.shop has passed away
Remove the deprecated methods used to generate special lines, yeah!
stock.picking.out is no longer there
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.
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.
Use relative imports and remove fast_suite, checks in tests
Use the new env when building special lines
Rename environment to connector_env (follows connector's changes)
Use the new API
Correctly raise the event when a picking becomes 'done'
Test that on_tracking_number_added is fired
Correctly fire the event for partial pickings
Update the manifest and description; bump to 3.0.0
Correction of typos
Use @api.one as we have nothing outside the loop
Corrections of more typos
---
connector_ecommerce/README.rst | 66 +++
connector_ecommerce/__init__.py | 18 +-
connector_ecommerce/__openerp__.py | 43 +-
connector_ecommerce/account.py | 56 ++-
.../i18n/connector_ecommerce.pot | 12 +-
connector_ecommerce/i18n/de.po | 12 +-
connector_ecommerce/i18n/es.po | 12 +-
connector_ecommerce/i18n/fr.po | 12 +-
connector_ecommerce/i18n/nl.po | 12 +-
connector_ecommerce/invoice.py | 39 +-
connector_ecommerce/payment_method.py | 70 ++-
connector_ecommerce/payment_method_view.xml | 4 +-
connector_ecommerce/product.py | 200 ++++-----
connector_ecommerce/sale.py | 415 +++++-------------
connector_ecommerce/stock.py | 102 +++--
connector_ecommerce/stock_view.xml | 30 +-
connector_ecommerce/tests/__init__.py | 14 +-
.../tests/test_invoice_event.py | 61 +--
connector_ecommerce/tests/test_onchange.py | 103 +++--
.../tests/test_picking_event.py | 98 +++++
connector_ecommerce/unit/__init__.py | 2 +-
.../unit/sale_order_onchange.py | 205 ++++-----
connector_ecommerce/wizard/__init__.py | 2 +-
.../wizard/sale_ignore_cancel.py | 28 +-
24 files changed, 776 insertions(+), 840 deletions(-)
create mode 100644 connector_ecommerce/README.rst
create mode 100644 connector_ecommerce/tests/test_picking_event.py
diff --git a/connector_ecommerce/README.rst b/connector_ecommerce/README.rst
new file mode 100644
index 00000000..56e5087a
--- /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 sales 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/__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/__openerp__.py b/connector_ecommerce/__openerp__.py
index a3f6ea84..172ee88e 100644
--- a/connector_ecommerce/__openerp__.py
+++ b/connector_ecommerce/__openerp__.py
@@ -20,47 +20,14 @@
##############################################################################
{'name': 'Connector for E-Commerce',
- 'version': '2.2.0',
- 'category': 'Connector',
- 'author': 'Connector Core Editors',
+ '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_automatic_workflow',
+ 'sale_payment_method_automatic_workflow',
'sale_exceptions',
'delivery',
'connector_base_product',
@@ -77,4 +44,4 @@
'account_view.xml',
],
'installable': True,
-}
+ }
diff --git a/connector_ecommerce/account.py b/connector_ecommerce/account.py
index 97c4d3aa..6dcbf053 100644
--- a/connector_ecommerce/account.py
+++ b/connector_ecommerce/account.py
@@ -19,27 +19,39 @@
#
##############################################################################
-from openerp.osv.orm import Model
-from openerp.osv import fields
-
-class account_tax_code(Model):
- _inherit='account.tax'
-
- def get_tax_from_rate(self, cr, uid, rate, is_tax_included=False, context=None):
- #TODO improve, if tax are not correctly mapped the order should be in exception (integration with sale_execption)
- tax_ids = self.pool.get('account.tax').search(cr, uid, [('price_include', '=', is_tax_included),
- ('type_tax_use', 'in', ['sale', 'all']), ('amount', '>=', rate - 0.001), ('amount', '<=', rate + 0.001)])
- if tax_ids and len(tax_ids) > 0:
+from openerp.osv import orm, fields
+
+
+class account_tax_code(orm.Model):
+ _inherit = 'account.tax'
+
+ def get_tax_from_rate(self, cr, uid, rate, is_tax_included=False,
+ context=None):
+ # TODO improve, if tax are not correctly mapped the order should
+ # be in exception (integration with sale_execption)
+ account_tax_obj = self.pool['account.tax']
+ tax_ids = account_tax_obj.search(
+ cr, uid,
+ [('price_include', '=', is_tax_included),
+ ('type_tax_use', 'in', ['sale', 'all']),
+ ('amount', '>=', rate - 0.001),
+ ('amount', '<=', rate + 0.001)])
+ if tax_ids:
return tax_ids[0]
else:
- #try to find a tax with less precision
- tax_ids = self.pool.get('account.tax').search(cr, uid, [('price_include', '=', is_tax_included),
- ('type_tax_use', 'in', ['sale', 'all']), ('amount', '>=', rate - 0.01), ('amount', '<=', rate + 0.01)])
- if tax_ids and len(tax_ids) > 0:
+ # try to find a tax with less precision
+ tax_ids = account_tax_obj.search(
+ cr, uid,
+ [('price_include', '=', is_tax_included),
+ ('type_tax_use', 'in', ['sale', 'all']),
+ ('amount', '>=', rate - 0.01),
+ ('amount', '<=', rate + 0.01)])
+ if tax_ids:
return tax_ids[0]
return False
-class account_tax_group(Model):
+
+class account_tax_group(orm.Model):
_name = 'account.tax.group'
_description = 'account tax group'
@@ -48,12 +60,14 @@ class account_tax_group(Model):
'tax_ids': fields.one2many('account.tax', 'group_id', 'Taxes'),
}
-class account_tax(Model):
+
+class account_tax(orm.Model):
_inherit = 'account.tax'
_columns = {
- 'group_id': fields.many2one('account.tax.group', 'Tax Group', help=("Choose the tax group."
- " This is needed for example with magento or prestashop")),
+ 'group_id': fields.many2one(
+ 'account.tax.group',
+ string='Tax Group',
+ help="Choose the tax group. "
+ "This is needed for example with Prestashop"),
}
-
-
diff --git a/connector_ecommerce/i18n/connector_ecommerce.pot b/connector_ecommerce/i18n/connector_ecommerce.pot
index f2f7538d..09671056 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
@@ -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 40d89a8c..b9e01765 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."
@@ -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 6a476ce3..3701bc7f 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"
@@ -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 19357ee2..7c98b831 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."
@@ -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 67153249..b05be271 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."
@@ -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/invoice.py b/connector_ecommerce/invoice.py
index 2e1cb70a..56c67572 100644
--- a/connector_ecommerce/invoice.py
+++ b/connector_ecommerce/invoice.py
@@ -19,37 +19,28 @@
#
##############################################################################
-from openerp.osv import fields, orm, osv
-from openerp.tools.translate import _
+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):
- _inherit='account.invoice'
+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 164f189a..028b19bd 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 sales 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 a payment method or create if it doesn't exist
+
+ :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')
- method_ids = pay_method_obj.search(cr, uid,
- [('name', '=ilike', payment_method)],
- 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
+ domain = [('name', '=ilike', payment_method)]
+ method = self.search(domain, limit=1)
+ if not method:
+ method = self.create({'name': payment_method})
+ return method
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.formpayment.method
-
+
@@ -40,7 +40,7 @@
payment.method.connector_ecommerce.treepayment.method
-
+
diff --git a/connector_ecommerce/product.py b/connector_ecommerce/product.py
index 2460b35e..7abb6fa8 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 magento or prestashop'),
- }
-
- def _price_changed(self, cr, uid, ids, vals, context=None):
+ # 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):
+ 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',
+ compute='_get_tax_group_id',
+ string='Tax Group',
+ help='Tax groups 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 29a9a9b6..e8fe1b93 100644
--- a/connector_ecommerce/sale.py
+++ b/connector_ecommerce/sale.py
@@ -23,38 +23,16 @@
import logging
-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_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):
+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
@@ -64,9 +42,9 @@ class sale_order(orm.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
@@ -74,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 chose 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 order needs cancel',
+ help='A parent sales order 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)
+ self.parent_id = 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
-
- _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.
@@ -155,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:
"
"
Cancel the linked invoices, delivery "
"orders, automatic payments.
"
"
Cancel the sales order manually.
"
"")
- 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':
@@ -175,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
@@ -195,222 +156,87 @@ 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:
- # 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
-
- def ignore_cancellation(self, cr, uid, ids, reason, context=None):
+ @api.multi
+ def action_cancel(self):
+ res = super(SaleOrder, self).action_cancel()
+ for sale in self:
+ # the sales order is canceled => considered as resolved
+ if (sale.canceled_in_backend and
+ not sale.cancellation_resolved):
+ sale.write({'cancellation_resolved': True})
+ return res
+
+ @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,
- 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") %
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):
- """ Return an action to display the parent sale order """
- if isinstance(ids, (list, tuple)):
- assert len(ids) == 1
- ids = ids[0]
+ @api.multi
+ def action_view_parent(self):
+ """ Return an action to display the parent sales order """
+ self.ensure_one()
- mod_obj = self.pool.get('ir.model.data')
- act_obj = self.pool.get('ir.actions.act_window')
-
- 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
- # XXX the 3 next methods seems very specific to magento
- def _convert_special_fields(self, cr, uid, vals, order_lines, context=None):
- """ 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 not 'shipping_tax_rate' in vals and check_key(vals.keys()):
- if not 'shipping_amount_tax_excluded' in vals:
- vals['shipping_amount_tax_excluded'] = vals['shipping_amount_tax_included'] - vals['shipping_tax_amount']
- elif not 'shipping_tax_amount' in vals:
- vals['shipping_tax_amount'] = vals['shipping_amount_tax_included'] - vals['shipping_amount_tax_excluded']
- if vals['shipping_amount_tax_excluded']:
- vals['shipping_tax_rate'] = vals['shipping_tax_amount'] / vals['shipping_amount_tax_excluded']
- 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
-
- def _get_special_fields(self, cr, uid, context=None):
- 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,
- },
- ]
-
- def _get_order_extra_line_vals(self, cr, uid, vals, option, product,
- price_unit, context=None):
- return {
- 'product_id': product.id,
- 'name': product.name,
- 'product_uom': product.uom_id.id,
- 'product_uom_qty': 1,
- 'price_unit': price_unit
- }
-
- def _add_order_extra_line(self, cr, uid, vals, option, context=None):
- """ 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 vals
-
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.
@@ -426,8 +252,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)
@@ -439,17 +265,13 @@ def __init__(self, environment):
def get_line(self):
assert self.product_ref or self.product
assert self.price_unit is not None
- line = {}
- 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,
@@ -462,8 +284,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
@@ -471,9 +293,10 @@ def __init__(self, environment):
class CashOnDeliveryLineBuilder(SpecialOrderLineBuilder):
""" Return values for a Cash on Delivery line """
_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
@@ -483,8 +306,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
diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py
index 121633f0..f0132c79 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,60 +19,74 @@
#
##############################################################################
-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"),
- }
+ related_backorder_ids = fields.One2many(
+ comodel_name='stock.picking',
+ inverse_name='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)
- # 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':
+ @api.multi
+ def write(self, vals):
+ res = super(StockPicking, self).write(vals)
+ if vals.get('carrier_tracking_ref'):
+ 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
+
+ @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_vals['related_backorder_ids']:
- picking_method = 'partial'
+ if picking.related_backorder_ids:
+ method = 'partial'
else:
- picking_method = 'complete'
- on_picking_out_done.fire(session, self._name,
- picking_vals['id'], picking_method)
- return res
+ method = 'complete'
+ on_picking_out_done.fire(session, 'stock.picking',
+ picking.id, method)
- 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)
+ return result
-class stock_picking_out(orm.Model):
- _inherit = 'stock.picking.out'
+class StockMove(models.Model):
+ _inherit = 'stock.move'
- 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)
- if vals.get('carrier_tracking_ref'):
- session = ConnectorSession(cr, uid, context=context)
- for record_id in ids:
- on_tracking_number_added.fire(session, self._name, record_id)
- return res
+ @api.multi
+ def action_done(self):
+ 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()
+
+ 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/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
+
+
+
+
+
+
+
+
+
+
diff --git a/connector_ecommerce/tests/__init__.py b/connector_ecommerce/tests/__init__.py
index fbfe23ee..f514ea16 100644
--- a/connector_ecommerce/tests/__init__.py
+++ b/connector_ecommerce/tests/__init__.py
@@ -19,14 +19,6 @@
#
##############################################################################
-import test_onchange
-import test_invoice_event
-
-fast_suite = [
-]
-
-checks = [
- test_onchange,
- test_invoice_event,
-]
-
+from . import test_onchange
+from . import test_invoice_event
+from . import test_picking_event
diff --git a/connector_ecommerce/tests/test_invoice_event.py b/connector_ecommerce/tests/test_invoice_event.py
index 2d8945a8..9a240a55 100644
--- a/connector_ecommerce/tests/test_invoice_event.py
+++ b/connector_ecommerce/tests/test_invoice_event.py
@@ -19,49 +19,40 @@
#
##############################################################################
-import unittest2
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'
+ 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 9f08aa45..bced71b0 100644
--- a/connector_ecommerce/tests/test_onchange.py
+++ b/connector_ecommerce/tests/test_onchange.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-###############################################################################
+###############################################################################
#
# connector-ecommerce for OpenERP
# Copyright (C) 2013-TODAY Akretion .
@@ -18,9 +18,8 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-###############################################################################
+###############################################################################
-import unittest2
import mock
from openerp.addons.connector_ecommerce.unit.sale_order_onchange import (
@@ -33,62 +32,80 @@
ADMIN_USER_ID = common.ADMIN_USER_ID
-class test_onchange(common.TransactionCase):
- """ Test if the onchanges are applied correctly on a sale order"""
+class TestOnchange(common.TransactionCase):
+ """ Test if the onchanges are applied correctly on a sales 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):
- """ 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
+ """ 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']
+ 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])]})
- shop_id = shop_model.create(cr, uid, {'name': 'My shop'})
+ 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 = {
- 'shop_id': shop_id,
+ 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,
- 'price_unit': 20,
- 'name': 'My Real Name',
- 'product_uom_qty': 1,
- }),
- ]
+ (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/tests/test_picking_event.py b/connector_ecommerce/tests/test_picking_event.py
new file mode 100644
index 00000000..b4d03cfc
--- /dev/null
+++ b/connector_ecommerce/tests/test_picking_event.py
@@ -0,0 +1,98 @@
+# -*- 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')
+
+ 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 """
+ 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)
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/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py
index 79066d79..015832c8 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 not key 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):
@@ -36,110 +47,102 @@ 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
: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_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']]
- 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):
- """ 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.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)
- #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)
+ 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
- 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
: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.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))
if not uos_qty:
uos_qty = float(line.get('product_uom_qty', 0))
- kwargs ={
+ kwargs = {
'qty': float(line.get('product_uom_qty', 0)),
'uom': line.get('product_uom'),
'qty_uos': uos_qty,
@@ -152,56 +155,54 @@ def _get_product_id_onchange_param(self, line, previous_lines, order):
'packaging': line.get('product_packaging'),
'fiscal_position': order.get('fiscal_position'),
'flag': False,
- 'context': self.session.context,
- }
+ 'context': onchange_context,
+ }
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
"""
- sale_line_model = self.session.pool.get('sale.order.line')
-
- #Play product_id onchange
+ 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 not key 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
+ """ Play the onchange of the sales order and it's lines
- :param order: data of the sale order
- :type: dict
+ 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)``.
- :return: the value of the sale order updated with the onchange result
- :rtype: dict
+ :param order: data of the sales order
+ :type: recordset
+ :param order_lines: data of the sales order lines
+ :type: recordset
+
+ :return: the sales order updated by the onchanges
+ :rtype: recordset
"""
- #play onchange on sale order
- with self.session.change_context(dict(shop_id=order.get('shop_id'))):
- order = self._play_order_onchange(order)
- #play onchanfe on sale order line
+ # play onchange on sales order
+ order = self._play_order_onchange(order)
+
+ # 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:
@@ -218,8 +219,10 @@ def play(self, order, order_lines):
old_line_data = command_line[2]
new_line_data = self._play_line_onchange(
old_line_data, processed_order_lines, order)
- new_line = (command_line[0], command_line[1], new_line_data)
+ new_line = (command_line[0],
+ 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
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
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 5afdff0411b2b446c3f31910f64f575daf0aca48 Mon Sep 17 00:00:00 2001
From: Yannick Vaucher
Date: Fri, 22 May 2015 19:45:57 +0200
Subject: [PATCH 31/86] Add bug tracker link on README.rst
---
connector_ecommerce/README.rst | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/connector_ecommerce/README.rst b/connector_ecommerce/README.rst
index 56e5087a..2222f2c9 100644
--- a/connector_ecommerce/README.rst
+++ b/connector_ecommerce/README.rst
@@ -40,6 +40,16 @@ 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.
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues `_.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
+`here `_.
+
+
Credits
=======
From 756d10fdce75e7ceca7ad31f3dc36ffd79130397 Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Thu, 23 Jul 2015 14:06:26 +0200
Subject: [PATCH 32/86] Trigger the change of price on the newly created
product
---
connector_ecommerce/product.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/connector_ecommerce/product.py b/connector_ecommerce/product.py
index 7abb6fa8..e0ef7acd 100644
--- a/connector_ecommerce/product.py
+++ b/connector_ecommerce/product.py
@@ -133,7 +133,7 @@ def write(self, vals):
@api.model
def create(self, vals):
product = super(ProductProduct, self).create(vals)
- self._price_changed(vals)
+ product._price_changed(vals)
return product
From 4acc323af95825df5c7d1057b57340846c2b0d92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Francisco=20Peir=C3=B3?=
Date: Thu, 27 Aug 2015 18:10:47 +0200
Subject: [PATCH 33/86] [FIX] Bug throwing exception importing sale order
---
connector_ecommerce/sale.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/sale.py
index e8fe1b93..fe973cec 100644
--- a/connector_ecommerce/sale.py
+++ b/connector_ecommerce/sale.py
@@ -141,7 +141,7 @@ def _try_auto_cancel(self):
order.action_cancel()
else:
raise ValueError('%s should not fall here.' % state)
- except (osv.except_osv, osv.orm.except_orm,
+ except (osv.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 "
From 1d518b672041f589b729a1bb4ad743961b6c6cb4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Bidoul?=
Date: Fri, 9 Oct 2015 09:59:49 +0200
Subject: [PATCH 34/86] [UPD] prefix versions with 8.0
---
connector_ecommerce/__openerp__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py
index 172ee88e..8622533e 100644
--- a/connector_ecommerce/__openerp__.py
+++ b/connector_ecommerce/__openerp__.py
@@ -20,7 +20,7 @@
##############################################################################
{'name': 'Connector for E-Commerce',
- 'version': '3.0.0',
+ 'version': '8.0.3.0.0',
'category': 'Hidden',
'author': "Camptocamp,Akretion,Odoo Community Association (OCA)",
'website': 'http://openerp-connector.com',
From c85ce9d505bcd29b8623c1cfc892e79c20b2a577 Mon Sep 17 00:00:00 2001
From: "Pedro M. Baeza"
Date: Wed, 14 Oct 2015 02:23:51 +0200
Subject: [PATCH 35/86] [MIG] Make modules uninstallable
---
connector_ecommerce/__openerp__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py
index 8622533e..e6f0288f 100644
--- a/connector_ecommerce/__openerp__.py
+++ b/connector_ecommerce/__openerp__.py
@@ -43,5 +43,5 @@
'payment_method_view.xml',
'account_view.xml',
],
- 'installable': True,
+ 'installable': False,
}
From 615c8e912087f1e8684bbe91f55abd5dbcd2892b Mon Sep 17 00:00:00 2001
From: Parthiv Patel
Date: Fri, 18 Mar 2016 14:33:55 +0530
Subject: [PATCH 36/86] [IMP] made module installable
[IMP] changes related to accounting views
[IMP] changes related to sales and stock views
[REN] renamed inherited class
[IMP] changes related to object rename
[FIX] indentation
[FIX] indentation with spaces
---
connector_ecommerce/__openerp__.py | 2 +-
connector_ecommerce/account_view.xml | 13 +--
connector_ecommerce/ecommerce_data.xml | 42 ++++----
connector_ecommerce/invoice_view.xml | 13 +--
connector_ecommerce/payment_method.py | 2 +-
connector_ecommerce/payment_method_view.xml | 39 ++++----
connector_ecommerce/product.py | 98 +++++++++----------
connector_ecommerce/sale_view.xml | 42 ++++----
connector_ecommerce/security/security.xml | 25 +++--
connector_ecommerce/stock_view.xml | 31 +++---
connector_ecommerce/tests/test_onchange.py | 2 +-
.../wizard/sale_ignore_cancel_view.xml | 47 ++++-----
12 files changed, 187 insertions(+), 169 deletions(-)
diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py
index e6f0288f..8622533e 100644
--- a/connector_ecommerce/__openerp__.py
+++ b/connector_ecommerce/__openerp__.py
@@ -43,5 +43,5 @@
'payment_method_view.xml',
'account_view.xml',
],
- 'installable': False,
+ 'installable': True,
}
diff --git a/connector_ecommerce/account_view.xml b/connector_ecommerce/account_view.xml
index 8f1c22e6..914c1eb4 100644
--- a/connector_ecommerce/account_view.xml
+++ b/connector_ecommerce/account_view.xml
@@ -8,7 +8,7 @@
-
+
@@ -19,8 +19,8 @@
account.tax.group
-
-
+
+
@@ -30,8 +30,8 @@
account.tax.group
@@ -43,7 +43,8 @@
tree,form
-
+
diff --git a/connector_ecommerce/ecommerce_data.xml b/connector_ecommerce/ecommerce_data.xml
index 803cb71e..fff97f62 100644
--- a/connector_ecommerce/ecommerce_data.xml
+++ b/connector_ecommerce/ecommerce_data.xml
@@ -12,7 +12,7 @@
0.0serviceShipping costs
-
+
@@ -21,7 +21,7 @@
0.0serviceCash on delivery
-
+
@@ -30,7 +30,7 @@
0.0serviceGift Certificate
-
+
@@ -39,39 +39,47 @@
0.0serviceDiscount Coupon
-
+
- Parent sales order canceled on the backend.
- The parent sales order has been canceled on the backend.
-You will not be able to process this sales order until the parent's one is canceled.
+ Parent sales order canceled on the
+ backend.
+ The parent sales order has been canceled
+ on the
+ backend.
+ You will not be able to process this sales order until the parent's one
+ is canceled.30sale.orderif order.parent_need_cancel:
- failed = True
-
+ failed = True
+ Sales order canceled on the backend.
- The sales order has been canceled on the backend.
+ The sales order has been canceled on the
+ backend.20sale.orderif order.need_cancel:
- failed = True
-
+ failed = True
+ A product needs to be reviewed.
- A product has been imported from a backend and needs to be reviewed.
-Go to Connectors > Checkpoint and review the new products.
+ A product has been imported from a backend
+ and
+ needs to be reviewed.
+ Go to Connectors > Checkpoint and review the new products.20sale.order.line
- if object.product_id and object.product_id.has_checkpoint:
- failed = True
-
+ if object.product_id and
+ object.product_id.has_checkpoint:
+ failed = True
+
diff --git a/connector_ecommerce/invoice_view.xml b/connector_ecommerce/invoice_view.xml
index 5a899fe6..1a675dca 100644
--- a/connector_ecommerce/invoice_view.xml
+++ b/connector_ecommerce/invoice_view.xml
@@ -5,14 +5,15 @@
account.invoice.connector.formaccount.invoice
-
+
-
-
-
+
+
+
-
+
diff --git a/connector_ecommerce/payment_method.py b/connector_ecommerce/payment_method.py
index 028b19bd..2560b72c 100644
--- a/connector_ecommerce/payment_method.py
+++ b/connector_ecommerce/payment_method.py
@@ -23,7 +23,7 @@
class PaymentMethod(models.Model):
- _inherit = "payment.method"
+ _inherit = "sale.payment.method"
@api.model
def _get_import_rules(self):
diff --git a/connector_ecommerce/payment_method_view.xml b/connector_ecommerce/payment_method_view.xml
index a6ef4428..978701b0 100644
--- a/connector_ecommerce/payment_method_view.xml
+++ b/connector_ecommerce/payment_method_view.xml
@@ -1,18 +1,16 @@
-
+
- payment.method.connector_ecommerce.form
- payment.method
-
+ sale.payment.method.connector_ecommerce.form
+ sale.payment.method
+
@@ -20,16 +18,22 @@
-
-
+
+
The sales orders using the payment method will never be imported.
-
+
The sales orders using the payment method will always be imported.
-
- The sales orders using the payment method will be imported
- only when they receive a payment on the E-Commerce backend.
+
+ The sales orders using the payment
+ method will be imported
+ only when they receive a payment on the E-Commerce backend.
+
@@ -38,9 +42,10 @@
- payment.method.connector_ecommerce.tree
- payment.method
-
+ sale.payment.method.connector_ecommerce.tree
+ sale.payment.method
+
diff --git a/connector_ecommerce/product.py b/connector_ecommerce/product.py
index e0ef7acd..87fbc0a6 100644
--- a/connector_ecommerce/product.py
+++ b/connector_ecommerce/product.py
@@ -53,30 +53,30 @@ def _price_changed(self, vals):
There is no guarantee that's the price actually changed,
because it depends on the pricelists.
"""
- type_model = self.env['product.price.type']
- price_fields = type_model.sale_price_fields()
+# 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 variants if a price field of the
# variant has been changed
- tmpl_fields = [field for field in vals if field in self._fields]
- if any(field in price_fields for field in tmpl_fields):
- 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 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_model._name,
- product.id)
+# tmpl_fields = [field for field in vals if field in self._fields]
+# if any(field in price_fields for field in tmpl_fields):
+ 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 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_model._name,
+ product.id)
@api.multi
def write(self, vals):
@@ -115,13 +115,13 @@ def _price_changed(self, vals):
There is no guarantee that's the price actually changed,
because it depends on the pricelists.
"""
- 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(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)
+# 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(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)
@api.multi
def write(self, vals):
@@ -137,25 +137,25 @@ def create(self, vals):
return product
-class ProductPriceType(models.Model):
- _inherit = 'product.price.type'
-
- pricelist_item_ids = fields.One2many(
- comodel_name='product.pricelist.item',
- inverse_name='base',
- string='Pricelist Items',
- readonly=True,
- )
-
- @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_model = self.env['product.pricelist.item']
- items = item_model.search(
- [('price_version_id.pricelist_id.type', '=', 'sale')],
- )
- types = self.search([('pricelist_item_ids', 'in', items.ids)])
- return [t.field for t in types]
+# class ProductPriceType(models.Model):
+# _inherit = 'product.price.type'
+#
+# pricelist_item_ids = fields.One2many(
+# comodel_name='product.pricelist.item',
+# inverse_name='base',
+# string='Pricelist Items',
+# readonly=True,
+# )
+#
+# @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_model = self.env['product.pricelist.item']
+# items = item_model.search(
+# [('price_version_id.pricelist_id.type', '=', 'sale')],
+# )
+# types = self.search([('pricelist_item_ids', 'in', items.ids)])
+# return [t.field for t in types]
diff --git a/connector_ecommerce/sale_view.xml b/connector_ecommerce/sale_view.xml
index 2361f072..d432dc56 100644
--- a/connector_ecommerce/sale_view.xml
+++ b/connector_ecommerce/sale_view.xml
@@ -5,48 +5,50 @@
sale.order.connector.formsale.order
-
+
-
-
-
+
+
+
+
-
+
sale_order.view_formsale.order
-
+
-
-
+
+
-
-
-
+
+
-
-
+ groups="base.group_user" />
+
+
-
+ groups="base.group_sale_manager" />
+
sale.order.searchsale.order
-
+
+ name="canceled_in_backend_filter" />
diff --git a/connector_ecommerce/security/security.xml b/connector_ecommerce/security/security.xml
index 169f7d9b..73d41dd7 100644
--- a/connector_ecommerce/security/security.xml
+++ b/connector_ecommerce/security/security.xml
@@ -2,20 +2,19 @@
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
diff --git a/connector_ecommerce/stock_view.xml b/connector_ecommerce/stock_view.xml
index 954c7050..cd56c70d 100644
--- a/connector_ecommerce/stock_view.xml
+++ b/connector_ecommerce/stock_view.xml
@@ -1,18 +1,19 @@
-
-
- stock.picking.form
- stock.picking
-
-
-
-
-
-
-
-
-
-
+
+
+ stock.picking.form
+ stock.picking
+
+
+
+
+
+
+
+
+
+
diff --git a/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py
index bced71b0..57be09d9 100644
--- a/connector_ecommerce/tests/test_onchange.py
+++ b/connector_ecommerce/tests/test_onchange.py
@@ -44,7 +44,7 @@ def test_play_onchange(self):
product_model = self.env['product.product']
partner_model = self.env['res.partner']
tax_model = self.env['account.tax']
- payment_method_model = self.env['payment.method']
+ payment_method_model = self.env['sale.payment.method']
backend_record = mock.Mock()
env = Environment(backend_record, self.session, 'sale.order')
diff --git a/connector_ecommerce/wizard/sale_ignore_cancel_view.xml b/connector_ecommerce/wizard/sale_ignore_cancel_view.xml
index 2688c491..13830f0e 100644
--- a/connector_ecommerce/wizard/sale_ignore_cancel_view.xml
+++ b/connector_ecommerce/wizard/sale_ignore_cancel_view.xml
@@ -5,28 +5,29 @@
Sale Ignore Cancelsale.ignore.cancel
-
+
@@ -36,7 +37,7 @@
sale.ignore.cancelformform
-
+ new
From b03bebcb7e6271b509a847b4dfbfa1b88f4bd717 Mon Sep 17 00:00:00 2001
From: Guewen Baconnier
Date: Tue, 12 Apr 2016 11:27:52 +0200
Subject: [PATCH 37/86] Replace product.price.type by predefined fields
Remove workflow related code in sales cancelation
Rework onchange manager as we have only new API
remove +x on csv
Move line builder units in the unit directory
Use ConnectorSession.from_env() idiom
Fix OnChangeManager unit
* pass model to play_onchanges()
* extract id from (id, name) tuples on many2one fields
* get actual model and not 'model'
---
connector_ecommerce/invoice.py | 6 +-
connector_ecommerce/product.py | 85 +++------
connector_ecommerce/sale.py | 110 +----------
.../security/ir.model.access.csv | 0
connector_ecommerce/stock.py | 9 +-
connector_ecommerce/unit/__init__.py | 1 +
connector_ecommerce/unit/line_builder.py | 94 +++++++++
.../unit/sale_order_onchange.py | 180 ++++--------------
8 files changed, 167 insertions(+), 318 deletions(-)
mode change 100755 => 100644 connector_ecommerce/security/ir.model.access.csv
create mode 100644 connector_ecommerce/unit/line_builder.py
diff --git a/connector_ecommerce/invoice.py b/connector_ecommerce/invoice.py
index 56c67572..5b7b802c 100644
--- a/connector_ecommerce/invoice.py
+++ b/connector_ecommerce/invoice.py
@@ -30,8 +30,7 @@ class AccountInvoice(models.Model):
@api.multi
def confirm_paid(self):
res = super(AccountInvoice, self).confirm_paid()
- session = ConnectorSession(self.env.cr, self.env.uid,
- context=self.env.context)
+ session = ConnectorSession.from_env(self.env)
for record_id in self.ids:
on_invoice_paid.fire(session, self._name, record_id)
return res
@@ -39,8 +38,7 @@ def confirm_paid(self):
@api.multi
def invoice_validate(self):
res = super(AccountInvoice, self).invoice_validate()
- session = ConnectorSession(self.env.cr, self.env.uid,
- context=self.env.context)
+ session = ConnectorSession.from_env(self.env)
for record_id in self.ids:
on_invoice_validated.fire(session, self._name, record_id)
return res
diff --git a/connector_ecommerce/product.py b/connector_ecommerce/product.py
index 87fbc0a6..4cc70b67 100644
--- a/connector_ecommerce/product.py
+++ b/connector_ecommerce/product.py
@@ -42,6 +42,10 @@ def _get_tax_group_id(self):
'system like Prestashop',
)
+ @api.model
+ def _price_changed_fields(self):
+ return {'list_price', 'lst_price', 'standard_price'}
+
@api.multi
def _price_changed(self, vals):
""" Fire the ``on_product_price_changed`` on all the variants of
@@ -53,30 +57,23 @@ def _price_changed(self, vals):
There is no guarantee that's the price actually changed,
because it depends on the pricelists.
"""
-# 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 variants if a price field of the
- # variant has been changed
-# tmpl_fields = [field for field in vals if field in self._fields]
-# if any(field in price_fields for field in tmpl_fields):
- 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 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_model._name,
- product.id)
+ price_fields = self._price_changed_fields()
+ if any(field in vals for field in price_fields):
+ product_model = self.env['product.product']
+ session = ConnectorSession.from_env(self.env)
+ 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 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_model._name,
+ product.id)
@api.multi
def write(self, vals):
@@ -104,6 +101,10 @@ def _get_checkpoint(self):
has_checkpoint = fields.Boolean(compute='_get_checkpoint',
string='Has Checkpoint')
+ @api.model
+ def _price_changed_fields(self):
+ return {'lst_price', 'standard_price', 'price', 'price_extra'}
+
@api.multi
def _price_changed(self, vals):
""" Fire the ``on_product_price_changed`` if the price
@@ -115,13 +116,11 @@ def _price_changed(self, vals):
There is no guarantee that's the price actually changed,
because it depends on the pricelists.
"""
-# 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(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)
+ price_fields = self._price_changed_fields()
+ if any(field in vals for field in price_fields):
+ session = ConnectorSession.from_env(self.env)
+ for prod_id in self.ids:
+ on_product_price_changed.fire(session, self._name, prod_id)
@api.multi
def write(self, vals):
@@ -135,27 +134,3 @@ def create(self, vals):
product = super(ProductProduct, self).create(vals)
product._price_changed(vals)
return product
-
-
-# class ProductPriceType(models.Model):
-# _inherit = 'product.price.type'
-#
-# pricelist_item_ids = fields.One2many(
-# comodel_name='product.pricelist.item',
-# inverse_name='base',
-# string='Pricelist Items',
-# readonly=True,
-# )
-#
-# @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_model = self.env['product.pricelist.item']
-# items = item_model.search(
-# [('price_version_id.pricelist_id.type', '=', 'sale')],
-# )
-# 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 fe973cec..82deb112 100644
--- a/connector_ecommerce/sale.py
+++ b/connector_ecommerce/sale.py
@@ -24,7 +24,6 @@
import logging
from openerp import models, fields, api, exceptions, _, osv
-from openerp.addons.connector.connector import ConnectorUnit
_logger = logging.getLogger(__name__)
@@ -116,8 +115,6 @@ def _try_auto_cancel(self):
If it can't cancel it, does nothing.
"""
- wkf_states = ('draft', 'sent')
- action_states = ('manual', 'progress')
resolution_msg = _("
Resolution:
"
"
Cancel the linked invoices, delivery "
"orders, automatic payments.