diff --git a/chouettecoop_addons/readme b/chouettecoop_addons/readme
index 587be6b4c3..6c5ba56ffa 100644
--- a/chouettecoop_addons/readme
+++ b/chouettecoop_addons/readme
@@ -1 +1,2 @@
-x
+
+Modules modifiés ou dévelopés par La Chouette Coop
diff --git a/chouettecoop_addons/restrict_db_mgr/README.md b/chouettecoop_addons/restrict_db_mgr/README.md
new file mode 100644
index 0000000000..2c7ec88fa4
--- /dev/null
+++ b/chouettecoop_addons/restrict_db_mgr/README.md
@@ -0,0 +1,5 @@
+Restrict access to Manage Databases feature,
+only administrator or members of 'Access Right' group allowed.
+
+Code modified by La Chouette Coop from original:
+https://github.com/OpenSur/Odoo_addons/tree/master/restrict_db_mgr
diff --git a/louve_addons/louve_custom_cpo/__init__.py b/chouettecoop_addons/restrict_db_mgr/__init__.py
old mode 100755
new mode 100644
similarity index 79%
rename from louve_addons/louve_custom_cpo/__init__.py
rename to chouettecoop_addons/restrict_db_mgr/__init__.py
index 1f82f98b08..5fb58fa823
--- a/louve_addons/louve_custom_cpo/__init__.py
+++ b/chouettecoop_addons/restrict_db_mgr/__init__.py
@@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Product - Average Consumption Module for Odoo
-# Copyright (C) 2013-Today GRAP (http://www.grap.coop)
-# @author Julien WESTE
-# @author Sylvain LE GAL (https://twitter.com/legalsylvain)
+# OpenERP, Open Source Enterprise Management Solution
+# risk_management Module
+# Copyright (C) 2014 OpenSur (comercial@opensur.com)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -20,5 +19,4 @@
# along with this program. If not, see .
#
##############################################################################
-
-from . import model
+from . import controllers
diff --git a/louve_addons/louve_custom_cpo/model/computed_purchase_order_line.py b/chouettecoop_addons/restrict_db_mgr/__openerp__.py
old mode 100755
new mode 100644
similarity index 58%
rename from louve_addons/louve_custom_cpo/model/computed_purchase_order_line.py
rename to chouettecoop_addons/restrict_db_mgr/__openerp__.py
index aeb80d6d75..658c642a3d
--- a/louve_addons/louve_custom_cpo/model/computed_purchase_order_line.py
+++ b/chouettecoop_addons/restrict_db_mgr/__openerp__.py
@@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Purchase - Computed Purchase Order Module for Odoo
-# Copyright (C) 2013-Today GRAP (http://www.grap.coop)
-# @author Julien WESTE
-# @author Sylvain LE GAL (https://twitter.com/legalsylvain)
+# OpenERP, Open Source Enterprise Management Solution
+# risk_management Module
+# Copyright (C) 2014 OpenSur (comercial@opensur.com)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -20,10 +19,20 @@
# along with this program. If not, see .
#
##############################################################################
+{
+ 'name' : 'Restrict access to Manage Databases',
+ 'summary' : "Restrict access to Manage Databases feature, only administrator or members of 'Access Right' group allowed.",
+ 'category' : 'Website',
+ 'author' : 'OpenSur SA',
+ 'website' : 'http://www.opensur.com',
+ 'version' : '9.0.0.1.0',
+ 'license' : "AGPL-3",
+ 'depends': [
+ 'base',
+ 'web',
+ ],
+ 'installable': True,
+ 'auto_install': True,
+ 'active': False,
+}
-from openerp import models
-
-
-class ComputedPurchaseOrderLine(models.Model):
- _inherit = 'computed.purchase.order.line'
- _order = 'product_code'
diff --git a/extra_addons/hw_cashlogy/controllers/__init__.py b/chouettecoop_addons/restrict_db_mgr/controllers/__init__.py
similarity index 81%
rename from extra_addons/hw_cashlogy/controllers/__init__.py
rename to chouettecoop_addons/restrict_db_mgr/controllers/__init__.py
index d91efc382f..d654e6ca28 100644
--- a/extra_addons/hw_cashlogy/controllers/__init__.py
+++ b/chouettecoop_addons/restrict_db_mgr/controllers/__init__.py
@@ -1,9 +1,9 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
##############################################################################
#
-# Hardware Telium Payment Terminal module for Odoo
-# Copyright (C) 2014 Akretion (http://www.akretion.com)
-# @author Alexis de Lattre
+# OpenERP, Open Source Enterprise Management Solution
+# risk_management Module
+# Copyright (C) 2014 OpenSur (comercial@opensur.com)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -19,6 +19,4 @@
# along with this program. If not, see .
#
##############################################################################
-
-
from . import main
diff --git a/chouettecoop_addons/restrict_db_mgr/controllers/main.py b/chouettecoop_addons/restrict_db_mgr/controllers/main.py
new file mode 100644
index 0000000000..999fcd964f
--- /dev/null
+++ b/chouettecoop_addons/restrict_db_mgr/controllers/main.py
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2014 OpenSur.
+#
+# 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 import http
+from openerp import SUPERUSER_ID
+from openerp.http import request
+from openerp.addons.web.controllers.main import Database
+from openerp.exceptions import AccessError
+import werkzeug.utils
+
+ADMIN_CATEGORY = 'Administration'
+ADMIN_GROUP = 'Access Rights'
+
+class Database_restrict(Database):
+
+ def _is_usr_admin(self):
+ uid = request.session.uid
+ if uid == SUPERUSER_ID:
+ return True
+ cr, context, registry = request.cr, request.context, request.registry
+ admin_category = registry('ir.module.category').search(
+ cr, SUPERUSER_ID, [('name','=',ADMIN_CATEGORY),])
+ if len(admin_category):
+ admin_group = registry('res.groups').search(cr, SUPERUSER_ID,
+ ['&', ('name','=',ADMIN_GROUP),
+ ('category_id','=',admin_category[0]),])
+ if len(admin_group):
+ user_id = registry('res.groups').search(
+ cr, SUPERUSER_ID,
+ [('id','=',admin_group[0]), ('users','in', [uid])],
+ context=context)
+ return user_id and True or False
+ return False
+
+ def _access_forbidden(self):
+ return werkzeug.utils.redirect('/web/login', 303)
+
+ @http.route('/web/database/manager')
+ def manager(self, *args, **kwargs):
+ if self._is_usr_admin():
+ return super(Database_restrict, self).manager(*args, **kwargs)
+ else:
+ return self._access_forbidden()
+
+ @http.route('/web/database/create')
+ def create(self, *args, **kwargs):
+ if self._is_usr_admin():
+ return super(Database_restrict, self).create(*args, **kwargs)
+ else:
+ return self._access_forbidden()
+
+ @http.route('/web/database/duplicate')
+ def duplicate(self, *args, **kwargs):
+ if self._is_usr_admin():
+ return super(Database_restrict, self).duplicate(*args, **kwargs)
+ else:
+ return self._access_forbidden()
+
+ @http.route('/web/database/drop')
+ def drop(self, *args, **kwargs):
+ if self._is_usr_admin():
+ return super(Database_restrict, self).drop(*args, **kwargs)
+ else:
+ return self._access_forbidden()
+
+ @http.route('/web/database/backup')
+ def backup(self, *args, **kwargs):
+ if self._is_usr_admin():
+ return super(Database_restrict, self).backup(*args, **kwargs)
+ else:
+ return self._access_forbidden()
+
+ @http.route('/web/database/restore')
+ def restore(self, *args, **kwargs):
+ if self._is_usr_admin():
+ return super(Database_restrict, self).restore(*args, **kwargs)
+ else:
+ return self._access_forbidden()
+
+ @http.route('/web/database/change_password')
+ def change_password(self, *args, **kwargs):
+ if self._is_usr_admin():
+ return super(Database_restrict, self).change_password(*args, **kwargs)
+ else:
+ return self._access_forbidden()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/chouettecoop_addons/restrict_db_mgr/static/description/icon.jpg b/chouettecoop_addons/restrict_db_mgr/static/description/icon.jpg
new file mode 100644
index 0000000000..c0e8e0b5be
Binary files /dev/null and b/chouettecoop_addons/restrict_db_mgr/static/description/icon.jpg differ
diff --git a/chouettecoop_addons/restrict_db_mgr/static/description/icon.png b/chouettecoop_addons/restrict_db_mgr/static/description/icon.png
new file mode 100644
index 0000000000..a135c0a453
Binary files /dev/null and b/chouettecoop_addons/restrict_db_mgr/static/description/icon.png differ
diff --git a/chouettecoop_addons/restrict_db_mgr/static/src/img/icon.jpg b/chouettecoop_addons/restrict_db_mgr/static/src/img/icon.jpg
new file mode 100644
index 0000000000..c0e8e0b5be
Binary files /dev/null and b/chouettecoop_addons/restrict_db_mgr/static/src/img/icon.jpg differ
diff --git a/chouettecoop_addons/restrict_db_mgr/static/src/img/icon.png b/chouettecoop_addons/restrict_db_mgr/static/src/img/icon.png
new file mode 100644
index 0000000000..a135c0a453
Binary files /dev/null and b/chouettecoop_addons/restrict_db_mgr/static/src/img/icon.png differ
diff --git a/chouettecoop_addons/user_menu_chouette/README.md b/chouettecoop_addons/user_menu_chouette/README.md
new file mode 100644
index 0000000000..0d858a544d
--- /dev/null
+++ b/chouettecoop_addons/user_menu_chouette/README.md
@@ -0,0 +1,9 @@
+User Menu for La Chouette Coop, Odoo addon
+==========================================
+
+Replace the standard top right UserMenu:
+
+ * Replace "Support" link from Odoo.com/buy to a link configurable in
+ Configuration/General Settings/Menu Support
+ * Remove "My Oddo Account" link
+
diff --git a/louve_addons/louve_custom_cpo/model/__init__.py b/chouettecoop_addons/user_menu_chouette/__init__.py
old mode 100755
new mode 100644
similarity index 78%
rename from louve_addons/louve_custom_cpo/model/__init__.py
rename to chouettecoop_addons/user_menu_chouette/__init__.py
index 74ccb4d501..a31d229ecf
--- a/louve_addons/louve_custom_cpo/model/__init__.py
+++ b/chouettecoop_addons/user_menu_chouette/__init__.py
@@ -1,10 +1,8 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Product - Average Consumption Module for Odoo
-# Copyright (C) 2013-Today GRAP (http://www.grap.coop)
-# @author Julien WESTE
-# @author Sylvain LE GAL (https://twitter.com/legalsylvain)
+# User Switch From Group, Odoo addon
+# Copyright La Chouette Coop
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -20,5 +18,4 @@
# along with this program. If not, see .
#
##############################################################################
-
-from . import computed_purchase_order_line
+from . import models
diff --git a/extra_addons/pos_automatic_cashdrawer/account_journal.py b/chouettecoop_addons/user_menu_chouette/__openerp__.py
similarity index 56%
rename from extra_addons/pos_automatic_cashdrawer/account_journal.py
rename to chouettecoop_addons/user_menu_chouette/__openerp__.py
index cca4be809b..26194964cf 100644
--- a/extra_addons/pos_automatic_cashdrawer/account_journal.py
+++ b/chouettecoop_addons/user_menu_chouette/__openerp__.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# POS Payment Terminal module for Odoo
-# Copyright (C) 2015 Mathieu VATEL
+# Require User Login, Odoo addon
+# Copyright La Chouette Coop
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -18,13 +18,25 @@
# along with this program. If not, see .
#
##############################################################################
-
-from openerp import models, fields
-
-
-class AccountJournal(models.Model):
- _inherit = 'account.journal'
-
- iface_automatic_cashdrawer = fields.Boolean(
- 'Automatic cashdrawer',
- help="Check this if this journal is linked to an automatic cashdrawer")
+{
+ 'name' : "User Menu for La Chouette Coop",
+ 'summary' : "Replace top right UserMenu: change support link, remvoe My Odoo Account link",
+ 'category' : 'Extra Tools',
+ 'author' : "La Chouette Coop",
+ 'website' : "http://www.lachouettecoop.fr",
+ 'license' : "AGPL-3",
+ 'version' : '9.0.0.0.1',
+ 'installable': True,
+ 'depends' : [
+ 'base_setup',
+ 'base',
+ 'web',
+ ],
+ 'data' : [
+ 'data/user_menu_chouette.xml',
+ 'views/res_config_view.xml',
+ ],
+ 'qweb' : [
+ 'static/src/xml/base.xml',
+ ],
+}
diff --git a/chouettecoop_addons/user_menu_chouette/data/user_menu_chouette.xml b/chouettecoop_addons/user_menu_chouette/data/user_menu_chouette.xml
new file mode 100644
index 0000000000..4899d29fa6
--- /dev/null
+++ b/chouettecoop_addons/user_menu_chouette/data/user_menu_chouette.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/chouettecoop_addons/user_menu_chouette/models/__init__.py b/chouettecoop_addons/user_menu_chouette/models/__init__.py
new file mode 100644
index 0000000000..fbae67240c
--- /dev/null
+++ b/chouettecoop_addons/user_menu_chouette/models/__init__.py
@@ -0,0 +1,2 @@
+
+from . import res_config
diff --git a/chouettecoop_addons/user_menu_chouette/models/res_config.py b/chouettecoop_addons/user_menu_chouette/models/res_config.py
new file mode 100644
index 0000000000..f96a88ad2a
--- /dev/null
+++ b/chouettecoop_addons/user_menu_chouette/models/res_config.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Require User Login, Odoo addon
+# Copyright La Chouette Coop
+#
+# 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 import api, fields, models
+
+class user_menu_chouette_config_settings(models.TransientModel):
+ """ Inherit the base setting to add the url to use for User Menu «Support» link. """
+
+ _inherit = 'base.config.settings'
+
+ x_user_menu_support_url = fields.Char("Menu Support", help="Lien «Support» dans le menu utilisateur")
+
+ @api.multi
+ def get_default_x_user_menu_support_url(self):
+ url = self.env["ir.config_parameter"].get_param("x_user_menu_support_url", default=None)
+ return { 'x_user_menu_support_url': url or False }
+
+ @api.multi
+ def set_x_user_menu_support_url(self):
+ for record in self:
+ self.env['ir.config_parameter'].set_param("x_user_menu_support_url", self.x_user_menu_support_url or '')
+
diff --git a/chouettecoop_addons/user_menu_chouette/static/description/icon.png b/chouettecoop_addons/user_menu_chouette/static/description/icon.png
new file mode 100644
index 0000000000..efc15d60ee
Binary files /dev/null and b/chouettecoop_addons/user_menu_chouette/static/description/icon.png differ
diff --git a/chouettecoop_addons/user_menu_chouette/static/src/js/menu.js b/chouettecoop_addons/user_menu_chouette/static/src/js/menu.js
new file mode 100644
index 0000000000..1ddb0cb1b4
--- /dev/null
+++ b/chouettecoop_addons/user_menu_chouette/static/src/js/menu.js
@@ -0,0 +1,21 @@
+odoo.define('user_menu_chouette.support_chouette', function (require) {
+"use strict";
+
+var Model = require('web.Model');
+var UserMenu = require('web.UserMenu');
+
+// Modify behaviour of addons/web/static/src/js/widgets/user_menu.js
+UserMenu.include({
+ on_menu_support_chouette: function () {
+ var support_window = window.open('', '_blank');
+ new Model('ir.config_parameter')
+ .call('get_param', ['x_user_menu_support_url'])
+ .then(function(url) {
+ if (url) {
+ support_window.location = url;
+ }
+ });
+ }
+});
+
+});
diff --git a/chouettecoop_addons/user_menu_chouette/static/src/xml/base.xml b/chouettecoop_addons/user_menu_chouette/static/src/xml/base.xml
new file mode 100644
index 0000000000..cc63cf7fbd
--- /dev/null
+++ b/chouettecoop_addons/user_menu_chouette/static/src/xml/base.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+ A reconciliation profile specifies, for one account, how
+ the entries should be reconciled.
+ You can select one or many reconciliation methods which will
+ be run sequentially to match the entries between them.
+
You have some changes on this template. You should consider or
diff --git a/intercoop_addons/coop_shift/wizard/update_shifts_wizard.py b/intercoop_addons/coop_shift/wizard/update_shifts_wizard.py
index 535e5ed385..d81f4ef80c 100644
--- a/intercoop_addons/coop_shift/wizard/update_shifts_wizard.py
+++ b/intercoop_addons/coop_shift/wizard/update_shifts_wizard.py
@@ -43,7 +43,7 @@ def _get_line_ids(self, template, date_from=None, date_to=None):
shift.state == "draft":
line_ids.append((0, 0, {
'wizard_id': self.id,
- 'shift_id': shift,
+ 'shift_id': shift.id,
'name': shift.name,
'user_ids': [(6, 0, shift.user_ids.ids)],
'shift_type_id': shift.shift_type_id.id,
@@ -61,6 +61,13 @@ def _default_line_ids(self):
return self._get_line_ids(
template, date_from=self.date_from, date_to=self.date_to)
+ @api.model
+ def _get_updated_fields(self):
+ template_id = self.env.context.get('active_id', False)
+ if template_id:
+ template = self.env['shift.template'].browse(template_id)
+ return template.updated_fields
+
@api.onchange('date_from', 'date_to')
def _onchange_dates(self):
template_id = self.env.context.get('active_id', False)
@@ -75,8 +82,9 @@ def _onchange_dates(self):
date_from = fields.Date('Update shifts from')
date_to = fields.Date('Update shifts until')
updated_fields = fields.Char(
- related='template_id.updated_fields',
- string="""Changes to repercute on selected shifts""")
+ default=_get_updated_fields,
+ string="""Changes to repercute on selected shifts"""
+ )
@api.multi
def update_lines(self, date_from=None, date_to=None):
@@ -101,7 +109,9 @@ def update_shifts(self):
del vals['shift_ticket_ids']
shift_obj.browse(shift_ids).with_context(
tracking_disable=True, special=special).write(vals)
- wizard.template_id.updated_fields = ""
+ wizard.template_id.write({
+ 'updated_fields': ''
+ })
return True
diff --git a/intercoop_addons/email_validation_check/data/email_template_data.xml b/intercoop_addons/email_validation_check/data/email_template_data.xml
index a4034e2350..6bdac5a349 100644
--- a/intercoop_addons/email_validation_check/data/email_template_data.xml
+++ b/intercoop_addons/email_validation_check/data/email_template_data.xml
@@ -6,7 +6,7 @@
${(object.company_id.email or '')|safe}${object.email|safe}${object.lang}
- no-reply@cooplalouve.fr
+ ${object.company_id.email and '@' in object.company_id.email and 'no-reply@%s' % object.company_id.email.split('@')[-1] or ''}Confirm validated emailDear ${object.name},
diff --git a/intercoop_addons/product_history/__openerp__.py b/intercoop_addons/product_history/__openerp__.py
index 258b0fcaf4..c415d9abe9 100755
--- a/intercoop_addons/product_history/__openerp__.py
+++ b/intercoop_addons/product_history/__openerp__.py
@@ -22,7 +22,7 @@
##############################################################################
{
'name': 'Product - History',
- 'version': '9.0.2',
+ 'version': '9.0.3',
'category': 'Product',
'description': """
Computes figures about the product's sales, purchases, stocks.
diff --git a/intercoop_addons/product_history/migrations/9.0.3/post-update-product-history.py b/intercoop_addons/product_history/migrations/9.0.3/post-update-product-history.py
new file mode 100644
index 0000000000..a20155f174
--- /dev/null
+++ b/intercoop_addons/product_history/migrations/9.0.3/post-update-product-history.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+
+from openerp.modules.registry import RegistryManager
+from openerp import SUPERUSER_ID
+
+
+def migrate(cr, installed_version):
+ registry = RegistryManager.get(cr.dbname)
+ history_obj = registry['product.history']
+ history_obj.product_history_update_background(cr, SUPERUSER_ID)
diff --git a/intercoop_addons/product_history/models/product_history.py b/intercoop_addons/product_history/models/product_history.py
index f02ae28a65..45df2b4fe5 100755
--- a/intercoop_addons/product_history/models/product_history.py
+++ b/intercoop_addons/product_history/models/product_history.py
@@ -22,6 +22,13 @@
##############################################################################
from openerp import models, fields, api
+from openerp import SUPERUSER_ID
+from openerp.addons.connector.session import ConnectorSession
+from openerp.addons.connector.queue.job import job, related_action
+from collections import defaultdict
+
+import logging
+logger = logging.getLogger('openerp.louve_change_translation')
HISTORY_RANGE = [
('days', 'Days'),
@@ -90,3 +97,92 @@ def create(self, vals):
vals.get('sale_qty', 0) == 0:
vals['ignored'] = True
return super(ProductHistory, self).create(vals)
+
+ @api.model
+ def get_products(self):
+ sql = """select distinct ph.product_id from product_history ph
+ left join product_product p on ph.product_id = p.id
+ where p.history_updated = 'f' or p.history_updated is null"""
+ self.env.cr.execute(sql)
+ return [p[0] for p in self.env.cr.fetchall()]
+
+ @api.model
+ def update_products_history(self, product_ids):
+ product_obj = self.env['product.product']
+ product_history_obj = self.env['product.history']
+ for product_id in product_ids:
+ logger.info('Updating Product ID: %s' % product_id)
+ try:
+ for history_range in ['days', 'weeks', 'months']:
+ history_lines = product_history_obj.search(
+ [('product_id', '=', product_id),
+ ('history_range', '=', history_range)],
+ order='from_date')
+ if history_lines:
+ sql = """
+ SELECT date_trunc(%s, sm.date)::date,
+ orig.usage usage,
+ CASE WHEN orig.usage = 'inventory'
+ THEN SUM(sm.product_qty)
+ ELSE -sum(sm.product_qty) END product_qty
+ FROM stock_move as sm, stock_location as orig,
+ stock_location as dest
+ WHERE sm.location_id = orig.id and
+ sm.location_dest_id = dest.id
+ and sm.product_id = %s and
+ sm.date >= %s and
+ sm.date <= %s and
+ (dest.usage = 'inventory' or
+ orig.usage = 'inventory') and
+ sm.state = 'done'
+ GROUP BY date_trunc(%s,sm.date), orig.usage
+ ORDER BY date_trunc(%s,sm.date)
+ """
+ params = (history_range[:-1], product_id,
+ history_lines[0].from_date,
+ history_lines[-1].to_date + ' 23:59:59',
+ history_range[:-1], history_range[:-1])
+ self.env.cr.execute(sql, params)
+ stock_moves = self.env.cr.fetchall()
+ stock_moves_dict = defaultdict(float)
+ for move in stock_moves:
+ # set sm.date as a key
+ stock_moves_dict[move[0]] += move[2]
+ opening_qty = history_lines[0].start_qty
+ for line in history_lines:
+ loss_qty = stock_moves_dict.get(line.from_date, 0)
+ end_qty = opening_qty + line.purchase_qty + \
+ line.sale_qty + loss_qty
+ line.write({'start_qty': opening_qty,
+ 'loss_qty': loss_qty,
+ 'end_qty': end_qty,
+ 'virtual_qty':
+ end_qty + line.incoming_qty +
+ line.outgoing_qty})
+ opening_qty = end_qty
+ product_obj.browse(product_id).write({'history_updated': True})
+
+ except Exception as e:
+ logger.error('Error while updating a product ID: %s, %s' % (
+ product_id, str(e)))
+ return True
+
+ @api.model
+ def product_history_update_background(self):
+ session = ConnectorSession(self._cr, SUPERUSER_ID)
+ product_ids = self.get_products()
+ num_prod_per_job = 50
+ splitted_prod_list = [product_ids[i: i + num_prod_per_job]
+ for i in range(0, len(product_ids),
+ num_prod_per_job)]
+ # Create jobs
+ for product_list in splitted_prod_list:
+ create_job_to_update_product_history.delay(
+ session, 'product.history', product_list, priority=1,
+ eta=10)
+
+
+@job
+def create_job_to_update_product_history(session, model_name, product_ids):
+ """ Job for Recomputing Loss Qty and Opening Qty of Product History """
+ session.env[model_name].update_products_history(product_ids)
diff --git a/intercoop_addons/product_history/models/product_product.py b/intercoop_addons/product_history/models/product_product.py
index d370eb9a95..dc2395f754 100755
--- a/intercoop_addons/product_history/models/product_product.py
+++ b/intercoop_addons/product_history/models/product_product.py
@@ -60,6 +60,7 @@ class ProductProduct(models.Model):
string='last day history record', comodel_name='product.history',)
last_history_month = fields.Many2one(
string='last day history record', comodel_name='product.history',)
+ history_updated = fields.Boolean('History Updated', default=False)
# Private section
@api.onchange(
diff --git a/intercoop_addons/purchase_compute_order/__openerp__.py b/intercoop_addons/purchase_compute_order/__openerp__.py
index 22279a2b81..fad3347c96 100755
--- a/intercoop_addons/purchase_compute_order/__openerp__.py
+++ b/intercoop_addons/purchase_compute_order/__openerp__.py
@@ -23,7 +23,7 @@
{
'name': 'Computed Purchase Order',
- 'version': '9.0.1',
+ 'version': '9.0.2',
'category': 'Purchase',
'description': """
Provide tools to help purchaser during purchase process
diff --git a/intercoop_addons/purchase_compute_order/i18n/fr.po b/intercoop_addons/purchase_compute_order/i18n/fr.po
old mode 100755
new mode 100644
index 48ad3b03da..fc9e05adb8
--- a/intercoop_addons/purchase_compute_order/i18n/fr.po
+++ b/intercoop_addons/purchase_compute_order/i18n/fr.po
@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 9.0c\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2016-12-14 13:26+0000\n"
-"PO-Revision-Date: 2016-12-14 13:26+0000\n"
+"POT-Creation-Date: 2019-11-26 20:33+0000\n"
+"PO-Revision-Date: 2019-11-26 20:33+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@@ -21,7 +21,7 @@ msgid "Active"
msgstr "Actif"
#. module: purchase_compute_order
-#: code:addons/purchase_compute_order/model/computed_purchase_order.py:376
+#: code:addons/purchase_compute_order/model/computed_purchase_order.py:377
#, python-format
msgid "All purchase quantities are set to 0!"
msgstr "Toutes les quantités d'achat sont à 0!"
@@ -36,10 +36,16 @@ msgstr "Montant de la commande"
msgid "Apply"
msgstr "Appliquer"
+#. module: purchase_compute_order
+#: selection:computed.purchase.order,line_order:0
+#: selection:res.partner,cpo_line_order:0
+msgid "Ascending"
+msgstr "Ascendant"
+
#. module: purchase_compute_order
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_displayed_average_consumption
msgid "Average Consumption"
-msgstr "Conso moy."
+msgstr "Conso moy"
#. module: purchase_compute_order
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_average_consumption
@@ -51,6 +57,16 @@ msgstr "Consommation Moyenne"
msgid "By unchecking the active field, you may hide this item without deleting it."
msgstr "En décochant la case actif, vous pouvez cacher cet enregistrement sans le supprimer."
+#. module: purchase_compute_order
+#: model:ir.model.fields,field_description:purchase_compute_order.field_res_partner_cpo_line_order_field
+msgid "CPO Lines Order"
+msgstr "Ordre des lignes CPO"
+
+#. module: purchase_compute_order
+#: model:ir.model.fields,field_description:purchase_compute_order.field_res_partner_cpo_line_order
+msgid "CPO Lines Order Direction"
+msgstr "Ordre des lignes CPO (direction)"
+
#. module: purchase_compute_order
#: model:ir.ui.view,arch_db:purchase_compute_order.view_update_products_form
msgid "Cancel"
@@ -167,9 +183,10 @@ msgid "Default Unit of Measure used for all stock operation."
msgstr "Unité de mesure par défaut utilisée pour toutes les opérations de stock"
#. module: purchase_compute_order
-#: model:ir.model.fields,field_description:purchase_compute_order.field_product_product_default_seller_id
-msgid "Default seller id"
-msgstr "Default seller id"
+#: selection:computed.purchase.order,line_order:0
+#: selection:res.partner,cpo_line_order:0
+msgid "Descending"
+msgstr "Descendant"
#. module: purchase_compute_order
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_discount
@@ -217,6 +234,11 @@ msgstr "Récupérer articles et stocks"
msgid "Gives the sequence order when displaying a list of purchase order lines."
msgstr "Donne le numéro de séquance lors de l'affichage des lignes."
+#. module: purchase_compute_order
+#: model:ir.model.fields,help:purchase_compute_order.field_computed_purchase_order_line_product_sequence
+msgid "Gives the sequence order when displaying a product list"
+msgstr "Indique l'ordre d'affichage lorsqu'une liste d'articles est affichée."
+
#. module: purchase_compute_order
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_id
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_id
@@ -264,7 +286,7 @@ msgstr "Dernière modification le"
#: model:ir.model.fields,field_description:purchase_compute_order.field_update_products_line_wizard_write_uid
#: model:ir.model.fields,field_description:purchase_compute_order.field_update_products_wizard_write_uid
msgid "Last Updated by"
-msgstr "Mis à jour par"
+msgstr "Dernière mise à jour par"
#. module: purchase_compute_order
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_write_date
@@ -272,7 +294,17 @@ msgstr "Mis à jour par"
#: model:ir.model.fields,field_description:purchase_compute_order.field_update_products_line_wizard_write_date
#: model:ir.model.fields,field_description:purchase_compute_order.field_update_products_wizard_write_date
msgid "Last Updated on"
-msgstr "Mis à jour le"
+msgstr "Dernière mise à jour le"
+
+#. module: purchase_compute_order
+#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_order_field
+msgid "Lines Order"
+msgstr "Lines Order"
+
+#. module: purchase_compute_order
+#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_order
+msgid "Lines Order Direction"
+msgstr "Lines Order Direction"
#. module: purchase_compute_order
#: model:ir.ui.view,arch_db:purchase_compute_order.view_computed_purchase_order_form
@@ -297,7 +329,7 @@ msgstr "Durée minimum après commande"
#. module: purchase_compute_order
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_weight
msgid "Net Weight"
-msgstr "Poids net"
+msgstr "Poids Net"
#. module: purchase_compute_order
#: code:addons/purchase_compute_order/model/computed_purchase_order.py:36
@@ -385,6 +417,12 @@ msgstr "Article"
msgid "Product Information"
msgstr "Information de l'article"
+#. module: purchase_compute_order
+#: selection:computed.purchase.order,line_order_field:0
+#: selection:res.partner,cpo_line_order_field:0
+msgid "Product Sequence"
+msgstr "Séquence"
+
#. module: purchase_compute_order
#: sql_constraint:computed.purchase.order.line:0
msgid "Product must be unique by computed purchase order!"
@@ -397,7 +435,7 @@ msgid "Products to order."
msgstr "Produits à commander."
#. module: purchase_compute_order
-#: code:addons/purchase_compute_order/model/computed_purchase_order.py:398
+#: code:addons/purchase_compute_order/model/computed_purchase_order.py:399
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_purchase_order_id
#: model:ir.ui.view,arch_db:purchase_compute_order.view_cpo_config_settings
#, python-format
@@ -463,6 +501,7 @@ msgid "Search Purchase Order"
msgstr "Chercher un bon de commande"
#. module: purchase_compute_order
+#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_product_sequence
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_sequence
msgid "Sequence"
msgstr "Séquence"
@@ -473,6 +512,12 @@ msgid "Shows if the product's information has been updated"
msgstr "Indique si les informations du produit ont été modifiées"
#. module: purchase_compute_order
+#: model:ir.ui.view,arch_db:purchase_compute_order.view_computed_purchase_order_form
+msgid "Sort lines"
+msgstr "Sort lines"
+
+#. module: purchase_compute_order
+#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_cpo_state
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_state
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_state
msgid "State"
@@ -488,11 +533,6 @@ msgstr "Stock"
msgid "Stock Duration (Days)"
msgstr "Durée (j)"
-#. module: purchase_compute_order
-#: model:ir.ui.view,arch_db:purchase_compute_order.view_computed_purchase_order_form
-msgid "Stock details"
-msgstr "Détail des stocks"
-
#. module: purchase_compute_order
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_stock_line_ids
msgid "Stock line ids"
@@ -509,18 +549,22 @@ msgid "Supplier"
msgstr "Fournisseur"
#. module: purchase_compute_order
+#: selection:computed.purchase.order,line_order_field:0
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_product_code
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_product_code_inv
#: model:ir.model.fields,field_description:purchase_compute_order.field_update_products_line_wizard_product_code
+#: selection:res.partner,cpo_line_order_field:0
msgid "Supplier Product Code"
-msgstr "Code (fourn)"
+msgstr "Référence fournisseur"
#. module: purchase_compute_order
+#: selection:computed.purchase.order,line_order_field:0
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_product_name
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_product_name_inv
#: model:ir.model.fields,field_description:purchase_compute_order.field_update_products_line_wizard_product_name
+#: selection:res.partner,cpo_line_order_field:0
msgid "Supplier Product Name"
-msgstr "Nom (fourn)"
+msgstr "Nom de l'article chez le fournisseur"
#. module: purchase_compute_order
#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_line_product_price
@@ -560,6 +604,12 @@ msgstr "Type d'objectif"
msgid "The available quantity on hand for this product"
msgstr "Le stock de produit disponible"
+#. module: purchase_compute_order
+#: model:ir.model.fields,help:purchase_compute_order.field_computed_purchase_order_line_order_field
+#: model:ir.model.fields,help:purchase_compute_order.field_res_partner_cpo_line_order_field
+msgid "The field used to sort the CPO lines"
+msgstr "The field used to sort the CPO lines"
+
#. module: purchase_compute_order
#: model:ir.model.fields,help:purchase_compute_order.field_update_products_line_wizard_package_qty
msgid "The minimal quantity to purchase to this supplier, expressed in the supplier Product Unit of Measure if not empty, in the default unit of measure of the product otherwise."
@@ -618,7 +668,7 @@ msgid "This price will be considered as a price for the supplier Unit of Measure
msgstr "Le prix du produit par UdM d'achat"
#. module: purchase_compute_order
-#: code:addons/purchase_compute_order/model/computed_purchase_order_line.py:329
+#: code:addons/purchase_compute_order/model/computed_purchase_order_line.py:340
#, python-format
msgid "This product is already in the list!"
msgstr "Ce produit est déjà dans la liste!"
@@ -645,6 +695,16 @@ msgstr "Cet outil vous permet de calculer vos besoins en se basant sur le stock
msgid "Total"
msgstr "Total"
+#. module: purchase_compute_order
+#: model:ir.model.fields,field_description:purchase_compute_order.field_computed_purchase_order_package_qty_count
+msgid "Total Quantity of Packages"
+msgstr "Nb. Colis"
+
+#. module: purchase_compute_order
+#: model:ir.model.fields,help:purchase_compute_order.field_computed_purchase_order_package_qty_count
+msgid "Total count of packages by the current vendor"
+msgstr "Total count of packages by the current vendor"
+
#. module: purchase_compute_order
#: model:ir.model.fields,help:purchase_compute_order.field_computed_purchase_order_name
msgid "Unique number of the automated purchase order, computed automatically when the computed purchase order is created."
diff --git a/intercoop_addons/purchase_compute_order/migrations/9.0.2/pre-migration.py b/intercoop_addons/purchase_compute_order/migrations/9.0.2/pre-migration.py
new file mode 100644
index 0000000000..c6ec5ac091
--- /dev/null
+++ b/intercoop_addons/purchase_compute_order/migrations/9.0.2/pre-migration.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp import api, SUPERUSER_ID
+
+import logging
+_logger = logging.getLogger(__name__)
+
+
+def migrate(cr, version):
+ if not version:
+ return
+
+ with api.Environment.manage():
+ env = api.Environment(cr, SUPERUSER_ID, {})
+ louve_custom_cpo = env['ir.module.module'].search([
+ ('name', '=', 'louve_custom_cpo'),
+ ('state', 'in', ['installed', 'to upgrade', 'to install']),
+ ])
+
+ if louve_custom_cpo:
+ _logger.info('Uninstalling louve_custom_cpo..')
+ louve_custom_cpo.button_immediate_uninstall()
+
+ # Reordering cpo lines
+ _logger.info('Updating sequence of previous orders..')
+ cr.execute("""
+ UPDATE computed_purchase_order_line AS cpol
+ SET sequence = ol.rownum
+ FROM (
+ SELECT
+ id,
+ ROW_NUMBER() OVER (
+ PARTITION BY computed_purchase_order_id
+ ORDER BY product_code asc
+ ) AS rownum
+ FROM computed_purchase_order_line
+ ) AS ol
+ WHERE cpol.id = ol.id
+ """)
diff --git a/intercoop_addons/purchase_compute_order/model/computed_purchase_order.py b/intercoop_addons/purchase_compute_order/model/computed_purchase_order.py
index 99a550227d..9dd5287042 100755
--- a/intercoop_addons/purchase_compute_order/model/computed_purchase_order.py
+++ b/intercoop_addons/purchase_compute_order/model/computed_purchase_order.py
@@ -92,7 +92,7 @@ class ComputedPurchaseOrder(models.Model):
purchase_target = fields.Integer('Purchase Target', default=0)
target_type = fields.Selection(
_TARGET_TYPE, 'Target Type', required=True,
- default='product_price_inv_eq',
+ default='time',
help="""This defines the amount of products you want to"""
""" purchase. \n"""
"""The system will compute a purchase order based on the stock"""
@@ -104,6 +104,26 @@ class ComputedPurchaseOrder(models.Model):
""" average consumption)\n"""
""" * Target type 'kg': computed purchase order will weight at"""
""" least the weight specified""")
+ line_order_field = fields.Selection(
+ [
+ ('product_code', 'Supplier Product Code'),
+ ('product_name', 'Supplier Product Name'),
+ ('product_sequence', 'Product Sequence'),
+ ],
+ string='Lines Order',
+ help='The field used to sort the CPO lines',
+ default='product_code',
+ required=True,
+ )
+ line_order = fields.Selection(
+ [
+ ('asc', 'Ascending'),
+ ('desc', 'Descending'),
+ ],
+ string='Lines Order Direction',
+ default='asc',
+ required=True,
+ )
valid_psi = fields.Selection(
_VALID_PSI, 'Supplier choice', required=True,
default='first',
@@ -113,6 +133,12 @@ class ComputedPurchaseOrder(models.Model):
digits_compute=dp.get_precision('Product Price'),
string='Amount of the computed order',
multi='computed_amount_duration')
+ package_qty_count = fields.Float(
+ string='Total Quantity of Packages',
+ help='Total count of packages by the current vendor',
+ compute='_compute_package_quantity_count',
+ readonly='True',
+ )
computed_duration = fields.Integer(
compute='_get_computed_amount_duration',
string='Minimum duration after order',
@@ -161,6 +187,8 @@ def onchange_partner_id(self):
if self.partner_id:
self.purchase_target = self.partner_id.purchase_target
self.target_type = self.partner_id.target_type
+ self.line_order_field = self.partner_id.cpo_line_order_field
+ self.line_order = self.partner_id.cpo_line_order
self.line_ids = map(lambda x: (2, x.id, False), self.line_ids)
# Overload Section
@@ -174,57 +202,23 @@ def create(self, vals):
@api.multi
def write(self, vals):
- cpo_id = super(ComputedPurchaseOrder, self).write(vals)
- if self.update_sorting(vals):
- self._sort_lines()
- return cpo_id
+ res = super(ComputedPurchaseOrder, self).write(vals)
+ if 'line_ids' in vals:
+ self.sort_lines()
+ return res
@api.multi
- def update_sorting(self, vals):
- for cpo in self:
- try:
- line_ids = vals.get('line_ids', False)
- if not line_ids:
- return False
- # this context check will allow you to change the field list
- # without overriding the whole function
- need_sorting_fields = self.env.context.get(
- 'need_sorting_fields', False)
- if not need_sorting_fields:
- need_sorting_fields = [
- 'average_consumption',
- 'computed_qty',
- 'stock_duration',
- 'manual_input_output_qty',
- ]
- for value in line_ids:
- if len(value) > 2 and value[2] and isinstance(
- value[2], dict) and (set(
- need_sorting_fields) & set(value[2].keys())):
- return True
- return False
- except:
- return False
+ def sort_lines(self):
+ for rec in self:
+ # sort based on field
+ lines = rec.line_ids.sorted(
+ key=lambda l: getattr(l, rec.line_order_field),
+ reverse=(rec.line_order == 'desc'))
+ # store new sequence
+ for i, line in enumerate(lines):
+ line.sequence = i
# Private Section
- @api.multi
- def _sort_lines(self):
- cpol_obj = self.env['computed.purchase.order.line']
- for cpo in self:
- lines = cpol_obj.browse([x.id for x in cpo.line_ids]).read(
- ['stock_duration', 'average_consumption'])
- lines = sorted(
- lines, key=lambda line: line['average_consumption'],
- reverse=True)
- lines = sorted(lines, key=lambda line: line['stock_duration'])
-
- id_index_list = {}
- for i in lines:
- id_index_list[i['id']] = lines.index(i)
- for line_id in id_index_list.keys():
- cpol_obj.browse(line_id).write(
- {'sequence': id_index_list[line_id]})
-
@api.model
def _make_po_lines(self):
all_lines = []
@@ -275,6 +269,13 @@ def _compute_purchase_quantities_days(self):
line.purchase_qty = quantity
line.purchase_qty_package = quantity / line.package_qty
+ @api.multi
+ @api.depends('line_ids.purchase_qty_package')
+ def _compute_package_quantity_count(self):
+ for rec in self:
+ rec.package_qty_count = sum(rec.mapped(
+ 'line_ids.purchase_qty_package'))
+
@api.multi
def _compute_purchase_quantities_other(self, field):
for cpo in self:
diff --git a/intercoop_addons/purchase_compute_order/model/computed_purchase_order_line.py b/intercoop_addons/purchase_compute_order/model/computed_purchase_order_line.py
index b8c255e565..2b2fccf6ab 100755
--- a/intercoop_addons/purchase_compute_order/model/computed_purchase_order_line.py
+++ b/intercoop_addons/purchase_compute_order/model/computed_purchase_order_line.py
@@ -53,6 +53,7 @@ class ComputedPurchaseOrderLine(models.Model):
domain=[('purchase_ok', '=', True)])
uom_id = fields.Many2one(
related='product_id.uom_id', string="UoM", readonly='True')
+ product_sequence = fields.Integer(related='product_id.sequence')
product_code = fields.Char('Supplier Product Code',)
product_code_inv = fields.Char(
compute='_get_product_information', inverse='_set_product_code',
diff --git a/intercoop_addons/purchase_compute_order/model/res_partner.py b/intercoop_addons/purchase_compute_order/model/res_partner.py
index 89c4ea98d6..b32b1b0245 100755
--- a/intercoop_addons/purchase_compute_order/model/res_partner.py
+++ b/intercoop_addons/purchase_compute_order/model/res_partner.py
@@ -50,3 +50,25 @@ class ResPartner(models.Model):
""" average consumption)\n"""
"""* Target type 'kg': computed purchase order will weight"""
""" at least the weight specified""")
+
+ cpo_line_order_field = fields.Selection(
+ [
+ ('product_code', 'Supplier Product Code'),
+ ('product_name', 'Supplier Product Name'),
+ ('product_sequence', 'Product Sequence'),
+ ],
+ string='CPO Lines Order',
+ help='The field used to sort the CPO lines',
+ default='product_code',
+ required=True,
+ )
+
+ cpo_line_order = fields.Selection(
+ [
+ ('asc', 'Ascending'),
+ ('desc', 'Descending'),
+ ],
+ string='CPO Lines Order Direction',
+ default='asc',
+ required=True,
+ )
diff --git a/intercoop_addons/purchase_compute_order/views/view.xml b/intercoop_addons/purchase_compute_order/views/view.xml
index a253895738..3f58729e15 100755
--- a/intercoop_addons/purchase_compute_order/views/view.xml
+++ b/intercoop_addons/purchase_compute_order/views/view.xml
@@ -42,6 +42,8 @@
+
+
-
-
+
+
+
+
+
+
+
+
-
+
res.partner.form.cpores.partner
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/louve_addons/l10n_fr_fec_group_sale_purchase/__init__.py b/louve_addons/l10n_fr_fec_group_sale_purchase/__init__.py
new file mode 100644
index 0000000000..40272379f7
--- /dev/null
+++ b/louve_addons/l10n_fr_fec_group_sale_purchase/__init__.py
@@ -0,0 +1 @@
+from . import wizard
diff --git a/louve_addons/l10n_fr_fec_group_sale_purchase/__openerp__.py b/louve_addons/l10n_fr_fec_group_sale_purchase/__openerp__.py
new file mode 100644
index 0000000000..cda4d8adaf
--- /dev/null
+++ b/louve_addons/l10n_fr_fec_group_sale_purchase/__openerp__.py
@@ -0,0 +1,16 @@
+# -*- encoding: utf-8 -*-
+{
+ 'name': 'France - FEC Group Sale Purchase',
+ 'version': '9.0.1.0.0',
+ 'category': 'Localization',
+ 'summary': "Fichier d'Échange Informatisé (FEC) for France",
+ 'author': "Druidoo",
+ 'website': 'www.druidoo.fr',
+ 'depends': [
+ 'l10n_fr_fec',
+ ],
+ 'data': [
+ 'wizard/fec_view.xml',
+ ],
+ 'installable': True,
+}
diff --git a/louve_addons/l10n_fr_fec_group_sale_purchase/wizard/__init__.py b/louve_addons/l10n_fr_fec_group_sale_purchase/wizard/__init__.py
new file mode 100644
index 0000000000..1f42c12044
--- /dev/null
+++ b/louve_addons/l10n_fr_fec_group_sale_purchase/wizard/__init__.py
@@ -0,0 +1 @@
+from . import fec
diff --git a/louve_addons/l10n_fr_fec_group_sale_purchase/wizard/fec.py b/louve_addons/l10n_fr_fec_group_sale_purchase/wizard/fec.py
new file mode 100644
index 0000000000..e34a1dca3d
--- /dev/null
+++ b/louve_addons/l10n_fr_fec_group_sale_purchase/wizard/fec.py
@@ -0,0 +1,198 @@
+# -*- encoding: utf-8 -*-
+from openerp import models, fields, api
+import csv
+import os
+
+
+class AccountFrFec(models.TransientModel):
+ _inherit = 'account.fr.fec'
+
+ group_sale_purchase = fields.Boolean('Group Sale and Purchase Journals',
+ default=True)
+
+ @api.multi
+ def write_fec_lines(self, file_path, delimiter, date_from, date_to):
+ self.ensure_one()
+ if not self.group_sale_purchase:
+ return super(AccountFrFec, self).write_fec_lines(
+ file_path, delimiter, date_from, date_to)
+ if not os.path.exists(file_path):
+ raise ValueError('File {} not found'.format(file_path))
+
+ fec_file = open(file_path, 'a+')
+ w = csv.writer(fec_file, delimiter=delimiter)
+ sql_query = '''
+ (SELECT
+ replace(aj.code, '|', '/') AS JournalCode,
+ replace(aj.name, '|', '/') AS JournalLib,
+ replace(am.name, '|', '/') AS EcritureNum,
+ TO_CHAR(am.date, 'YYYYMMDD') AS EcritureDate,
+ aa.code AS CompteNum,
+ replace(aa.name, '|', '/') AS CompteLib,
+ CASE WHEN rp.ref IS null OR rp.ref = ''
+ THEN COALESCE('ID ' || rp.id, '')
+ ELSE rp.ref
+ END
+ AS CompAuxNum,
+ COALESCE(replace(rp.name, '|', '/'), '') AS CompAuxLib,
+ CASE WHEN am.ref IS null OR am.ref = ''
+ THEN '-'
+ ELSE replace(am.ref, '|', '/')
+ END
+ AS PieceRef,
+ TO_CHAR(am.date, 'YYYYMMDD') AS PieceDate,
+ CASE WHEN aml.name IS NULL THEN '/'
+ WHEN aml.name SIMILAR TO '[\t|\s|\n]*' THEN '/'
+ ELSE replace(aml.name, '|', '/') END AS EcritureLib,
+ replace(CASE WHEN aml.debit = 0 THEN '0,00' ELSE
+ to_char(aml.debit, '000000000000000D99') END, '.', ',')
+ AS Debit,
+ replace(CASE WHEN aml.credit = 0 THEN '0,00' ELSE
+ to_char(aml.credit, '000000000000000D99') END, '.', ',')
+ AS Credit,
+ CASE WHEN rec.name IS NULL THEN '' ELSE rec.name
+ END AS EcritureLet,
+ CASE WHEN aml.full_reconcile_id IS NULL THEN '' ELSE
+ TO_CHAR(rec.create_date, 'YYYYMMDD') END AS DateLet,
+ TO_CHAR(am.date, 'YYYYMMDD') AS ValidDate,
+ CASE
+ WHEN aml.amount_currency IS NULL OR
+ aml.amount_currency = 0 THEN ''
+ ELSE replace(to_char(aml.amount_currency,
+ '000000000000000D99'), '.', ',')
+ END AS Montantdevise,
+ CASE WHEN aml.currency_id IS NULL THEN '' ELSE rc.name END
+ AS Idevise,
+ TO_CHAR(aml.account_id, '0'),
+ TO_CHAR(aml.partner_id, '0')
+ FROM
+ account_move_line aml
+ LEFT JOIN account_move am ON am.id=aml.move_id
+ LEFT JOIN res_partner rp ON rp.id=aml.partner_id
+ JOIN account_journal aj ON aj.id = am.journal_id
+ JOIN account_account aa ON aa.id = aml.account_id
+ LEFT JOIN res_currency rc ON rc.id = aml.currency_id
+ LEFT JOIN account_full_reconcile rec ON
+ rec.id = aml.full_reconcile_id
+ WHERE
+ am.date >= %s
+ AND aj.type not in ('sale', 'purchase')
+ AND am.date <= %s
+ AND am.company_id = %s
+ AND (aml.debit != 0 OR aml.credit != 0)
+ '''
+
+ # For official report: only use posted entries
+ if self.export_type == "official":
+ sql_query += '''
+ AND am.state = 'posted'
+ '''
+
+ sql_query += '''
+ ORDER BY
+ am.date,
+ am.name,
+ aml.id)
+ '''
+
+ sql_query2 = '''
+ SELECT
+ replace(STRING_AGG(distinct aj.code, ';'), '|', '/') AS
+ JournalCode,
+ replace(STRING_AGG(distinct aj.name, ';'), '|', '/')
+ AS JournalLib,
+ replace(am.name, '|', '/') AS EcritureNum,
+ TO_CHAR(MAX(am.date), 'YYYYMMDD') AS
+ EcritureDate,
+ STRING_AGG(distinct aa.code, ';') AS CompteNum,
+ replace(STRING_AGG(distinct aa.name, ';'), '|', '/')
+ AS CompteLib,
+ CASE WHEN MIN(rp.ref) IS null OR MIN(rp.ref) = ''
+ THEN COALESCE('ID ' || min(rp.id), '')
+ ELSE MIN(rp.ref)
+ END
+ AS CompAuxNum,
+ COALESCE(replace(MAX(rp.name), '|', '/'), '') AS
+ CompAuxLib,
+ CASE WHEN MIN(am.ref) IS null OR MIN(am.ref) = ''
+ THEN '-'
+ ELSE replace(MIN(am.ref), '|', '/')
+ END
+ AS PieceRef,
+ TO_CHAR(MAX(am.date), 'YYYYMMDD') AS PieceDate,
+ CASE WHEN MIN(aml.name) IS NULL THEN '/'
+ WHEN MIN(aml.name) SIMILAR TO '[\t|\s|\n]*' THEN '/'
+ ELSE replace(MAX(aml.name), '|', '/') END AS
+ EcritureLib,
+ replace(CASE WHEN sum(aml.debit) = 0 THEN '0,00' ELSE
+ to_char(sum(aml.debit), '000000000000000D99') END, '.', ',
+ ') AS Debit,
+ replace(CASE WHEN sum(aml.credit) = 0 THEN '0,00' ELSE
+ to_char(sum(aml.credit), '000000000000000D99') END, '.', ',
+ ') AS Credit,
+ CASE WHEN MIN(rec.name) IS NULL THEN '' ELSE MIN(rec.name)
+ END AS EcritureLet,
+ CASE WHEN MIN(aml.full_reconcile_id) IS NULL THEN '' ELSE
+ TO_CHAR(MIN(rec.create_date), 'YYYYMMDD') END AS DateLet,
+ TO_CHAR(MIN(am.date), 'YYYYMMDD') AS ValidDate,
+ CASE
+ WHEN MIN(aml.amount_currency) IS NULL OR
+ MIN(aml.amount_currency) = 0 THEN ''
+ ELSE replace(to_char(MIN(aml.amount_currency),
+ '000000000000000D99'), '.', ',')
+ END AS Montantdevise,
+ CASE WHEN MIN(aml.currency_id) IS NULL THEN '' ELSE
+ MIN(rc.name) END AS Idevise,
+ TO_CHAR(aml.account_id, '0'),
+ TO_CHAR(aml.partner_id, '0')
+ FROM
+ account_move_line aml
+ LEFT JOIN account_move am ON am.id=aml.move_id
+ LEFT JOIN res_partner rp ON rp.id=aml.partner_id
+ JOIN account_journal aj ON aj.id = am.journal_id
+ JOIN account_account aa ON aa.id = aml.account_id
+ LEFT JOIN res_currency rc ON rc.id = aml.currency_id
+ LEFT JOIN account_full_reconcile rec ON
+ rec.id = aml.full_reconcile_id
+ WHERE
+ am.date >= %s
+ AND aj.type in ('sale', 'purchase')
+ AND am.date <= %s
+ AND am.company_id = %s
+ AND (aml.debit != 0 OR aml.credit != 0)
+ '''
+
+ # For official report: only use posted entries
+ if self.export_type == "official":
+ sql_query2 += '''
+ AND am.state = 'posted'
+ '''
+
+ sql_query2 += '''
+ GROUP BY
+ am.name,
+ aml.account_id,
+ aml.partner_id
+ '''
+ sql_query2 += '''
+ ORDER BY
+ MIN(am.date),
+ MIN(am.name),
+ MIN(aml.id)
+ '''
+
+ sql_query = sql_query + '''
+ UNION (
+ ''' + sql_query2 + ''' )
+ ORDER BY
+ PieceDate,
+ EcritureNum
+ '''
+
+ company = self.env.user.company_id
+ for row in self.minimize_execute(
+ sql_query, (date_from, date_to, company.id, date_from,
+ date_to, company.id)):
+ listrow = list(row)
+ w.writerow([s.encode("utf-8") if s else '' for s in listrow])
+ fec_file.close()
diff --git a/louve_addons/l10n_fr_fec_group_sale_purchase/wizard/fec_view.xml b/louve_addons/l10n_fr_fec_group_sale_purchase/wizard/fec_view.xml
new file mode 100644
index 0000000000..68a42b0cae
--- /dev/null
+++ b/louve_addons/l10n_fr_fec_group_sale_purchase/wizard/fec_view.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ account.fr.fec.form.view
+ account.fr.fec
+
+
+
+
+
+
+
+
+
+
diff --git a/louve_addons/louve_custom_cpo/__openerp__.py b/louve_addons/louve_custom_cpo/__openerp__.py
deleted file mode 100755
index 4ac82e81a6..0000000000
--- a/louve_addons/louve_custom_cpo/__openerp__.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# -*- encoding: utf-8 -*-
-##############################################################################
-#
-# Purchase - Computed Purchase Order Module for Odoo
-# Copyright (C) 2013-Today GRAP (http://www.grap.coop)
-# @author Julien WESTE
-# @author Sylvain LE GAL (https://twitter.com/legalsylvain)
-#
-# 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 .
-#
-##############################################################################
-
-{
- 'name': 'Louve Custom CPO',
- 'version': '9.0.1',
- 'category': 'Purchase',
- 'description': """
-Adaptation du module purchase_compute_order aux besoins de la Coopérative
-La Louve
-=======================================================
-
-Functionnality :
- Modification de la vue
-
-Copyright, Author and Licence :
--------------------------------
- * Copyright : 2013-Today, Groupement Régional Alimentaire de Proximité;
- * Author :
- * Julien WESTE;
- * Sylvain LE GAL (https://twitter.com/legalsylvain);
- * Licence : AGPL-3 (http://www.gnu.org/licenses/)
- """,
- 'author': 'GRAP',
- 'website': 'http://www.grap.coop',
- 'license': 'AGPL-3',
- 'depends': [
- 'purchase_compute_order',
- ],
- 'data': [
- 'view/view.xml',
- ],
-}
diff --git a/louve_addons/louve_custom_cpo/view/view.xml b/louve_addons/louve_custom_cpo/view/view.xml
deleted file mode 100755
index 89db5f7a68..0000000000
--- a/louve_addons/louve_custom_cpo/view/view.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
-
-
-
-
- computed.purchase.order.form.louve
- computed.purchase.order
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
-
-
- True
-
-
- True
-
-
- True
-
-
-
-
-
\ No newline at end of file