~unifield-team/unifield-wm/us-826

« back to all changes in this revision

Viewing changes to msf_doc_import/account.py

  • Committer: matthieu.choplin at msf
  • Date: 2012-08-30 07:48:00 UTC
  • mto: This revision was merged to the branch mainline in revision 1118.
  • Revision ID: matthieu.choplin@geneva.msf.org-20120830074800-l442bu42mt0yzutn
[uf-1374]- change the write and create by an _sql_constraint on the financing contract check dates

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env python
2
 
# -*- coding: utf-8 -*-
3
 
##############################################################################
4
 
#
5
 
#    OpenERP, Open Source Management Solution
6
 
#    Copyright (C) 2011 TeMPO Consulting, MSF. All Rights Reserved
7
 
#    Developer: Olivier DOSSMANN
8
 
#
9
 
#    This program is free software: you can redistribute it and/or modify
10
 
#    it under the terms of the GNU Affero General Public License as
11
 
#    published by the Free Software Foundation, either version 3 of the
12
 
#    License, or (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 Affero General Public License for more details.
18
 
#
19
 
#    You should have received a copy of the GNU Affero General Public License
20
 
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 
#
22
 
##############################################################################
23
 
 
24
 
from osv import osv
25
 
from osv import fields
26
 
from tools.translate import _
27
 
from time import strftime
28
 
from tempfile import NamedTemporaryFile
29
 
from base64 import decodestring
30
 
from spreadsheet_xml.spreadsheet_xml import SpreadsheetXML
31
 
from csv import DictReader
32
 
import threading
33
 
import pooler
34
 
from msf_doc_import import ACCOUNTING_IMPORT_JOURNALS
35
 
 
36
 
class msf_doc_import_accounting(osv.osv_memory):
37
 
    _name = 'msf.doc.import.accounting'
38
 
 
39
 
    _columns = {
40
 
        'date': fields.date(string="Date", required=True),
41
 
        'file': fields.binary(string="File", filters='*.xml, *.xls', required=True),
42
 
        'filename': fields.char(string="Imported filename", size=256),
43
 
        'progression': fields.float(string="Progression", readonly=True),
44
 
        'message': fields.char(string="Message", size=256, readonly=True),
45
 
        'state': fields.selection([('draft', 'Created'), ('inprogress', 'In Progress'), ('error', 'Error'), ('done', 'Done')], string="State", readonly=True, required=True),
46
 
        'error_ids': fields.one2many('msf.doc.import.accounting.errors', 'wizard_id', "Errors", readonly=True),
47
 
    }
48
 
 
49
 
    _defaults = {
50
 
        'date': lambda *a: strftime('%Y-%m-%d'),
51
 
        'progression': lambda *a: 0.0,
52
 
        'state': lambda *a: 'draft',
53
 
        'message': lambda *a: _('Initialization…'),
54
 
    }
55
 
 
56
 
    def create_entries(self, cr, uid, ids, journal_id, context=None):
57
 
        """
58
 
        Create journal entry 
59
 
        """
60
 
        # Checks
61
 
        if not context:
62
 
            context = {}
63
 
        try:
64
 
            msf_fp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_msf_private_funds')[1]
65
 
        except ValueError:
66
 
            msf_fp_id = 0
67
 
        # Browse all wizards
68
 
        for w in self.browse(cr, uid, ids):
69
 
            # Search lines
70
 
            entries = self.pool.get('msf.doc.import.accounting.lines').search(cr, uid, [('wizard_id', '=', w.id)])
71
 
            if not entries:
72
 
                raise osv.except_osv(_('Error'), _('No lines…'))
73
 
            # Browse result
74
 
            b_entries = self.pool.get('msf.doc.import.accounting.lines').browse(cr, uid, entries)
75
 
            # Update wizard
76
 
            self.write(cr, uid, [w.id], {'message': _('Grouping by currencies…'), 'progression': 10.0})
77
 
            # Search all currencies (to create moves)
78
 
            available_currencies = {}
79
 
            for entry in b_entries:
80
 
                if (entry.currency_id.id, entry.period_id.id) not in available_currencies:
81
 
                    available_currencies[(entry.currency_id.id, entry.period_id.id)] = []
82
 
                available_currencies[(entry.currency_id.id, entry.period_id.id)].append(entry)
83
 
            # Update wizard
84
 
            self.write(cr, uid, ids, {'message': _('Writing a move for each currency…'), 'progression': 20.0})
85
 
            num = 1
86
 
            nb_currencies = float(len(available_currencies))
87
 
            current_percent = 20.0
88
 
            remaining_percent = 80.0
89
 
            step = float(remaining_percent / nb_currencies)
90
 
            for c_id, p_id in available_currencies:
91
 
                # Create a move
92
 
                move_vals = {
93
 
                    'currency_id': c_id,
94
 
                    'manual_currency_id': c_id,
95
 
                    'journal_id': journal_id,
96
 
                    'document_date': w.date,
97
 
                    'date': w.date,
98
 
                    'period_id': p_id,
99
 
                    'status': 'manu',
100
 
                    'imported': True,
101
 
                }
102
 
                move_id = self.pool.get('account.move').create(cr, uid, move_vals, context)
103
 
                for l_num, l in enumerate(available_currencies[(c_id, p_id)]):
104
 
                    # Update wizard
105
 
                    progression = 20.0 + ((float(l_num) / float(len(b_entries))) * step) + (float(num - 1) * step)
106
 
                    self.write(cr, uid, [w.id], {'progression': progression})
107
 
                    distrib_id = False
108
 
                    # Create analytic distribution
109
 
                    if l.account_id.is_analytic_addicted:
110
 
                        distrib_id = self.pool.get('analytic.distribution').create(cr, uid, {}, context)
111
 
                        common_vals = {
112
 
                            'distribution_id': distrib_id,
113
 
                            'currency_id': c_id,
114
 
                            'percentage': 100.0,
115
 
                            'date': l.date,
116
 
                            'source_date': l.date,
117
 
                            'destination_id': l.destination_id.id,
118
 
                        }
119
 
                        common_vals.update({'analytic_id': l.cost_center_id.id,})
120
 
                        cc_res = self.pool.get('cost.center.distribution.line').create(cr, uid, common_vals)
121
 
                        common_vals.update({'analytic_id': l.funding_pool_id.id, 'cost_center_id': l.cost_center_id.id,})
122
 
                        fp_res = self.pool.get('funding.pool.distribution.line').create(cr, uid, common_vals)
123
 
                    # Create move line
124
 
                    move_line_vals = {
125
 
                        'move_id': move_id,
126
 
                        'name': l.description,
127
 
                        'reference': l.ref,
128
 
                        'account_id': l.account_id.id,
129
 
                        'period_id': p_id,
130
 
                        'document_date': l.document_date,
131
 
                        'date': l.date,
132
 
                        'journal_id': journal_id,
133
 
                        'debit_currency': l.debit,
134
 
                        'credit_currency': l.credit,
135
 
                        'currency_id': c_id,
136
 
                        'analytic_distribution_id': distrib_id,
137
 
                        'partner_id': l.partner_id and l.partner_id.id or False,
138
 
                        'employee_id': l.employee_id and l.employee_id.id or False,
139
 
                        'transfer_journal_id': l.transfer_journal_id and l.transfer_journal_id.id or False,
140
 
                    }
141
 
                    self.pool.get('account.move.line').create(cr, uid, move_line_vals, context, check=False)
142
 
                # Validate the Journal Entry for lines to be valid (if possible)
143
 
                self.write(cr, uid, [w.id], {'message': _('Validating journal entry…')})
144
 
                self.pool.get('account.move').validate(cr, uid, [move_id], context=context)
145
 
                # Update wizard
146
 
                progression = 20.0 + (float(num) * step)
147
 
                self.write(cr, uid, [w.id], {'progression': progression})
148
 
                num += 1
149
 
        return True
150
 
 
151
 
    def _import(self, dbname, uid, ids, context=None):
152
 
        """
153
 
        Do treatment before validation:
154
 
        - check data from wizard
155
 
        - check that file exists and that data are inside
156
 
        - check integrity of data in files
157
 
        """
158
 
        # Some checks
159
 
        if not context:
160
 
            context = {}
161
 
        # Prepare some values
162
 
        from_yml = False
163
 
        if context.get('from_yml', False):
164
 
            from_yml = context.get('from_yml')
165
 
        # Do changes because of YAML tests
166
 
        if from_yml:
167
 
            cr = dbname
168
 
        else:
169
 
            cr = pooler.get_db(dbname).cursor()
170
 
        try:
171
 
            msf_fp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_msf_private_funds')[1]
172
 
        except ValueError:
173
 
            msf_fp_id = 0
174
 
        created = 0
175
 
        processed = 0
176
 
        errors = []
177
 
        current_instance = self.pool.get('res.users').browse(cr, uid, uid).company_id.instance_id.id or False
178
 
 
179
 
        try:
180
 
            # Update wizard
181
 
            self.write(cr, uid, ids, {'message': _('Cleaning up old imports…'), 'progression': 1.00})
182
 
            # Clean up old temporary imported lines
183
 
            old_lines_ids = self.pool.get('msf.doc.import.accounting.lines').search(cr, uid, [])
184
 
            self.pool.get('msf.doc.import.accounting.lines').unlink(cr, uid, old_lines_ids)
185
 
 
186
 
            # Check wizard data
187
 
            for wiz in self.browse(cr, uid, ids):
188
 
                # Update wizard
189
 
                self.write(cr, uid, [wiz.id], {'message': _('Checking file…'), 'progression': 2.00})
190
 
                # UF-2045: Check that the given date is in an open period
191
 
                wiz_period_ids = self.pool.get('account.period').get_period_from_date(cr, uid, wiz.date, context)
192
 
                if not wiz_period_ids:
193
 
                    raise osv.except_osv(_('Warning'), _('No period found!'))
194
 
                period = self.pool.get('account.period').browse(cr, uid, wiz_period_ids[0], context)
195
 
                if not period or period.state in ['created', 'done']:
196
 
                    raise osv.except_osv(_('Warning'), _('Period is not open!'))
197
 
                date = wiz.date or False
198
 
 
199
 
                # Check that a file was given
200
 
                if not wiz.file:
201
 
                    raise osv.except_osv(_('Error'), _('Nothing to import.'))
202
 
                # Update wizard
203
 
                self.write(cr, uid, [wiz.id], {'message': _('Copying file…'), 'progression': 3.00})
204
 
                fileobj = NamedTemporaryFile('w+b', delete=False)
205
 
                fileobj.write(decodestring(wiz.file))
206
 
                fileobj.close()
207
 
                content = SpreadsheetXML(xmlfile=fileobj.name)
208
 
                if not content:
209
 
                    raise osv.except_osv(_('Warning'), _('No content'))
210
 
                # Update wizard
211
 
                self.write(cr, uid, [wiz.id], {'message': _('Processing line…'), 'progression': 4.00})
212
 
                rows = content.getRows()
213
 
                nb_rows = len([x for x in content.getRows()])
214
 
                # Update wizard
215
 
                self.write(cr, uid, [wiz.id], {'message': _('Reading headers…'), 'progression': 5.00})
216
 
                # Use the first row to find which column to use
217
 
                cols = {}
218
 
                col_names = ['Journal Code', 'Description', 'Reference', 'Document Date', 'Posting Date', 'G/L Account', 'Partner', 'Employee', 'Journal', 'Destination', 'Cost Centre', 'Funding Pool', 'Booking Debit', 'Booking Credit', 'Booking Currency']
219
 
                for num, r in enumerate(rows):
220
 
                    header = [x and x.data for x in r.iter_cells()]
221
 
                    for el in col_names:
222
 
                        if el in header:
223
 
                            cols[el] = header.index(el)
224
 
                    break
225
 
                # Number of line to bypass in line's count
226
 
                base_num = 2
227
 
 
228
 
                # global journal code for the file
229
 
                file_journal_id = 0
230
 
                aj_obj = self.pool.get('account.journal')
231
 
 
232
 
                for el in col_names:
233
 
                    if not el in cols:
234
 
                        raise osv.except_osv(_('Error'), _("'%s' column not found in file.") % (el or '',))
235
 
                # All lines
236
 
                money = {}
237
 
                # Update wizard
238
 
                self.write(cr, uid, [wiz.id], {'message': _('Reading lines…'), 'progression': 6.00})
239
 
                # Check file's content
240
 
                for num, r in enumerate(rows):
241
 
                    # Update wizard
242
 
                    percent = (float(num+1) / float(nb_rows+1)) * 100.0
243
 
                    progression = ((float(num+1) * 94) / float(nb_rows)) + 6
244
 
                    self.write(cr, uid, [wiz.id], {'message': _('Checking file…'), 'progression': progression})
245
 
                    # Prepare some values
246
 
                    r_debit = 0
247
 
                    r_credit = 0
248
 
                    r_currency = False
249
 
                    r_partner = False
250
 
                    r_employee = False
251
 
                    r_journal = False
252
 
                    r_account = False
253
 
                    r_destination = False
254
 
                    r_fp = False
255
 
                    r_cc = False
256
 
                    # UTP-1047: Use Document date column (contrary of UTP-766)
257
 
                    r_document_date = False
258
 
                    current_line_num = num + base_num
259
 
                    # Fetch all XML row values
260
 
                    line = self.pool.get('import.cell.data').get_line_values(cr, uid, ids, r)
261
 
                    # Check document date
262
 
                    if not line[cols['Document Date']]:
263
 
                        errors.append(_('Line %s. No document date specified!') % (current_line_num,))
264
 
                        continue
265
 
                    r_document_date = line[cols['Document Date']].strftime('%Y-%m-%d')
266
 
                    # Bypass this line if NO debit AND NO credit
267
 
                    try:
268
 
                        bd = line[cols['Booking Debit']]
269
 
                    except IndexError, e:
270
 
                        continue
271
 
                    try:
272
 
                        bc = line[cols['Booking Credit']]
273
 
                    except IndexError, e:
274
 
                        continue
275
 
                    if not line[cols['Booking Debit']] and not line[cols['Booking Credit']]:
276
 
                        continue
277
 
                    processed += 1
278
 
                    # Check that currency is active
279
 
                    if not line[cols['Booking Currency']]:
280
 
                        errors.append(_('Line %s. No currency specified!') % (current_line_num,))
281
 
                        continue
282
 
                    curr_ids = self.pool.get('res.currency').search(cr, uid, [('name', '=', line[cols['Booking Currency']])])
283
 
                    if not curr_ids:
284
 
                        errors.append(_('Line %s. Currency not found: %s') % (current_line_num, line[cols['Booking Currency']],))
285
 
                        continue
286
 
                    for c in self.pool.get('res.currency').browse(cr, uid, curr_ids):
287
 
                        if not c.active:
288
 
                            errors.append(_('Line %s. Currency is not active: %s') % (current_line_num, line[cols['Booking Currency']],))
289
 
                            continue
290
 
                    r_currency = curr_ids[0]
291
 
                    if not line[cols['Booking Currency']] in money:
292
 
                        money[line[cols['Booking Currency']]] = {}
293
 
                    if not 'debit' in money[line[cols['Booking Currency']]]:
294
 
                        money[line[cols['Booking Currency']]]['debit'] = 0
295
 
                    if not 'credit' in money[line[cols['Booking Currency']]]:
296
 
                        money[line[cols['Booking Currency']]]['credit'] = 0
297
 
                    if not 'name' in money[line[cols['Booking Currency']]]:
298
 
                        money[line[cols['Booking Currency']]]['name'] = line[cols['Booking Currency']]
299
 
                    # Increment global debit/credit
300
 
                    if line[cols['Booking Debit']]:
301
 
                        money[line[cols['Booking Currency']]]['debit'] += line[cols['Booking Debit']]
302
 
                        r_debit = line[cols['Booking Debit']]
303
 
                    if line[cols['Booking Credit']]:
304
 
                        money[line[cols['Booking Currency']]]['credit'] += line[cols['Booking Credit']]
305
 
                        r_credit = line[cols['Booking Credit']]
306
 
 
307
 
                    # Check which journal it is to be posted to: should be of type OD, MIG or INT
308
 
                    if not line[cols['Journal Code']]:
309
 
                        errors.append(_('Line %s. No Journal Code specified') % (current_line_num,))
310
 
                        continue
311
 
                    else:
312
 
                        # check for a valid journal code
313
 
                        aj_ids = aj_obj.search(cr, uid, [('code', '=', line[cols['Journal Code']]), ('instance_id', '=', current_instance)])
314
 
                        if not aj_ids:
315
 
                            errors.append(_('Line %s. Journal Code not found: %s.') % (current_line_num, line[cols['Journal Code']]))
316
 
                            continue
317
 
                        else:
318
 
                            aj_data = aj_obj.read(cr, uid, aj_ids, ['type'])[0]
319
 
                            if aj_data.get('type', False) is False or aj_data.get('type', False) not in ACCOUNTING_IMPORT_JOURNALS:
320
 
                                journal_list = ', '.join([x[1] for x in aj_obj.get_journal_type(cr, uid) if x[0] in ACCOUNTING_IMPORT_JOURNALS])
321
 
                                errors.append(_('Line %s. Import of entries only allowed on the following journal(s): %s') % (current_line_num, journal_list))
322
 
                                continue
323
 
                        aj_id = aj_ids[0]
324
 
                        if num == 0:
325
 
                            file_journal_id = aj_id
326
 
                        else:
327
 
                            if file_journal_id != aj_id:
328
 
                                errors.append(_('Line %s. Only a single Journal Code can be specified per file') % (current_line_num,))
329
 
                                continue
330
 
 
331
 
                    # Check G/L account
332
 
                    if not line[cols['G/L Account']]:
333
 
                        errors.append(_('Line %s. No G/L account specified!') % (current_line_num,))
334
 
                        continue
335
 
                    account_ids = self.pool.get('account.account').search(cr, uid, [('code', '=', line[cols['G/L Account']])])
336
 
                    if not account_ids:
337
 
                        errors.append(_('Line %s. G/L account %s not found!') % (current_line_num, line[cols['G/L Account']],))
338
 
                        continue
339
 
                    r_account = account_ids[0]
340
 
                    account = self.pool.get('account.account').browse(cr, uid, r_account)
341
 
                    # Check that Third party exists (if not empty)
342
 
                    tp_label = False
343
 
                    tp_content = False
344
 
                    if line[cols['Partner']]:
345
 
                        tp_ids = self.pool.get('res.partner').search(cr, uid, [('name', '=', line[cols['Partner']])])
346
 
                        if not tp_ids:
347
 
                            tp_label = _('Partner')
348
 
                            tp_content = line[cols['Partner']]
349
 
                        else:
350
 
                            r_partner = tp_ids[0]
351
 
                    if line[cols['Employee']]:
352
 
                        tp_ids = self.pool.get('hr.employee').search(cr, uid, [('name', '=', line[cols['Employee']])])
353
 
                        if not tp_ids:
354
 
                            tp_label = _('Employee')
355
 
                            tp_content = line[cols['Employee']]
356
 
                        else:
357
 
                            r_employee = tp_ids[0]
358
 
                    if line[cols['Journal']]:
359
 
                        tp_ids = self.pool.get('account.journal').search(cr, uid, ['|', ('name', '=', line[cols['Journal']]), ('code', '=', line[cols['Journal']]), ('instance_id', '=', current_instance)])
360
 
                        if not tp_ids:
361
 
                            tp_label = _('Journal')
362
 
                            tp_content = line[cols['Journal']]
363
 
                        else:
364
 
                            r_journal = tp_ids[0]
365
 
                    if tp_label and tp_content:
366
 
                        errors.append(_('Line %s. %s not found: %s') % (current_line_num, tp_label, tp_content,))
367
 
                        continue
368
 
                    list_third_party = []
369
 
                    if r_employee:
370
 
                        list_third_party.append(r_employee)
371
 
                    if r_partner:
372
 
                        list_third_party.append(r_partner)
373
 
                    if r_journal:
374
 
                        list_third_party.append(r_journal)
375
 
                    if len(list_third_party) > 1:
376
 
                        errors.append(_('Line %s. You cannot only add partner or employee or journal.') % (current_line_num,))
377
 
                        continue
378
 
                    # Check analytic axis only if G/L account is analytic-a-holic
379
 
                    if account.is_analytic_addicted:
380
 
                        # Check Destination
381
 
                        if not line[cols['Destination']]:
382
 
                            errors.append(_('Line %s. No destination specified!') % (current_line_num,))
383
 
                            continue
384
 
                        destination_ids = self.pool.get('account.analytic.account').search(cr, uid, [('category', '=', 'DEST'), '|', ('name', '=', line[cols['Destination']]), ('code', '=', line[cols['Destination']])])
385
 
                        if not destination_ids:
386
 
                            errors.append(_('Line %s. Destination %s not found!') % (current_line_num, line[cols['Destination']],))
387
 
                            continue
388
 
                        r_destination = destination_ids[0]
389
 
                        # Check Cost Center
390
 
                        if not line[cols['Cost Centre']]:
391
 
                            errors.append(_('Line %s. No cost center specified!') % (current_line_num,))
392
 
                            continue
393
 
                        cc_ids = self.pool.get('account.analytic.account').search(cr, uid, [('category', '=', 'OC'), '|', ('name', '=', line[cols['Cost Centre']]), ('code', '=', line[cols['Cost Centre']])])
394
 
                        if not cc_ids:
395
 
                            errors.append(_('Line %s. Cost Center %s not found!') % (current_line_num, line[cols['Cost Centre']]))
396
 
                            continue
397
 
                        r_cc = cc_ids[0]
398
 
                        # Check Funding Pool (added since UTP-1082)
399
 
                        r_fp = msf_fp_id
400
 
                        if line[cols['Funding Pool']]:
401
 
                            fp_ids = self.pool.get('account.analytic.account').search(cr, uid, [('category', '=', 'FUNDING'), '|', ('name', '=', line[cols['Funding Pool']]), ('code', '=', line[cols['Funding Pool']])])
402
 
                            if not fp_ids:
403
 
                                errors.append(_('Line %s. Funding Pool %s not found!') % (current_line_num, line[cols['Funding Pool']]))
404
 
                                continue
405
 
                            r_fp = fp_ids[0]
406
 
                    # NOTE: There is no need to check G/L account, Cost Center and Destination regarding document/posting date because this check is already done at Journal Entries validation.
407
 
 
408
 
                    # Registering data regarding these "keys":
409
 
                    # - G/L Account
410
 
                    # - Third Party
411
 
                    # - Destination
412
 
                    # - Cost Centre
413
 
                    # - Booking Currency
414
 
                    vals = {
415
 
                        'description': line[cols['Description']] or '',
416
 
                        'ref': line[cols['Reference']] or '',
417
 
                        'account_id': r_account or False,
418
 
                        'debit': r_debit or 0.0,
419
 
                        'credit': r_credit or 0.0,
420
 
                        'cost_center_id': r_cc or False,
421
 
                        'destination_id': r_destination or False,
422
 
                        'document_date': r_document_date or False,
423
 
                        'funding_pool_id': r_fp or False,
424
 
                        'date': date or False,
425
 
                        'currency_id': r_currency or False,
426
 
                        'wizard_id': wiz.id,
427
 
                        'period_id': period and period.id or False,
428
 
                        'employee_id': r_employee or False,
429
 
                        'partner_id': r_partner or False,
430
 
                        'transfer_journal_id': r_journal or False,
431
 
                    }
432
 
                    # UTP-1056: Add employee possibility. So we need to check if employee and/or partner is authorized
433
 
                    partner_needs = self.pool.get('account.bank.statement.line').onchange_account(cr, uid, False, account_id=account.id, context=context)
434
 
                    if not partner_needs:
435
 
                        errors.append(_('Line %s. No info about given account: %s') % (current_line_num, account.code,))
436
 
                        continue
437
 
                    # Check result
438
 
                    partner_options = partner_needs['value']['partner_type']['options']
439
 
                    if r_partner and ('res.partner', 'Partner') not in partner_options:
440
 
                        errors.append(_('Line %s. You cannot use a partner for the given account: %s.') % (current_line_num, account.code))
441
 
                        continue
442
 
                    if r_employee and ('hr.employee', 'Employee') not in partner_options:
443
 
                        errors.append(_('Line %s. You cannot use an employee for the given account: %s.') % (current_line_num, account.code))
444
 
                        continue
445
 
                    if r_journal and ('account.journal', 'Journal') not in partner_options:
446
 
                        errors.append(_('Line %s. You cannot use a journal for the given account: %s.') % (current_line_num, account.code))
447
 
                    line_res = self.pool.get('msf.doc.import.accounting.lines').create(cr, uid, vals, context)
448
 
                    if not line_res:
449
 
                        errors.append(_('Line %s. A problem occured for line registration. Please contact an Administrator.') % (current_line_num,))
450
 
                        continue
451
 
                    created += 1
452
 
                # Check if all is ok for the file
453
 
                ## The lines should be balanced for each currency
454
 
                for c in money:
455
 
                    if abs(money[c]['debit'] - money[c]['credit']) >= 10**-2:
456
 
                        raise osv.except_osv(_('Error'), _('Currency %s is not balanced: %s') % (money[c]['name'], (money[c]['debit'] - money[c]['credit']),))
457
 
            # Update wizard
458
 
            self.write(cr, uid, ids, {'message': _('Check complete. Reading potential errors or write needed changes.'), 'progression': 100.0})
459
 
 
460
 
            wiz_state = 'done'
461
 
            # If errors, cancel probable modifications
462
 
            if errors:
463
 
                cr.rollback()
464
 
                created = 0
465
 
                message = _('Import FAILED.')
466
 
                # Delete old errors
467
 
                error_ids = self.pool.get('msf.doc.import.accounting.errors').search(cr, uid, [], context)
468
 
                if error_ids:
469
 
                    self.pool.get('msf.doc.import.accounting.errors').unlink(cr, uid, error_ids ,context)
470
 
                # create errors lines
471
 
                for e in errors:
472
 
                    self.pool.get('msf.doc.import.accounting.errors').create(cr, uid, {'wizard_id': wiz.id, 'name': e}, context)
473
 
                wiz_state = 'error'
474
 
            else:
475
 
                # Update wizard
476
 
                self.write(cr, uid, ids, {'message': _('Writing changes…'), 'progression': 0.0})
477
 
                # Create all journal entries
478
 
                self.create_entries(cr, uid, ids, file_journal_id, context)
479
 
                message = _('Import successful.')
480
 
 
481
 
            # Update wizard
482
 
            self.write(cr, uid, ids, {'message': message, 'state': wiz_state, 'progression': 100.0})
483
 
 
484
 
            # Close cursor
485
 
            if not from_yml:
486
 
                cr.commit()
487
 
                cr.close(True)
488
 
        except osv.except_osv as osv_error:
489
 
            cr.rollback()
490
 
            self.write(cr, uid, ids, {'message': _("An error occured. %s: %s") % (osv_error.name, osv_error.value,), 'state': 'done', 'progression': 100.0})
491
 
            if not from_yml:
492
 
                cr.close(True)
493
 
        except Exception as e:
494
 
            cr.rollback()
495
 
            self.write(cr, uid, ids, {'message': _("An error occured: %s") % (e.args and e.args[0] or '',), 'state': 'done', 'progression': 100.0})
496
 
            if not from_yml:
497
 
                cr.close(True)
498
 
        return True
499
 
 
500
 
    def button_validate(self, cr, uid, ids, context=None):
501
 
        """
502
 
        Launch process in a thread and return a wizard
503
 
        """
504
 
        # Some checks
505
 
        if not context:
506
 
            context = {}
507
 
        if context.get('from_yml', False):
508
 
            res = self.write(cr, uid, ids, {'state': 'inprogress'}, context=context)
509
 
            self._import(cr, uid, ids, context=context)
510
 
        else:
511
 
            # Launch a thread if we come from web
512
 
            thread = threading.Thread(target=self._import, args=(cr.dbname, uid, ids, context))
513
 
            thread.start()
514
 
            res = self.write(cr, uid, ids, {'state': 'inprogress'}, context=context)
515
 
        return res
516
 
 
517
 
    def button_update(self, cr, uid, ids, context=None):
518
 
        """
519
 
        Update view
520
 
        """
521
 
        return False
522
 
 
523
 
msf_doc_import_accounting()
524
 
 
525
 
class msf_doc_import_accounting_lines(osv.osv):
526
 
    _name = 'msf.doc.import.accounting.lines'
527
 
    _rec_name = 'document_date'
528
 
 
529
 
    _columns = {
530
 
        'description': fields.text("Description", required=False, readonly=True),
531
 
        'ref': fields.text("Reference", required=False, readonly=True),
532
 
        'document_date': fields.date("Document date", required=True, readonly=True),
533
 
        'date': fields.date("Posting date", required=True, readonly=True),
534
 
        'account_id': fields.many2one('account.account', "G/L Account", required=True, readonly=True),
535
 
        'destination_id': fields.many2one('account.analytic.account', "Destination", required=False, readonly=True),
536
 
        'cost_center_id': fields.many2one('account.analytic.account', "Cost Center", required=False, readonly=True),
537
 
        'funding_pool_id': fields.many2one('account.analytic.account', "Funding Pool", required=False, readonly=True),
538
 
        'debit': fields.float("Debit", required=False, readonly=True),
539
 
        'credit': fields.float("Credit", required=False, readonly=True),
540
 
        'currency_id': fields.many2one('res.currency', "Currency", required=True, readonly=True),
541
 
        'partner_id': fields.many2one('res.partner', "Partner", required=False, readonly=True),
542
 
        'employee_id': fields.many2one('hr.employee', "Employee", required=False, readonly=True),
543
 
        'transfer_journal_id': fields.many2one('account.journal', 'Journal', required=False, readonly=True),
544
 
        'period_id': fields.many2one('account.period', "Period", required=True, readonly=True),
545
 
        'wizard_id': fields.integer("Wizard", required=True, readonly=True),
546
 
    }
547
 
 
548
 
    _defaults = {
549
 
        'description': lambda *a: '',
550
 
        'ref': lambda *a: '',
551
 
        'document_date': lambda *a: strftime('%Y-%m-%d'),
552
 
        'date': lambda *a: strftime('%Y-%m-%d'),
553
 
        'debit': lambda *a: 0.0,
554
 
        'credit': lambda *a: 0.0,
555
 
    }
556
 
 
557
 
msf_doc_import_accounting_lines()
558
 
 
559
 
class msf_doc_import_accounting_errors(osv.osv_memory):
560
 
    _name = 'msf.doc.import.accounting.errors'
561
 
 
562
 
    _columns = {
563
 
        'name': fields.text("Description", readonly=True, required=True),
564
 
        'wizard_id': fields.many2one('msf.doc.import.accounting', "Wizard", required=True, readonly=True),
565
 
    }
566
 
 
567
 
msf_doc_import_accounting_errors()
568
 
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: