[IMP] Improved typo in Warning
[odoo/odoo.git] / addons / l10n_be / wizard / l10n_be_partner_vat_listing.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6 #
7 #    Corrections & modifications by Noviat nv/sa, (http://www.noviat.be):
8 #    - VAT listing based upon year in stead of fiscal year
9 #    - sql query adapted to select only 'tax-out' move lines
10 #    - extra button to print readable PDF report
11 #
12 #    This program is free software: you can redistribute it and/or modify
13 #    it under the terms of the GNU Affero General Public License as
14 #    published by the Free Software Foundation, either version 3 of the
15 #    License, or (at your option) any later version.
16 #
17 #    This program is distributed in the hope that it will be useful,
18 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
19 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 #    GNU Affero General Public License for more details.
21 #
22 #    You should have received a copy of the GNU Affero General Public License
23 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 #
25 ##############################################################################
26
27 import time
28 import base64
29 from openerp.tools.translate import _
30 from openerp.osv import fields, osv
31 from openerp.report import report_sxw
32
33 class vat_listing_clients(osv.osv_memory):
34     _name = 'vat.listing.clients'
35     _columns = {
36         'name': fields.char('Client Name', size=32),
37         'vat': fields.char('VAT', size=64),
38         'turnover': fields.float('Base Amount'),
39         'vat_amount': fields.float('VAT Amount'),
40     }
41
42
43 class partner_vat(osv.osv_memory):
44     """ Vat Listing """
45     _name = "partner.vat"
46
47     def get_partner(self, cr, uid, ids, context=None):
48         obj_period = self.pool.get('account.period')
49         obj_partner = self.pool.get('res.partner')
50         obj_vat_lclient = self.pool.get('vat.listing.clients')
51         obj_model_data = self.pool.get('ir.model.data')
52         obj_module = self.pool.get('ir.module.module')
53         data  = self.read(cr, uid, ids)[0]
54         year = data['year']
55         date_start = year + '-01-01'
56         date_stop = year + '-12-31'
57         if context.get('company_id', False):
58             company_id = context['company_id']
59         else:
60             company_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
61         period_ids = obj_period.search(cr, uid, [('date_start' ,'>=', date_start), ('date_stop','<=',date_stop), ('company_id','=',company_id)])
62         if not period_ids:
63              raise osv.except_osv(_('insufficient data!'), _('No data for the selected year.'))
64
65         partners = []
66         partner_ids = obj_partner.search(cr, uid, [('vat_subjected', '!=', False), ('vat','ilike','BE%')], context=context)
67         if not partner_ids:
68              raise osv.except_osv(_('Error'),_('No belgium contact with a VAT number in your database.'))
69         cr.execute("""SELECT sub1.partner_id, sub1.name, sub1.vat, sub1.turnover, sub2.vat_amount
70                 FROM (SELECT l.partner_id, p.name, p.vat, SUM(CASE WHEN c.code ='49' THEN -l.tax_amount ELSE l.tax_amount END) as turnover
71                       FROM account_move_line l
72                       LEFT JOIN res_partner p ON l.partner_id = p.id
73                       LEFT JOIN account_tax_code c ON l.tax_code_id = c.id
74                       WHERE c.code IN ('00','01','02','03','45','49')
75                       AND l.partner_id IN %s
76                       AND l.period_id IN %s
77                       GROUP BY l.partner_id, p.name, p.vat) AS sub1
78                 LEFT JOIN (SELECT l2.partner_id, SUM(CASE WHEN c2.code ='64' THEN -l2.tax_amount ELSE l2.tax_amount END) as vat_amount
79                       FROM account_move_line l2
80                       LEFT JOIN account_tax_code c2 ON l2.tax_code_id = c2.id
81                       WHERE c2.code IN ('54','64')
82                       AND l2.partner_id IN %s
83                       AND l2.period_id IN %s
84                       GROUP BY l2.partner_id) AS sub2 ON sub1.partner_id = sub2.partner_id
85                     """,(tuple(partner_ids),tuple(period_ids),tuple(partner_ids),tuple(period_ids)))
86         for record in cr.dictfetchall():
87             record['vat'] = record['vat'].replace(' ','').upper()
88             if record['turnover'] >= data['limit_amount']:
89                 id_client = obj_vat_lclient.create(cr, uid, record, context=context)
90                 partners.append(id_client)
91         
92         if not partners:
93             raise osv.except_osv(_('insufficient data!'), _('No data found for the selected year.'))
94         context.update({'partner_ids': partners, 'year': data['year'], 'limit_amount': data['limit_amount']})
95         model_data_ids = obj_model_data.search(cr, uid, [('model','=','ir.ui.view'), ('name','=','view_vat_listing')])
96         resource_id = obj_model_data.read(cr, uid, model_data_ids, fields=['res_id'])[0]['res_id']
97         return {
98             'name': _('Vat Listing'),
99             'view_type': 'form',
100             'view_mode': 'form',
101             'res_model': 'partner.vat.list',
102             'views': [(resource_id,'form')],
103             'context': context,
104             'type': 'ir.actions.act_window',
105             'target': 'new',
106         }
107
108     _columns = {
109         'year': fields.char('Year', size=4, required=True),
110         'limit_amount': fields.integer('Limit Amount', required=True),
111     }
112
113     _defaults={
114         'year': lambda *a: str(int(time.strftime('%Y'))-1),
115         'limit_amount': 250,
116     }
117
118
119 class partner_vat_list(osv.osv_memory):
120     """ Partner Vat Listing """
121     _name = "partner.vat.list"
122     _columns = {
123         'partner_ids': fields.many2many('vat.listing.clients', 'vat_partner_rel', 'vat_id', 'partner_id', 'Clients', help='You can remove clients/partners which you do not want to show in xml file'),
124         'name': fields.char('File Name', size=32),
125         'file_save' : fields.binary('Save File', readonly=True),
126         'comments': fields.text('Comments'),
127     }
128
129     def _get_partners(self, cr, uid, context=None):
130         return context.get('partner_ids', [])
131
132     _defaults={
133         'partner_ids': _get_partners,
134     }
135
136     def _get_datas(self, cr, uid, ids, context=None):
137         obj_vat_lclient = self.pool.get('vat.listing.clients')
138         datas = []
139         data = self.read(cr, uid, ids)[0]
140         for partner in data['partner_ids']:
141             if isinstance(partner, list) and partner:
142                 datas.append(partner[2])
143             else:
144                 client_data = obj_vat_lclient.read(cr, uid, partner, context=context)
145                 datas.append(client_data)
146         client_datas = []
147         seq = 0
148         sum_tax = 0.00
149         sum_turnover = 0.00
150         amount_data = {}
151         for line in datas:
152             if not line:
153                 continue
154             seq += 1
155             sum_tax += line['vat_amount']
156             sum_turnover += line['turnover']
157             vat = line['vat'].replace(' ','').upper()
158             amount_data ={
159                 'seq': str(seq),
160                 'vat': vat,
161                 'only_vat': vat[2:],
162                 'turnover': '%.2f' %line['turnover'],
163                 'vat_amount': '%.2f' %line['vat_amount'],
164                 'sum_tax': '%.2f' %sum_tax,
165                 'sum_turnover': '%.2f' %sum_turnover,
166                 'partner_name': line['name'],
167             }
168             client_datas += [amount_data]
169         return client_datas
170
171     def create_xml(self, cr, uid, ids, context=None):
172
173         obj_sequence = self.pool.get('ir.sequence')
174         obj_users = self.pool.get('res.users')
175         obj_partner = self.pool.get('res.partner')
176         obj_model_data = self.pool.get('ir.model.data')
177         seq_declarantnum = obj_sequence.get(cr, uid, 'declarantnum')
178         obj_cmpny = obj_users.browse(cr, uid, uid, context=context).company_id
179         company_vat = obj_cmpny.partner_id.vat
180
181         if not company_vat:
182             raise osv.except_osv(_('Insufficient Data!'),_('No VAT number associated with the company.'))
183
184         company_vat = company_vat.replace(' ','').upper()
185         SenderId = company_vat[2:]
186         issued_by = company_vat[:2]
187         seq_declarantnum = obj_sequence.get(cr, uid, 'declarantnum')
188         dnum = company_vat[2:] + seq_declarantnum[-4:]
189         street = city = country = ''
190         addr = obj_partner.address_get(cr, uid, [obj_cmpny.partner_id.id], ['invoice'])
191         if addr.get('invoice',False):
192             ads = obj_partner.browse(cr, uid, [addr['invoice']], context=context)[0]
193             phone = ads.phone and ads.phone.replace(' ','') or ''
194             email = ads.email or ''
195             name = ads.name or ''
196             city = ads.city or ''
197             zip = obj_partner.browse(cr, uid, ads.id, context=context).zip or ''
198             if not city:
199                 city = ''
200             if ads.street:
201                 street = ads.street
202             if ads.street2:
203                 street += ' ' + ads.street2
204             if ads.country_id:
205                 country = ads.country_id.code
206
207         data = self.read(cr, uid, ids)[0]
208         sender_date = time.strftime('%Y-%m-%d')
209         comp_name = obj_cmpny.name
210
211         if not email:
212             raise osv.except_osv(_('Insufficient Data!'),_('No email address associated with the company.'))
213         if not phone:
214             raise osv.except_osv(_('Insufficient Data!'),_('No phone associated with the company.'))
215         annual_listing_data = {
216             'issued_by': issued_by,
217             'company_vat': company_vat,
218             'comp_name': comp_name,
219             'street': street,
220             'zip': zip,
221             'city': city,
222             'country': country,
223             'email': email,
224             'phone': phone,
225             'SenderId': SenderId,
226             'period': context['year'],
227             'comments': data['comments'] or ''
228         }
229
230         data_file = """<?xml version="1.0" encoding="ISO-8859-1"?>
231 <ns2:ClientListingConsignment xmlns="http://www.minfin.fgov.be/InputCommon" xmlns:ns2="http://www.minfin.fgov.be/ClientListingConsignment" ClientListingsNbr="1">
232     <ns2:Representative>
233         <RepresentativeID identificationType="NVAT" issuedBy="%(issued_by)s">%(SenderId)s</RepresentativeID>
234         <Name>%(comp_name)s</Name>
235         <Street>%(street)s</Street>
236         <PostCode>%(zip)s</PostCode>
237         <City>%(city)s</City>"""
238         if annual_listing_data['country']:
239             data_file +="\n\t\t<CountryCode>%(country)s</CountryCode>"
240         data_file += """
241         <EmailAddress>%(email)s</EmailAddress>
242         <Phone>%(phone)s</Phone>
243     </ns2:Representative>"""
244         data_file = data_file % annual_listing_data
245
246         data_comp = """
247         <ns2:Declarant>
248             <VATNumber>%(SenderId)s</VATNumber>
249             <Name>%(comp_name)s</Name>
250             <Street>%(street)s</Street>
251             <PostCode>%(zip)s</PostCode>
252             <City>%(city)s</City>
253             <CountryCode>%(country)s</CountryCode>
254             <EmailAddress>%(email)s</EmailAddress>
255             <Phone>%(phone)s</Phone>
256         </ns2:Declarant>
257         <ns2:Period>%(period)s</ns2:Period>
258         """ % annual_listing_data
259
260         # Turnover and Farmer tags are not included
261         client_datas = self._get_datas(cr, uid, ids, context=context)
262         if not client_datas:
263             raise osv.except_osv(_('Data Insufficient!'),_('No data available for the client.'))
264         data_client_info = ''
265         for amount_data in client_datas:
266             data_client_info += """
267         <ns2:Client SequenceNumber="%(seq)s">
268             <ns2:CompanyVATNumber issuedBy="BE">%(only_vat)s</ns2:CompanyVATNumber>
269             <ns2:TurnOver>%(turnover)s</ns2:TurnOver>
270             <ns2:VATAmount>%(vat_amount)s</ns2:VATAmount>
271         </ns2:Client>""" % amount_data
272
273         amount_data_begin = client_datas[-1]
274         amount_data_begin.update({'dnum':dnum})
275         data_begin = """
276     <ns2:ClientListing SequenceNumber="1" ClientsNbr="%(seq)s" DeclarantReference="%(dnum)s"
277         TurnOverSum="%(sum_turnover)s" VATAmountSum="%(sum_tax)s">
278 """ % amount_data_begin
279
280         data_end = """
281
282         <ns2:Comment>%(comments)s</ns2:Comment>
283     </ns2:ClientListing>
284 </ns2:ClientListingConsignment>
285 """ % annual_listing_data
286
287         data_file += data_begin + data_comp + data_client_info + data_end
288         file_save = base64.encodestring(data_file.encode('utf8'))
289         self.write(cr, uid, ids, {'file_save':file_save, 'name':'vat_list.xml'}, context=context)
290         model_data_ids = obj_model_data.search(cr, uid, [('model','=','ir.ui.view'), ('name','=','view_vat_listing_result')])
291         resource_id = obj_model_data.read(cr, uid, model_data_ids, fields=['res_id'])[0]['res_id']
292
293         return {
294             'name': _('XML File has been Created'),
295             'res_id': ids[0],
296             'view_type': 'form',
297             'view_mode': 'form',
298             'res_model': 'partner.vat.list',
299             'views': [(resource_id,'form')],
300             'context': context,
301             'type': 'ir.actions.act_window',
302             'target': 'new',
303         }
304
305     def print_vatlist(self, cr, uid, ids, context=None):
306         if context is None:
307             context = {}
308         obj_vat_lclient = self.pool.get('vat.listing.clients')
309         datas = {'ids': []}
310         datas['model'] = 'res.company'
311         datas['year'] = context['year']
312         datas['limit_amount'] = context['limit_amount']
313         datas['client_datas'] = self._get_datas(cr, uid, ids, context=context)
314         if not datas['client_datas']:
315             raise osv.except_osv(_('Error!'),_('No record to print.'))
316         return {
317             'type': 'ir.actions.report.xml',
318             'report_name': 'partner.vat.listing.print',
319             'datas': datas,
320         }
321
322
323 class partner_vat_listing_print(report_sxw.rml_parse):
324
325     def __init__(self, cr, uid, name, context):
326         super(partner_vat_listing_print, self).__init__(cr, uid, name, context=context)
327         self.localcontext.update( {
328             'time': time,
329         })
330
331     def set_context(self, objects, data, ids, report_type=None):
332         client_datas = data['client_datas']
333         self.localcontext.update( {
334             'year': data['year'],
335             'sum_turnover': client_datas[-1]['sum_turnover'],
336             'sum_tax': client_datas[-1]['sum_tax'],
337             'client_list': client_datas,
338         })
339         super(partner_vat_listing_print, self).set_context(objects, data, ids)
340
341 report_sxw.report_sxw('report.partner.vat.listing.print', 'res.partner', 'addons/l10n_be/wizard/l10n_be_partner_vat_listing.rml', parser=partner_vat_listing_print,header=False)
342
343 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: