示例#1
0
文件: invoice.py 项目: BADEP/addons
    def do_merge(self):
        """
        To merge similar type of account invoices.
        Invoices will only be merged if:
        * Account invoices are in draft
        * Account invoices belong to the same partner
        * Account invoices are have same company, partner, address, currency,
          journal, currency, salesman, account, type
        Lines will only be merged if:
        * Invoice lines are exactly the same except for the quantity and unit

         @param self: The object pointer.
         @param cr: A database cursor
         @param uid: ID of the user currently logged in
         @param ids: the ID or list of IDs
         @param context: A standard dictionary

         @return: new account invoice id

        """
        def make_key(br, fields):
            list_key = []
            for field in fields:
                field_val = getattr(br, field)
                if field in ('product_id', 'account_id'):
                    if not field_val:
                        field_val = False
                if (isinstance(field_val, browse_record) and
                   field != 'invoice_line_tax_id'):
                    field_val = field_val.id
                elif isinstance(field_val, browse_null):
                    field_val = False
                elif (isinstance(field_val, list) or
                      field == 'invoice_line_tax_id'):
                    field_val = ((6, 0, tuple([v.id for v in field_val])),)
                list_key.append((field, field_val))
            list_key.sort()
            return tuple(list_key)

        # compute what the new invoices should contain

        new_invoices = {}
        draft_invoices = [invoice
                          for invoice in self
                          if invoice.state == 'draft']
        seen_origins = {}
        seen_client_refs = {}

        for account_invoice in draft_invoices:
            invoice_key = make_key(
                account_invoice, INVOICE_KEY_COLS)
            new_invoice = new_invoices.setdefault(invoice_key, ({}, []))
            origins = seen_origins.setdefault(invoice_key, set())
            client_refs = seen_client_refs.setdefault(invoice_key, set())
            new_invoice[1].append(account_invoice.id)
            invoice_infos = new_invoice[0]
            if not invoice_infos:
                invoice_infos.update(
                    self._get_first_invoice_fields(account_invoice))
                origins.add(account_invoice.origin)
                client_refs.add(account_invoice.reference)
            else:
                if account_invoice.name:
                    invoice_infos['name'] = \
                        (invoice_infos['name'] or '') + \
                        (' %s' % (account_invoice.name,))
                if account_invoice.origin and \
                        account_invoice.origin not in origins:
                    invoice_infos['origin'] = \
                        (invoice_infos['origin'] or '') + ' ' + \
                        account_invoice.origin
                    origins.add(account_invoice.origin)
                if account_invoice.reference \
                        and account_invoice.reference not in client_refs:
                    invoice_infos['reference'] = \
                        (invoice_infos['reference'] or '') + \
                        (' %s' % (account_invoice.reference,))
                    client_refs.add(account_invoice.reference)
            for invoice_line in account_invoice.invoice_line:
                line_key = make_key(
                    invoice_line, INVOICE_LINE_KEY_COLS)
                o_line = invoice_infos['invoice_line'].setdefault(line_key, {})
                uos_factor = (invoice_line.uos_id and
                              invoice_line.uos_id.factor or 1.0)
                if o_line:
                    # merge the line with an existing line
                    o_line['quantity'] += invoice_line.quantity * \
                        uos_factor / o_line['uom_factor']
                else:
                    # append a new "standalone" line
                    for field in ('quantity', 'uos_id'):
                        field_val = getattr(invoice_line, field)
                        if isinstance(field_val, browse_record):
                            field_val = field_val.id
                        o_line[field] = field_val
                    o_line['uom_factor'] = uos_factor
        allinvoices = []
        invoices_info = {}
        for invoice_key, (invoice_data, old_ids) in new_invoices.iteritems():
            # skip merges with only one invoice
            if len(old_ids) < 2:
                allinvoices += (old_ids or [])
                continue
            # cleanup invoice line data
            for key, value in invoice_data['invoice_line'].iteritems():
                del value['uom_factor']
                value.update(dict(key))
            invoice_data['invoice_line'] = [
                (0, 0, value) for value in
                invoice_data['invoice_line'].itervalues()]
            # create the new invoice
            newinvoice = self.with_context(is_merge=True).create(invoice_data)
            invoices_info.update({newinvoice.id: old_ids})
            allinvoices.append(newinvoice.id)
            # make triggers pointing to the old invoices point to the new
            # invoice
            for old_id in old_ids:
                workflow.trg_redirect(
                    self.env.uid, 'account.invoice', old_id, newinvoice.id,
                    self.env.cr)
                workflow.trg_validate(
                    self.env.uid, 'account.invoice', old_id, 'invoice_cancel',
                    self.env.cr)
        # make link between original sale order or purchase order
        # None if sale is not installed
        so_obj = self.env['sale.order']\
            if 'sale.order' in self.env.registry else False
        invoice_line_obj = self.env['account.invoice.line']
        # None if purchase is not installed
        po_obj = self.env['purchase.order']\
            if 'purchase.order' in self.env.registry else False
        for new_invoice_id in invoices_info:
            if so_obj:
                todos = so_obj.search(
                    [('invoice_ids', 'in', invoices_info[new_invoice_id])])
                todos.write({'invoice_ids': [(4, new_invoice_id)]})
                for org_so in todos:
                    for so_line in org_so.order_line:
                        invoice_line_ids = invoice_line_obj.search(
                            [('product_id', '=', so_line.product_id.id),
                             ('invoice_id', '=', new_invoice_id)])
                        if invoice_line_ids:
                            so_line.write(
                                {'invoice_lines': [(6, 0, invoice_line_ids)]})
            if po_obj:
                todos = po_obj.search(
                    [('invoice_ids', 'in', invoices_info[new_invoice_id])])
                todos.write({'invoice_ids': [(4, new_invoice_id)]})
        # recreate link (if any) between original analytic account line
        # (invoice time sheet for example) and this new invoice
        anal_line_obj = self.env['account.analytic.line']
        if 'invoice_id' in anal_line_obj._columns:
            for new_invoice_id in invoices_info:
                todos = anal_line_obj.search(
                    [('invoice_id', 'in', invoices_info[new_invoice_id])])
                todos.write({'invoice_id': new_invoice_id})
        return invoices_info
示例#2
0
    def do_merge(self):
        """
        To merge similar type of account invoices.
        Invoices will only be merged if:
        * Account invoices are in draft
        * Account invoices belong to the same partner
        * Account invoices are have same company, partner, address, currency,
          journal, currency, salesman, account, type
        Lines will only be merged if:
        * Invoice lines are exactly the same except for the quantity and unit

         @param self: The object pointer.
         @param cr: A database cursor
         @param uid: ID of the user currently logged in
         @param ids: the ID or list of IDs
         @param context: A standard dictionary

         @return: new account invoice id

        """
        def make_key(br, fields):
            list_key = []
            for field in fields:
                field_val = getattr(br, field)
                if field in ('product_id', 'account_id'):
                    if not field_val:
                        field_val = False
                if (isinstance(field_val, browse_record)
                        and field != 'invoice_line_tax_id'):
                    field_val = field_val.id
                elif isinstance(field_val, browse_null):
                    field_val = False
                elif (isinstance(field_val, list)
                      or field == 'invoice_line_tax_id'):
                    field_val = ((6, 0, tuple([v.id for v in field_val])), )
                list_key.append((field, field_val))
            list_key.sort()
            return tuple(list_key)

        # compute what the new invoices should contain

        new_invoices = {}
        draft_invoices = [
            invoice for invoice in self if invoice.state == 'draft'
        ]
        seen_origins = {}
        seen_client_refs = {}

        for account_invoice in draft_invoices:
            invoice_key = make_key(account_invoice, INVOICE_KEY_COLS)
            new_invoice = new_invoices.setdefault(invoice_key, ({}, []))
            origins = seen_origins.setdefault(invoice_key, set())
            client_refs = seen_client_refs.setdefault(invoice_key, set())
            new_invoice[1].append(account_invoice.id)
            invoice_infos = new_invoice[0]
            if not invoice_infos:
                invoice_infos.update(
                    self._get_first_invoice_fields(account_invoice))
                origins.add(account_invoice.origin)
                client_refs.add(account_invoice.reference)
            else:
                if account_invoice.name:
                    invoice_infos['name'] = \
                        (invoice_infos['name'] or '') + \
                        (' %s' % (account_invoice.name,))
                if account_invoice.origin and \
                        account_invoice.origin not in origins:
                    invoice_infos['origin'] = \
                        (invoice_infos['origin'] or '') + ' ' + \
                        account_invoice.origin
                    origins.add(account_invoice.origin)
                if account_invoice.reference \
                        and account_invoice.reference not in client_refs:
                    invoice_infos['reference'] = \
                        (invoice_infos['reference'] or '') + \
                        (' %s' % (account_invoice.reference,))
                    client_refs.add(account_invoice.reference)
            for invoice_line in account_invoice.invoice_line:
                line_key = make_key(invoice_line, INVOICE_LINE_KEY_COLS)
                o_line = invoice_infos['invoice_line'].setdefault(line_key, {})
                uos_factor = (invoice_line.uos_id
                              and invoice_line.uos_id.factor or 1.0)
                if o_line:
                    # merge the line with an existing line
                    o_line['quantity'] += invoice_line.quantity * \
                        uos_factor / o_line['uom_factor']
                else:
                    # append a new "standalone" line
                    for field in ('quantity', 'uos_id'):
                        field_val = getattr(invoice_line, field)
                        if isinstance(field_val, browse_record):
                            field_val = field_val.id
                        o_line[field] = field_val
                    o_line['uom_factor'] = uos_factor
        allinvoices = []
        invoices_info = {}
        for invoice_key, (invoice_data, old_ids) in new_invoices.iteritems():
            # skip merges with only one invoice
            if len(old_ids) < 2:
                allinvoices += (old_ids or [])
                continue
            # cleanup invoice line data
            for key, value in invoice_data['invoice_line'].iteritems():
                del value['uom_factor']
                value.update(dict(key))
            invoice_data['invoice_line'] = [
                (0, 0, value)
                for value in invoice_data['invoice_line'].itervalues()
            ]
            # create the new invoice
            newinvoice = self.with_context(is_merge=True).create(invoice_data)
            invoices_info.update({newinvoice.id: old_ids})
            allinvoices.append(newinvoice.id)
            # make triggers pointing to the old invoices point to the new
            # invoice
            for old_id in old_ids:
                workflow.trg_redirect(self.env.uid, 'account.invoice', old_id,
                                      newinvoice.id, self.env.cr)
                workflow.trg_validate(self.env.uid, 'account.invoice', old_id,
                                      'invoice_cancel', self.env.cr)
        # make link between original sale order or purchase order
        # None if sale is not installed
        so_obj = self.env['sale.order']\
            if 'sale.order' in self.env.registry else False
        invoice_line_obj = self.env['account.invoice.line']
        # None if purchase is not installed
        po_obj = self.env['purchase.order']\
            if 'purchase.order' in self.env.registry else False
        for new_invoice_id in invoices_info:
            if so_obj:
                todos = so_obj.search([('invoice_ids', 'in',
                                        invoices_info[new_invoice_id])])
                todos.write({'invoice_ids': [(4, new_invoice_id)]})
                for org_so in todos:
                    for so_line in org_so.order_line:
                        invoice_line_ids = invoice_line_obj.search([
                            ('product_id', '=', so_line.product_id.id),
                            ('invoice_id', '=', new_invoice_id)
                        ])
                        if invoice_line_ids:
                            so_line.write(
                                {'invoice_lines': [(6, 0, invoice_line_ids)]})
            if po_obj:
                todos = po_obj.search([('invoice_ids', 'in',
                                        invoices_info[new_invoice_id])])
                todos.write({'invoice_ids': [(4, new_invoice_id)]})
        # recreate link (if any) between original analytic account line
        # (invoice time sheet for example) and this new invoice
        anal_line_obj = self.env['account.analytic.line']
        if 'invoice_id' in anal_line_obj._columns:
            for new_invoice_id in invoices_info:
                todos = anal_line_obj.search([('invoice_id', 'in',
                                               invoices_info[new_invoice_id])])
                todos.write({'invoice_id': new_invoice_id})
        return invoices_info
    def do_merge(self, keep_references=True, date_invoice=False):
        """
        To merge similar type of account invoices.
        Invoices will only be merged if:
        * Account invoices are in draft
        * Account invoices belong to the same partner
        * Account invoices are have same company, partner, address, currency,
          journal, currency, salesman, account, type
        Lines will only be merged if:
        * Invoice lines are exactly the same except for the quantity and unit

         @param self: The object pointer.
         @param keep_references: If True, keep reference of original invoices

         @return: new account invoice id

        """
        def make_key(br, fields):
            list_key = []
            for field in fields:
                field_val = getattr(br, field)
                if field in ('product_id', 'account_id'):
                    if not field_val:
                        field_val = False
                if (isinstance(field_val, browse_record)
                        and field != 'invoice_line_tax_id'):
                    field_val = field_val.id
                elif isinstance(field_val, browse_null):
                    field_val = False
                elif (isinstance(field_val, list)
                      or field == 'invoice_line_tax_id'):
                    field_val = ((6, 0, tuple([v.id for v in field_val])), )
                list_key.append((field, field_val))
            list_key.sort()
            return tuple(list_key)

        # compute what the new invoices should contain

        new_invoices = {}
        draft_invoices = [
            invoice for invoice in self if invoice.state == 'draft'
        ]
        seen_origins = {}
        seen_client_refs = {}

        for account_invoice in draft_invoices:
            invoice_key = make_key(account_invoice,
                                   self._get_invoice_key_cols())
            new_invoice = new_invoices.setdefault(invoice_key, ({}, []))
            origins = seen_origins.setdefault(invoice_key, set())
            client_refs = seen_client_refs.setdefault(invoice_key, set())
            new_invoice[1].append(account_invoice.id)
            invoice_infos = new_invoice[0]
            if not invoice_infos:
                invoice_infos.update(
                    self._get_first_invoice_fields(account_invoice))
                origins.add(account_invoice.origin)
                client_refs.add(account_invoice.reference)
                if not keep_references:
                    invoice_infos.pop('name')
            else:
                if account_invoice.name and keep_references:
                    invoice_infos['name'] = \
                        (invoice_infos['name'] or '') + \
                        (' %s' % (account_invoice.name,))
                if account_invoice.origin and \
                        account_invoice.origin not in origins:
                    invoice_infos['origin'] = \
                        (invoice_infos['origin'] or '') + ' ' + \
                        account_invoice.origin
                    origins.add(account_invoice.origin)
                if account_invoice.reference \
                        and account_invoice.reference not in client_refs:
                    invoice_infos['reference'] = \
                        (invoice_infos['reference'] or '') + \
                        (' %s' % (account_invoice.reference,))
                    client_refs.add(account_invoice.reference)
            for invoice_line in account_invoice.invoice_line:
                line_key = make_key(invoice_line,
                                    self._get_invoice_line_key_cols())
                o_line = invoice_infos['invoice_line'].setdefault(line_key, {})
                if o_line:
                    self._merge_invoice_line_values(o_line, invoice_line)
                    o_line['o_line_ids'].append(invoice_line.id)
                else:
                    # append a new "standalone" line
                    o_line.update(
                        invoice_line._convert_to_write(invoice_line._cache))
                    del o_line['invoice_id']
                    o_line['o_line_ids'] = [invoice_line.id]
        allinvoices = []
        invoices_info = {}
        invoice_lines_info = {}
        for invoice_key, (invoice_data, old_ids) in new_invoices.iteritems():
            # skip merges with only one invoice
            if len(old_ids) < 2:
                allinvoices += (old_ids or [])
                continue
            if date_invoice:
                invoice_data['date_invoice'] = date_invoice
            # create the new invoice
            invoice_line_data = invoice_data['invoice_line']
            del invoice_data['invoice_line']
            newinvoice = self.with_context(is_merge=True).create(invoice_data)
            invoice_lines_info[newinvoice.id] = {}
            for entry in invoice_line_data.values():
                o_line_ids = entry['o_line_ids']
                del entry['o_line_ids']
                entry['invoice_id'] = newinvoice.id
                inv_line = self.env['account.invoice.line'].create(entry)
                for o_line_id in o_line_ids:
                    invoice_lines_info[newinvoice.id][o_line_id] = inv_line.id
            newinvoice.button_reset_taxes()
            invoices_info.update({newinvoice.id: old_ids})
            allinvoices.append(newinvoice.id)
            # make triggers pointing to the old invoices point to the new
            # invoice
            for old_id in old_ids:
                workflow.trg_redirect(self.env.uid, 'account.invoice', old_id,
                                      newinvoice.id, self.env.cr)
                workflow.trg_validate(self.env.uid, 'account.invoice', old_id,
                                      'invoice_cancel', self.env.cr)
        # make link between original sale order if sale is not installed
        # None if purchase is not installed
        if 'sale.order' in self.env.registry:
            so_obj = self.env['sale.order']
            for new_invoice_id in invoices_info:
                todos = so_obj.search([('invoice_ids', 'in',
                                        invoices_info[new_invoice_id])])
                todos.write({'invoice_ids': [(4, new_invoice_id)]})
                for org_so in todos:
                    for so_line in org_so.order_line:
                        org_ilines = so_line.mapped('invoice_lines')
                        invoice_line_ids = []
                        for org_iline in org_ilines:
                            invoice_line_ids.append(
                                invoice_lines_info[new_invoice_id][
                                    org_iline.id])
                        so_line.write(
                            {'invoice_lines': [(6, 0, invoice_line_ids)]})
        # recreate link (if any) between original analytic account line
        # (invoice time sheet for example) and this new invoice
        anal_line_obj = self.env['account.analytic.line']
        if 'invoice_id' in anal_line_obj._columns:
            for new_invoice_id in invoices_info:
                todos = anal_line_obj.search([('invoice_id', 'in',
                                               invoices_info[new_invoice_id])])
                todos.write({'invoice_id': new_invoice_id})
        return invoices_info, invoice_lines_info
    def do_merge(self,
                 keep_references=True,
                 date_invoice=False,
                 remove_empty_invoice_lines=True):
        """
        To merge similar type of account invoices.
        Invoices will only be merged if:
        * Account invoices are in draft
        * Account invoices belong to the same partner
        * Account invoices are have same company, partner, address, currency,
          journal, currency, salesman, account, type
        Lines will only be merged if:
        * Invoice lines are exactly the same except for the quantity and unit

         @param self: The object pointer.
         @param keep_references: If True, keep reference of original invoices

         @return: new account invoice id

        """
        def make_key(br, fields):
            list_key = []
            for field in fields:
                field_val = getattr(br, field)
                if field in ('product_id', 'account_id'):
                    if not field_val:
                        field_val = False
                if (isinstance(field_val, browse_record)
                        and field != 'invoice_line_tax_ids'
                        and field != 'sale_line_ids'):
                    field_val = field_val.id
                elif isinstance(field_val, browse_null):
                    field_val = False
                elif (isinstance(field_val, list)
                      or field == 'invoice_line_tax_ids'
                      or field == 'sale_line_ids'):
                    field_val = ((6, 0, tuple([v.id for v in field_val])), )
                list_key.append((field, field_val))
            list_key.sort()
            return tuple(list_key)

        # compute what the new invoices should contain

        new_invoices = {}
        draft_invoices = [
            invoice for invoice in self if invoice.state == 'draft'
        ]
        seen_origins = {}
        seen_client_refs = {}

        for account_invoice in draft_invoices:
            invoice_key = make_key(account_invoice,
                                   self._get_invoice_key_cols())
            new_invoice = new_invoices.setdefault(invoice_key, ({}, []))
            origins = seen_origins.setdefault(invoice_key, set())
            client_refs = seen_client_refs.setdefault(invoice_key, set())
            new_invoice[1].append(account_invoice.id)
            invoice_infos = new_invoice[0]
            if not invoice_infos:
                invoice_infos.update(
                    self._get_first_invoice_fields(account_invoice))
                origins.add(account_invoice.origin)
                client_refs.add(account_invoice.reference)
                if not keep_references:
                    invoice_infos.pop('name')
            else:
                if account_invoice.name and keep_references:
                    invoice_infos['name'] = \
                        (invoice_infos['name'] or '') + ' ' + \
                        account_invoice.name
                if account_invoice.origin and \
                        account_invoice.origin not in origins:
                    invoice_infos['origin'] = \
                        (invoice_infos['origin'] or '') + ' ' + \
                        account_invoice.origin
                    origins.add(account_invoice.origin)
                if account_invoice.reference \
                        and account_invoice.reference not in client_refs:
                    invoice_infos['reference'] = \
                        (invoice_infos['reference'] or '') + ' ' + \
                        account_invoice.reference
                    client_refs.add(account_invoice.reference)

            for invoice_line in account_invoice.invoice_line_ids:
                line_key = make_key(invoice_line,
                                    self._get_invoice_line_key_cols())

                o_line = invoice_infos['invoice_line_ids'].\
                    setdefault(line_key, {})

                if o_line:
                    # merge the line with an existing line
                    o_line['quantity'] += invoice_line.quantity
                else:
                    # append a new "standalone" line
                    o_line['quantity'] = invoice_line.quantity

        allinvoices = []
        allnewinvoices = []
        invoices_info = {}
        qty_prec = self.env['decimal.precision'].precision_get(
            'Product Unit of Measure')
        for invoice_key, (invoice_data, old_ids) in new_invoices.iteritems():
            # skip merges with only one invoice
            if len(old_ids) < 2:
                allinvoices += (old_ids or [])
                continue
            # cleanup invoice line data
            for key, value in invoice_data['invoice_line_ids'].iteritems():
                value.update(dict(key))

            if remove_empty_invoice_lines:
                invoice_data['invoice_line_ids'] = [
                    (0, 0, value)
                    for value in invoice_data['invoice_line_ids'].itervalues()
                    if not float_is_zero(value['quantity'],
                                         precision_digits=qty_prec)
                ]
            else:
                invoice_data['invoice_line_ids'] = [
                    (0, 0, value)
                    for value in invoice_data['invoice_line_ids'].itervalues()
                ]

            if date_invoice:
                invoice_data['date_invoice'] = date_invoice

            # create the new invoice
            newinvoice = self.with_context(is_merge=True).create(invoice_data)
            invoices_info.update({newinvoice.id: old_ids})
            allinvoices.append(newinvoice.id)
            allnewinvoices.append(newinvoice)
            # make triggers pointing to the old invoices point to the new
            # invoice
            for old_id in old_ids:
                workflow.trg_redirect(self.env.uid, 'account.invoice', old_id,
                                      newinvoice.id, self.env.cr)
                workflow.trg_validate(self.env.uid, 'account.invoice', old_id,
                                      'invoice_cancel', self.env.cr)

        # Make link between original sale order
        # None if sale is not installed
        so_line_obj = self.env['sale.order.line'] \
            if 'sale.order' in self.env.registry else False
        invoice_line_obj = self.env['account.invoice.line']
        for new_invoice_id in invoices_info:
            if so_line_obj is not False:
                so_lines = so_line_obj.search([
                    ('invoice_lines.invoice_id', 'in',
                     invoices_info[new_invoice_id])
                ])
                for so_line in so_lines:
                    invoice_lines = invoice_line_obj.search([
                        ('product_id', '=', so_line.product_id.id),
                        ('invoice_id', '=', new_invoice_id)
                    ])
                    if invoice_lines:
                        so_line.write(
                            {'invoice_lines': [(6, 0, invoice_lines.ids)]})

        # recreate link (if any) between original analytic account line
        # (invoice time sheet for example) and this new invoice
        anal_line_obj = self.env['account.analytic.line']
        if 'invoice_id' in anal_line_obj._columns:
            for new_invoice_id in invoices_info:
                todos = anal_line_obj.search([('invoice_id', 'in',
                                               invoices_info[new_invoice_id])])
                todos.write({'invoice_id': new_invoice_id})

        for new_invoice in allnewinvoices:
            new_invoice.compute_taxes()

        return invoices_info