odoo/addons/l10n_be_invoice_bba/models/account_invoice.py

186 lines
9.7 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
# Copyright (c) 2011 Noviat nv/sa (www.noviat.be). All rights reserved.
import random
import re
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
"""
account.invoice object:
- Add support for Belgian structured communication
- Rename 'reference' field labels to 'Communication'
"""
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
@api.model
def _get_reference_type(self):
"""Add BBA Structured Communication Type and change labels from 'reference' into 'communication' """
res = super(AccountInvoice, self)._get_reference_type()
res[[i for i, x in enumerate(res) if x[0] == 'none'][0]] = ('none', _('Free Communication'))
res.append(('bba', 'BBA Structured Communication'))
return res
reference_type = fields.Selection('_get_reference_type', string='Payment Reference',
required=True, readonly=True)
@api.constrains('reference', 'reference_type')
def _check_communication(self):
for inv in self:
if inv.reference_type == 'bba' and not self.check_bbacomm(inv.reference):
raise ValidationError(_('Invalid BBA Structured Communication !'))
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
@api.onchange('partner_id', 'type')
def _onchange_partner_id(self):
result = super(AccountInvoice, self)._onchange_partner_id()
reference = False
reference_type = 'none'
if self.partner_id:
if (self.type == 'out_invoice'):
reference_type = self.partner_id.out_inv_comm_type
if reference_type:
reference = self.generate_bbacomm(self.type, reference_type, self.partner_id.id, '')['value']['reference']
self.reference_type = reference_type or 'none'
self.reference = reference
return result
@api.multi
def generate_bbacomm(self, type, reference_type, partner_id, reference):
reference = reference or ''
algorithm = False
if partner_id:
algorithm = self.env['res.partner'].browse(partner_id).out_inv_comm_algorithm
algorithm = algorithm or 'random'
if (type == 'out_invoice'):
if reference_type == 'bba':
if algorithm == 'date':
if not self.check_bbacomm(reference):
date = fields.Date.from_string(fields.Date.today())
doy = date.strftime('%j')
year = date.strftime('%Y')
seq = '001'
invoices = self.search([('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'),
('reference', 'like', '+++%s/%s/%%' % (doy, year))], order='reference')
if invoices:
prev_seq = int(invoices[-1].reference[12:15])
if prev_seq < 999:
seq = '%03d' % (prev_seq + 1)
else:
raise UserError(_('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.env['res.partner'].browse(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 UserError(_('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'
invoices = self.search([('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'),
('reference', 'like', '+++%s/%s/%%' % (partner_ref_nr[:3], partner_ref_nr[3:]))], order='reference')
if invoices:
prev_seq = int(invoices[-1].reference[12:15])
if prev_seq < 999:
seq = '%03d' % (prev_seq + 1)
else:
raise UserError(_('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(10, '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 UserError(_("Unsupported Structured Communication Type Algorithm '%s' !"
"\nPlease contact your Odoo support channel.") % algorithm)
return {'value': {'reference': reference}}
@api.model
def create(self, vals):
reference = vals.get('reference', False)
reference_type = vals.get('reference_type', False)
if vals.get('type') == 'out_invoice' and not reference_type:
# fallback on default communication type for partner
partner = self.env['res.partner'].browse(vals['partner_id'])
reference_type = partner.out_inv_comm_type
if reference_type == 'bba':
reference = self.generate_bbacomm(vals['type'], reference_type, partner.id, '')['value']['reference']
vals.update({
'reference_type': reference_type or 'none',
'reference': reference,
})
if reference_type == 'bba':
if not reference:
raise UserError(_('Empty BBA Structured Communication!'
'\nPlease fill in a unique BBA Structured Communication.'))
if self.check_bbacomm(reference):
reference = re.sub('\D', '', reference)
vals['reference'] = '+++' + reference[0:3] + '/' + reference[3:7] + '/' + reference[7:] + '+++'
same_ids = self.search([('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'), ('reference', '=', vals['reference'])])
if same_ids:
raise UserError(_('The BBA Structured Communication has already been used!'
'\nPlease create manually a unique BBA Structured Communication.'))
return super(AccountInvoice, self).create(vals)
@api.multi
def write(self, vals):
for invoice in self:
if 'reference_type' in vals:
reference_type = vals['reference_type']
else:
reference_type = invoice.reference_type or ''
if reference_type == 'bba' and 'reference' in vals:
if self.check_bbacomm(vals['reference']):
reference = re.sub('\D', '', vals['reference'])
vals['reference'] = '+++' + reference[0:3] + '/' + reference[3:7] + '/' + reference[7:] + '+++'
same_ids = self.search([('id', '!=', invoice.id), ('type', '=', 'out_invoice'),
('reference_type', '=', 'bba'), ('reference', '=', vals['reference'])])
if same_ids:
raise UserError(_('The BBA Structured Communication has already been used!'
'\nPlease create manually a unique BBA Structured Communication.'))
return super(AccountInvoice, self).write(vals)
@api.multi
def copy(self, default=None):
self.ensure_one()
default = default or {}
if self.type in ['out_invoice']:
reference_type = self.reference_type or 'none'
default['reference_type'] = reference_type
if reference_type == 'bba':
default['reference'] = self.generate_bbacomm(self.type, reference_type, self.partner_id.id, '')['value']['reference']
return super(AccountInvoice, self).copy(default)