openerp-community-reviewer team mailing list archive
-
openerp-community-reviewer team
-
Mailing list archive
-
Message #00898
lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
Joël Grand-Guillaume @ camptocamp has proposed merging lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl.
Commit message:
[MOVE] Move here the sale_exceptions module from the lp:e-commerce-addons
Requested reviews:
Sale Core Editors (sale-core-editors)
For more details, see:
https://code.launchpad.net/~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge/+merge/193567
Hi,
I suggest to move this module from e-commerce-addons to here because it really concerns the sales workflow in a more generic way than just the e-commerce context.
I put the branch under the reviewer team so feel free to fix stuff if you'd like.
Regards,
Joël
--
https://code.launchpad.net/~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge/+merge/193567
Your team OpenERP Community Reviewer is subscribed to branch lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge.
=== added directory 'sale_exceptions'
=== added file 'sale_exceptions/__init__.py'
--- sale_exceptions/__init__.py 1970-01-01 00:00:00 +0000
+++ sale_exceptions/__init__.py 2013-11-01 10:07:07 +0000
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import sale
+import wizard
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+
=== added file 'sale_exceptions/__openerp__.py'
--- sale_exceptions/__openerp__.py 1970-01-01 00:00:00 +0000
+++ sale_exceptions/__openerp__.py 2013-11-01 10:07:07 +0000
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2011 Akretion LTDA.
+# authors: Raphaël Valyi, Renato Lima
+# Copyright (C) 2010-2012 Akretion Sébastien BEAU <sebastien.beau@xxxxxxxxxxxx>
+# Copyright (C) 2012 Camptocamp SA (Guewen Baconnier)
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+
+{
+ 'name': 'Sale Exceptions',
+ 'version': '0.1',
+ 'category': 'Generic Modules/Sale',
+ 'description': """
+This module allows you attach several customizable exceptions to your sale order in a way that you can filter orders by exceptions type and fix them.
+This is especially useful in an order importation scenario such as with the base_sale_multi_channels module, because it's likely a few orders have errors when you import them (like product not found in OpenERP, wrong line format etc...)
+""",
+ 'author': 'Akretion',
+ 'website': 'http://www.akretion.com',
+ 'depends': ['sale'],
+ 'init_xml': [
+ 'settings/sale.exception.csv',
+ ],
+ 'update_xml': ['sale_workflow.xml',
+ 'sale_view.xml',
+ 'sale_exceptions_data.xml',
+ 'wizard/sale_exception_confirm_view.xml',
+ 'security/ir.model.access.csv'],
+ 'demo_xml': [],
+ 'installable': True,
+}
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
=== added file 'sale_exceptions/sale.py'
--- sale_exceptions/sale.py 1970-01-01 00:00:00 +0000
+++ sale_exceptions/sale.py 2013-11-01 10:07:07 +0000
@@ -0,0 +1,208 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2011 Akretion LTDA.
+# Copyright (C) 2010-2012 Akretion Sébastien BEAU <sebastien.beau@xxxxxxxxxxxx>
+# Copyright (C) 2012 Camptocamp SA (Guewen Baconnier)
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import time
+import netsvc
+
+from openerp.osv.orm import Model
+from openerp.osv import fields
+from openerp.osv.osv import except_osv
+from tools.safe_eval import safe_eval as eval
+from tools.translate import _
+
+class sale_exception(Model):
+ _name = "sale.exception"
+ _description = "Sale Exceptions"
+ _order="active desc, sequence asc"
+ _columns = {
+ 'name': fields.char('Exception Name', size=64, required=True, translate=True),
+ 'description': fields.text('Description', translate=True),
+ 'sequence': fields.integer('Sequence', help="Gives the sequence order when applying the test"),
+ 'model': fields.selection([('sale.order', 'Sale Order'),
+ ('sale.order.line', 'Sale Order Line')],
+ string='Apply on', required=True),
+ 'active': fields.boolean('Active'),
+ 'code': fields.text('Python Code',
+ help="Python code executed to check if the exception apply or not. " \
+ "The code must apply block = True to apply the exception."),
+ 'sale_order_ids': fields.many2many('sale.order', 'sale_order_exception_rel',
+ 'exception_id', 'sale_order_id',
+ string='Sale Orders', readonly=True),
+ }
+
+ _defaults = {
+ 'code': """# Python code. Use failed = True to block the sale order.
+# You can use the following variables :
+# - self: ORM model of the record which is checked
+# - order or line: browse_record of the sale order or sale order line
+# - object: same as order or line, browse_record of the sale order or sale order line
+# - pool: ORM model pool (i.e. self.pool)
+# - time: Python time module
+# - cr: database cursor
+# - uid: current user id
+# - context: current context
+"""
+ }
+
+class sale_order(Model):
+ _inherit = "sale.order"
+
+ _order = 'main_exception_id asc, date_order desc, name desc'
+
+ def _get_main_error(self, cr, uid, ids, name, args, context=None):
+ res = {}
+ for sale_order in self.browse(cr, uid, ids, context=context):
+ if sale_order.state == 'draft' and sale_order.exceptions_ids:
+ res[sale_order.id] = sale_order.exceptions_ids[0].id
+ else:
+ res[sale_order.id] = False
+ return res
+
+ _columns = {
+ 'main_exception_id': fields.function(_get_main_error,
+ type='many2one',
+ relation="sale.exception",
+ string='Main Exception',
+ store={
+ 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['exceptions_ids', 'state'], 10),
+ }),
+ 'exceptions_ids': fields.many2many('sale.exception', 'sale_order_exception_rel',
+ 'sale_order_id', 'exception_id',
+ string='Exceptions'),
+ 'ignore_exceptions': fields.boolean('Ignore Exceptions'),
+ }
+
+ def test_all_draft_orders(self, cr, uid, context=None):
+ ids = self.search(cr, uid, [('state', '=', 'draft')])
+ self.test_exceptions(cr, uid, ids)
+ return True
+
+ def _popup_exceptions(self, cr, uid, order_id, context=None):
+ model_data_obj = self.pool.get('ir.model.data')
+ list_obj = self.pool.get('sale.exception.confirm')
+ ctx = context.copy()
+ ctx.update({'active_id': order_id,
+ 'active_ids': [order_id]})
+ list_id = list_obj.create(cr, uid, {}, context=ctx)
+ view_id = model_data_obj.get_object_reference(
+ cr, uid, 'sale_exceptions', 'view_sale_exception_confirm')[1]
+ action = {
+ 'name': _("Exceptions On Sale Order"),
+ 'type': 'ir.actions.act_window',
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'res_model': 'sale.exception.confirm',
+ 'view_id': [view_id],
+ 'target': 'new',
+ 'nodestroy': True,
+ 'res_id': list_id,
+ }
+ return action
+
+ def action_button_confirm(self, cr, uid, ids, context=None):
+ exception_ids = self.detect_exceptions(cr, uid, ids, context=context)
+ if exception_ids:
+ return self._popup_exceptions(cr, uid, ids[0], context=context)
+ else:
+ return super(sale_order, self).action_button_confirm(cr, uid, ids, context=context)
+
+ def test_exceptions(self, cr, uid, ids, context=None):
+ """
+ Condition method for the workflow from draft to confirm
+ """
+ exception_ids = self.detect_exceptions(cr, uid, ids, context=context)
+ if exception_ids:
+ return False
+ return True
+
+ def detect_exceptions(self, cr, uid, ids, context=None):
+ exception_obj = self.pool.get('sale.exception')
+ order_exception_ids = exception_obj.search(cr, uid,
+ [('model', '=', 'sale.order')], context=context)
+ line_exception_ids = exception_obj.search(cr, uid,
+ [('model', '=', 'sale.order.line')], context=context)
+
+ order_exceptions = exception_obj.browse(cr, uid, order_exception_ids, context=context)
+ line_exceptions = exception_obj.browse(cr, uid, line_exception_ids, context=context)
+
+ exception_ids = False
+ for order in self.browse(cr, uid, ids):
+ if order.ignore_exceptions:
+ continue
+ exception_ids = self._detect_exceptions(cr, uid, order,
+ order_exceptions, line_exceptions, context=context)
+
+ self.write(cr, uid, [order.id], {'exceptions_ids': [(6, 0, exception_ids)]})
+ return exception_ids
+
+ def _exception_rule_eval_context(self, cr, uid, obj_name, obj, context=None):
+ if context is None:
+ context = {}
+
+ return {obj_name: obj,
+ 'self': self.pool.get(obj._name),
+ 'object': obj,
+ 'obj': obj,
+ 'pool': self.pool,
+ 'cr': cr,
+ 'uid': uid,
+ 'user': self.pool.get('res.users').browse(cr, uid, uid),
+ 'time': time,
+ # copy context to prevent side-effects of eval
+ 'context': dict(context),}
+
+ def _rule_eval(self, cr, uid, rule, obj_name, obj, context):
+ expr = rule.code
+ space = self._exception_rule_eval_context(cr, uid, obj_name, obj,
+ context=context)
+ try:
+ eval(expr, space,
+ mode='exec', nocopy=True) # nocopy allows to return 'result'
+ except Exception, e:
+ raise except_osv(_('Error'), _('Error when evaluating the sale exception rule :\n %s \n(%s)') %
+ (rule.name, e))
+ return space.get('failed', False)
+
+ def _detect_exceptions(self, cr, uid, order, order_exceptions, line_exceptions, context=None):
+ exception_ids = []
+ for rule in order_exceptions:
+ if self._rule_eval(cr, uid, rule, 'order', order, context):
+ exception_ids.append(rule.id)
+
+ for order_line in order.order_line:
+ for rule in line_exceptions:
+ if rule.id in exception_ids:
+ continue # we do not matter if the exception as already been
+ # found for an order line of this order
+ if self._rule_eval(cr, uid, rule, 'line', order_line, context):
+ exception_ids.append(rule.id)
+
+ return exception_ids
+
+ def copy(self, cr, uid, id, default=None, context=None):
+ if default is None:
+ default = {}
+ default.update({
+ 'ignore_exceptions': False,
+ })
+ return super(sale_order, self).copy(cr, uid, id, default=default, context=context)
=== added file 'sale_exceptions/sale_exceptions_data.xml'
--- sale_exceptions/sale_exceptions_data.xml 1970-01-01 00:00:00 +0000
+++ sale_exceptions/sale_exceptions_data.xml 2013-11-01 10:07:07 +0000
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data noupdate="1">
+
+ <record forcecreate="True" id="ir_cron_test_orders" model="ir.cron">
+ <field name="name">Test Draft Orders</field>
+ <field eval="False" name="active"/>
+ <field name="user_id" ref="base.user_root"/>
+ <field name="interval_number">20</field>
+ <field name="interval_type">minutes</field>
+ <field name="numbercall">-1</field>
+ <field eval="False" name="doall"/>
+ <field eval="'sale.order'" name="model"/>
+ <field eval="'test_all_draft_orders'" name="function"/>
+ <field eval="'()'" name="args"/>
+ </record>
+
+ </data>
+</openerp>
=== added file 'sale_exceptions/sale_view.xml'
--- sale_exceptions/sale_view.xml 1970-01-01 00:00:00 +0000
+++ sale_exceptions/sale_view.xml 2013-11-01 10:07:07 +0000
@@ -0,0 +1,106 @@
+<?xml version="1.0" ?>
+<openerp>
+ <data>
+
+ <record id="view_sale_exception_tree" model="ir.ui.view">
+ <field name="name">sale.exception.tree</field>
+ <field name="model">sale.exception</field>
+ <field name="type">tree</field>
+ <field name="arch" type="xml">
+ <tree string="Sale Exception">
+ <field name="active"/>
+ <field name="name"/>
+ <field name="description"/>
+ <field name="model"/>
+ <field name="sequence"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="view_sale_exception_form" model="ir.ui.view">
+ <field name="name">sale.exception.form</field>
+ <field name="model">sale.exception</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <form string="Sale Exception Setup">
+ <group colspan="4" col="2">
+ <field name="name"/>
+ <field name="description"/>
+ </group>
+ <group col="4" colspan="4" groups="base.group_sale_manager">
+ <field name="active"/>
+ <field name="sequence"/>
+ <group colspan="4" col="2" groups="base.group_system">
+ <field name="model"/>
+ <field name="code"/>
+ </group>
+ </group>
+ <group colspan="4" col="2">
+ <separator string="Affected Sales Orders"/>
+ <newline/>
+ <field name="sale_order_ids" nolabel="1" domain="[('state', '=', 'draft')]"/>
+ </group>
+ </form>
+ </field>
+ </record>
+
+ <record id="action_sale_test_tree" model="ir.actions.act_window">
+ <field name="name">Exception Rules</field>
+ <field name="res_model">sale.exception</field>
+ <field name="view_type">form</field>
+ <field name="view_mode">tree,form</field>
+ <field name="view_id" ref="view_sale_exception_tree"/>
+ <field name="context">{'active_test': False}</field>
+ </record>
+
+ <menuitem action="action_sale_test_tree" id="menu_sale_test" parent="base.menu_sale_config_sales" />
+
+
+ <record id="view_order_form" model="ir.ui.view">
+ <field name="name">sale_exceptions.view_order_form</field>
+ <field name="model">sale.order</field>
+ <field name="type">form</field>
+ <field name="priority">100</field>
+ <field name="inherit_id" ref="sale.view_order_form"/>
+ <field name="arch" type="xml">
+ <field name="name" position="after">
+ <field name="main_exception_id" nolabel="1"
+ attrs="{'invisible':[('main_exception_id','=', False)]}"/>
+ </field>
+ <xpath expr="//page[@string='Other Information']/group"
+ position="inside">
+ <group name="exception" colspan="2" col="2">
+ <separator string="Exception" colspan="2"/>
+ <field name="exceptions_ids" colspan="2" nolabel="1"/>
+ </group>
+ </xpath>
+ </field>
+ </record>
+
+ <record id="view_order_tree" model="ir.ui.view">
+ <field name="name">sale_exceptions.view_order_tree</field>
+ <field name="model">sale.order</field>
+ <field name="type">tree</field>
+ <field name="inherit_id" ref="sale.view_order_tree"/>
+ <field name="arch" type="xml">
+ <field name="state" position="after">
+ <field name="main_exception_id"/>
+ </field>
+ </field>
+ </record>
+
+ <record id="view_sales_order_filter" model="ir.ui.view">
+ <field name="name">sale_exceptions.view_sales_order_filter</field>
+ <field name="model">sale.order</field>
+ <field name="inherit_id" ref="sale.view_sales_order_filter" />
+ <field name="type">search</field>
+ <field eval="32" name="priority"/>
+ <field name="arch" type="xml">
+ <filter icon="terp-check" string="Sales" position="after">
+ <separator orientation="vertical"/>
+ <filter icon="terp-emblem-important" name="tofix" string="TO FIX" domain="[('main_exception_id','!=',False)]"/>
+ </filter>
+ </field>
+ </record>
+ </data>
+</openerp>
=== added file 'sale_exceptions/sale_workflow.xml'
--- sale_exceptions/sale_workflow.xml 1970-01-01 00:00:00 +0000
+++ sale_exceptions/sale_workflow.xml 2013-11-01 10:07:07 +0000
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+ <record id="sale.trans_draft_router" model="workflow.transition">
+ <field name="signal">order_confirm</field>
+ <field name="condition">test_exceptions()</field>
+ </record>
+ </data>
+</openerp>
=== added directory 'sale_exceptions/security'
=== added file 'sale_exceptions/security/ir.model.access.csv'
--- sale_exceptions/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
+++ sale_exceptions/security/ir.model.access.csv 2013-11-01 10:07:07 +0000
@@ -0,0 +1,3 @@
+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
+"access_sale_exception","sale.exception","model_sale_exception","base.group_user",1,0,0,0
+"access_sale_exception_manager","sale.exception","model_sale_exception","base.group_sale_manager",1,1,1,1
=== added directory 'sale_exceptions/settings'
=== added file 'sale_exceptions/settings/sale.exception.csv'
--- sale_exceptions/settings/sale.exception.csv 1970-01-01 00:00:00 +0000
+++ sale_exceptions/settings/sale.exception.csv 2013-11-01 10:07:07 +0000
@@ -0,0 +1,5 @@
+"id","name","description","sequence","model","code","active"
+"excep_no_zip","No ZIP code on destination",,50,"sale.order","if not order.partner_shipping_id.zip:
+ failed=True",False
+"excep_no_stock","Not Enough Virtual Stock",,50,"sale.order.line","if line.product_id and line.product_id.type == 'product' and line.product_id.virtual_available < line.product_uom_qty:
+ failed=True",False
=== added directory 'sale_exceptions/wizard'
=== added file 'sale_exceptions/wizard/__init__.py'
--- sale_exceptions/wizard/__init__.py 1970-01-01 00:00:00 +0000
+++ sale_exceptions/wizard/__init__.py 2013-11-01 10:07:07 +0000
@@ -0,0 +1,1 @@
+import sale_exception_confirm
=== added file 'sale_exceptions/wizard/sale_exception_confirm.py'
--- sale_exceptions/wizard/sale_exception_confirm.py 1970-01-01 00:00:00 +0000
+++ sale_exceptions/wizard/sale_exception_confirm.py 2013-11-01 10:07:07 +0000
@@ -0,0 +1,56 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# Copyright Camptocamp SA
+# @author: Guewen Baconnier
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import netsvc
+
+from osv import osv, fields
+
+
+class SaleExceptionConfirm(osv.osv_memory):
+
+ _name = 'sale.exception.confirm'
+
+ _columns = {
+ 'sale_id': fields.many2one('sale.order', 'Sale'),
+ 'exception_ids': fields.many2many('sale.exception', string='Exceptions to resolve', readonly=True),
+ 'ignore': fields.boolean('Ignore Exceptions'),
+ }
+
+ def default_get(self, cr, uid, fields, context=None):
+ res = super(SaleExceptionConfirm, self).default_get(cr, uid, fields, context=context)
+ order_obj = self.pool.get('sale.order')
+ sale_id = context.get('active_id', False)
+ if sale_id:
+ sale = order_obj.browse(cr, uid, sale_id, context=context)
+ exception_ids = [e.id for e in sale.exceptions_ids]
+ res.update({'exception_ids': [(6, 0, exception_ids)]})
+
+ res.update({'sale_id': sale_id})
+ return res
+
+ def action_confirm(self, cr, uid, ids, context=None):
+ form = self.browse(cr, uid, ids[0], context=context)
+ if form.ignore:
+ self.pool.get('sale.order').write(cr, uid, form.sale_id.id,
+ {'ignore_exceptions': True}, context=context)
+ return {'type': 'ir.actions.act_window_close'}
+
+SaleExceptionConfirm()
=== added file 'sale_exceptions/wizard/sale_exception_confirm_view.xml'
--- sale_exceptions/wizard/sale_exception_confirm_view.xml 1970-01-01 00:00:00 +0000
+++ sale_exceptions/wizard/sale_exception_confirm_view.xml 2013-11-01 10:07:07 +0000
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+
+ <record id="view_sale_exception_confirm" model="ir.ui.view">
+ <field name="name">Sale Exceptions</field>
+ <field name="model">sale.exception.confirm</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <form string="Sale Exceptions On Sale Order" version="7.0">
+ <group>
+ <field name="exception_ids" nolabel="1" colspan="4">
+ <form string="Sale Exception">
+ <field name="name" colspan="4"/>
+ <field name="description" colspan="4"/>
+ </form>
+ <tree string="Sale Exceptions">
+ <field name="name"/>
+ <field name="description"/>
+ </tree>
+ </field>
+ <newline/>
+ <field name="ignore" groups='base.group_sale_manager'/>
+ </group>
+ <footer>
+ <button name="action_confirm" string="_Ok"
+ colspan="1" type="object" icon="gtk-ok" />
+ </footer>
+ </form>
+ </field>
+ </record>
+
+ <record id="action_sale_exception_confirm" model="ir.actions.act_window">
+ <field name="name">Sale Exceptions</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">sale.exception.confirm</field>
+ <field name="view_type">form</field>
+ <field name="view_mode">form</field>
+ <field name="view_id" ref="view_sale_exception_confirm"/>
+ <field name="target">new</field>
+ </record>
+
+ </data>
+</openerp>
Follow ups
-
lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: noreply, 2013-11-15
-
Re: lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: Nicolas Bessi - Camptocamp, 2013-11-15
-
Re: lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: Nicolas Bessi - Camptocamp, 2013-11-15
-
Re: lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: Guewen Baconnier @ Camptocamp, 2013-11-11
-
Re: lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: Joël Grand-Guillaume, 2013-11-05
-
Re: lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: Sébastien BEAU - http : //www . akretion . com, 2013-11-04
-
Re: lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: Sébastien BEAU - http : //www . akretion . com, 2013-11-04
-
Re: lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: Joël Grand-Guillaume, 2013-11-04
-
Re: lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: Pedro Manuel Baeza, 2013-11-04
-
Re: lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: Sébastien BEAU - http : //www . akretion . com, 2013-11-04
-
Re: lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: Pedro Manuel Baeza, 2013-11-01
-
lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: Joël Grand-Guillaume, 2013-11-01
-
lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:sale-wkfl
From: Joël Grand-Guillaume, 2013-11-01