[FIX] hr_attendance: typo introduced at rev 1c9e8ba077b296ec9c334800915fbbf76c81310c
[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.osv import fields, osv\r
25 from openerp.tools.translate import _\r
26 import logging\r
27 _logger = logging.getLogger(__name__)\r
28 \r
29 """\r
30 account.invoice object:\r
31     - Add support for Belgian structured communication\r
32     - Rename 'reference' field labels to 'Communication'\r
33 """\r
34 \r
35 class account_invoice(osv.osv):\r
36     _inherit = 'account.invoice'\r
37 \r
38     def _get_reference_type(self, cursor, user, context=None):\r
39         """Add BBA Structured Communication Type and change labels from 'reference' into 'communication' """\r
40         res = super(account_invoice, self)._get_reference_type(cursor, user,\r
41                 context=context)\r
42         res[[i for i,x in enumerate(res) if x[0] == 'none'][0]] = ('none', 'Free Communication')\r
43         res.append(('bba', 'BBA Structured Communication'))\r
44         #l_logger.warning('reference_type =  %s' %res )\r
45         return res\r
46 \r
47     def check_bbacomm(self, val):\r
48         supported_chars = '0-9+*/ '\r
49         pattern = re.compile('[^' + supported_chars + ']')\r
50         if pattern.findall(val or ''):\r
51             return False\r
52         bbacomm = re.sub('\D', '', val or '')\r
53         if len(bbacomm) == 12:\r
54             base = int(bbacomm[:10])\r
55             mod = base % 97 or 97\r
56             if mod == int(bbacomm[-2:]):\r
57                 return True\r
58         return False\r
59 \r
60     def _check_communication(self, cr, uid, ids):\r
61         for inv in self.browse(cr, uid, ids):\r
62             if inv.reference_type == 'bba':\r
63                 return self.check_bbacomm(inv.reference)\r
64         return True\r
65 \r
66     def onchange_partner_id(self, cr, uid, ids, type, partner_id,\r
67             date_invoice=False, payment_term=False, partner_bank_id=False, company_id=False):\r
68         result = super(account_invoice, self).onchange_partner_id(cr, uid, ids, type, partner_id,\r
69             date_invoice, payment_term, partner_bank_id, company_id)\r
70 #        reference_type = self.default_get(cr, uid, ['reference_type'])['reference_type']\r
71 #        _logger.warning('partner_id %s' % partner_id)\r
72         reference = False\r
73         reference_type = 'none'\r
74         if partner_id:\r
75             if (type == 'out_invoice'):\r
76                 reference_type = self.pool.get('res.partner').browse(cr, uid, partner_id).out_inv_comm_type\r
77                 if reference_type:\r
78                     reference = self.generate_bbacomm(cr, uid, ids, type, reference_type, partner_id, '', context={})['value']['reference']\r
79         res_update = {\r
80             'reference_type': reference_type or 'none',\r
81             'reference': reference,\r
82         }\r
83         result['value'].update(res_update)\r
84         return result\r
85 \r
86     def generate_bbacomm(self, cr, uid, ids, type, reference_type, partner_id, reference, context=None):\r
87         partner_obj =  self.pool.get('res.partner')\r
88         reference = reference or ''\r
89         algorithm = False\r
90         if partner_id:\r
91             algorithm = partner_obj.browse(cr, uid, partner_id, context=context).out_inv_comm_algorithm\r
92         algorithm = algorithm or 'random'\r
93         if (type == 'out_invoice'):\r
94             if reference_type == 'bba':\r
95                 if algorithm == 'date':\r
96                     if not self.check_bbacomm(reference):\r
97                         doy = time.strftime('%j')\r
98                         year = time.strftime('%Y')\r
99                         seq = '001'\r
100                         seq_ids = self.search(cr, uid,\r
101                             [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'),\r
102                              ('reference', 'like', '+++%s/%s/%%' % (doy, year))], order='reference')\r
103                         if seq_ids:\r
104                             prev_seq = int(self.browse(cr, uid, seq_ids[-1]).reference[12:15])\r
105                             if prev_seq < 999:\r
106                                 seq = '%03d' % (prev_seq + 1)\r
107                             else:\r
108                                 raise osv.except_osv(_('Warning!'),\r
109                                     _('The daily maximum of outgoing invoices with an automatically generated BBA Structured Communications has been exceeded!' \\r
110                                       '\nPlease create manually a unique BBA Structured Communication.'))\r
111                         bbacomm = doy + year + seq\r
112                         base = int(bbacomm)\r
113                         mod = base % 97 or 97\r
114                         reference = '+++%s/%s/%s%02d+++' % (doy, year, seq, mod)\r
115                 elif algorithm == 'partner_ref':\r
116                     if not self.check_bbacomm(reference):\r
117                         partner_ref = self.pool.get('res.partner').browse(cr, uid, partner_id).ref\r
118                         partner_ref_nr = re.sub('\D', '', partner_ref or '')\r
119                         if (len(partner_ref_nr) < 3) or (len(partner_ref_nr) > 7):\r
120                             raise osv.except_osv(_('Warning!'),\r
121                                 _('The Partner should have a 3-7 digit Reference Number for the generation of BBA Structured Communications!' \\r
122                                   '\nPlease correct the Partner record.'))\r
123                         else:\r
124                             partner_ref_nr = partner_ref_nr.ljust(7, '0')\r
125                             seq = '001'\r
126                             seq_ids = self.search(cr, uid,\r
127                                 [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'),\r
128                                  ('reference', 'like', '+++%s/%s/%%' % (partner_ref_nr[:3], partner_ref_nr[3:]))], order='reference')\r
129                             if seq_ids:\r
130                                 prev_seq = int(self.browse(cr, uid, seq_ids[-1]).reference[12:15])\r
131                                 if prev_seq < 999:\r
132                                     seq = '%03d' % (prev_seq + 1)\r
133                                 else:\r
134                                     raise osv.except_osv(_('Warning!'),\r
135                                         _('The daily maximum of outgoing invoices with an automatically generated BBA Structured Communications has been exceeded!' \\r
136                                           '\nPlease create manually a unique BBA Structured Communication.'))\r
137                         bbacomm = partner_ref_nr + seq\r
138                         base = int(bbacomm)\r
139                         mod = base % 97 or 97\r
140                         reference = '+++%s/%s/%s%02d+++' % (partner_ref_nr[:3], partner_ref_nr[3:], seq, mod)\r
141                 elif algorithm == 'random':\r
142                     if not self.check_bbacomm(reference):\r
143                         base = random.randint(1, 9999999999)\r
144                         bbacomm = str(base).rjust(10, '0')\r
145                         base = int(bbacomm)\r
146                         mod = base % 97 or 97\r
147                         mod = str(mod).rjust(2, '0')\r
148                         reference = '+++%s/%s/%s%s+++' % (bbacomm[:3], bbacomm[3:7], bbacomm[7:], mod)\r
149                 else:\r
150                     raise osv.except_osv(_('Error!'),\r
151                         _("Unsupported Structured Communication Type Algorithm '%s' !" \\r
152                           "\nPlease contact your OpenERP support channel.") % algorithm)\r
153         return {'value': {'reference': reference}}\r
154 \r
155     def create(self, cr, uid, vals, context=None):\r
156         reference = vals.get('reference', False)\r
157         reference_type = vals.get('reference_type', False)\r
158         if vals.get('type') == 'out_invoice' and not reference_type:\r
159             # fallback on default communication type for partner\r
160             reference_type = self.pool.get('res.partner').browse(cr, uid, vals['partner_id']).out_inv_comm_type\r
161             if reference_type == 'bba':\r
162                 reference = self.generate_bbacomm(cr, uid, [], vals['type'], reference_type, vals['partner_id'], '', context={})['value']['reference']\r
163             vals.update({\r
164                 'reference_type': reference_type or 'none',\r
165                 'reference': reference,\r
166             })\r
167 \r
168         if reference_type == 'bba':\r
169             if not reference:\r
170                 raise osv.except_osv(_('Warning!'),\r
171                     _('Empty BBA Structured Communication!' \\r
172                       '\nPlease fill in a unique BBA Structured Communication.'))\r
173             if self.check_bbacomm(reference):\r
174                 reference = re.sub('\D', '', reference)\r
175                 vals['reference'] = '+++' + reference[0:3] + '/' + reference[3:7] + '/' + reference[7:] + '+++'\r
176                 same_ids = self.search(cr, uid,\r
177                     [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'),\r
178                      ('reference', '=', vals['reference'])])\r
179                 if same_ids:\r
180                     raise osv.except_osv(_('Warning!'),\r
181                         _('The BBA Structured Communication has already been used!' \\r
182                           '\nPlease create manually a unique BBA Structured Communication.'))\r
183         return super(account_invoice, self).create(cr, uid, vals, context=context)\r
184 \r
185     def write(self, cr, uid, ids, vals, context=None):\r
186         if isinstance(ids, (int, long)):\r
187             ids = [ids]\r
188         for inv in self.browse(cr, uid, ids, context):\r
189             if vals.has_key('reference_type'):\r
190                 reference_type = vals['reference_type']\r
191             else:\r
192                 reference_type = inv.reference_type or ''\r
193             if reference_type == 'bba':\r
194                 if vals.has_key('reference'):\r
195                     bbacomm = vals['reference']\r
196                 else:\r
197                     bbacomm = inv.reference or ''\r
198                 if self.check_bbacomm(bbacomm):\r
199                     reference = re.sub('\D', '', bbacomm)\r
200                     vals['reference'] = '+++' + reference[0:3] + '/' + reference[3:7] + '/' + reference[7:] + '+++'\r
201                     same_ids = self.search(cr, uid,\r
202                         [('id', '!=', inv.id), ('type', '=', 'out_invoice'),\r
203                          ('reference_type', '=', 'bba'), ('reference', '=', vals['reference'])])\r
204                     if same_ids:\r
205                         raise osv.except_osv(_('Warning!'),\r
206                             _('The BBA Structured Communication has already been used!' \\r
207                               '\nPlease create manually a unique BBA Structured Communication.'))\r
208         return super(account_invoice, self).write(cr, uid, ids, vals, context)\r
209 \r
210     def copy(self, cr, uid, id, default=None, context=None):\r
211         default = default or {}\r
212         invoice = self.browse(cr, uid, id, context=context)\r
213         if invoice.type in ['out_invoice']:\r
214             reference_type = invoice.reference_type or 'none'\r
215             default['reference_type'] = reference_type\r
216             if reference_type == 'bba':\r
217                 partner = invoice.partner_id\r
218                 default['reference'] = self.generate_bbacomm(cr, uid, id,\r
219                     invoice.type, reference_type,\r
220                     partner.id, '', context=context)['value']['reference']\r
221         return super(account_invoice, self).copy(cr, uid, id, default, context=context)\r
222 \r
223     _columns = {\r
224         'reference': fields.char('Communication', size=64, help="The partner reference of this invoice."),\r
225         'reference_type': fields.selection(_get_reference_type, 'Communication Type',\r
226             required=True),\r
227     }\r
228     _constraints = [\r
229         (_check_communication, 'Invalid BBA Structured Communication !', ['Communication']),\r
230         ]\r
231 \r
232 account_invoice()\r
233 \r
234 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:\r