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 + +
+ + +
- base_sale_multichannel.view_sales_order_filter + sale.order.search 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 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 - -
- - - + groups="base.group_sale_manager" /> +
sale.order.search sale.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 Cancel sale.ignore.cancel -
-

- This sales order has been canceled from the backend. - The usual action would be to cancel it in OpenERP along - all the documents generated (delivery orders, invoices, ...). -

-

- However, if for any reason you need to keep it open in OpenERP, - write the reason here and it will stay open. -

- - -
-
-
+
+

+ This sales order has been canceled from the backend. + The usual action would be to cancel it in OpenERP along + all the documents generated (delivery orders, invoices, ...). +

+

+ However, if for any reason you need to keep it open in OpenERP, + write the reason here and it will stay open. +

+ + +
+
+
@@ -36,7 +37,7 @@ sale.ignore.cancel form form - + 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:

    " "
  1. Cancel the linked invoices, delivery " "orders, automatic payments.
  2. " @@ -130,17 +127,9 @@ def _try_auto_cancel(self): elif state == 'done': message = _("The sales order cannot be automatically " "canceled because it is already done.") - elif state in wkf_states + action_states: + else: 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: - order.signal_workflow('cancel') - elif state in action_states: - order.action_cancel() - else: - raise ValueError('%s should not fall here.' % state) + order.action_cancel() except (osv.osv.except_osv, osv.orm.except_orm, exceptions.Warning): # the 'cancellation_resolved' flag will stay to False @@ -149,13 +138,6 @@ def _try_auto_cancel(self): 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 order.message_post(body=message) @api.multi @@ -231,91 +213,3 @@ def action_view_parent(self): action['views'] = [(view.id if view else False, 'form')] action['res_id'] = parent.id return action - - -class SpecialOrderLineBuilder(ConnectorUnit): - """ Base class to build a sales order line for a sales 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. - - 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, 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) - self.price_unit = None - self.quantity = 1 - self.sign = 1 - self.sequence = 980 - - def get_line(self): - assert self.product_ref or self.product - assert self.price_unit is not None - - product = self.product - if product is None: - product = self.env.ref('.'.join(self.product_ref)) - - 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, - 'product_uom_qty': self.quantity, - 'price_unit': self.price_unit * self.sign, - 'sequence': self.sequence} - - -class ShippingLineBuilder(SpecialOrderLineBuilder): - """ Return values for a Shipping line """ - _model_name = None - - def __init__(self, connector_env): - super(ShippingLineBuilder, self).__init__(connector_env) - self.product_ref = ('connector_ecommerce', 'product_product_shipping') - self.sequence = 999 - - -class CashOnDeliveryLineBuilder(SpecialOrderLineBuilder): - """ Return values for a Cash on Delivery line """ - _model_name = None - _model_name = None - - def __init__(self, connector_env): - super(CashOnDeliveryLineBuilder, self).__init__(connector_env) - self.product_ref = ('connector_ecommerce', - 'product_product_cash_on_delivery') - self.sequence = 995 - - -class GiftOrderLineBuilder(SpecialOrderLineBuilder): - """ Return values for a Gift line """ - _model_name = None - - def __init__(self, connector_env): - super(GiftOrderLineBuilder, self).__init__(connector_env) - self.product_ref = ('connector_ecommerce', - 'product_product_gift') - self.sign = -1 - self.gift_code = None - self.sequence = 990 - - 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 diff --git a/connector_ecommerce/security/ir.model.access.csv b/connector_ecommerce/security/ir.model.access.csv old mode 100755 new mode 100644 diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/stock.py index f0132c79..c639919f 100644 --- a/connector_ecommerce/stock.py +++ b/connector_ecommerce/stock.py @@ -38,8 +38,7 @@ class StockPicking(models.Model): 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) + session = ConnectorSession.from_env(self.env) for record_id in self.ids: on_tracking_number_added.fire(session, self._name, record_id) return res @@ -50,8 +49,7 @@ def do_transfer(self): # 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) + session = ConnectorSession.from_env(self.env) for picking in self: if picking.picking_type_id.code != 'outgoing': continue @@ -78,8 +76,7 @@ def action_done(self): result = super(StockMove, self).action_done() if fire_event: - session = ConnectorSession(self.env.cr, self.env.uid, - context=self.env.context) + session = ConnectorSession.from_env(self.env) for picking in pickings: if states[picking.id] != 'done' and picking.state == 'done': if picking.picking_type_id.code != 'outgoing': diff --git a/connector_ecommerce/unit/__init__.py b/connector_ecommerce/unit/__init__.py index 45443ad8..694f7972 100644 --- a/connector_ecommerce/unit/__init__.py +++ b/connector_ecommerce/unit/__init__.py @@ -1,2 +1,3 @@ # -*- coding: utf-8 -*- from . import sale_order_onchange +from . import line_builder diff --git a/connector_ecommerce/unit/line_builder.py b/connector_ecommerce/unit/line_builder.py new file mode 100644 index 00000000..412aee93 --- /dev/null +++ b/connector_ecommerce/unit/line_builder.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- +# © 2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from openerp import models +from openerp.addons.connector.connector import ConnectorUnit + + +class SpecialOrderLineBuilder(ConnectorUnit): + """ Base class to build a sales order line for a sales 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. + + 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, 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) + self.price_unit = None + self.quantity = 1 + self.sign = 1 + self.sequence = 980 + + def get_line(self): + assert self.product_ref or self.product + assert self.price_unit is not None + + product = self.product + if product is None: + product = self.env.ref('.'.join(self.product_ref)) + + 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, + 'product_uom_qty': self.quantity, + 'price_unit': self.price_unit * self.sign, + 'sequence': self.sequence} + + +class ShippingLineBuilder(SpecialOrderLineBuilder): + """ Return values for a Shipping line """ + _model_name = None + + def __init__(self, connector_env): + super(ShippingLineBuilder, self).__init__(connector_env) + self.product_ref = ('connector_ecommerce', 'product_product_shipping') + self.sequence = 999 + + +class CashOnDeliveryLineBuilder(SpecialOrderLineBuilder): + """ Return values for a Cash on Delivery line """ + _model_name = None + _model_name = None + + def __init__(self, connector_env): + super(CashOnDeliveryLineBuilder, self).__init__(connector_env) + self.product_ref = ('connector_ecommerce', + 'product_product_cash_on_delivery') + self.sequence = 995 + + +class GiftOrderLineBuilder(SpecialOrderLineBuilder): + """ Return values for a Gift line """ + _model_name = None + + def __init__(self, connector_env): + super(GiftOrderLineBuilder, self).__init__(connector_env) + self.product_ref = ('connector_ecommerce', + 'product_product_gift') + self.sign = -1 + self.gift_code = None + self.sequence = 990 + + 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 diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py index 015832c8..646ddc16 100644 --- a/connector_ecommerce/unit/sale_order_onchange.py +++ b/connector_ecommerce/unit/sale_order_onchange.py @@ -25,10 +25,6 @@ class OnChangeManager(ConnectorUnit): - 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', {}) new_values = {} @@ -36,171 +32,63 @@ def get_new_values(self, record, on_change_result, model=None): if fieldname not in record: if model: column = self.env[model]._fields[fieldname] - if column.type == 'many2many': - value = [(6, 0, value)] + if column.type == 'many2one': + value = value[0] # many2one are tuple (id, name) new_values[fieldname] = value return new_values - -class SaleOrderOnChange(OnChangeManager): - _model_name = None - - def _get_partner_id_onchange_param(self, order): - """ Prepare the arguments for calling the partner_id change - 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 sales order - :type: dict - - :return: a tuple of args and kwargs for the onchange - :rtype: tuple - """ - args = [ - order.get('partner_id'), - ] - kwargs = {} - return args, kwargs - - def _play_order_onchange(self, order): - """ Play the onchange of the sales order - - :param order: a dictionary of the value of your sales order - :type: dict - - :return: the value of the sales order updated with the onchange result - :rtype: dict - """ - sale_model = self.env['sale.order'] - onchange_specs = sale_model._onchange_spec() + def play_onchanges(self, model, values, onchange_fields): + model = self.env[model] + onchange_specs = 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: + all_values = values.copy() + for field in model._fields: if field not in all_values: all_values[field] = False # we work on a temporary record - order_record = sale_model.new(all_values) + new_record = model.new(all_values) new_values = {} - - # Play partner_id onchange - args, kwargs = self._get_partner_id_onchange_param(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) + for field in onchange_fields: + onchange_values = new_record.onchange(all_values, + field, onchange_specs) + new_values.update(self.get_new_values(values, onchange_values, + model=model._name)) + all_values.update(new_values) res = {f: v for f, v in all_values.iteritems() - if f in order or f in new_values} + if f in values 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 sales order line. You can overwrite this method in your own - module if they modify the onchange signature - - :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 sales order - :type: dict - - :return: a tuple of args and kwargs for the onchange - :rtype: tuple - """ - args = [ - order.get('pricelist_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 = { - 'qty': float(line.get('product_uom_qty', 0)), - 'uom': line.get('product_uom'), - 'qty_uos': uos_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': onchange_context, - } - return args, kwargs - - def _play_line_onchange(self, line, previous_lines, order): - """ Play the onchange of the sales order line - - :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 sales order - :type: dict - - :return: the value of the sales order updated with the onchange result - :rtype: dict - """ - line_model = self.env['sale.order.line'] - # Play product_id onchange - args, kwargs = self._get_product_id_onchange_param(line, - previous_lines, - order) - 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 +class SaleOrderOnChange(OnChangeManager): + _model_name = None def play(self, order, order_lines): """ Play the onchange of the sales order and it's lines - It expects to receive a recordset containing one sales order. - It could have been generated with - ``self.env['sale.order'].new(values)`` or - ``self.env['sale.order'].create(values)``. - - :param order: data of the sales order - :type: recordset + :param order: sales order values + :type: dict :param order_lines: data of the sales order lines - :type: recordset + :type: list of dict :return: the sales order updated by the onchanges - :rtype: recordset + :rtype: dict """ # play onchange on sales order - order = self._play_order_onchange(order) + order_onchange_fields = [ + 'partner_id', + 'partner_shipping_id', + 'payment_method_id', + 'workflow_process_id', + ] + line_onchange_fields = [ + 'product_id', + ] + order = self.play_onchanges('sale.order', order, order_onchange_fields) # play onchange on sales order line processed_order_lines = [] @@ -211,14 +99,16 @@ def play(self, order, 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, command_line in enumerate(line_list): # line_list format:[(0, 0, {...}), (0, 0, {...})] 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_data = self.play_onchanges( + 'sale.order.line', old_line_data, line_onchange_fields + ) new_line = (command_line[0], command_line[1], new_line_data) From 51d7bddc65cf2cf8e4fbe2ec52ae4f9182508604 Mon Sep 17 00:00:00 2001 From: "Atchuthan, Sodexis" Date: Thu, 12 May 2016 19:13:41 +0530 Subject: [PATCH 38/86] [FIX] changed to MVC structure [FIX] changed to MVC structure - modifications [IMP] modifications for account_payment_mode --- connector_ecommerce/__init__.py | 8 +------ connector_ecommerce/__openerp__.py | 18 +++++++-------- .../{ => data}/ecommerce_data.xml | 0 connector_ecommerce/models/__init__.py | 8 +++++++ connector_ecommerce/{ => models}/account.py | 6 ++--- connector_ecommerce/{ => models}/event.py | 0 connector_ecommerce/{ => models}/invoice.py | 0 .../{ => models}/payment_method.py | 4 ++-- connector_ecommerce/{ => models}/product.py | 0 connector_ecommerce/{ => models}/sale.py | 0 connector_ecommerce/{ => models}/stock.py | 0 connector_ecommerce/tests/test_onchange.py | 4 ++-- .../{ => views}/account_view.xml | 0 .../{ => views}/invoice_view.xml | 0 .../payment_mode_view.xml} | 22 +++++++++---------- connector_ecommerce/{ => views}/sale_view.xml | 0 .../{ => views}/stock_view.xml | 0 17 files changed, 35 insertions(+), 35 deletions(-) rename connector_ecommerce/{ => data}/ecommerce_data.xml (100%) create mode 100644 connector_ecommerce/models/__init__.py rename connector_ecommerce/{ => models}/account.py (96%) rename connector_ecommerce/{ => models}/event.py (100%) rename connector_ecommerce/{ => models}/invoice.py (100%) rename connector_ecommerce/{ => models}/payment_method.py (96%) rename connector_ecommerce/{ => models}/product.py (100%) rename connector_ecommerce/{ => models}/sale.py (100%) rename connector_ecommerce/{ => models}/stock.py (100%) rename connector_ecommerce/{ => views}/account_view.xml (100%) rename connector_ecommerce/{ => views}/invoice_view.xml (100%) rename connector_ecommerce/{payment_method_view.xml => views/payment_mode_view.xml} (70%) rename connector_ecommerce/{ => views}/sale_view.xml (100%) rename connector_ecommerce/{ => views}/stock_view.xml (100%) diff --git a/connector_ecommerce/__init__.py b/connector_ecommerce/__init__.py index 8a51dd0b..2c4b43e0 100644 --- a/connector_ecommerce/__init__.py +++ b/connector_ecommerce/__init__.py @@ -19,12 +19,6 @@ # ############################################################################## -from . import stock -from . import account -from . import product -from . import invoice -from . import payment_method -from . import event +from . import models from . import unit -from . import sale from . import wizard diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py index 8622533e..a4b6c600 100644 --- a/connector_ecommerce/__openerp__.py +++ b/connector_ecommerce/__openerp__.py @@ -20,15 +20,15 @@ ############################################################################## {'name': 'Connector for E-Commerce', - 'version': '8.0.3.0.0', + 'version': '9.0.1.0.0', 'category': 'Hidden', 'author': "Camptocamp,Akretion,Odoo Community Association (OCA)", 'website': 'http://openerp-connector.com', 'license': 'AGPL-3', 'depends': [ 'connector', - 'sale_payment_method_automatic_workflow', - 'sale_exceptions', + 'sale_automatic_workflow_payment_mode', + 'sale_exception', 'delivery', 'connector_base_product', ], @@ -36,12 +36,12 @@ 'security/security.xml', 'security/ir.model.access.csv', 'wizard/sale_ignore_cancel_view.xml', - 'sale_view.xml', - 'invoice_view.xml', - 'ecommerce_data.xml', - 'stock_view.xml', - 'payment_method_view.xml', - 'account_view.xml', + 'data/ecommerce_data.xml', + 'views/sale_view.xml', + 'views/invoice_view.xml', + 'views/stock_view.xml', + 'views/payment_mode_view.xml', + 'views/account_view.xml', ], 'installable': True, } diff --git a/connector_ecommerce/ecommerce_data.xml b/connector_ecommerce/data/ecommerce_data.xml similarity index 100% rename from connector_ecommerce/ecommerce_data.xml rename to connector_ecommerce/data/ecommerce_data.xml diff --git a/connector_ecommerce/models/__init__.py b/connector_ecommerce/models/__init__.py new file mode 100644 index 00000000..d41f3582 --- /dev/null +++ b/connector_ecommerce/models/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from . import stock +from . import account +from . import product +from . import invoice +from . import payment_method +from . import event +from . import sale diff --git a/connector_ecommerce/account.py b/connector_ecommerce/models/account.py similarity index 96% rename from connector_ecommerce/account.py rename to connector_ecommerce/models/account.py index 6dcbf053..67dc7ad0 100644 --- a/connector_ecommerce/account.py +++ b/connector_ecommerce/models/account.py @@ -22,7 +22,7 @@ from openerp.osv import orm, fields -class account_tax_code(orm.Model): +class AccountTaxCode(orm.Model): _inherit = 'account.tax' def get_tax_from_rate(self, cr, uid, rate, is_tax_included=False, @@ -51,7 +51,7 @@ def get_tax_from_rate(self, cr, uid, rate, is_tax_included=False, return False -class account_tax_group(orm.Model): +class AccountTaxGroup(orm.Model): _name = 'account.tax.group' _description = 'account tax group' @@ -61,7 +61,7 @@ class account_tax_group(orm.Model): } -class account_tax(orm.Model): +class AccountTax(orm.Model): _inherit = 'account.tax' _columns = { diff --git a/connector_ecommerce/event.py b/connector_ecommerce/models/event.py similarity index 100% rename from connector_ecommerce/event.py rename to connector_ecommerce/models/event.py diff --git a/connector_ecommerce/invoice.py b/connector_ecommerce/models/invoice.py similarity index 100% rename from connector_ecommerce/invoice.py rename to connector_ecommerce/models/invoice.py diff --git a/connector_ecommerce/payment_method.py b/connector_ecommerce/models/payment_method.py similarity index 96% rename from connector_ecommerce/payment_method.py rename to connector_ecommerce/models/payment_method.py index 2560b72c..0d88e849 100644 --- a/connector_ecommerce/payment_method.py +++ b/connector_ecommerce/models/payment_method.py @@ -22,8 +22,8 @@ from openerp import models, fields, api -class PaymentMethod(models.Model): - _inherit = "sale.payment.method" +class AccountPaymentMode(models.Model): + _inherit = "account.payment.mode" @api.model def _get_import_rules(self): diff --git a/connector_ecommerce/product.py b/connector_ecommerce/models/product.py similarity index 100% rename from connector_ecommerce/product.py rename to connector_ecommerce/models/product.py diff --git a/connector_ecommerce/sale.py b/connector_ecommerce/models/sale.py similarity index 100% rename from connector_ecommerce/sale.py rename to connector_ecommerce/models/sale.py diff --git a/connector_ecommerce/stock.py b/connector_ecommerce/models/stock.py similarity index 100% rename from connector_ecommerce/stock.py rename to connector_ecommerce/models/stock.py diff --git a/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py index 57be09d9..522f43c6 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['sale.payment.method'] + payment_mode_model = self.env['account.payment.mode'] backend_record = mock.Mock() env = Environment(backend_record, self.session, 'sale.order') @@ -63,7 +63,7 @@ def test_play_onchange(self): 'weight': 15, 'taxes_id': [(6, 0, [tax.id])]}) payment_term = self.env.ref('account.account_payment_term_advance') - payment_method = payment_method_model.create({ + payment_method = payment_mode_model.create({ 'name': 'Cash', 'payment_term_id': payment_term.id, }) diff --git a/connector_ecommerce/account_view.xml b/connector_ecommerce/views/account_view.xml similarity index 100% rename from connector_ecommerce/account_view.xml rename to connector_ecommerce/views/account_view.xml diff --git a/connector_ecommerce/invoice_view.xml b/connector_ecommerce/views/invoice_view.xml similarity index 100% rename from connector_ecommerce/invoice_view.xml rename to connector_ecommerce/views/invoice_view.xml diff --git a/connector_ecommerce/payment_method_view.xml b/connector_ecommerce/views/payment_mode_view.xml similarity index 70% rename from connector_ecommerce/payment_method_view.xml rename to connector_ecommerce/views/payment_mode_view.xml index 978701b0..b8dcb3ec 100644 --- a/connector_ecommerce/payment_method_view.xml +++ b/connector_ecommerce/views/payment_mode_view.xml @@ -6,13 +6,12 @@ - - sale.payment.method.connector_ecommerce.form - sale.payment.method - + + account.payment.mode.connector_ecommerce.form + account.payment.mode + - + @@ -41,13 +40,12 @@ - - sale.payment.method.connector_ecommerce.tree - sale.payment.method - + + account.payment.mode.connector_ecommerce.tree + account.payment.mode + - + diff --git a/connector_ecommerce/sale_view.xml b/connector_ecommerce/views/sale_view.xml similarity index 100% rename from connector_ecommerce/sale_view.xml rename to connector_ecommerce/views/sale_view.xml diff --git a/connector_ecommerce/stock_view.xml b/connector_ecommerce/views/stock_view.xml similarity index 100% rename from connector_ecommerce/stock_view.xml rename to connector_ecommerce/views/stock_view.xml From 9e1228902fb34b0d2262aa54431934929e17fced Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 26 May 2016 11:40:16 +0200 Subject: [PATCH 39/86] Remove account.tax.group, now exists in 'account' Improve phrasing, short license headers, ... Rename class Environment to ConnectorEnvironment Following the upstream change --- connector_ecommerce/__init__.py | 19 ---- connector_ecommerce/__openerp__.py | 25 +----- connector_ecommerce/data/ecommerce_data.xml | 6 +- connector_ecommerce/models/__init__.py | 6 +- connector_ecommerce/models/account.py | 86 +++++-------------- connector_ecommerce/models/event.py | 21 +---- connector_ecommerce/models/invoice.py | 21 +---- connector_ecommerce/models/payment_method.py | 21 +---- connector_ecommerce/models/product.py | 33 ++----- connector_ecommerce/models/sale.py | 29 ++----- connector_ecommerce/models/stock.py | 21 +---- .../security/ir.model.access.csv | 2 - connector_ecommerce/security/security.xml | 12 +-- connector_ecommerce/tests/__init__.py | 19 ---- .../tests/test_invoice_event.py | 21 +---- connector_ecommerce/tests/test_onchange.py | 26 +----- .../tests/test_picking_event.py | 21 +---- connector_ecommerce/unit/line_builder.py | 2 +- .../unit/sale_order_onchange.py | 23 +---- connector_ecommerce/views/account_view.xml | 50 ----------- .../wizard/sale_ignore_cancel.py | 21 +---- 21 files changed, 73 insertions(+), 412 deletions(-) delete mode 100644 connector_ecommerce/views/account_view.xml diff --git a/connector_ecommerce/__init__.py b/connector_ecommerce/__init__.py index 2c4b43e0..ad8909f6 100644 --- a/connector_ecommerce/__init__.py +++ b/connector_ecommerce/__init__.py @@ -1,23 +1,4 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# 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 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 . import models from . import unit diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__openerp__.py index a4b6c600..4543d269 100644 --- a/connector_ecommerce/__openerp__.py +++ b/connector_ecommerce/__openerp__.py @@ -1,29 +1,13 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# 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 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 . -# -############################################################################## +# © 2013-2016 Camptocamp SA +# © 2013-2016 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) {'name': 'Connector for E-Commerce', 'version': '9.0.1.0.0', 'category': 'Hidden', 'author': "Camptocamp,Akretion,Odoo Community Association (OCA)", - 'website': 'http://openerp-connector.com', + 'website': 'http://odoo-connector.com', 'license': 'AGPL-3', 'depends': [ 'connector', @@ -41,7 +25,6 @@ 'views/invoice_view.xml', 'views/stock_view.xml', 'views/payment_mode_view.xml', - 'views/account_view.xml', ], 'installable': True, } diff --git a/connector_ecommerce/data/ecommerce_data.xml b/connector_ecommerce/data/ecommerce_data.xml index fff97f62..6e313866 100644 --- a/connector_ecommerce/data/ecommerce_data.xml +++ b/connector_ecommerce/data/ecommerce_data.xml @@ -46,8 +46,7 @@ Parent sales order canceled on the backend. The parent sales order has been canceled - on the - backend. + on the backend. You will not be able to process this sales order until the parent's one is canceled. 30 @@ -71,8 +70,7 @@ A product needs to be reviewed. A product has been imported from a backend - and - needs to be reviewed. + and needs to be reviewed. Go to Connectors > Checkpoint and review the new products. 20 sale.order.line diff --git a/connector_ecommerce/models/__init__.py b/connector_ecommerce/models/__init__.py index d41f3582..7fb6acc9 100644 --- a/connector_ecommerce/models/__init__.py +++ b/connector_ecommerce/models/__init__.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- -from . import stock from . import account -from . import product +from . import event from . import invoice from . import payment_method -from . import event +from . import product from . import sale +from . import stock diff --git a/connector_ecommerce/models/account.py b/connector_ecommerce/models/account.py index 67dc7ad0..57a66c17 100644 --- a/connector_ecommerce/models/account.py +++ b/connector_ecommerce/models/account.py @@ -1,73 +1,31 @@ # -*- 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 . -# -############################################################################## +# © 2011-2013 Akretion (Sébastien Beau) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) -from openerp.osv import orm, fields +from openerp import models -class AccountTaxCode(orm.Model): +class AccountTaxCode(models.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, + def get_tax_from_rate(self, rate, is_tax_included=False): + account_tax_model = self.env['account.tax'] + tax = account_tax_model.search( [('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 = 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 AccountTaxGroup(orm.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 AccountTax(orm.Model): - _inherit = 'account.tax' - - _columns = { - 'group_id': fields.many2one( - 'account.tax.group', - string='Tax Group', - help="Choose the tax group. " - "This is needed for example with Prestashop"), - } + ('amount', '<=', rate + 0.001)], + limit=1, + ) + if tax: + return tax + + # try to find a tax with less precision + tax = account_tax_model.search( + [('price_include', '=', is_tax_included), + ('type_tax_use', 'in', ['sale', 'all']), + ('amount', '>=', rate - 0.01), + ('amount', '<=', rate + 0.01)], + limit=1, + ) + return tax diff --git a/connector_ecommerce/models/event.py b/connector_ecommerce/models/event.py index 5941d8b8..c4106e1b 100644 --- a/connector_ecommerce/models/event.py +++ b/connector_ecommerce/models/event.py @@ -1,23 +1,6 @@ # -*- 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 . -# -############################################################################## +# © 2013 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from openerp.addons.connector.event import Event diff --git a/connector_ecommerce/models/invoice.py b/connector_ecommerce/models/invoice.py index 5b7b802c..d49ad243 100644 --- a/connector_ecommerce/models/invoice.py +++ b/connector_ecommerce/models/invoice.py @@ -1,23 +1,6 @@ # -*- 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 . -# -############################################################################## +# © 2013 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from openerp import models, api from openerp.addons.connector.session import ConnectorSession diff --git a/connector_ecommerce/models/payment_method.py b/connector_ecommerce/models/payment_method.py index 0d88e849..eadeefaf 100644 --- a/connector_ecommerce/models/payment_method.py +++ b/connector_ecommerce/models/payment_method.py @@ -1,23 +1,6 @@ # -*- 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 . -# -############################################################################## +# © 2011-2013 Akretion (Sébastien Beau) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from openerp import models, fields, api diff --git a/connector_ecommerce/models/product.py b/connector_ecommerce/models/product.py index 4cc70b67..bf54d7b1 100644 --- a/connector_ecommerce/models/product.py +++ b/connector_ecommerce/models/product.py @@ -1,23 +1,6 @@ # -*- 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 . -# -############################################################################## +# © 2011-2013 Akretion (Sébastien Beau) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from openerp import models, fields, api from openerp.addons.connector.session import ConnectorSession @@ -29,14 +12,14 @@ class ProductTemplate(models.Model): # 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): + @api.depends('taxes_id', 'taxes_id.tax_group_id') + def _compute_tax_group_id(self): taxes = self.taxes_id - self.tax_group_id = taxes[0].group_id.id if taxes else False + self.tax_group_id = taxes[0].tax_group_id.id if taxes else False tax_group_id = fields.Many2one( comodel_name='account.tax.group', - compute='_get_tax_group_id', + compute='_compute_tax_group_id', string='Tax Group', help='Tax groups are used with some external ' 'system like Prestashop', @@ -86,7 +69,7 @@ class ProductProduct(models.Model): _inherit = 'product.product' @api.depends() - def _get_checkpoint(self): + def _compute_has_checkpoint(self): checkpoint_model = self.env['connector.checkpoint'] model_model = self.env['ir.model'] model = model_model.search([('model', '=', 'product.product')]) @@ -98,7 +81,7 @@ def _get_checkpoint(self): ) product.has_checkpoint = bool(points) - has_checkpoint = fields.Boolean(compute='_get_checkpoint', + has_checkpoint = fields.Boolean(compute='_compute_has_checkpoint', string='Has Checkpoint') @api.model diff --git a/connector_ecommerce/models/sale.py b/connector_ecommerce/models/sale.py index 82deb112..de270a74 100644 --- a/connector_ecommerce/models/sale.py +++ b/connector_ecommerce/models/sale.py @@ -1,25 +1,8 @@ # -*- 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 . -# -############################################################################## +# © 2011-2013 Camptocamp +# © 2010-2013 Akretion (Sébastien Beau) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) +# -*- coding: utf-8 -*- import logging @@ -125,8 +108,8 @@ def _try_auto_cancel(self): if state == 'cancel': continue elif state == 'done': - message = _("The sales order cannot be automatically " - "canceled because it is already done.") + message = _('The sales order cannot be automatically ' + 'canceled because it is already in "Done" state.') else: try: order.action_cancel() diff --git a/connector_ecommerce/models/stock.py b/connector_ecommerce/models/stock.py index c639919f..2fda1446 100644 --- a/connector_ecommerce/models/stock.py +++ b/connector_ecommerce/models/stock.py @@ -1,23 +1,6 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Author: Joel Grand-Guillaume -# 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 -# 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 . -# -############################################################################## +# © 2013-2015 Camptocamp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from openerp import models, fields, api diff --git a/connector_ecommerce/security/ir.model.access.csv b/connector_ecommerce/security/ir.model.access.csv index e972b444..415e4072 100644 --- a/connector_ecommerce/security/ir.model.access.csv +++ b/connector_ecommerce/security/ir.model.access.csv @@ -1,4 +1,2 @@ "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/security/security.xml b/connector_ecommerce/security/security.xml index 73d41dd7..eafa54a2 100644 --- a/connector_ecommerce/security/security.xml +++ b/connector_ecommerce/security/security.xml @@ -2,15 +2,16 @@ - + + eval="[(4, ref('sale.group_discount_per_so_line')), (4, ref('sale.group_delivery_invoice_address'))]" /> - @@ -18,4 +19,3 @@ - diff --git a/connector_ecommerce/tests/__init__.py b/connector_ecommerce/tests/__init__.py index f514ea16..7e00a83a 100644 --- a/connector_ecommerce/tests/__init__.py +++ b/connector_ecommerce/tests/__init__.py @@ -1,23 +1,4 @@ # -*- 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 . -# -############################################################################## from . import test_onchange from . import test_invoice_event diff --git a/connector_ecommerce/tests/test_invoice_event.py b/connector_ecommerce/tests/test_invoice_event.py index 9a240a55..0130579f 100644 --- a/connector_ecommerce/tests/test_invoice_event.py +++ b/connector_ecommerce/tests/test_invoice_event.py @@ -1,23 +1,6 @@ # -*- 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 . -# -############################################################################## +# © 2013 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) import mock diff --git a/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py index 522f43c6..b514e679 100644 --- a/connector_ecommerce/tests/test_onchange.py +++ b/connector_ecommerce/tests/test_onchange.py @@ -1,31 +1,13 @@ # -*- 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 . -# -############################################################################### +# © 2013-TODAY Akretion (Sébastien Beau) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) import mock 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 +from openerp.addons.connector.connector import ConnectorEnvironment import openerp.tests.common as common DB = common.DB @@ -47,7 +29,7 @@ def test_play_onchange(self): payment_mode_model = self.env['account.payment.mode'] backend_record = mock.Mock() - env = Environment(backend_record, self.session, 'sale.order') + env = ConnectorEnvironment(backend_record, self.session, 'sale.order') partner = partner_model.create({'name': 'seb', 'zip': '69100', diff --git a/connector_ecommerce/tests/test_picking_event.py b/connector_ecommerce/tests/test_picking_event.py index b4d03cfc..5f6f8eda 100644 --- a/connector_ecommerce/tests/test_picking_event.py +++ b/connector_ecommerce/tests/test_picking_event.py @@ -1,23 +1,6 @@ # -*- 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 . -# -############################################################################## +# © 2015-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) import mock diff --git a/connector_ecommerce/unit/line_builder.py b/connector_ecommerce/unit/line_builder.py index 412aee93..4b0ae7f4 100644 --- a/connector_ecommerce/unit/line_builder.py +++ b/connector_ecommerce/unit/line_builder.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# © 2016 Camptocamp SA +# © 2013-2016 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from openerp import models diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py index 646ddc16..a879c247 100644 --- a/connector_ecommerce/unit/sale_order_onchange.py +++ b/connector_ecommerce/unit/sale_order_onchange.py @@ -1,24 +1,7 @@ # -*- 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 . -# -############################################################################## +# © 2013-TODAY Akretion (Sébastien Beau) +# © 2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from openerp.addons.connector.connector import ConnectorUnit diff --git a/connector_ecommerce/views/account_view.xml b/connector_ecommerce/views/account_view.xml deleted file mode 100644 index 914c1eb4..00000000 --- a/connector_ecommerce/views/account_view.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - 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/wizard/sale_ignore_cancel.py b/connector_ecommerce/wizard/sale_ignore_cancel.py index e58de7db..1fc36ede 100644 --- a/connector_ecommerce/wizard/sale_ignore_cancel.py +++ b/connector_ecommerce/wizard/sale_ignore_cancel.py @@ -1,23 +1,6 @@ # -*- 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 . -# -############################################################################## +# © 2013-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from openerp import models, fields, api From 30c4323438e10aa373c3e6b12a50a6643f4936ae Mon Sep 17 00:00:00 2001 From: "Atchuthan, Sodexis" Date: Fri, 27 May 2016 12:46:25 +0530 Subject: [PATCH 40/86] [FIX] renamed filename to account_payment_mode [FIX] sale exception rule eval correction and xml odoo definition --- connector_ecommerce/data/ecommerce_data.xml | 3 +-- connector_ecommerce/models/__init__.py | 2 +- .../{payment_method.py => account_payment_mode.py} | 0 connector_ecommerce/security/security.xml | 4 ++-- connector_ecommerce/unit/sale_order_onchange.py | 2 +- connector_ecommerce/views/invoice_view.xml | 6 ++---- connector_ecommerce/views/payment_mode_view.xml | 10 ++-------- connector_ecommerce/views/sale_view.xml | 6 ++---- connector_ecommerce/views/stock_view.xml | 6 ++---- connector_ecommerce/wizard/sale_ignore_cancel_view.xml | 6 ++---- 10 files changed, 15 insertions(+), 30 deletions(-) rename connector_ecommerce/models/{payment_method.py => account_payment_mode.py} (100%) diff --git a/connector_ecommerce/data/ecommerce_data.xml b/connector_ecommerce/data/ecommerce_data.xml index 6e313866..2623cade 100644 --- a/connector_ecommerce/data/ecommerce_data.xml +++ b/connector_ecommerce/data/ecommerce_data.xml @@ -74,8 +74,7 @@ Go to Connectors > Checkpoint and review the new products.
    20 sale.order.line - if object.product_id and - object.product_id.has_checkpoint: + if object.product_id and object.product_id.has_checkpoint: failed = True
    diff --git a/connector_ecommerce/models/__init__.py b/connector_ecommerce/models/__init__.py index 7fb6acc9..4fd7b876 100644 --- a/connector_ecommerce/models/__init__.py +++ b/connector_ecommerce/models/__init__.py @@ -2,7 +2,7 @@ from . import account from . import event from . import invoice -from . import payment_method +from . import account_payment_mode from . import product from . import sale from . import stock diff --git a/connector_ecommerce/models/payment_method.py b/connector_ecommerce/models/account_payment_mode.py similarity index 100% rename from connector_ecommerce/models/payment_method.py rename to connector_ecommerce/models/account_payment_mode.py diff --git a/connector_ecommerce/security/security.xml b/connector_ecommerce/security/security.xml index eafa54a2..7c959943 100644 --- a/connector_ecommerce/security/security.xml +++ b/connector_ecommerce/security/security.xml @@ -1,5 +1,5 @@ - + + - - - - account.payment.mode.connector_ecommerce.form account.payment.mode @@ -51,5 +46,4 @@
    -
    - + diff --git a/connector_ecommerce/views/sale_view.xml b/connector_ecommerce/views/sale_view.xml index d432dc56..85c0bf58 100644 --- a/connector_ecommerce/views/sale_view.xml +++ b/connector_ecommerce/views/sale_view.xml @@ -1,6 +1,5 @@ - - + sale.order.connector.form @@ -61,5 +60,4 @@ - - + diff --git a/connector_ecommerce/views/stock_view.xml b/connector_ecommerce/views/stock_view.xml index cd56c70d..7eac5f80 100644 --- a/connector_ecommerce/views/stock_view.xml +++ b/connector_ecommerce/views/stock_view.xml @@ -1,6 +1,5 @@ - - + stock.picking.form stock.picking @@ -15,5 +14,4 @@ - - + diff --git a/connector_ecommerce/wizard/sale_ignore_cancel_view.xml b/connector_ecommerce/wizard/sale_ignore_cancel_view.xml index 13830f0e..e6834cc9 100644 --- a/connector_ecommerce/wizard/sale_ignore_cancel_view.xml +++ b/connector_ecommerce/wizard/sale_ignore_cancel_view.xml @@ -1,6 +1,5 @@ - - + Sale Ignore Cancel sale.ignore.cancel @@ -40,5 +39,4 @@ new - - + From afd9990f29b096675a49ebe380b1556169c6b1e4 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 27 May 2016 11:40:33 +0200 Subject: [PATCH 41/86] Capitalize products names for consistency Correct tests of connector_ecommerce Do not copy sale fields (+ _compute naming) --- connector_ecommerce/data/ecommerce_data.xml | 4 +- connector_ecommerce/models/sale.py | 19 ++++---- .../tests/test_invoice_event.py | 45 ++++++++++--------- connector_ecommerce/tests/test_onchange.py | 23 ++++------ .../tests/test_picking_event.py | 8 ++-- 5 files changed, 51 insertions(+), 48 deletions(-) diff --git a/connector_ecommerce/data/ecommerce_data.xml b/connector_ecommerce/data/ecommerce_data.xml index 2623cade..e77be46c 100644 --- a/connector_ecommerce/data/ecommerce_data.xml +++ b/connector_ecommerce/data/ecommerce_data.xml @@ -11,7 +11,7 @@ 0.0 0.0 service - Shipping costs + Shipping Costs @@ -20,7 +20,7 @@ 0.0 0.0 service - Cash on delivery + Cash on Delivery diff --git a/connector_ecommerce/models/sale.py b/connector_ecommerce/models/sale.py index de270a74..29c9107e 100644 --- a/connector_ecommerce/models/sale.py +++ b/connector_ecommerce/models/sale.py @@ -35,23 +35,26 @@ class SaleOrder(models.Model): _inherit = 'sale.order' canceled_in_backend = fields.Boolean(string='Canceled in backend', - readonly=True) + readonly=True, + copy=False) # 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') + 'backend resolved', + copy=False) parent_id = fields.Many2one(comodel_name='sale.order', - compute='get_parent_id', + compute='_compute_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', + need_cancel = fields.Boolean(compute='_compute_need_cancel', string='Need to be canceled', + copy=False, help='Has been canceled on the backend' ', need to be canceled.') parent_need_cancel = fields.Boolean( - compute='_parent_need_cancel', + compute='_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.', @@ -59,7 +62,7 @@ class SaleOrder(models.Model): @api.one @api.depends() - def get_parent_id(self): + def _compute_parent_id(self): """ Need to be inherited in the connectors to implement the parent logic. @@ -69,7 +72,7 @@ def get_parent_id(self): @api.one @api.depends('canceled_in_backend', 'cancellation_resolved') - def _need_cancel(self): + def _compute_need_cancel(self): """ Return True if the sales order need to be canceled (has been canceled on the Backend) """ @@ -79,7 +82,7 @@ def _need_cancel(self): @api.one @api.depends('need_cancel', 'parent_id', 'parent_id.need_cancel', 'parent_id.parent_need_cancel') - def _parent_need_cancel(self): + def _compute_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. diff --git a/connector_ecommerce/tests/test_invoice_event.py b/connector_ecommerce/tests/test_invoice_event.py index 0130579f..6f321929 100644 --- a/connector_ecommerce/tests/test_invoice_event.py +++ b/connector_ecommerce/tests/test_invoice_event.py @@ -13,27 +13,38 @@ class TestInvoiceEvent(common.TransactionCase): def setUp(self): super(TestInvoiceEvent, self).setUp() self.invoice_model = self.env['account.invoice'] + invoice_line_model = self.env['account.invoice.line'] 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, - 'quantity': 5, - 'price_unit': 200})], } - onchange_res = self.invoice_model.onchange_partner_id('out_invoice', - partner.id) - invoice_vals.update(onchange_res['value']) - self.invoice = self.invoice_model.create(invoice_vals) + invoice = self.invoice_model.new(invoice_vals) + invoice._onchange_partner_id() + + self.invoice = self.invoice_model.create( + invoice._convert_to_write(invoice._cache) + ) + + line_vals = {'name': "LCD Screen", + 'product_id': product, + 'quantity': 5, + 'price_unit': 200, + 'invoice_id': self.invoice, + } + line = invoice_line_model.new(line_vals) + line._onchange_product_id() + invoice_line_model.create( + line._convert_to_write(line._cache) + ) def test_event_validated(self): """ Test if the ``on_invoice_validated`` event is fired when an invoice is validated """ assert self.invoice, "The invoice has not been created" event = ('openerp.addons.connector_ecommerce.' - 'invoice.on_invoice_validated') + 'models.invoice.on_invoice_validated') with mock.patch(event) as event_mock: self.invoice.signal_workflow('invoice_open') self.assertEqual(self.invoice.state, 'open') @@ -47,20 +58,14 @@ def test_event_paid(self): assert self.invoice, "The invoice has not been created" self.invoice.signal_workflow('invoice_open') self.assertEqual(self.invoice.state, 'open') - 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' + journal = self.env['account.journal'].search([], limit=1) + event = ('openerp.addons.connector_ecommerce.models.' + 'invoice.on_invoice_paid') with mock.patch(event) as event_mock: self.invoice.pay_and_reconcile( + journal, 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.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 b514e679..84e19c99 100644 --- a/connector_ecommerce/tests/test_onchange.py +++ b/connector_ecommerce/tests/test_onchange.py @@ -19,14 +19,13 @@ class TestOnchange(common.TransactionCase): def setUp(self): super(TestOnchange, self).setUp() - self.session = ConnectorSession(self.cr, self.uid) + self.session = ConnectorSession.from_env(self.env) def test_play_onchange(self): """ 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_mode_model = self.env['account.payment.mode'] backend_record = mock.Mock() env = ConnectorEnvironment(backend_record, self.session, 'sale.order') @@ -39,21 +38,18 @@ def test_play_onchange(self): 'city': 'Lausanne', 'type': 'invoice', 'parent_id': partner.id}) - tax = tax_model.create({'name': 'My Tax'}) + tax = tax_model.create({'name': 'My Tax', 'amount': 1.0}) 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_mode_model.create({ - 'name': 'Cash', - 'payment_term_id': payment_term.id, - }) + payment_mode_xmlid = 'account_payment_mode.payment_mode_inbound_ct2' + payment_mode = self.env.ref(payment_mode_xmlid) order_vals = { 'name': 'mag_10000001', 'partner_id': partner.id, - 'payment_method_id': payment_method.id, + 'payment_mode_id': payment_mode.id, 'order_line': [ (0, 0, {'product_id': product.id, 'price_unit': 20, @@ -81,13 +77,12 @@ def test_play_onchange(self): order = onchange.play(order_vals, extra_lines) 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'], [(6, 0, [tax.id])]) + self.assertEqual(line['product_uom'], product.uom_id.id) + self.assertEqual(line['tax_id'], [(5,), (4, 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])]) + self.assertEqual(line['product_uom'], product.uom_id.id) + self.assertEqual(line['tax_id'], [(5,), (4, tax.id)]) diff --git a/connector_ecommerce/tests/test_picking_event.py b/connector_ecommerce/tests/test_picking_event.py index 5f6f8eda..849843d1 100644 --- a/connector_ecommerce/tests/test_picking_event.py +++ b/connector_ecommerce/tests/test_picking_event.py @@ -35,14 +35,14 @@ def setUp(self): 'product_uom': self.env.ref('product.product_uom_unit').id, 'price_unit': 405, }) - self.sale.signal_workflow('order_confirm') + self.sale.action_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.' + event = ('openerp.addons.connector_ecommerce.models.' 'stock.on_picking_out_done') with mock.patch(event) as event_mock: self.picking.action_done() @@ -59,7 +59,7 @@ def test_event_on_picking_out_done_partial(self): self.picking.do_prepare_partial() for operation in self.picking.pack_operation_ids: operation.product_qty = 1 - event = ('openerp.addons.connector_ecommerce.' + event = ('openerp.addons.connector_ecommerce.models.' 'stock.on_picking_out_done') with mock.patch(event) as event_mock: self.picking.do_transfer() @@ -72,7 +72,7 @@ def test_event_on_picking_out_done_partial(self): 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.' + event = ('openerp.addons.connector_ecommerce.models.' 'stock.on_tracking_number_added') with mock.patch(event) as event_mock: self.picking.carrier_tracking_ref = 'XYZ' From d1f89c958569af372bb33330a236dd8f25ed024c Mon Sep 17 00:00:00 2001 From: Parthiv Patel Date: Wed, 24 Aug 2016 10:40:23 +0530 Subject: [PATCH 42/86] [FIX] removed duplicate line [FIX] dependency on taxes_id for tax_group [FIX] indentetion issue with python expression [FIX] code optimization for tax [REM] removed unnecessary attribute [FIX] flake8 validation --- connector_ecommerce/data/ecommerce_data.xml | 6 ++---- connector_ecommerce/models/product.py | 5 ++--- connector_ecommerce/unit/line_builder.py | 1 - connector_ecommerce/wizard/sale_ignore_cancel_view.xml | 3 +-- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/connector_ecommerce/data/ecommerce_data.xml b/connector_ecommerce/data/ecommerce_data.xml index e77be46c..d85a915d 100644 --- a/connector_ecommerce/data/ecommerce_data.xml +++ b/connector_ecommerce/data/ecommerce_data.xml @@ -62,8 +62,7 @@ backend. 20 sale.order - if order.need_cancel: - failed = True + if order.need_cancel: failed = True @@ -74,8 +73,7 @@ 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 + if object.product_id and object.product_id.has_checkpoint: failed = True diff --git a/connector_ecommerce/models/product.py b/connector_ecommerce/models/product.py index bf54d7b1..cb825e3d 100644 --- a/connector_ecommerce/models/product.py +++ b/connector_ecommerce/models/product.py @@ -12,11 +12,10 @@ class ProductTemplate(models.Model): # TODO implement set function and also support multi tax @api.one - @api.depends('taxes_id', 'taxes_id.tax_group_id') + @api.depends('taxes_id.tax_group_id') def _compute_tax_group_id(self): taxes = self.taxes_id - self.tax_group_id = taxes[0].tax_group_id.id if taxes else False - + self.tax_group_id = taxes[:-1].tax_group_id.id tax_group_id = fields.Many2one( comodel_name='account.tax.group', compute='_compute_tax_group_id', diff --git a/connector_ecommerce/unit/line_builder.py b/connector_ecommerce/unit/line_builder.py index 4b0ae7f4..f4b38414 100644 --- a/connector_ecommerce/unit/line_builder.py +++ b/connector_ecommerce/unit/line_builder.py @@ -66,7 +66,6 @@ def __init__(self, connector_env): class CashOnDeliveryLineBuilder(SpecialOrderLineBuilder): """ Return values for a Cash on Delivery line """ _model_name = None - _model_name = None def __init__(self, connector_env): super(CashOnDeliveryLineBuilder, self).__init__(connector_env) diff --git a/connector_ecommerce/wizard/sale_ignore_cancel_view.xml b/connector_ecommerce/wizard/sale_ignore_cancel_view.xml index e6834cc9..3a4dc2d2 100644 --- a/connector_ecommerce/wizard/sale_ignore_cancel_view.xml +++ b/connector_ecommerce/wizard/sale_ignore_cancel_view.xml @@ -4,8 +4,7 @@ Sale Ignore Cancel sale.ignore.cancel -
    +

    This sales order has been canceled from the backend. The usual action would be to cancel it in OpenERP along From f389cc7eb9845e7e93e5275687e0c7d807edf49b Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 8 Sep 2016 08:34:19 +0200 Subject: [PATCH 43/86] Extract onchange fields for better extensibility Subclasses of the SaleOrderOnChange are now able to add or remove fields from the list of fields on which the onchanges are applied. --- .../unit/sale_order_onchange.py | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py index d5171889..a698d140 100644 --- a/connector_ecommerce/unit/sale_order_onchange.py +++ b/connector_ecommerce/unit/sale_order_onchange.py @@ -50,6 +50,17 @@ def play_onchanges(self, model, values, onchange_fields): class SaleOrderOnChange(OnChangeManager): _model_name = None + order_onchange_fields = [ + 'partner_id', + 'partner_shipping_id', + 'payment_mode_id', + 'workflow_process_id', + ] + + line_onchange_fields = [ + 'product_id', + ] + def play(self, order, order_lines): """ Play the onchange of the sales order and it's lines @@ -62,16 +73,8 @@ def play(self, order, order_lines): :rtype: dict """ # play onchange on sales order - order_onchange_fields = [ - 'partner_id', - 'partner_shipping_id', - 'payment_mode_id', - 'workflow_process_id', - ] - line_onchange_fields = [ - 'product_id', - ] - order = self.play_onchanges('sale.order', order, order_onchange_fields) + order = self.play_onchanges('sale.order', order, + self.order_onchange_fields) # play onchange on sales order line processed_order_lines = [] @@ -90,7 +93,9 @@ def play(self, order, order_lines): # keeps command number and ID (or 0) old_line_data = command_line[2] new_line_data = self.play_onchanges( - 'sale.order.line', old_line_data, line_onchange_fields + 'sale.order.line', + old_line_data, + self.line_onchange_fields ) new_line = (command_line[0], command_line[1], From 113d9ba112f7c218fdbc41315e47f63fe0875656 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Thu, 6 Oct 2016 14:49:12 +0200 Subject: [PATCH 44/86] [MIG] Make modules uninstallable [MIG] Rename manifest files --- connector_ecommerce/{__openerp__.py => __manifest__.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename connector_ecommerce/{__openerp__.py => __manifest__.py} (97%) diff --git a/connector_ecommerce/__openerp__.py b/connector_ecommerce/__manifest__.py similarity index 97% rename from connector_ecommerce/__openerp__.py rename to connector_ecommerce/__manifest__.py index 4543d269..fe597c81 100644 --- a/connector_ecommerce/__openerp__.py +++ b/connector_ecommerce/__manifest__.py @@ -26,5 +26,5 @@ 'views/stock_view.xml', 'views/payment_mode_view.xml', ], - 'installable': True, + 'installable': False, } From 23050c5bdd4edd4ab6d6124cbcc4d339ccc7fb41 Mon Sep 17 00:00:00 2001 From: Sergio Teruel Albert Date: Fri, 20 Jan 2017 18:06:33 +0100 Subject: [PATCH 45/86] connector_ecommerce: Add security groups to avoid show information always. --- connector_ecommerce/views/sale_view.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/connector_ecommerce/views/sale_view.xml b/connector_ecommerce/views/sale_view.xml index 85c0bf58..bbac7d56 100644 --- a/connector_ecommerce/views/sale_view.xml +++ b/connector_ecommerce/views/sale_view.xml @@ -5,6 +5,8 @@ sale.order.connector.form sale.order + From b077bbba47c03389e6d57b9d7cbaae572b5f6b78 Mon Sep 17 00:00:00 2001 From: sesousy Date: Thu, 24 Nov 2016 01:19:29 +0200 Subject: [PATCH 46/86] [MIG] Migration to 10.0 --- connector_ecommerce/__manifest__.py | 4 ++-- connector_ecommerce/data/ecommerce_data.xml | 4 ++-- connector_ecommerce/i18n/connector_ecommerce.pot | 8 ++++---- connector_ecommerce/i18n/de.po | 12 ++++++------ connector_ecommerce/i18n/es.po | 14 +++++++------- connector_ecommerce/i18n/fr.po | 12 ++++++------ connector_ecommerce/i18n/nl.po | 14 +++++++------- connector_ecommerce/models/account.py | 2 +- connector_ecommerce/models/account_payment_mode.py | 2 +- connector_ecommerce/models/event.py | 2 +- connector_ecommerce/models/invoice.py | 4 ++-- connector_ecommerce/models/product.py | 4 ++-- connector_ecommerce/models/sale.py | 2 +- connector_ecommerce/models/stock.py | 4 ++-- connector_ecommerce/security/ir.model.access.csv | 2 +- connector_ecommerce/security/security.xml | 2 +- connector_ecommerce/tests/test_invoice_event.py | 6 +++--- connector_ecommerce/tests/test_onchange.py | 8 ++++---- connector_ecommerce/tests/test_picking_event.py | 8 ++++---- connector_ecommerce/unit/line_builder.py | 4 ++-- connector_ecommerce/unit/sale_order_onchange.py | 4 ++-- connector_ecommerce/wizard/sale_ignore_cancel.py | 2 +- .../wizard/sale_ignore_cancel_view.xml | 4 ++-- 23 files changed, 64 insertions(+), 64 deletions(-) diff --git a/connector_ecommerce/__manifest__.py b/connector_ecommerce/__manifest__.py index fe597c81..136ffcdd 100644 --- a/connector_ecommerce/__manifest__.py +++ b/connector_ecommerce/__manifest__.py @@ -4,7 +4,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) {'name': 'Connector for E-Commerce', - 'version': '9.0.1.0.0', + 'version': '10.0.1.0.0', 'category': 'Hidden', 'author': "Camptocamp,Akretion,Odoo Community Association (OCA)", 'website': 'http://odoo-connector.com', @@ -26,5 +26,5 @@ 'views/stock_view.xml', 'views/payment_mode_view.xml', ], - 'installable': False, + 'installable': True, } diff --git a/connector_ecommerce/data/ecommerce_data.xml b/connector_ecommerce/data/ecommerce_data.xml index d85a915d..f7e2113e 100644 --- a/connector_ecommerce/data/ecommerce_data.xml +++ b/connector_ecommerce/data/ecommerce_data.xml @@ -1,5 +1,5 @@ - + @@ -78,4 +78,4 @@ - + diff --git a/connector_ecommerce/i18n/connector_ecommerce.pot b/connector_ecommerce/i18n/connector_ecommerce.pot index 09671056..ec07a289 100644 --- a/connector_ecommerce/i18n/connector_ecommerce.pot +++ b/connector_ecommerce/i18n/connector_ecommerce.pot @@ -1,10 +1,10 @@ -# Translation of OpenERP Server. +# Translation of Odoo Server. # This file contains the translation of the following modules: # * connector_ecommerce # msgid "" msgstr "" -"Project-Id-Version: OpenERP Server 7.0\n" +"Project-Id-Version: Odoo 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" @@ -65,7 +65,7 @@ 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" +" The usual action would be to cancel it in Odoo along\n" " all the documents generated (delivery orders, invoices, ...)." msgstr "" @@ -188,7 +188,7 @@ msgstr "" #. 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 Odoo,\n" " write the reason here and it will stay open." msgstr "" diff --git a/connector_ecommerce/i18n/de.po b/connector_ecommerce/i18n/de.po index b9e01765..23f710dd 100644 --- a/connector_ecommerce/i18n/de.po +++ b/connector_ecommerce/i18n/de.po @@ -1,11 +1,11 @@ -# German translation for openerp-connector-ecommerce +# German translation for odoo-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. +# This file is distributed under the same license as the odoo-connector-ecommerce package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" -"Project-Id-Version: openerp-connector-ecommerce\n" +"Project-Id-Version: odoo-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" @@ -79,12 +79,12 @@ msgstr "" #: 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" +" The usual action would be to cancel it in Odoo 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" +"Die übliche Aktion wäre das Abbrechen von allen Odoo\n" "Belegen (Lieferaufträge, Rechnungen, ...)." #. module: connector_ecommerce @@ -213,7 +213,7 @@ 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" +"However, if for any reason you need to keep it open in Odoo,\n" " write the reason here and it will stay open." msgstr "" diff --git a/connector_ecommerce/i18n/es.po b/connector_ecommerce/i18n/es.po index 3701bc7f..8136e0ad 100644 --- a/connector_ecommerce/i18n/es.po +++ b/connector_ecommerce/i18n/es.po @@ -1,11 +1,11 @@ -# Spanish translation for openerp-connector-ecommerce +# Spanish translation for odoo-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. +# This file is distributed under the same license as the odoo-connector-ecommerce package. # Alberto Garcia , 2014. # msgid "" msgstr "" -"Project-Id-Version: openerp-connector-ecommerce\n" +"Project-Id-Version: odoo-connector-ecommerce\n" "Report-Msgid-Bugs-To: Alberto Garcia \n" "POT-Creation-Date: 2013-05-01 14:34+0000\n" "PO-Revision-Date: 2014-06-06 00:02+0000\n" @@ -78,12 +78,12 @@ msgstr "" #: 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" +" The usual action would be to cancel it in Odoo along\n" " 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 " +" La acción habitual sería cancelarlo en Odoo junto " "con\n" " todos los documentos generados (ordenes de entrega, " "facturas, ...)." @@ -213,10 +213,10 @@ msgstr "Importar Regla" #. module: connector_ecommerce #: view:sale.ignore.cancel:0 msgid "" -"However, if for any reason you need to keep it open in OpenERP,\n" +"However, if for any reason you need to keep it open in Odoo,\n" " write the reason here and it will stay open." msgstr "" -"Sin embargo. si por alguna razón necesita mantenerlo abierto en OpenERP,\n" +"Sin embargo. si por alguna razón necesita mantenerlo abierto en Odoo,\n" "\t\t\t\t\tescriba la razón aquí y se mantendrá abierto." #. module: connector_ecommerce diff --git a/connector_ecommerce/i18n/fr.po b/connector_ecommerce/i18n/fr.po index 7c98b831..f0f55cb9 100644 --- a/connector_ecommerce/i18n/fr.po +++ b/connector_ecommerce/i18n/fr.po @@ -1,10 +1,10 @@ -# Translation of OpenERP Server. +# Translation of Odoo Server. # This file contains the translation of the following modules: # * connector_ecommerce # msgid "" msgstr "" -"Project-Id-Version: OpenERP Server 7.0\n" +"Project-Id-Version: Odoo Server 7.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-05-01 14:34+0000\n" "PO-Revision-Date: 2014-01-14 09:42+0000\n" @@ -77,12 +77,12 @@ msgstr "" #: 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" +" The usual action would be to cancel it in Odoo 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 " +" L'action standard est d'annuler la commande dans Odoo " "ainsi\n" " que tous les documents qu'elle a générés (bons de " "livraison, factures, ...)." @@ -212,11 +212,11 @@ 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" +"However, if for any reason you need to keep it open in Odoo,\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" +"Odoo,\n" " écrivez la raison ici et confirmez.." #. module: connector_ecommerce diff --git a/connector_ecommerce/i18n/nl.po b/connector_ecommerce/i18n/nl.po index b05be271..425af28d 100644 --- a/connector_ecommerce/i18n/nl.po +++ b/connector_ecommerce/i18n/nl.po @@ -1,11 +1,11 @@ -# Dutch translation for openerp-connector-ecommerce +# Dutch translation for odoo-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. +# This file is distributed under the same license as the odoo-connector-ecommerce package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" -"Project-Id-Version: openerp-connector-ecommerce\n" +"Project-Id-Version: odoo-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" @@ -76,12 +76,12 @@ msgstr "De verkooporder met deze betaalwijze zal altijd worden geïmporteerd." #: 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" +" The usual action would be to cancel it in Odoo 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 " +" De normale actie is om deze order ook in Odoo te " "annuleren,\n" " tezamen met de overige documenten, zoals uitgaande " "levering en factuur." @@ -211,10 +211,10 @@ 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" +"However, if for any reason you need to keep it open in Odoo,\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" +"Indien u, voor welke reden dan ook, deze open wilt houden in Odoo,\n" " schrijf dan hier de reden en hij blijft open." #. module: connector_ecommerce diff --git a/connector_ecommerce/models/account.py b/connector_ecommerce/models/account.py index 57a66c17..b29004b7 100644 --- a/connector_ecommerce/models/account.py +++ b/connector_ecommerce/models/account.py @@ -2,7 +2,7 @@ # © 2011-2013 Akretion (Sébastien Beau) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) -from openerp import models +from odoo import models class AccountTaxCode(models.Model): diff --git a/connector_ecommerce/models/account_payment_mode.py b/connector_ecommerce/models/account_payment_mode.py index eadeefaf..d1aee605 100644 --- a/connector_ecommerce/models/account_payment_mode.py +++ b/connector_ecommerce/models/account_payment_mode.py @@ -2,7 +2,7 @@ # © 2011-2013 Akretion (Sébastien Beau) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) -from openerp import models, fields, api +from odoo import models, fields, api class AccountPaymentMode(models.Model): diff --git a/connector_ecommerce/models/event.py b/connector_ecommerce/models/event.py index c4106e1b..57a9310c 100644 --- a/connector_ecommerce/models/event.py +++ b/connector_ecommerce/models/event.py @@ -2,7 +2,7 @@ # © 2013 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) -from openerp.addons.connector.event import Event +from odoo.addons.connector.event import Event on_picking_out_done = Event() diff --git a/connector_ecommerce/models/invoice.py b/connector_ecommerce/models/invoice.py index d49ad243..e6d04aa6 100644 --- a/connector_ecommerce/models/invoice.py +++ b/connector_ecommerce/models/invoice.py @@ -2,8 +2,8 @@ # © 2013 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) -from openerp import models, api -from openerp.addons.connector.session import ConnectorSession +from odoo import models, api +from odoo.addons.connector.session import ConnectorSession from .event import on_invoice_paid, on_invoice_validated diff --git a/connector_ecommerce/models/product.py b/connector_ecommerce/models/product.py index cb825e3d..619d9e48 100644 --- a/connector_ecommerce/models/product.py +++ b/connector_ecommerce/models/product.py @@ -2,8 +2,8 @@ # © 2011-2013 Akretion (Sébastien Beau) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) -from openerp import models, fields, api -from openerp.addons.connector.session import ConnectorSession +from odoo import models, fields, api +from odoo.addons.connector.session import ConnectorSession from .event import on_product_price_changed diff --git a/connector_ecommerce/models/sale.py b/connector_ecommerce/models/sale.py index 29c9107e..5fa1153b 100644 --- a/connector_ecommerce/models/sale.py +++ b/connector_ecommerce/models/sale.py @@ -6,7 +6,7 @@ import logging -from openerp import models, fields, api, exceptions, _, osv +from odoo import models, fields, api, exceptions, _, osv _logger = logging.getLogger(__name__) diff --git a/connector_ecommerce/models/stock.py b/connector_ecommerce/models/stock.py index 2fda1446..6b339cd7 100644 --- a/connector_ecommerce/models/stock.py +++ b/connector_ecommerce/models/stock.py @@ -2,9 +2,9 @@ # © 2013-2015 Camptocamp # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) -from openerp import models, fields, api +from odoo import models, fields, api -from openerp.addons.connector.session import ConnectorSession +from odoo.addons.connector.session import ConnectorSession from .event import on_picking_out_done, on_tracking_number_added diff --git a/connector_ecommerce/security/ir.model.access.csv b/connector_ecommerce/security/ir.model.access.csv index 415e4072..d3b45490 100644 --- a/connector_ecommerce/security/ir.model.access.csv +++ b/connector_ecommerce/security/ir.model.access.csv @@ -1,2 +1,2 @@ "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" -access_connector_checkpoint_sale_user,connector checkpoint sales user,connector.model_connector_checkpoint,base.group_sale_salesman,1,0,0,0 +access_connector_checkpoint_sale_user,connector checkpoint sales user,connector.model_connector_checkpoint,sales_team.group_sale_salesman,1,0,0,0 diff --git a/connector_ecommerce/security/security.xml b/connector_ecommerce/security/security.xml index 7c959943..84c2423f 100644 --- a/connector_ecommerce/security/security.xml +++ b/connector_ecommerce/security/security.xml @@ -14,7 +14,7 @@ - + diff --git a/connector_ecommerce/tests/test_invoice_event.py b/connector_ecommerce/tests/test_invoice_event.py index 6f321929..04ef7a7c 100644 --- a/connector_ecommerce/tests/test_invoice_event.py +++ b/connector_ecommerce/tests/test_invoice_event.py @@ -4,7 +4,7 @@ import mock -import openerp.tests.common as common +import odoo.tests.common as common class TestInvoiceEvent(common.TransactionCase): @@ -43,7 +43,7 @@ def test_event_validated(self): """ Test if the ``on_invoice_validated`` event is fired when an invoice is validated """ assert self.invoice, "The invoice has not been created" - event = ('openerp.addons.connector_ecommerce.' + event = ('odoo.addons.connector_ecommerce.' 'models.invoice.on_invoice_validated') with mock.patch(event) as event_mock: self.invoice.signal_workflow('invoice_open') @@ -59,7 +59,7 @@ def test_event_paid(self): self.invoice.signal_workflow('invoice_open') self.assertEqual(self.invoice.state, 'open') journal = self.env['account.journal'].search([], limit=1) - event = ('openerp.addons.connector_ecommerce.models.' + event = ('odoo.addons.connector_ecommerce.models.' 'invoice.on_invoice_paid') with mock.patch(event) as event_mock: self.invoice.pay_and_reconcile( diff --git a/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py index 84e19c99..85831867 100644 --- a/connector_ecommerce/tests/test_onchange.py +++ b/connector_ecommerce/tests/test_onchange.py @@ -4,11 +4,11 @@ import mock -from openerp.addons.connector_ecommerce.unit.sale_order_onchange import ( +from odoo.addons.connector_ecommerce.unit.sale_order_onchange import ( SaleOrderOnChange) -from openerp.addons.connector.session import ConnectorSession -from openerp.addons.connector.connector import ConnectorEnvironment -import openerp.tests.common as common +from odoo.addons.connector.session import ConnectorSession +from odoo.addons.connector.connector import ConnectorEnvironment +import odoo.tests.common as common DB = common.DB ADMIN_USER_ID = common.ADMIN_USER_ID diff --git a/connector_ecommerce/tests/test_picking_event.py b/connector_ecommerce/tests/test_picking_event.py index 849843d1..fec8c8a4 100644 --- a/connector_ecommerce/tests/test_picking_event.py +++ b/connector_ecommerce/tests/test_picking_event.py @@ -4,7 +4,7 @@ import mock -import openerp.tests.common as common +import odoo.tests.common as common class TestPickingEvent(common.TransactionCase): @@ -42,7 +42,7 @@ 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.models.' + event = ('odoo.addons.connector_ecommerce.models.' 'stock.on_picking_out_done') with mock.patch(event) as event_mock: self.picking.action_done() @@ -59,7 +59,7 @@ def test_event_on_picking_out_done_partial(self): self.picking.do_prepare_partial() for operation in self.picking.pack_operation_ids: operation.product_qty = 1 - event = ('openerp.addons.connector_ecommerce.models.' + event = ('odoo.addons.connector_ecommerce.models.' 'stock.on_picking_out_done') with mock.patch(event) as event_mock: self.picking.do_transfer() @@ -72,7 +72,7 @@ def test_event_on_picking_out_done_partial(self): 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.models.' + event = ('odoo.addons.connector_ecommerce.models.' 'stock.on_tracking_number_added') with mock.patch(event) as event_mock: self.picking.carrier_tracking_ref = 'XYZ' diff --git a/connector_ecommerce/unit/line_builder.py b/connector_ecommerce/unit/line_builder.py index f4b38414..04abee7b 100644 --- a/connector_ecommerce/unit/line_builder.py +++ b/connector_ecommerce/unit/line_builder.py @@ -2,8 +2,8 @@ # © 2013-2016 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) -from openerp import models -from openerp.addons.connector.connector import ConnectorUnit +from odoo import models +from odoo.addons.connector.connector import ConnectorUnit class SpecialOrderLineBuilder(ConnectorUnit): diff --git a/connector_ecommerce/unit/sale_order_onchange.py b/connector_ecommerce/unit/sale_order_onchange.py index a698d140..c040dca5 100644 --- a/connector_ecommerce/unit/sale_order_onchange.py +++ b/connector_ecommerce/unit/sale_order_onchange.py @@ -3,7 +3,7 @@ # © 2016 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) -from openerp.addons.connector.connector import ConnectorUnit +from odoo.addons.connector.connector import ConnectorUnit class OnChangeManager(ConnectorUnit): @@ -83,7 +83,7 @@ def play(self, order, 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 + # shipping fees with an Odoo Product line_lists.append(order['order_line']) for line_list in line_lists: diff --git a/connector_ecommerce/wizard/sale_ignore_cancel.py b/connector_ecommerce/wizard/sale_ignore_cancel.py index 1fc36ede..7e2da95f 100644 --- a/connector_ecommerce/wizard/sale_ignore_cancel.py +++ b/connector_ecommerce/wizard/sale_ignore_cancel.py @@ -2,7 +2,7 @@ # © 2013-2016 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) -from openerp import models, fields, api +from odoo import models, fields, api class SaleIgnoreCancel(models.TransientModel): diff --git a/connector_ecommerce/wizard/sale_ignore_cancel_view.xml b/connector_ecommerce/wizard/sale_ignore_cancel_view.xml index 3a4dc2d2..63f71eb0 100644 --- a/connector_ecommerce/wizard/sale_ignore_cancel_view.xml +++ b/connector_ecommerce/wizard/sale_ignore_cancel_view.xml @@ -7,11 +7,11 @@

    This sales order has been canceled from the backend. - The usual action would be to cancel it in OpenERP along + The usual action would be to cancel it in Odoo along all the documents generated (delivery orders, invoices, ...).

    - However, if for any reason you need to keep it open in OpenERP, + However, if for any reason you need to keep it open in Odoo, write the reason here and it will stay open.

    From 2431f791c8a8029217c4d75068c8dbb1e712ea89 Mon Sep 17 00:00:00 2001 From: "Laurent Mignon (ACSONE)" Date: Mon, 15 May 2017 14:22:30 +0200 Subject: [PATCH 47/86] [MIG] Migration to 10.0: Adapt code to 10.0 --- connector_ecommerce/data/ecommerce_data.xml | 13 ++++++++----- connector_ecommerce/models/invoice.py | 11 ++++------- connector_ecommerce/models/product.py | 7 ++----- connector_ecommerce/models/stock.py | 10 +++------- connector_ecommerce/tests/test_invoice_event.py | 4 ++-- connector_ecommerce/tests/test_onchange.py | 10 +--------- connector_ecommerce/tests/test_picking_event.py | 8 ++++---- 7 files changed, 24 insertions(+), 39 deletions(-) diff --git a/connector_ecommerce/data/ecommerce_data.xml b/connector_ecommerce/data/ecommerce_data.xml index f7e2113e..60903b3c 100644 --- a/connector_ecommerce/data/ecommerce_data.xml +++ b/connector_ecommerce/data/ecommerce_data.xml @@ -42,7 +42,7 @@ - + Parent sales order canceled on the backend. The parent sales order has been canceled @@ -51,22 +51,24 @@ is canceled. 30 sale.order - if order.parent_need_cancel: + if sale.parent_need_cancel: failed = True + sale - + Sales order canceled on the backend. The sales order has been canceled on the backend. 20 sale.order - if order.need_cancel: failed = True + if sale.need_cancel: failed = True + sale - + A product needs to be reviewed. A product has been imported from a backend and needs to be reviewed. @@ -75,6 +77,7 @@ sale.order.line if object.product_id and object.product_id.has_checkpoint: failed = True + sale diff --git a/connector_ecommerce/models/invoice.py b/connector_ecommerce/models/invoice.py index e6d04aa6..23dc7ea1 100644 --- a/connector_ecommerce/models/invoice.py +++ b/connector_ecommerce/models/invoice.py @@ -3,7 +3,6 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from odoo import models, api -from odoo.addons.connector.session import ConnectorSession from .event import on_invoice_paid, on_invoice_validated @@ -11,17 +10,15 @@ class AccountInvoice(models.Model): _inherit = 'account.invoice' @api.multi - def confirm_paid(self): - res = super(AccountInvoice, self).confirm_paid() - session = ConnectorSession.from_env(self.env) + def action_invoice_paid(self): + res = super(AccountInvoice, self).action_invoice_paid() for record_id in self.ids: - on_invoice_paid.fire(session, self._name, record_id) + on_invoice_paid.fire(self.env, self._name, record_id) return res @api.multi def invoice_validate(self): res = super(AccountInvoice, self).invoice_validate() - session = ConnectorSession.from_env(self.env) for record_id in self.ids: - on_invoice_validated.fire(session, self._name, record_id) + on_invoice_validated.fire(self.env, self._name, record_id) return res diff --git a/connector_ecommerce/models/product.py b/connector_ecommerce/models/product.py index 619d9e48..eeab494b 100644 --- a/connector_ecommerce/models/product.py +++ b/connector_ecommerce/models/product.py @@ -3,7 +3,6 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from odoo import models, fields, api -from odoo.addons.connector.session import ConnectorSession from .event import on_product_price_changed @@ -42,7 +41,6 @@ def _price_changed(self, vals): 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)] ) @@ -53,7 +51,7 @@ def _price_changed(self, vals): remove_products = product_model.browse(from_product_ids) products -= remove_products for product in products: - on_product_price_changed.fire(session, + on_product_price_changed.fire(self.env, product_model._name, product.id) @@ -100,9 +98,8 @@ def _price_changed(self, vals): """ 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) + on_product_price_changed.fire(self.env, self._name, prod_id) @api.multi def write(self, vals): diff --git a/connector_ecommerce/models/stock.py b/connector_ecommerce/models/stock.py index 6b339cd7..59bfb6ad 100644 --- a/connector_ecommerce/models/stock.py +++ b/connector_ecommerce/models/stock.py @@ -4,7 +4,6 @@ from odoo import models, fields, api -from odoo.addons.connector.session import ConnectorSession from .event import on_picking_out_done, on_tracking_number_added @@ -21,9 +20,8 @@ class StockPicking(models.Model): def write(self, vals): res = super(StockPicking, self).write(vals) if vals.get('carrier_tracking_ref'): - session = ConnectorSession.from_env(self.env) for record_id in self.ids: - on_tracking_number_added.fire(session, self._name, record_id) + on_tracking_number_added.fire(self.env, self._name, record_id) return res @api.multi @@ -32,7 +30,6 @@ def do_transfer(self): # 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.from_env(self.env) for picking in self: if picking.picking_type_id.code != 'outgoing': continue @@ -40,7 +37,7 @@ def do_transfer(self): method = 'partial' else: method = 'complete' - on_picking_out_done.fire(session, 'stock.picking', + on_picking_out_done.fire(self.env, 'stock.picking', picking.id, method) return result @@ -59,14 +56,13 @@ def action_done(self): result = super(StockMove, self).action_done() if fire_event: - session = ConnectorSession.from_env(self.env) 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', + on_picking_out_done.fire(self.env, 'stock.picking', picking.id, 'complete') return result diff --git a/connector_ecommerce/tests/test_invoice_event.py b/connector_ecommerce/tests/test_invoice_event.py index 04ef7a7c..e7f8f020 100644 --- a/connector_ecommerce/tests/test_invoice_event.py +++ b/connector_ecommerce/tests/test_invoice_event.py @@ -46,7 +46,7 @@ def test_event_validated(self): event = ('odoo.addons.connector_ecommerce.' 'models.invoice.on_invoice_validated') with mock.patch(event) as event_mock: - self.invoice.signal_workflow('invoice_open') + self.invoice.action_invoice_open() self.assertEqual(self.invoice.state, 'open') event_mock.fire.assert_called_with(mock.ANY, 'account.invoice', @@ -56,7 +56,7 @@ def test_event_paid(self): """ Test if the ``on_invoice_paid`` event is fired when an invoice is paid """ assert self.invoice, "The invoice has not been created" - self.invoice.signal_workflow('invoice_open') + self.invoice.action_invoice_open() self.assertEqual(self.invoice.state, 'open') journal = self.env['account.journal'].search([], limit=1) event = ('odoo.addons.connector_ecommerce.models.' diff --git a/connector_ecommerce/tests/test_onchange.py b/connector_ecommerce/tests/test_onchange.py index 85831867..ce171ee6 100644 --- a/connector_ecommerce/tests/test_onchange.py +++ b/connector_ecommerce/tests/test_onchange.py @@ -6,8 +6,6 @@ from odoo.addons.connector_ecommerce.unit.sale_order_onchange import ( SaleOrderOnChange) -from odoo.addons.connector.session import ConnectorSession -from odoo.addons.connector.connector import ConnectorEnvironment import odoo.tests.common as common DB = common.DB @@ -17,19 +15,12 @@ class TestOnchange(common.TransactionCase): """ Test if the onchanges are applied correctly on a sales order""" - def setUp(self): - super(TestOnchange, self).setUp() - self.session = ConnectorSession.from_env(self.env) - def test_play_onchange(self): """ 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'] - backend_record = mock.Mock() - env = ConnectorEnvironment(backend_record, self.session, 'sale.order') - partner = partner_model.create({'name': 'seb', 'zip': '69100', 'city': 'Villeurbanne'}) @@ -73,6 +64,7 @@ def test_play_onchange(self): extra_lines = order_vals['backend_order_line'] + env = mock.MagicMock(env=self.env) onchange = SaleOrderOnChange(env) order = onchange.play(order_vals, extra_lines) diff --git a/connector_ecommerce/tests/test_picking_event.py b/connector_ecommerce/tests/test_picking_event.py index fec8c8a4..c89b6342 100644 --- a/connector_ecommerce/tests/test_picking_event.py +++ b/connector_ecommerce/tests/test_picking_event.py @@ -21,16 +21,16 @@ def setUp(self): 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_id': self.env.ref('product.product_product_6').id, + 'name': "iPad Mini", '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_id': self.env.ref('product.product_product_7').id, + 'name': "Apple In-Ear Headphones", 'product_uom_qty': 2, 'product_uom': self.env.ref('product.product_uom_unit').id, 'price_unit': 405, From 4b4ad4554da44f923a079543533653f03ec98ff7 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 9 Jun 2017 15:17:54 +0200 Subject: [PATCH 48/86] fix message_post() expecting a len(recordset) == 1 Use new component system Correct model name Add new style events Show connector tab only for connector manager Fix indentation of views Dispatch on_picking_out_done on stock.picking Create sale shipping line as 'is_delivery' And do not recreate it on delivery if it has been created in the first place Bump connector_ecommerce version --- connector_ecommerce/README.rst | 16 ++- connector_ecommerce/__init__.py | 1 + connector_ecommerce/__manifest__.py | 2 +- connector_ecommerce/components/__init__.py | 3 + .../components/line_builder.py | 109 +++++++++++++++++ .../components/sale_order_onchange.py | 112 ++++++++++++++++++ connector_ecommerce/data/ecommerce_data.xml | 3 + connector_ecommerce/models/invoice.py | 12 +- connector_ecommerce/models/product.py | 8 +- connector_ecommerce/models/sale.py | 19 ++- connector_ecommerce/models/stock.py | 12 +- connector_ecommerce/views/invoice_view.xml | 31 ++--- .../views/payment_mode_view.xml | 80 ++++++------- connector_ecommerce/views/sale_view.xml | 112 +++++++++--------- connector_ecommerce/views/stock_view.xml | 30 ++--- 15 files changed, 408 insertions(+), 142 deletions(-) create mode 100644 connector_ecommerce/components/__init__.py create mode 100644 connector_ecommerce/components/line_builder.py create mode 100644 connector_ecommerce/components/sale_order_onchange.py diff --git a/connector_ecommerce/README.rst b/connector_ecommerce/README.rst index 2222f2c9..66e744b6 100644 --- a/connector_ecommerce/README.rst +++ b/connector_ecommerce/README.rst @@ -15,10 +15,18 @@ 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 + On which the connectors can subscribe listeners. + The events it adds are: + + * ``on_invoice_paid(self, record)`` + * ``on_invoice_validated(self, record)`` + * ``on_invoice_validated(self, record)`` + * ``on_picking_out_done(self, record, method)`` where method is + 'partial' or 'complete' + * ``on_tracking_number_added(self, record)`` + * ``on_product_price_changed(self, record)`` + + Components A piece of code which allows to play all the ``onchanges`` required when we create a sales order. diff --git a/connector_ecommerce/__init__.py b/connector_ecommerce/__init__.py index ad8909f6..6ca5d754 100644 --- a/connector_ecommerce/__init__.py +++ b/connector_ecommerce/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from . import components from . import models from . import unit from . import wizard diff --git a/connector_ecommerce/__manifest__.py b/connector_ecommerce/__manifest__.py index 136ffcdd..b046e3db 100644 --- a/connector_ecommerce/__manifest__.py +++ b/connector_ecommerce/__manifest__.py @@ -4,7 +4,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) {'name': 'Connector for E-Commerce', - 'version': '10.0.1.0.0', + 'version': '10.0.1.1.0', 'category': 'Hidden', 'author': "Camptocamp,Akretion,Odoo Community Association (OCA)", 'website': 'http://odoo-connector.com', diff --git a/connector_ecommerce/components/__init__.py b/connector_ecommerce/components/__init__.py new file mode 100644 index 00000000..09542ea2 --- /dev/null +++ b/connector_ecommerce/components/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +from . import line_builder +from . import sale_order_onchange diff --git a/connector_ecommerce/components/line_builder.py b/connector_ecommerce/components/line_builder.py new file mode 100644 index 00000000..40913a71 --- /dev/null +++ b/connector_ecommerce/components/line_builder.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +# © 2013-2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from odoo import models +from odoo.addons.component.core import Component + + +class SpecialOrderLineBuilder(Component): + """ Base class to build a sales order line for a sales 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. + + It can be subclassed to customize the way the lines are created. + + Usage:: + + builder = self.components(usage='shipping.line.builder', + model_name='sale.order.line') + builder.price_unit = 100 + builder.get_line() + + """ + _name = 'ecommerce.order.line.builder' + _inherit = 'base.connector' + _usage = 'order.line.builder' + + def __init__(self, work_context): + super(SpecialOrderLineBuilder, self).__init__(work_context) + 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 + self.sequence = 980 + + def get_line(self): + assert self.product_ref or self.product + assert self.price_unit is not None + + product = self.product + if product is None: + product = self.env.ref('.'.join(self.product_ref)) + + 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, + 'product_uom_qty': self.quantity, + 'price_unit': self.price_unit * self.sign, + 'sequence': self.sequence} + + +class ShippingLineBuilder(Component): + """ Return values for a Shipping line """ + + _name = 'ecommerce.order.line.builder.shipping' + _inherit = 'ecommerce.order.line.builder' + _usage = 'order.line.builder.shipping' + + def __init__(self, work_context): + super(ShippingLineBuilder, self).__init__(work_context) + self.product_ref = ('connector_ecommerce', 'product_product_shipping') + self.sequence = 999 + + def get_line(self): + values = super(ShippingLineBuilder, self).get_line() + values['is_delivery'] = True + return values + + +class CashOnDeliveryLineBuilder(Component): + """ Return values for a Cash on Delivery line """ + + _name = 'ecommerce.order.line.builder.cod' + _inherit = 'ecommerce.order.line.builder' + _usage = 'order.line.builder.cod' + + def __init__(self, work_context): + super(CashOnDeliveryLineBuilder, self).__init__(work_context) + self.product_ref = ('connector_ecommerce', + 'product_product_cash_on_delivery') + self.sequence = 995 + + +class GiftOrderLineBuilder(Component): + """ Return values for a Gift line """ + + _name = 'ecommerce.order.line.builder.gift' + _inherit = 'ecommerce.order.line.builder' + _usage = 'order.line.builder.gift' + + def __init__(self, work_context): + super(GiftOrderLineBuilder, self).__init__(work_context) + self.product_ref = ('connector_ecommerce', + 'product_product_gift') + self.sign = -1 + self.gift_code = None + self.sequence = 990 + + 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 diff --git a/connector_ecommerce/components/sale_order_onchange.py b/connector_ecommerce/components/sale_order_onchange.py new file mode 100644 index 00000000..5d3aef6b --- /dev/null +++ b/connector_ecommerce/components/sale_order_onchange.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +# © 2013-TODAY Akretion (Sébastien Beau) +# © 2016 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from odoo.addons.component.core import Component + + +class OnChangeManager(Component): + + _name = 'ecommerce.onchange.manager' + _inherit = 'base.connector' + + def get_new_values(self, record, on_change_result, model=None): + vals = on_change_result.get('value', {}) + new_values = {} + for fieldname, value in vals.iteritems(): + if fieldname not in record: + if model: + column = self.env[model]._fields[fieldname] + if column.type == 'many2one': + value = value[0] # many2one are tuple (id, name) + new_values[fieldname] = value + return new_values + + def play_onchanges(self, model, values, onchange_fields): + model = self.env[model] + onchange_specs = model._onchange_spec() + + # we need all fields in the dict even the empty ones + # otherwise 'onchange()' will not apply changes to them + all_values = values.copy() + for field in model._fields: + if field not in all_values: + all_values[field] = False + + # we work on a temporary record + new_record = model.new(all_values) + + new_values = {} + for field in onchange_fields: + onchange_values = new_record.onchange(all_values, + field, onchange_specs) + new_values.update(self.get_new_values(values, onchange_values, + model=model._name)) + all_values.update(new_values) + + res = {f: v for f, v in all_values.iteritems() + if f in values or f in new_values} + return res + + +class SaleOrderOnChange(Component): + + _name = 'ecommerce.onchange.manager.sale.order' + _inherit = 'ecommerce.onchange.manager' + _usage = 'ecommerce.onchange.manager.sale.order' + + order_onchange_fields = [ + 'partner_id', + 'partner_shipping_id', + 'payment_mode_id', + 'workflow_process_id', + ] + + line_onchange_fields = [ + 'product_id', + ] + + def play(self, order, order_lines): + """ Play the onchange of the sales order and it's lines + + :param order: sales order values + :type: dict + :param order_lines: data of the sales order lines + :type: list of dict + + :return: the sales order updated by the onchanges + :rtype: dict + """ + # play onchange on sales order + order = self.play_onchanges('sale.order', order, + self.order_onchange_fields) + + # 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: + # we have both backend-dependent and oerp-native order + # lines. + # oerp-native lines can have been added to map + # shipping fees with an Odoo Product + line_lists.append(order['order_line']) + + for line_list in line_lists: + for idx, command_line in enumerate(line_list): + # line_list format:[(0, 0, {...}), (0, 0, {...})] + 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_onchanges( + 'sale.order.line', + old_line_data, + self.line_onchange_fields + ) + new_line = (command_line[0], + command_line[1], + new_line_data) + processed_order_lines.append(new_line) + # in place modification of the sales order line in the list + line_list[idx] = new_line + return order diff --git a/connector_ecommerce/data/ecommerce_data.xml b/connector_ecommerce/data/ecommerce_data.xml index 60903b3c..90d50886 100644 --- a/connector_ecommerce/data/ecommerce_data.xml +++ b/connector_ecommerce/data/ecommerce_data.xml @@ -51,6 +51,7 @@ is canceled. 30 sale.order + sale if sale.parent_need_cancel: failed = True @@ -63,6 +64,7 @@ backend. 20 sale.order + sale if sale.need_cancel: failed = True sale @@ -75,6 +77,7 @@ Go to Connectors > Checkpoint and review the new products. 20 sale.order.line + sale if object.product_id and object.product_id.has_checkpoint: failed = True sale diff --git a/connector_ecommerce/models/invoice.py b/connector_ecommerce/models/invoice.py index 23dc7ea1..fb21547c 100644 --- a/connector_ecommerce/models/invoice.py +++ b/connector_ecommerce/models/invoice.py @@ -12,13 +12,17 @@ class AccountInvoice(models.Model): @api.multi def action_invoice_paid(self): res = super(AccountInvoice, self).action_invoice_paid() - for record_id in self.ids: - on_invoice_paid.fire(self.env, self._name, record_id) + for record in self: + self._event('on_invoice_paid').notify(record) + # deprecated: + on_invoice_paid.fire(self.env, self._name, record.id) return res @api.multi def invoice_validate(self): res = super(AccountInvoice, self).invoice_validate() - for record_id in self.ids: - on_invoice_validated.fire(self.env, self._name, record_id) + for record in self: + self._event('on_invoice_validated').notify(record) + # deprecated: + on_invoice_validated.fire(self.env, self._name, record.id) return res diff --git a/connector_ecommerce/models/product.py b/connector_ecommerce/models/product.py index eeab494b..fb925220 100644 --- a/connector_ecommerce/models/product.py +++ b/connector_ecommerce/models/product.py @@ -51,6 +51,8 @@ def _price_changed(self, vals): remove_products = product_model.browse(from_product_ids) products -= remove_products for product in products: + self._event('on_product_price_changed').notify(product) + # deprecated: on_product_price_changed.fire(self.env, product_model._name, product.id) @@ -98,8 +100,10 @@ def _price_changed(self, vals): """ price_fields = self._price_changed_fields() if any(field in vals for field in price_fields): - for prod_id in self.ids: - on_product_price_changed.fire(self.env, self._name, prod_id) + for product in self: + self._event('on_product_price_changed').notify(product) + # deprecated: + on_product_price_changed.fire(self.env, self._name, product.id) @api.multi def write(self, vals): diff --git a/connector_ecommerce/models/sale.py b/connector_ecommerce/models/sale.py index 5fa1153b..665ca831 100644 --- a/connector_ecommerce/models/sale.py +++ b/connector_ecommerce/models/sale.py @@ -66,7 +66,7 @@ def _compute_parent_id(self): """ Need to be inherited in the connectors to implement the parent logic. - See an implementation example in ``magentoerpconnect``. + See an implementation example in ``connector_magento``. """ self.parent_id = False @@ -133,10 +133,10 @@ def _log_canceled_in_backend(self): for order in self: message = _("Warning: the origin sales order %s has been canceled " "on the backend.") % order.name - if order.picking_ids: - order.picking_ids.message_post(body=message) - if order.invoice_ids: - order.invoice_ids.message_post(body=message) + for picking in order.picking_ids: + picking.message_post(body=message) + for invoice in order.invoice_ids: + invoice.message_post(body=message) @api.model def create(self, values): @@ -199,3 +199,12 @@ def action_view_parent(self): action['views'] = [(view.id if view else False, 'form')] action['res_id'] = parent.id return action + + def _create_delivery_line(self, carrier, price_unit): + if self.order_line.filtered(lambda r: r.is_delivery): + # skip if we have already a delivery line (created by + # import of order) + return + else: + return super(SaleOrder, self)._create_delivery_line(carrier, + price_unit) diff --git a/connector_ecommerce/models/stock.py b/connector_ecommerce/models/stock.py index 59bfb6ad..3d3b6d62 100644 --- a/connector_ecommerce/models/stock.py +++ b/connector_ecommerce/models/stock.py @@ -20,8 +20,10 @@ class StockPicking(models.Model): def write(self, vals): res = super(StockPicking, self).write(vals) if vals.get('carrier_tracking_ref'): - for record_id in self.ids: - on_tracking_number_added.fire(self.env, self._name, record_id) + for record in self: + self._event('on_tracking_number_added').notify(record) + # deprecated: + on_tracking_number_added.fire(self.env, self._name, record.id) return res @api.multi @@ -37,6 +39,8 @@ def do_transfer(self): method = 'partial' else: method = 'complete' + self._event('on_picking_out_done').notify(picking, method) + # deprecated: on_picking_out_done.fire(self.env, 'stock.picking', picking.id, method) @@ -62,6 +66,10 @@ def action_done(self): continue # partial pickings are handled in # StockPicking.do_transfer() + picking._event('on_picking_out_done').notify( + picking, 'complete' + ) + # deprecated: on_picking_out_done.fire(self.env, 'stock.picking', picking.id, 'complete') diff --git a/connector_ecommerce/views/invoice_view.xml b/connector_ecommerce/views/invoice_view.xml index 1cb4945e..3984fdb2 100644 --- a/connector_ecommerce/views/invoice_view.xml +++ b/connector_ecommerce/views/invoice_view.xml @@ -1,19 +1,22 @@ - - account.invoice.connector.form - account.invoice - - - - - - - - - + + account.invoice.connector.form + account.invoice + + + + + + + + + + + diff --git a/connector_ecommerce/views/payment_mode_view.xml b/connector_ecommerce/views/payment_mode_view.xml index 6044dcdb..db5dfc0e 100644 --- a/connector_ecommerce/views/payment_mode_view.xml +++ b/connector_ecommerce/views/payment_mode_view.xml @@ -1,49 +1,49 @@ - - account.payment.mode.connector_ecommerce.form - account.payment.mode - - - - - - - - - -

    - 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. -
    -

    -
    + + account.payment.mode.connector_ecommerce.form + account.payment.mode + + + + + + + + + +

    + 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. +
    +

    -
    -
    +
    +
    +
    - - account.payment.mode.connector_ecommerce.tree - account.payment.mode - - - - - + + account.payment.mode.connector_ecommerce.tree + account.payment.mode + + + + - + +
    diff --git a/connector_ecommerce/views/sale_view.xml b/connector_ecommerce/views/sale_view.xml index bbac7d56..5fadefdb 100644 --- a/connector_ecommerce/views/sale_view.xml +++ b/connector_ecommerce/views/sale_view.xml @@ -1,65 +1,65 @@ - - sale.order.connector.form - sale.order - - - - + + sale.order.connector.form + sale.order + + + + - - - - - - + + + + + + - - sale_order.view_form - sale.order - - - - - - - - -