<commit_before># -*- coding: utf-8 -*-
# Copyright 2015 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from openerp import models, fields, api, exceptions
from openerp.tools.translate import _
import importers


class AccountWinbizImport(models.TransientModel):
    _name = 'account.winbiz.import'
    _description = 'Import Accounting Winbiz'
    _rec_name = 'state'

    company_id = fields.Many2one('res.company', 'Company', invisible=True)
    enable_account_based_line_merging = fields.Boolean(
        "Group Balance Sheet accounts lines", default=False)
    report = fields.Text('Report', readonly=True)
    state = fields.Selection(selection=[
        ('draft', "Draft"),
        ('done', "Done"),
        ('error', "Error")],
        readonly=True,
        default='draft')
    file = fields.Binary('File', required=True)
    imported_move_ids = fields.Many2many(
        'account.move', 'import_winbiz_move_rel',
        string='Imported moves')
    file_format= fields.Selection(string="File Format", selection=[
        ('xls', "Excel spreadsheet"),
        ('xml', "XML data")],
        default='xls')

    @api.multi
    def _standardise_data(self, data, importer):
        """
        This function split one line of the spreadsheet into multiple lines.
        Winbiz just writes one line per move.
        """

        tax_obj = self.env['account.tax']
        journal_obj = self.env['account.journal']
        account_obj = self.env['account.account']

        def find_account(code):
            res = account_obj.search([('code',  '=', code)], limit=1)
            if not res:
                raise exceptions.MissingError(
                    _("No account with code %s") % code)
            return res

        def prepare_move(lines, journal, date, ref):
            return {'line_ids': [(0, 0, dict(ln)) for ln in lines],
                    'journal_id': journal.id,
                    'date': date,
                    'ref': ref}

        def account_line_merge(lines):
            lines_orig = lines
            lines = [ln for ln in lines
                     if ln.account.user_type_id.include_initial_balance]
            lines.sort(key=lambda ln: ln.account.code)
            to_remove = []
            previous = None
            for current in lines:
                if previous is not None \
                        and previous.account == current.account:
                    previous.amount += current.amount
                    to_remove.append(current)
                else:
                    previous = current

            lines = lines_orig
            for elem in to_remove:
                lines.remove(elem)
            return lines

        if self.enable_account_based_line_merging:
            prepare_move_orig = prepare_move

            def prepare_move(lines, journal, date, ref):
                return prepare_move_orig(account_line_merge(lines),
                                         journal, date, ref)

        class LineIntermediate(object):
            '''has a single ``amount`` attribute that's negative for debit, but
            can be converted into a dict for the ORM ``create()`` with
            ``dict(self)``
            '''
            def __init__(self, name, account, amount=0,
                         tax=None, originator_tax=None):
                self.name = name
                self.account = account
                self.amount = amount
                self.tax = tax
                self.originator_tax = originator_tax

            def __iter__(self):
                yield 'name', self.name
                yield 'account_id', self.account.id
                if self.amount < 0:
                    yield 'debit', -self.amount
                else:
                    yield 'credit', self.amount
                if self.tax:
                    yield 'tax_ids', [(4, self.tax.id, 0)]
                if self.originator_tax:
                    yield 'tax_line_id', self.originator_tax.id

        prepare_line = LineIntermediate

        # loop
        incomplete = None
        previous_pce = None
        previous_date = None
        previous_journal = None
        previous_tax = None
        lines = []
        for self.index, winbiz_item in enumerate(data, 1):
            if previous_pce not in (None, winbiz_item[u'pièce']):
                yield prepare_move(lines, previous_journal, previous_date,
                                   ref=previous_pce)
                lines = []
                incomplete = None
            previous_pce = winbiz_item[u'pièce']
            previous_date = importer.parse_date(winbiz_item[u'date'])
            journal = journal_obj.search(
                [('winbiz_mapping', '=', winbiz_item[u'journal'])],
                limit=1)
            if not journal:
                raise exceptions.MissingError(
                    u"No journal ‘%s’"
                    % winbiz_item[u'journal'])
            previous_journal = journal

            # tvatyp:  0 no vat was applied (internal transfers for example)
            #          1 there is vat but it's not on this line
            #          2 sales vat
            #          3 purchases vat
            #         -1 pure vat
            tvatyp = int(winbiz_item['ecr_tvatyp'])
            if tvatyp > 1:
                if tvatyp == 2:
                    scope = 'sale'
                else:
                    assert tvatyp == 3
                    scope = 'purchase'
                if winbiz_item['ecr_tvabn'] == 2:
                    included = True
                else:
                    assert winbiz_item['ecr_tvabn'] == 1
                    included = False
                tax = tax_obj.search([
                    ('amount', '=', winbiz_item['ecr_tvatx']),
                    ('price_include', '=', included),
                    ('type_tax_use', '=', scope)], limit=1)
                if not tax:
                    raise exceptions.MissingError(
                        "No tax found with amount = %r and type = %r"
                        % (winbiz_item['ecr_tvatx'], scope))
            else:
                tax = None
            if int(winbiz_item['ecr_tvatyp']) < 0:
                assert previous_tax is not None
                originator_tax = previous_tax
            else:
                originator_tax = None
            previous_tax = tax

            amount = float(winbiz_item[u'montant'])
            recto_line = verso_line = None
            if winbiz_item[u'cpt_débit'] != 'Multiple':
                account = find_account(winbiz_item[u'cpt_débit'])
                if incomplete is not None and incomplete.account == account:
                    incomplete.amount -= amount
                else:
                    recto_line = prepare_line(
                        name=winbiz_item[u'libellé'],<commit_msg>[FIX] handling of xml numbers (tvabn)<commit_after># -*- coding: utf-8 -*-
# Copyright 2015 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from openerp import models, fields, api, exceptions
from openerp.tools.translate import _
import importers


class AccountWinbizImport(models.TransientModel):
    _name = 'account.winbiz.import'
    _description = 'Import Accounting Winbiz'
    _rec_name = 'state'

    company_id = fields.Many2one('res.company', 'Company', invisible=True)
    enable_account_based_line_merging = fields.Boolean(
        "Group Balance Sheet accounts lines", default=False)
    report = fields.Text('Report', readonly=True)
    state = fields.Selection(selection=[
        ('draft', "Draft"),
        ('done', "Done"),
        ('error', "Error")],
        readonly=True,
        default='draft')
    file = fields.Binary('File', required=True)
    imported_move_ids = fields.Many2many(
        'account.move', 'import_winbiz_move_rel',
        string='Imported moves')
    file_format= fields.Selection(string="File Format", selection=[
        ('xls', "Excel spreadsheet"),
        ('xml', "XML data")],
        default='xls')

    @api.multi
    def _standardise_data(self, data, importer):
        """
        This function split one line of the spreadsheet into multiple lines.
        Winbiz just writes one line per move.
        """

        tax_obj = self.env['account.tax']
        journal_obj = self.env['account.journal']
        account_obj = self.env['account.account']

        def find_account(code):
            res = account_obj.search([('code',  '=', code)], limit=1)
            if not res:
                raise exceptions.MissingError(
                    _("No account with code %s") % code)
            return res

        def prepare_move(lines, journal, date, ref):
            return {'line_ids': [(0, 0, dict(ln)) for ln in lines],
                    'journal_id': journal.id,
                    'date': date,
                    'ref': ref}

        def account_line_merge(lines):
            lines_orig = lines
            lines = [ln for ln in lines
                     if ln.account.user_type_id.include_initial_balance]
            lines.sort(key=lambda ln: ln.account.code)
            to_remove = []
            previous = None
            for current in lines:
                if previous is not None \
                        and previous.account == current.account:
                    previous.amount += current.amount
                    to_remove.append(current)
                else:
                    previous = current

            lines = lines_orig
            for elem in to_remove:
                lines.remove(elem)
            return lines

        if self.enable_account_based_line_merging:
            prepare_move_orig = prepare_move

            def prepare_move(lines, journal, date, ref):
                return prepare_move_orig(account_line_merge(lines),
                                         journal, date, ref)

        class LineIntermediate(object):
            '''has a single ``amount`` attribute that's negative for debit, but
            can be converted into a dict for the ORM ``create()`` with
            ``dict(self)``
            '''
            def __init__(self, name, account, amount=0,
                         tax=None, originator_tax=None):
                self.name = name
                self.account = account
                self.amount = amount
                self.tax = tax
                self.originator_tax = originator_tax

            def __iter__(self):
                yield 'name', self.name
                yield 'account_id', self.account.id
                if self.amount < 0:
                    yield 'debit', -self.amount
                else:
                    yield 'credit', self.amount
                if self.tax:
                    yield 'tax_ids', [(4, self.tax.id, 0)]
                if self.originator_tax:
                    yield 'tax_line_id', self.originator_tax.id

        prepare_line = LineIntermediate

        # loop
        incomplete = None
        previous_pce = None
        previous_date = None
        previous_journal = None
        previous_tax = None
        lines = []
        for self.index, winbiz_item in enumerate(data, 1):
            if previous_pce not in (None, winbiz_item[u'pièce']):
                yield prepare_move(lines, previous_journal, previous_date,
                                   ref=previous_pce)
                lines = []
                incomplete = None
            previous_pce = winbiz_item[u'pièce']
            previous_date = importer.parse_date(winbiz_item[u'date'])
            journal = journal_obj.search(
                [('winbiz_mapping', '=', winbiz_item[u'journal'])],
                limit=1)
            if not journal:
                raise exceptions.MissingError(
                    u"No journal ‘%s’"
                    % winbiz_item[u'journal'])
            previous_journal = journal

            # tvatyp:  0 no vat was applied (internal transfers for example)
            #          1 there is vat but it's not on this line
            #          2 sales vat
            #          3 purchases vat
            #         -1 pure vat
            tvatyp = int(winbiz_item['ecr_tvatyp'])
            if tvatyp > 1:
                if tvatyp == 2:
                    scope = 'sale'
                else:
                    assert tvatyp == 3
                    scope = 'purchase'
                tvabn = int(winbiz_item['ecr_tvabn'])
                if tvabn == 2:
                    included = True
                else:
                    assert tvabn == 1
                    included = False
                tax = tax_obj.search([
                    ('amount', '=', winbiz_item['ecr_tvatx']),
                    ('price_include', '=', included),
                    ('type_tax_use', '=', scope)], limit=1)
                if not tax:
                    raise exceptions.MissingError(
                        "No tax found with amount = %r and type = %r"
                        % (winbiz_item['ecr_tvatx'], scope))
            else:
                tax = None
            if int(winbiz_item['ecr_tvatyp']) < 0:
                assert previous_tax is not None
                originator_tax = previous_tax
            else:
                originator_tax = None
            previous_tax = tax

            amount = float(winbiz_item[u'montant'])
            recto_line = verso_line = None
            if winbiz_item[u'cpt_débit'] != 'Multiple':
                account = find_account(winbiz_item[u'cpt_débit'])
                if incomplete is not None and incomplete.account == account:
                    incomplete.amount -= amount
                else:
                    recto_line = prepare_line(
                        name=winbiz_item[u'libellé'],
{'fraction_non_alphanumeric': 0.09522773426167681, 'fraction_numerical': 0.004351610095735422, 'mean_word_length': 1.4894385268098935, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 3}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3014243', 'n_tokens_mistral': 3810, 'n_tokens_neox': 3519, 'n_words': 914}