You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
4.6 KiB

  1. # -*- coding: utf-8 -*-
  2. # noqa: This is a backport from Odoo. OCA has no control over style here.
  3. # flake8: noqa
  4. import dateutil.parser
  5. import StringIO
  6. from openerp.tools.translate import _
  7. from openerp.osv import osv, fields
  8. from openerp.exceptions import Warning
  9. class account_bank_statement_import(osv.TransientModel):
  10. _inherit = "account.bank.statement.import"
  11. _columns = {
  12. 'journal_id': fields.many2one('account.journal', string='Journal', help='Accounting journal related to the bank statement you\'re importing. It has be be manually chosen for statement formats which doesn\'t allow automatic journal detection (QIF for example).'),
  13. 'hide_journal_field': fields.boolean('Hide the journal field in the view'),
  14. }
  15. def _get_hide_journal_field(self, cr, uid, context=None):
  16. return context and 'journal_id' in context or False
  17. _defaults = {
  18. 'hide_journal_field': _get_hide_journal_field,
  19. }
  20. def _get_journal(self, cr, uid, currency_id, bank_account_id, account_number, context=None):
  21. """ As .QIF format does not allow us to detect the journal, we need to let the user choose it.
  22. We set it in context before to call super so it's the same as calling the widget from a journal """
  23. if context is None:
  24. context = {}
  25. if context.get('active_id'):
  26. record = self.browse(cr, uid, context.get('active_id'), context=context)
  27. if record.journal_id:
  28. context['journal_id'] = record.journal_id.id
  29. return super(account_bank_statement_import, self)._get_journal(cr, uid, currency_id, bank_account_id, account_number, context=context)
  30. def _check_qif(self, cr, uid, data_file, context=None):
  31. return data_file.strip().startswith('!Type:')
  32. def _parse_file(self, cr, uid, data_file, context=None):
  33. if not self._check_qif(cr, uid, data_file, context=context):
  34. return super(account_bank_statement_import, self)._parse_file(cr, uid, data_file, context=context)
  35. try:
  36. file_data = ""
  37. for line in StringIO.StringIO(data_file).readlines():
  38. file_data += line
  39. if '\r' in file_data:
  40. data_list = file_data.split('\r')
  41. else:
  42. data_list = file_data.split('\n')
  43. header = data_list[0].strip()
  44. header = header.split(":")[1]
  45. except:
  46. raise Warning(_('Could not decipher the QIF file.'))
  47. transactions = []
  48. vals_line = {}
  49. total = 0
  50. if header == "Bank":
  51. vals_bank_statement = {}
  52. for line in data_list:
  53. line = line.strip()
  54. if not line:
  55. continue
  56. if line[0] == 'D': # date of transaction
  57. vals_line['date'] = dateutil.parser.parse(line[1:], fuzzy=True).date()
  58. elif line[0] == 'T': # Total amount
  59. total += float(line[1:].replace(',', ''))
  60. vals_line['amount'] = float(line[1:].replace(',', ''))
  61. elif line[0] == 'N': # Check number
  62. vals_line['ref'] = line[1:]
  63. elif line[0] == 'P': # Payee
  64. vals_line['name'] = 'name' in vals_line and line[1:] + ': ' + vals_line['name'] or line[1:]
  65. # Since QIF doesn't provide account numbers, we'll have to find res.partner and res.partner.bank here
  66. # (normal behavious is to provide 'account_number', which the generic module uses to find partner/bank)
  67. ids = self.pool.get('res.partner.bank').search(cr, uid, [('owner_name', '=', line[1:])], context=context)
  68. if ids:
  69. vals_line['bank_account_id'] = bank_account_id = ids[0]
  70. vals_line['partner_id'] = self.pool.get('res.partner.bank').browse(cr, uid, bank_account_id, context=context).partner_id.id
  71. elif line[0] == 'M': # Memo
  72. vals_line['name'] = 'name' in vals_line and vals_line['name'] + ': ' + line[1:] or line[1:]
  73. elif line[0] == '^': # end of item
  74. transactions.append(vals_line)
  75. vals_line = {}
  76. elif line[0] == '\n':
  77. transactions = []
  78. else:
  79. pass
  80. else:
  81. raise Warning(_('This file is either not a bank statement or is not correctly formed.'))
  82. vals_bank_statement.update({
  83. 'balance_end_real': total,
  84. 'transactions': transactions
  85. })
  86. return None, None, [vals_bank_statement]