[FIX] website info view remove optional tag
[odoo/odoo.git] / addons / l10n_be_invoice_bba / invoice.py
1 # -*- encoding: utf-8 -*-\r
2 ##############################################################################\r
3 #\r
4 #    OpenERP, Open Source Management Solution\r
5 #\r
6 #    Copyright (c) 2011 Noviat nv/sa (www.noviat.be). All rights reserved.\r
7 #\r
8 #    This program is free software: you can redistribute it and/or modify\r
9 #    it under the terms of the GNU Affero General Public License as\r
10 #    published by the Free Software Foundation, either version 3 of the\r
11 #    License, or (at your option) any later version.\r
12 #\r
13 #    This program is distributed in the hope that it will be useful,\r
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16 #    GNU Affero General Public License for more details.\r
17 #\r
18 #    You should have received a copy of the GNU Affero General Public License\r
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
20 #\r
21 ##############################################################################\r
22 \r
23 import re, time, random\r
24 from openerp import api\r
25 from openerp.osv import fields, osv\r
26 from openerp.tools.translate import _\r
27 import logging\r
28 _logger = logging.getLogger(__name__)\r
29 \r
30 """\r
31 account.invoice object:\r
32     - Add support for Belgian structured communication\r
33     - Rename 'reference' field labels to 'Communication'\r
34 """\r
35 \r
36 class account_invoice(osv.osv):\r
37     _inherit = 'account.invoice'\r
38 \r
39     @api.cr_uid_context\r
40     def _get_reference_type(self, cursor, user, context=None):\r
41         """Add BBA Structured Communication Type and change labels from 'reference' into 'communication' """\r
42         res = super(account_invoice, self)._get_reference_type(cursor, user,\r
43                 context=context)\r
44         res[[i for i,x in enumerate(res) if x[0] == 'none'][0]] = ('none', 'Free Communication')\r
45         res.append(('bba', 'BBA Structured Communication'))\r
46         #l_logger.warning('reference_type =  %s' %res )\r
47         return res\r
48 \r
49     def check_bbacomm(self, val):\r
50         supported_chars = '0-9+*/ '\r
51         pattern = re.compile('[^' + supported_chars + ']')\r
52         if pattern.findall(val or ''):\r
53             return False\r
54         bbacomm = re.sub('\D', '', val or '')\r
55         if len(bbacomm) == 12:\r
56             base = int(bbacomm[:10])\r
57             mod = base % 97 or 97\r
58             if mod == int(bbacomm[-2:]):\r
59                 return True\r
60         return False\r
61 \r
62     def _check_communication(self, cr, uid, ids):\r
63         for inv in self.browse(cr, uid, ids):\r
64             if inv.reference_type == 'bba':\r
65                 return self.check_bbacomm(inv.reference)\r
66         return True\r
67 \r
68     def onchange_partner_id(self, cr, uid, ids, type, partner_id,\r
69                             date_invoice=False, payment_term=False,\r
70                             partner_bank_id=False, company_id=False,\r
71                             context=None):\r
72         result = super(account_invoice, self).onchange_partner_id(cr, uid, ids, type, partner_id,\r
73             date_invoice, payment_term, partner_bank_id, company_id, context)\r
74 #        reference_type = self.default_get(cr, uid, ['reference_type'])['reference_type']\r
75 #        _logger.warning('partner_id %s' % partner_id)\r
76         reference = False\r
77         reference_type = 'none'\r
78         if partner_id:\r
79             if (type == 'out_invoice'):\r
80                 reference_type = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context).out_inv_comm_type\r
81                 if reference_type:\r
82                     reference = self.generate_bbacomm(cr, uid, ids, type, reference_type, partner_id, '', context=context)['value']['reference']\r
83         res_update = {\r
84             'reference_type': reference_type or 'none',\r
85             'reference': reference,\r
86         }\r
87         result['value'].update(res_update)\r
88         return result\r
89 \r
90     def generate_bbacomm(self, cr, uid, ids, type, reference_type, partner_id, reference, context=None):\r
91         partner_obj =  self.pool.get('res.partner')\r
92         reference = reference or ''\r
93         algorithm = False\r
94         if partner_id:\r
95             algorithm = partner_obj.browse(cr, uid, partner_id, context=context).out_inv_comm_algorithm\r
96         algorithm = algorithm or 'random'\r
97         if (type == 'out_invoice'):\r
98             if reference_type == 'bba':\r
99                 if algorithm == 'date':\r
100                     if not self.check_bbacomm(reference):\r
101                         doy = time.strftime('%j')\r
102                         year = time.strftime('%Y')\r
103                         seq = '001'\r
104                         seq_ids = self.search(cr, uid,\r
105                             [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'),\r
106                              ('reference', 'like', '+++%s/%s/%%' % (doy, year))], order='reference')\r
107                         if seq_ids:\r
108                             prev_seq = int(self.browse(cr, uid, seq_ids[-1]).reference[12:15])\r
109                             if prev_seq < 999:\r
110                                 seq = '%03d' % (prev_seq + 1)\r
111                             else:\r
112                                 raise osv.except_osv(_('Warning!'),\r
113                                     _('The daily maximum of outgoing invoices with an automatically generated BBA Structured Communications has been exceeded!' \\r
114                                       '\nPlease create manually a unique BBA Structured Communication.'))\r
115                         bbacomm = doy + year + seq\r
116                         base = int(bbacomm)\r
117                         mod = base % 97 or 97\r
118                         reference = '+++%s/%s/%s%02d+++' % (doy, year, seq, mod)\r
119                 elif algorithm == 'partner_ref':\r
120                     if not self.check_bbacomm(reference):\r
121                         partner_ref = self.pool.get('res.partner').browse(cr, uid, partner_id).ref\r
122                         partner_ref_nr = re.sub('\D', '', partner_ref or '')\r
123                         if (len(partner_ref_nr) < 3) or (len(partner_ref_nr) > 7):\r
124                             raise osv.except_osv(_('Warning!'),\r
125                                 _('The Partner should have a 3-7 digit Reference Number for the generation of BBA Structured Communications!' \\r
126                                   '\nPlease correct the Partner record.'))\r
127                         else:\r
128                             partner_ref_nr = partner_ref_nr.ljust(7, '0')\r
129                             seq = '001'\r
130                             seq_ids = self.search(cr, uid,\r
131                                 [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'),\r
132                                  ('reference', 'like', '+++%s/%s/%%' % (partner_ref_nr[:3], partner_ref_nr[3:]))], order='reference')\r
133                             if seq_ids:\r
134                                 prev_seq = int(self.browse(cr, uid, seq_ids[-1]).reference[12:15])\r
135                                 if prev_seq < 999:\r
136                                     seq = '%03d' % (prev_seq + 1)\r
137                                 else:\r
138                                     raise osv.except_osv(_('Warning!'),\r
139                                         _('The daily maximum of outgoing invoices with an automatically generated BBA Structured Communications has been exceeded!' \\r
140                                           '\nPlease create manually a unique BBA Structured Communication.'))\r
141                         bbacomm = partner_ref_nr + seq\r
142                         base = int(bbacomm)\r
143                         mod = base % 97 or 97\r
144                         reference = '+++%s/%s/%s%02d+++' % (partner_ref_nr[:3], partner_ref_nr[3:], seq, mod)\r
145                 elif algorithm == 'random':\r
146                     if not self.check_bbacomm(reference):\r
147                         base = random.randint(1, 9999999999)\r
148                         bbacomm = str(base).rjust(10, '0')\r
149                         base = int(bbacomm)\r
150                         mod = base % 97 or 97\r
151                         mod = str(mod).rjust(2, '0')\r
152                         reference = '+++%s/%s/%s%s+++' % (bbacomm[:3], bbacomm[3:7], bbacomm[7:], mod)\r
153                 else:\r
154                     raise osv.except_osv(_('Error!'),\r
155                         _("Unsupported Structured Communication Type Algorithm '%s' !" \\r
156                           "\nPlease contact your Odoo support channel.") % algorithm)\r
157         return {'value': {'reference': reference}}\r
158 \r
159     def create(self, cr, uid, vals, context=None):\r
160         reference = vals.get('reference', False)\r
161         reference_type = vals.get('reference_type', False)\r
162         if vals.get('type') == 'out_invoice' and not reference_type:\r
163             # fallback on default communication type for partner\r
164             reference_type = self.pool.get('res.partner').browse(cr, uid, vals['partner_id']).out_inv_comm_type\r
165             if reference_type == 'bba':\r
166                 reference = self.generate_bbacomm(cr, uid, [], vals['type'], reference_type, vals['partner_id'], '', context={})['value']['reference']\r
167             vals.update({\r
168                 'reference_type': reference_type or 'none',\r
169                 'reference': reference,\r
170             })\r
171 \r
172         if reference_type == 'bba':\r
173             if not reference:\r
174                 raise osv.except_osv(_('Warning!'),\r
175                     _('Empty BBA Structured Communication!' \\r
176                       '\nPlease fill in a unique BBA Structured Communication.'))\r
177             if self.check_bbacomm(reference):\r
178                 reference = re.sub('\D', '', reference)\r
179                 vals['reference'] = '+++' + reference[0:3] + '/' + reference[3:7] + '/' + reference[7:] + '+++'\r
180                 same_ids = self.search(cr, uid,\r
181                     [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'),\r
182                      ('reference', '=', vals['reference'])])\r
183                 if same_ids:\r
184                     raise osv.except_osv(_('Warning!'),\r
185                         _('The BBA Structured Communication has already been used!' \\r
186                           '\nPlease create manually a unique BBA Structured Communication.'))\r
187         return super(account_invoice, self).create(cr, uid, vals, context=context)\r
188 \r
189     def write(self, cr, uid, ids, vals, context=None):\r
190         if isinstance(ids, (int, long)):\r
191             ids = [ids]\r
192         for inv in self.browse(cr, uid, ids, context):\r
193             if vals.has_key('reference_type'):\r
194                 reference_type = vals['reference_type']\r
195             else:\r
196                 reference_type = inv.reference_type or ''\r
197             if reference_type == 'bba':\r
198                 if vals.has_key('reference'):\r
199                     bbacomm = vals['reference']\r
200                 else:\r
201                     bbacomm = inv.reference or ''\r
202                 if self.check_bbacomm(bbacomm):\r
203                     reference = re.sub('\D', '', bbacomm)\r
204                     vals['reference'] = '+++' + reference[0:3] + '/' + reference[3:7] + '/' + reference[7:] + '+++'\r
205                     same_ids = self.search(cr, uid,\r
206                         [('id', '!=', inv.id), ('type', '=', 'out_invoice'),\r
207                          ('reference_type', '=', 'bba'), ('reference', '=', vals['reference'])])\r
208                     if same_ids:\r
209                         raise osv.except_osv(_('Warning!'),\r
210                             _('The BBA Structured Communication has already been used!' \\r
211                               '\nPlease create manually a unique BBA Structured Communication.'))\r
212         return super(account_invoice, self).write(cr, uid, ids, vals, context)\r
213 \r
214     def copy(self, cr, uid, id, default=None, context=None):\r
215         default = default or {}\r
216         invoice = self.browse(cr, uid, id, context=context)\r
217         if invoice.type in ['out_invoice']:\r
218             reference_type = invoice.reference_type or 'none'\r
219             default['reference_type'] = reference_type\r
220             if reference_type == 'bba':\r
221                 partner = invoice.partner_id\r
222                 default['reference'] = self.generate_bbacomm(cr, uid, id,\r
223                     invoice.type, reference_type,\r
224                     partner.id, '', context=context)['value']['reference']\r
225         return super(account_invoice, self).copy(cr, uid, id, default, context=context)\r
226 \r
227     _columns = {\r
228         'reference': fields.char('Communication', help="The partner reference of this invoice."),\r
229         'reference_type': fields.selection(_get_reference_type, 'Communication Type',\r
230             required=True),\r
231     }\r
232     _constraints = [\r
233         (_check_communication, 'Invalid BBA Structured Communication !', ['Communication']),\r
234         ]\r
235 \r
236 account_invoice()\r
237 \r
238 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:\r