~openerp-spain-team/openerp-spain/6.0-git

« back to all changes in this revision

Viewing changes to l10n_es_aeat_mod347/wizard/wizard_calculate.py

  • Committer: Borja L.S.
  • Date: 2010-10-18 10:04:25 UTC
  • Revision ID: git-v1:271c47a993616dbba60585d48b8b98d603199d93
[REF] *: Refactorización para portar a 6.0 - Paso 1.

- Se han renombrado los módulos para usar la nomenclatura propuesta
  por OpenERP: l10n_es para el módulo base de localización (plan de 
  cuentas), l10n_es_* para el resto de módulos.

- Se eliminan los módulos extra_addons/* que deberían moverse a 
  los extra-addons genéricos (no son específicos de España).

- Se renombran los __terp__.py por __openerp__.py

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
# -*- encoding: utf-8 -*-
 
3
##############################################################################
 
4
#
 
5
#    OpenERP - Import operations model 347 engine
 
6
#    Copyright (C) 2009 Asr Oss. All Rights Reserved
 
7
#    $Id$
 
8
#
 
9
#    This program is free software: you can redistribute it and/or modify
 
10
#    it under the terms of the GNU General Public License as published by
 
11
#    the Free Software Foundation, either version 3 of the License, or
 
12
#    (at your option) any later version.
 
13
#
 
14
#    This program is distributed in the hope that it will be useful,
 
15
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
#    GNU General Public License for more details.
 
18
#
 
19
#    You should have received a copy of the GNU General Public License
 
20
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
#
 
22
##############################################################################
 
23
 
 
24
"""
 
25
Import operations model 347 engine wizards
 
26
"""
 
27
__author__ = """Alejandro Sanchez Ramirez Asr Oss - alejandro@asr-oss.com
 
28
                Borja López Soilán (Pexego) - borjals@pexego.es"""
 
29
 
 
30
 
 
31
 
 
32
import wizard
 
33
import pooler
 
34
import time
 
35
import threading
 
36
import sql_db
 
37
import re
 
38
import netsvc
 
39
 
 
40
class wizard_calculate(wizard.interface):
 
41
    """
 
42
    Wizard to calculates the 347 model report from the OpenERP invoices/payments.
 
43
    """
 
44
 
 
45
    ############################################################################
 
46
    # Forms
 
47
    ############################################################################
 
48
 
 
49
    _init_form = """<?xml version="1.0" encoding="utf-8"?>
 
50
    <form string="Calculate partner records" colspan="4" width="400">
 
51
        <label string="This wizard will calculate the partner operations records of the 347 report." colspan="4"/>
 
52
        <label string="" colspan="4"/>
 
53
        <label string="It will create records for the next operations:" colspan="4"/>
 
54
        <label string="  A - Purchases of goods and services over the limit (1)." colspan="4"/>
 
55
        <label string="  B - Sales of goods and services over the limit (1)." colspan="4"/>
 
56
        <!-- <label string=" C - Received payments on behalf of third parties over the limit (3)." colspan="4"/> -->
 
57
    </form>"""
 
58
 
 
59
 
 
60
    _progress_form = '''<?xml version="1.0"?>
 
61
    <form string="Calculating partner records" colspan="4" width="400">
 
62
        <label string="The calculation may take a while." colspan="4"/>
 
63
        <label string="" colspan="4"/>
 
64
        <field name="progress" widget="progressbar"/>
 
65
    </form>'''
 
66
 
 
67
    _progress_fields = {
 
68
        'progress': { 'string': 'Progress', 'type':'float' },
 
69
    }
 
70
 
 
71
 
 
72
    _done_form = """<?xml version="1.0" encoding="utf-8"?>
 
73
    <form string="Calculation done" colspan="4" width="400">
 
74
        <label string="The partner operation records have been calculated." colspan="4"/>
 
75
        <label string="" colspan="4"/>
 
76
    </form>"""
 
77
 
 
78
    _show_exception_form = """<?xml version="1.0" encoding="utf-8"?>
 
79
    <form string="Calculation failed!" colspan="4" width="400">
 
80
        <label string="Error: The calculation operation has failed!" colspan="4"/>
 
81
        <label string="" colspan="4"/>
 
82
        <separator string="Details"/>
 
83
        <field name="exception_text" colspan="4" nolabel="1"/>
 
84
    </form>"""
 
85
 
 
86
    _show_exception_fields = {
 
87
        'exception_text': {'string': 'Exception', 'type':'text' },
 
88
    }
 
89
 
 
90
    ############################################################################
 
91
    # Actions
 
92
    ############################################################################
 
93
 
 
94
    def _calculate(self, db_name, uid, data, context=None):
 
95
        """
 
96
        Calculates the 347 model report from the OpenERP invoices/payments data.
 
97
        """
 
98
        try:
 
99
            conn = sql_db.db_connect(db_name)
 
100
            cr = conn.cursor()
 
101
            pool = pooler.get_pool(cr.dbname)
 
102
 
 
103
            report = pool.get('l10n.es.aeat.mod347.report').browse(cr, uid, data['id'], context=context)
 
104
 
 
105
            pool.get('l10n.es.aeat.mod347.report').write(cr, uid, data['id'], {
 
106
                'state': 'calc',
 
107
                'calc_date': time.strftime('%Y-%m-%d %H:%M:%S')
 
108
            })
 
109
 
 
110
            #
 
111
            # Delete the previous partner records
 
112
            #
 
113
            pool.get('l10n.es.aeat.mod347.partner_record').unlink(cr, uid, [r.id for r in report.partner_records])
 
114
 
 
115
            # Get the cash journals (moves on this journals will be considered cash)
 
116
            cash_journal_ids = pool.get('account.journal').search(cr, uid, [('cash_journal', '=', True)])
 
117
 
 
118
            # Get the fiscal year period ids of the non-special periods
 
119
            # (to ignore closing/opening entries)
 
120
            period_ids = [period.id for period in report.fiscalyear_id.period_ids if not period.special]
 
121
 
 
122
            #
 
123
            # We will check every partner with include_in_mod347
 
124
            #
 
125
            partner_ids = pool.get('res.partner').search(cr, uid, [('include_in_mod347', '=', True)])
 
126
            partners_done = 0
 
127
            total_partners = len(partner_ids)
 
128
            for partner in pool.get('res.partner').browse(cr, uid, partner_ids):
 
129
 
 
130
                #
 
131
                # Search for invoices
 
132
                #
 
133
                # We will repeat the process for sales and purchases:
 
134
                for invoice_type, refund_type in zip(('out_invoice', 'in_invoice'), ('out_refund', 'in_refund')):
 
135
                    #
 
136
                    # CHECK THE SALE/PURCHASES INVOICE LIMIT -------------------
 
137
                    # (A and B operation keys)
 
138
                    #
 
139
 
 
140
                    #
 
141
                    # Search for invoices to this partner (with account moves).
 
142
                    #
 
143
                    invoice_ids = pool.get('account.invoice').search(cr, uid, [
 
144
                                ('partner_id', '=', partner.id),
 
145
                                ('type', '=', invoice_type),
 
146
                                ('period_id', 'in', period_ids),
 
147
                                ('move_id', '!=', None),
 
148
                            ])
 
149
                    refund_ids = pool.get('account.invoice').search(cr, uid, [
 
150
                                ('partner_id', '=', partner.id),
 
151
                                ('type', '=', refund_type),
 
152
                                ('period_id', 'in', period_ids),
 
153
                                ('move_id', '!=', None),
 
154
                            ])
 
155
                    invoices = pool.get('account.invoice').browse(cr, uid, invoice_ids)
 
156
                    refunds = pool.get('account.invoice').browse(cr, uid, refund_ids)
 
157
 
 
158
                    # Calculate the invoiced amount
 
159
                    invoice_amount = sum([invoice.cc_amount_total for invoice in invoices])
 
160
                    refund_amount = sum([invoice.cc_amount_total for invoice in refunds])
 
161
                    total_amount = invoice_amount - refund_amount
 
162
 
 
163
                    #
 
164
                    # Search for payments received in cash from this partner.
 
165
                    #
 
166
                    cash_account_move_line_ids = pool.get('account.move.line').search(cr, uid, [
 
167
                                ('partner_id', '=', partner.id),
 
168
                                ('account_id', '=', partner.property_account_receivable.id),
 
169
                                ('journal_id', 'in', cash_journal_ids),
 
170
                                ('period_id', 'in', period_ids),
 
171
                            ])
 
172
                    cash_account_move_lines = pool.get('account.move.line').browse(cr, uid, cash_account_move_line_ids)
 
173
 
 
174
                    # Calculate the cash amount
 
175
                    received_cash_amount = sum([line.credit for line in cash_account_move_lines])
 
176
 
 
177
                    #
 
178
                    # If the invoiced amount is greater than the limit
 
179
                    # we will add an partner record to the report.
 
180
                    #
 
181
                    if total_amount > report.operations_limit:
 
182
                        if invoice_type == 'out_invoice':
 
183
                            operation_key = 'B' # Note: B = Sale operations
 
184
                        else:
 
185
                            assert invoice_type == 'in_invoice'
 
186
                            operation_key = 'A' # Note: A = Purchase operations
 
187
 
 
188
                        #
 
189
                        # Get the default invoice address of the partner
 
190
                        #
 
191
                        address = None
 
192
                        address_ids = pool.get('res.partner').address_get(cr, uid, [partner.id], ['invoice', 'default'])
 
193
                        if address_ids.get('invoice'):
 
194
                            address = pool.get('res.partner.address').browse(cr, uid, address_ids.get('invoice'))
 
195
                        elif address_ids.get('default'):
 
196
                            address = pool.get('res.partner.address').browse(cr, uid, address_ids.get('default'))
 
197
 
 
198
                        #
 
199
                        # Get the partner data
 
200
                        #
 
201
                        partner_vat = partner.vat and re.match(r"([A-Z]{0,2})(.*)", partner.vat).groups()[1]
 
202
                        partner_state_code = address.state_id and address.state_id.code or ''
 
203
                        partner_country_code = address.country_id and address.country_id.code or ''
 
204
                        if partner.vat:
 
205
                            partner_country_code, partner_vat = re.match("(ES){0,1}(.*)", partner.vat).groups()
 
206
 
 
207
                        # Create the partner record
 
208
                        partner_record = pool.get('l10n.es.aeat.mod347.partner_record').create(cr, uid, {
 
209
                                'report_id': report.id ,
 
210
                                'operation_key' : operation_key,
 
211
                                'partner_id': partner.id,
 
212
                                'partner_vat': partner_vat,
 
213
                                'representative_vat': '',
 
214
                                'partner_state_code': partner_state_code,
 
215
                                'partner_country_code' : partner_country_code,
 
216
                                'amount': total_amount,
 
217
                                'cash_amount': received_cash_amount > report.received_cash_limit and received_cash_amount or 0,
 
218
                            })
 
219
 
 
220
                        #
 
221
                        # Add the invoices detail to the partner record
 
222
                        #
 
223
                        for invoice in invoices:
 
224
                            pool.get('l10n.es.aeat.mod347.invoice_record').create(cr, uid, {
 
225
                                'partner_record_id' : partner_record,
 
226
                                'invoice_id': invoice.id,
 
227
                                'date': invoice.date_invoice,
 
228
                                'amount': invoice.cc_amount_total,
 
229
                            })
 
230
                        for invoice in refunds:
 
231
                            pool.get('l10n.es.aeat.mod347.invoice_record').create(cr, uid, {
 
232
                                'partner_record_id' : partner_record,
 
233
                                'invoice_id': invoice.id,
 
234
                                'date': invoice.date_invoice,
 
235
                                'amount': -invoice.cc_amount_total,
 
236
                            })
 
237
 
 
238
                        #
 
239
                        # Add the cash detail to the partner record if over limit
 
240
                        #
 
241
                        if received_cash_amount > report.received_cash_limit:
 
242
                            for line in cash_account_move_lines:
 
243
                                pool.get('l10n.es.aeat.mod347.cash_record').create(cr, uid, {
 
244
                                    'partner_record_id' : partner_record,
 
245
                                    'move_line_id' : line.id,
 
246
                                    'date': line.date,
 
247
                                    'amount': line.credit,
 
248
                                })
 
249
 
 
250
                    #
 
251
                    # TODO: Calculate records of operation keys C-D-E-F-G !
 
252
                    #
 
253
 
 
254
                #
 
255
                # Update the progress:
 
256
                #
 
257
                partners_done += 1
 
258
                data['calculation_progress'] = (partners_done * 100.0) / total_partners
 
259
 
 
260
            #
 
261
            # Set the report as calculated
 
262
            #
 
263
            wf_service = netsvc.LocalService("workflow")
 
264
            wf_service.trg_validate(uid, 'l10n.es.aeat.mod347.report', report.id, 'calculate', cr)
 
265
 
 
266
            data['calculation_progress'] = 100
 
267
            cr.commit()
 
268
        except Exception, ex:
 
269
            data['calculation_exception'] = ex
 
270
            cr.rollback()
 
271
            raise
 
272
        finally:
 
273
            cr.close()
 
274
            data['calculation_done'] = True
 
275
        return {}
 
276
 
 
277
 
 
278
    def _calculate_in_background_choice(self, cr, uid, data, context):
 
279
        """
 
280
        Choice-like action that runs the calculation on background,
 
281
        waiting for it to end or timeout.
 
282
        """
 
283
        if not data.get('calculation_thread'):
 
284
            # Run the calculation in background
 
285
            data['calculation_done'] = False
 
286
            data['calculation_exception'] = None
 
287
            data['calculation_thread'] = threading.Thread(target=self._calculate, args=(cr.dbname, uid, data, context))
 
288
            data['calculation_thread'].start()
 
289
        #
 
290
        # Wait up some seconds seconds for the task to end.
 
291
        #
 
292
        time_left = 20
 
293
        while not data['calculation_done'] and time_left > 0:
 
294
            time_left = time_left - 1
 
295
            time.sleep(1)
 
296
        #
 
297
        # Check if we are done
 
298
        #
 
299
        if data['calculation_done']:
 
300
            if data['calculation_exception']:
 
301
                return 'show_exception'
 
302
            else:
 
303
                return 'done'
 
304
        else:
 
305
            return 'progress'
 
306
 
 
307
 
 
308
    def _progress_action(self, cr, uid, data, context):
 
309
        """
 
310
        Action that gets the current progress
 
311
        """
 
312
        return { 'progress': data['calculation_progress'] }
 
313
 
 
314
    def _show_exception_action(self, cr, uid, data, context):
 
315
        """
 
316
        Action that gets the calculation exception text
 
317
        """
 
318
        try:
 
319
            exception_text = unicode(data.get('process_exception', ''))
 
320
        except UnicodeDecodeError:
 
321
            exception_text = str(data.get('process_exception', ''))
 
322
        return { 'exception_text': exception_text }
 
323
 
 
324
    ############################################################################
 
325
    # States
 
326
    ############################################################################
 
327
 
 
328
    states = {
 
329
        'init': {
 
330
            'actions': [],
 
331
            'result': {'type':'form', 'arch': _init_form, 'fields': {}, 'state':[('end', 'Cancel', 'gtk-cancel', True), ('calculate_records', 'Calculate', 'gtk-apply', True)]}
 
332
        },
 
333
        'calculate_records': {
 
334
            'actions': [],
 
335
            'result': {'type': 'choice', 'next_state': _calculate_in_background_choice}
 
336
        },
 
337
        'progress': {
 
338
            'actions': [_progress_action],
 
339
            'result': {'type': 'form', 'arch': _progress_form, 'fields': _progress_fields, 'state':[('end','Close (continues in background)', 'gtk-cancel', True),('calculate_records','Keep waiting', 'gtk-go-forward', True)]}
 
340
        },
 
341
        'done': {
 
342
            'actions': [],
 
343
            'result': {'type': 'form', 'arch': _done_form, 'fields': {}, 'state':[('end','Done', 'gtk-ok', True)]}
 
344
        },
 
345
        'show_exception': {
 
346
            'actions': [_show_exception_action],
 
347
            'result': {'type': 'form', 'arch': _show_exception_form, 'fields': _show_exception_fields, 'state':[('end','Done', 'gtk-ok', True)]}
 
348
        }
 
349
    }
 
350
 
 
351
 
 
352
wizard_calculate('l10n_es_aeat_mod347.calculate_wizard')
 
353