diff --git a/addons/account_invoice_be/__init__.py b/addons/account_invoice_be/__init__.py
new file mode 100644
index 00000000000..176d1b9a904
--- /dev/null
+++ b/addons/account_invoice_be/__init__.py
@@ -0,0 +1,24 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+#
+# Copyright (c) 2011 Noviat nv/sa (www.noviat.be). All rights reserved.
+#
+# 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 partner
+import invoice
diff --git a/addons/account_invoice_be/__openerp__.py b/addons/account_invoice_be/__openerp__.py
new file mode 100644
index 00000000000..c8d08d02a81
--- /dev/null
+++ b/addons/account_invoice_be/__openerp__.py
@@ -0,0 +1,55 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+#
+# Copyright (c) 2011 Noviat nv/sa (www.noviat.be). All rights reserved.
+#
+# 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': 'Add support for Belgian structured communication to Invoices',
+ 'version': '1.2',
+ 'license': 'AGPL-3',
+ 'author': 'Noviat',
+ 'category' : 'Localization/Accounting',
+ 'description': """
+
+Belgian localisation for in- and outgoing invoices (prereq to account_coda):
+ - Rename 'reference' field labels to 'Communication'
+ - Add support for Belgian Structured Communication
+
+A Structured Communication can be generated automatically on outgoing invoices according to the following algorithms:
+ 1) Random : +++RRR/RRRR/RRRDD+++
+ R..R = Random Digits, DD = Check Digits
+ 2) Date : +++DOY/YEAR/SSSDD+++
+ DOY = Day of the Year, SSS = Sequence Number, DD = Check Digits)
+ 3) Customer Reference +++RRR/RRRR/SSSDDD+++
+ R..R = Customer Reference without non-numeric characters, SSS = Sequence Number, DD = Check Digits)
+
+The preferred type of Structured Communication and associated Algorithm can be specified on the Partner records.
+A 'random' Structured Communication will generated if no algorithm is specified on the Partner record.
+
+ """,
+ 'depends': ['account', 'account_cancel'],
+ 'demo_xml': [],
+ 'init_xml': [],
+ 'update_xml' : [
+ 'partner_view.xml',
+ 'account_invoice_view.xml',
+ ],
+ 'active': False,
+ 'installable': True,}
diff --git a/addons/account_invoice_be/account_invoice_view.xml b/addons/account_invoice_be/account_invoice_view.xml
new file mode 100644
index 00000000000..8cabe036dfb
--- /dev/null
+++ b/addons/account_invoice_be/account_invoice_view.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+ account.invoice.form.inherit
+ account.invoice
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/account_invoice_be/i18n/fr.po b/addons/account_invoice_be/i18n/fr.po
new file mode 100644
index 00000000000..f6f88f0c9a0
--- /dev/null
+++ b/addons/account_invoice_be/i18n/fr.po
@@ -0,0 +1,26 @@
+# French translation of openobject-addons.
+# This file contains the translation of the following modules:
+# * l10n_be_extra
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: support@noviat.be\n"
+"POT-Creation-Date: 2011-01-16 17:06:14.002000\n"
+"PO-Revision-Date: 2011-01-16 17:06:14.002000\n"
+"Last-Translator: Luc De Meyer (Noviat nv/sa)\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. module: l10n_be_extra
+#: field:account.invoice,reference:0
+msgid "Communication"
+msgstr "Communication"
+
+#. module: l10n_be_extra
+#: field:account.invoice,reference_type:0
+msgid "Communication Type"
+msgstr "Type de communication"
+
diff --git a/addons/account_invoice_be/i18n/nl.po b/addons/account_invoice_be/i18n/nl.po
new file mode 100644
index 00000000000..42221219bbe
--- /dev/null
+++ b/addons/account_invoice_be/i18n/nl.po
@@ -0,0 +1,26 @@
+# Dutch translation of openobject-addons.
+# This file contains the translation of the following modules:
+# * l10n_be_extra
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: support@noviat.be\n"
+"POT-Creation-Date: 2011-01-16 17:05:57.465000\n"
+"PO-Revision-Date: 2011-01-16 17:05:57.465000\n"
+"Last-Translator: Luc De Meyer (Noviat nv/sa)\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. module: l10n_be_extra
+#: field:account.invoice,reference:0
+msgid "Communication"
+msgstr "Mededeling"
+
+#. module: l10n_be_extra
+#: field:account.invoice,reference_type:0
+msgid "Communication Type"
+msgstr "Type mededeling"
+
diff --git a/addons/account_invoice_be/invoice.py b/addons/account_invoice_be/invoice.py
new file mode 100644
index 00000000000..6aea22376fc
--- /dev/null
+++ b/addons/account_invoice_be/invoice.py
@@ -0,0 +1,215 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+#
+# Copyright (c) 2011 Noviat nv/sa (www.noviat.be). All rights reserved.
+#
+# 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 re, time, random
+from osv import fields, osv
+from tools.translate import _
+import netsvc
+logger=netsvc.Logger()
+
+"""
+account.invoice object:
+ - Add support for Belgian structured communication
+ - Rename 'reference' field labels to 'Communication'
+"""
+
+class account_invoice(osv.osv):
+ _inherit = 'account.invoice'
+
+ def _get_reference_type(self, cursor, user, context=None):
+ """Add BBA Structured Communication Type and change labels from 'reference' into 'communication' """
+ res = super(account_invoice, self)._get_reference_type(cursor, user,
+ context=context)
+ res[[i for i,x in enumerate(res) if x[0] == 'none'][0]] = ('none', 'Free Communication')
+ res.append(('bba', 'BBA Structured Communication'))
+ #logger.notifyChannel('addons.'+self._name, netsvc.LOG_WARNING, 'reference_type = %s' %res )
+ return res
+
+ def check_bbacomm(self, val):
+ supported_chars = '0-9+*/ '
+ pattern = re.compile('[^' + supported_chars + ']')
+ if pattern.findall(val or ''):
+ return False
+ bbacomm = re.sub('\D', '', val or '')
+ if len(bbacomm) == 12:
+ base = int(bbacomm[:10])
+ mod = base % 97 or 97
+ if mod == int(bbacomm[-2:]):
+ return True
+ return False
+
+ def _check_communication(self, cr, uid, ids):
+ for inv in self.browse(cr, uid, ids):
+ if inv.reference_type == 'bba':
+ return self.check_bbacomm(inv.reference)
+ return True
+
+ def onchange_partner_id(self, cr, uid, ids, type, partner_id,
+ date_invoice=False, payment_term=False, partner_bank_id=False, company_id=False):
+ result = super(account_invoice, self).onchange_partner_id(cr, uid, ids, type, partner_id,
+ date_invoice, payment_term, partner_bank_id, company_id)
+# reference_type = self.default_get(cr, uid, ['reference_type'])['reference_type']
+# logger.notifyChannel('addons.'+self._name, netsvc.LOG_WARNING, 'partner_id %s' % partner_id)
+ reference = False
+ reference_type = 'none'
+ if partner_id:
+ if (type == 'out_invoice'):
+ reference_type = self.pool.get('res.partner').browse(cr, uid, partner_id).out_inv_comm_type
+ if reference_type:
+ algorithm = self.pool.get('res.partner').browse(cr, uid, partner_id).out_inv_comm_algorithm
+ if not algorithm:
+ algorithm = 'random'
+ reference = self.generate_bbacomm(cr, uid, ids, type, reference_type, algorithm, partner_id, '')['value']['reference']
+ res_update = {
+ 'reference_type': reference_type,
+ 'reference': reference,
+ }
+ result['value'].update(res_update)
+ return result
+
+ def generate_bbacomm(self, cr, uid, ids, type, reference_type, algorithm, partner_id, reference):
+ partner_obj = self.pool.get('res.partner')
+ reference = reference or ''
+ if (type == 'out_invoice'):
+ if reference_type == 'bba':
+ if not algorithm:
+ if partner_id:
+ algorithm = partner_obj.browse(cr, uid, partner_id).out_inv_comm_algorithm
+ if not algorithm:
+ if not algorithm:
+ algorithm = 'random'
+ if algorithm == 'date':
+ if not self.check_bbacomm(reference):
+ doy = time.strftime('%j')
+ year = time.strftime('%Y')
+ seq = '001'
+ seq_ids = self.search(cr, uid,
+ [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'),
+ ('reference', 'like', '+++%s/%s/%%' % (doy, year))], order='reference')
+ if seq_ids:
+ prev_seq = int(self.browse(cr, uid, seq_ids[-1]).reference[12:15])
+ if prev_seq < 999:
+ seq = '%03d' % (prev_seq + 1)
+ else:
+ raise osv.except_osv(_('Warning!'),
+ _('The daily maximum of outgoing invoices with an automatically generated BBA Structured Communications has been exceeded!' \
+ '\nPlease create manually a unique BBA Structured Communication.'))
+ bbacomm = doy + year + seq
+ base = int(bbacomm)
+ mod = base % 97 or 97
+ reference = '+++%s/%s/%s%02d+++' % (doy, year, seq, mod)
+ elif algorithm == 'partner_ref':
+ if not self.check_bbacomm(reference):
+ partner_ref = self.pool.get('res.partner').browse(cr, uid, partner_id).ref
+ partner_ref_nr = re.sub('\D', '', partner_ref or '')
+ if (len(partner_ref_nr) < 3) or (len(partner_ref_nr) > 7):
+ raise osv.except_osv(_('Warning!'),
+ _('The Partner should have a 3-7 digit Reference Number for the generation of BBA Structured Communications!' \
+ '\nPlease correct the Partner record.'))
+ else:
+ partner_ref_nr = partner_ref_nr.ljust(7, '0')
+ seq = '001'
+ seq_ids = self.search(cr, uid,
+ [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'),
+ ('reference', 'like', '+++%s/%s/%%' % (partner_ref_nr[:3], partner_ref_nr[3:]))], order='reference')
+ if seq_ids:
+ prev_seq = int(self.browse(cr, uid, seq_ids[-1]).reference[12:15])
+ if prev_seq < 999:
+ seq = '%03d' % (prev_seq + 1)
+ else:
+ raise osv.except_osv(_('Warning!'),
+ _('The daily maximum of outgoing invoices with an automatically generated BBA Structured Communications has been exceeded!' \
+ '\nPlease create manually a unique BBA Structured Communication.'))
+ bbacomm = partner_ref_nr + seq
+ base = int(bbacomm)
+ mod = base % 97 or 97
+ reference = '+++%s/%s/%s%02d+++' % (partner_ref_nr[:3], partner_ref_nr[3:], seq, mod)
+ elif algorithm == 'random':
+ if not self.check_bbacomm(reference):
+ base = random.randint(1, 9999999999)
+ bbacomm = str(base).rjust(7, '0')
+ base = int(bbacomm)
+ mod = base % 97 or 97
+ mod = str(mod).rjust(2, '0')
+ reference = '+++%s/%s/%s%s+++' % (bbacomm[:3], bbacomm[3:7], bbacomm[7:], mod)
+ else:
+ raise osv.except_osv(_('Error!'),
+ _("Unsupported Structured Communication Type Algorithm '%s' !" \
+ "\nPlease contact your OpenERP support channel.") % algorithm)
+ return {'value': {'reference': reference}}
+
+ def create(self, cr, uid, vals, context=None):
+ if vals.has_key('reference_type'):
+ reference_type = vals['reference_type']
+ if reference_type == 'bba':
+ if vals.has_key('reference'):
+ bbacomm = vals['reference']
+ else:
+ raise osv.except_osv(_('Warning!'),
+ _('Empty BBA Structured Communication!' \
+ '\nPlease fill in a unique BBA Structured Communication.'))
+ if self.check_bbacomm(bbacomm):
+ reference = re.sub('\D', '', bbacomm)
+ vals['reference'] = '+++' + reference[0:3] + '/' + reference[3:7] + '/' + reference[7:] + '+++'
+ same_ids = self.search(cr, uid,
+ [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'),
+ ('reference', '=', vals['reference'])])
+ if same_ids:
+ raise osv.except_osv(_('Warning!'),
+ _('The BBA Structured Communication has already been used!' \
+ '\nPlease create manually a unique BBA Structured Communication.'))
+ return super(account_invoice, self).create(cr, uid, vals, context=context)
+
+ def write(self, cr, uid, ids, vals, context={}):
+ for inv in self.browse(cr, uid, ids, context):
+ if vals.has_key('reference_type'):
+ reference_type = vals['reference_type']
+ else:
+ reference_type = inv.reference_type or ''
+ if reference_type == 'bba':
+ if vals.has_key('reference'):
+ bbacomm = vals['reference']
+ else:
+ bbacomm = inv.reference or ''
+ if self.check_bbacomm(bbacomm):
+ reference = re.sub('\D', '', bbacomm)
+ vals['reference'] = '+++' + reference[0:3] + '/' + reference[3:7] + '/' + reference[7:] + '+++'
+ same_ids = self.search(cr, uid,
+ [('id', '!=', inv.id), ('type', '=', 'out_invoice'),
+ ('reference_type', '=', 'bba'), ('reference', '=', vals['reference'])])
+ if same_ids:
+ raise osv.except_osv(_('Warning!'),
+ _('The BBA Structured Communication has already been used!' \
+ '\nPlease create manually a unique BBA Structured Communication.'))
+ return super(account_invoice, self).write(cr, uid, ids, vals, context)
+
+ _columns = {
+ 'reference': fields.char('Communication', size=64, help="The partner reference of this invoice."),
+ 'reference_type': fields.selection(_get_reference_type, 'Communication Type',
+ required=True),
+ }
+
+ _constraints = [
+ (_check_communication, 'Invalid BBA Structured Communication !', ['Communication']),
+ ]
+
+account_invoice()
diff --git a/addons/account_invoice_be/partner.py b/addons/account_invoice_be/partner.py
new file mode 100644
index 00000000000..2794b81670c
--- /dev/null
+++ b/addons/account_invoice_be/partner.py
@@ -0,0 +1,48 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+#
+# Created by Luc De Meyer
+# Copyright (c) 2010 Noviat nv/sa (www.noviat.be). All rights reserved.
+#
+# 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 osv import fields, osv
+import time
+from tools.translate import _
+import netsvc
+logger=netsvc.Logger()
+
+class res_partner(osv.osv):
+ """ add field to indicate default 'Communication Type' on customer invoices """
+ _inherit = 'res.partner'
+
+ def _get_comm_type(self, cr, uid, context=None):
+ res = self.pool.get('account.invoice')._get_reference_type(cr, uid,context=context)
+ return res
+
+ _columns = {
+ 'out_inv_comm_type': fields.selection(_get_comm_type, 'Communication Type', change_default=True,
+ help='Select Default Communication Type for Outgoing Invoices.' ),
+ 'out_inv_comm_algorithm': fields.selection([
+ ('random','Random'),
+ ('date','Date'),
+ ('partner_ref','Customer Reference'),
+ ], 'Communication Algorithm',
+ help='Select Algorithm to generate the Structured Communication on Outgoing Invoices.' ),
+ }
+res_partner()
diff --git a/addons/account_invoice_be/partner_view.xml b/addons/account_invoice_be/partner_view.xml
new file mode 100644
index 00000000000..7489322a665
--- /dev/null
+++ b/addons/account_invoice_be/partner_view.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ res.partner.inv_comm_type.form.inherit
+ res.partner
+ form
+
+
+
+
+
+
+
+
+
+
+