简体   繁体   中英

TypeError: unhashable type: 'list' | Porting Odoo v8 to Odoo 12

I'm trying to read a record of invoice but I get a problem the next problem, bellow is my terminal log:

Odoo Server Error

Traceback (most recent call last):
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/http.py", line 654, in _handle_exception
    return super(JsonRequest, self)._handle_exception(exception)
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/http.py", line 312, in _handle_exception
    raise pycompat.reraise(type(exception), exception, sys.exc_info()[2])
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/tools/pycompat.py", line 87, in reraise
    raise value
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/http.py", line 696, in dispatch
    result = self._call_function(**self.params)
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/http.py", line 344, in _call_function
    return checked_call(self.db, *args, **kwargs)
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/service/model.py", line 97, in wrapper
    return f(dbname, *args, **kwargs)
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/http.py", line 337, in checked_call
    result = self.endpoint(*a, **kw)
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/http.py", line 939, in __call__
    return self.method(*args, **kw)
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/http.py", line 517, in response_wrap
    response = f(*args, **kw)
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/addons/web/controllers/main.py", line 966, in call_button
    action = self._call_kw(model, method, args, {})
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/addons/web/controllers/main.py", line 954, in _call_kw
    return call_kw(request.env[model], method, args, kwargs)
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/api.py", line 749, in call_kw
    return _call_kw_multi(method, model, args, kwargs)
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/api.py", line 736, in _call_kw_multi
    result = method(recs, *args, **kwargs)
  File "/home/desarrollo/Documentos/odoo-12/custom/l10n-ve/l10n_vzla_dcnote/wizard/account_invoice_debit.py", line 178, in invoice_debit
    return self.compute_debit()
  File "/home/desarrollo/Documentos/odoo-12/custom/l10n-ve/l10n_vzla_dcnote/wizard/account_invoice_debit.py", line 111, in compute_debit
    'journal_id', 'period_id'])
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/models.py", line 2747, in read
    fields = self.check_field_access_rights('read', fields)
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/models.py", line 2722, in check_field_access_rights
    invalid_fields = {name for name in fields if not valid(name)}
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/models.py", line 2722, in <setcomp>
    invalid_fields = {name for name in fields if not valid(name)}
  File "/home/desarrollo/Documentos/odoo-12/odoo-12.0/odoo/models.py", line 2713, in valid
    field = self._fields.get(fname)
TypeError: unhashable type: 'list'

I try to remove some fields but still get the error.

Here is my custom module:

# coding: utf-8
import time

from odoo import api, fields, models, _
from odoo.tools.translate import _
from odoo.osv import osv

class AccountInvoiceDebit(models.TransientModel):

    """Debits Note from Invoice"""

    _name = "account.invoice.debit"
    _description = "Invoice Debit Note"

    date = fields.Date('Operation date',
                        help='This date will be used as the invoice date '
                                'for Refund Invoice and Period will be '
                                'chosen accordingly!')
    period = fields.Many2one('account.period', 'Force period')
    journal_id = fields.Many2one('account.journal',
                                    'Refund Journal',
                                    help='You can select here the journal '
                                        'to use for the refund invoice '
                                        'that will be created. If you '
                                        'leave that field empty, it will '
                                        'use the same journal as the '
                                        'current invoice.')
    description = fields.Char('Description', size=128, required=True)
    comment = fields.Text('Comment', required=True)

    def _get_journal(self, cr, uid, context=None):
        obj_journal = self.pool.get('account.journal')
        user_obj = self.pool.get('res.users')
        if context is None:
            context = {}
        inv_type = context.get('type', 'out_invoice')
        company_id = user_obj.browse(
            cr, uid, uid, context=context).company_id.id
        type = (inv_type == 'out_invoice') and 'sale_refund' or \
               (inv_type == 'out_refund') and 'sale' or \
               (inv_type == 'in_invoice') and 'purchase_refund' or \
               (inv_type == 'in_refund') and 'purchase'
        journal = obj_journal.search(cr, uid, [('type', '=', type), (
            'company_id', '=', company_id)], limit=1, context=context)
        return journal and journal[0] or False

    _defaults = {
        'date': lambda *a: time.strftime('%Y-%m-%d'),
        'journal_id': _get_journal,
    }

    def _get_period(self, cr, uid, context={}):
        """
        Return  default account period value
        """
        account_period_obj = self.pool.get('account.period')
        ids = account_period_obj.find(cr, uid, context=context)
        period_id = False
        if ids:
            period_id = ids[0]
        return period_id

    def _get_orig(self, cr, uid, inv, ref, context={}):
        """
        Return  default origin value
        """
        nro_ref = ref
        if inv.type == 'out_invoice':
            nro_ref = inv.number
        orig = _('INV:') + (nro_ref or '') + _('- DATE:') + (
            inv.date_invoice or '') + (' TOTAL:' + str(inv.amount_total) or '')
        return orig

    @api.model
    def compute_debit(self, context=None):
        """
        @param cr: the current row, from the database cursor,
        @param uid: the current user’s ID for security checks,
        @param ids: the account invoice refund’s ID or list of IDs

        """
        inv_obj = self.env['account.invoice']
        mod_obj = self.env['ir.model.data']
        act_obj = self.env['ir.actions.act_window']
        inv_tax_obj = self.env['account.invoice.tax']
        inv_line_obj = self.env['account.invoice.line']
        res_users_obj = self.env['res.users']
        record = self._context.get('active_ids')
        if context is None:
            context = {}

        for form in self.browse(self):
            created_inv = []
            date = False
            period = False
            description = False
            company = res_users_obj.company_id
            journal_id = self.journal_id
            for inv in inv_obj.browse(record):


                # we get original data of invoice to create a new invoice that
                # is the copy of the original
                invoice = inv.read([record],
                                       ['name', 'type', 'number', 'reference',
                                        'comment', 'date_due', 'partner_id',
                                        'partner_insite', 'partner_contact',
                                        'partner_ref', 'payment_term',
                                        'account_id', 'currency_id',
                                        'invoice_line', 'tax_line',
                                        'journal_id', 'period_id'])
                invoice = invoice[0]
                del invoice['id']
                invoice_lines = inv_line_obj.browse(
                    cr, uid, invoice['invoice_line'], context=context)
                invoice_lines = inv._refund_cleanup_lines(
                    cr, uid, invoice_lines, context=context)
                tax_lines = inv_tax_obj.browse(
                    cr, uid, invoice['tax_line'], context=context)
                tax_lines = inv_obj._refund_cleanup_lines(
                    cr, uid, tax_lines, context=context)
                # Add origin, parent and comment values
                orig = self._get_orig(cr, uid, inv, invoice[
                                      'reference'], context)
                invoice.update({
                    'type': inv.type == 'in_invoice' and 'in_refund' or
                    inv.type == 'out_invoice' and 'out_refund',
                    'date_invoice': date,
                    'state': 'draft',
                    'number': False,
                    'invoice_line': invoice_lines,
                    'tax_line': tax_lines,
                    'period_id': period,
                    'parent_id': inv.id,
                    'name': description,
                    'origin': orig,
                    'comment': form['comment']
                })
                # take the id part of the tuple returned for many2one fields
                for field in ('partner_id', 'account_id', 'currency_id',
                              'payment_term', 'journal_id'):
                    invoice[field] = invoice[field] and invoice[field][0]
                # create the new invoice
                inv_id = inv_obj.create(self, invoice, {})
                # we compute due date
                if inv.payment_term.id:
                    data = inv_obj.onchange_payment_term_date_invoice(
                        cr, uid, [inv_id], inv.payment_term.id, date)
                    if 'value' in data and data['value']:
                        inv_obj.write(cr, uid, [inv_id], data['value'])
                created_inv.append(inv_id)
            # we get the view id
            """
            xml_id = (inv_obj.type == 'out_refund') and 'action_invoice_tree1' or \
                     (inv_obj.type == 'in_refund') and 'invoice_supplier_form' or \
                     (inv_obj.type == 'out_invoice') and 'action_invoice_out_refund' or \
                     (inv_obj.type == 'in_invoice') and 'action_invoice_in_refund'
            """

            raise osv.except_osv(created_inv)
            # we get the model
            """
            result = mod_obj.get_object_reference('account.invoice', xml_id)
            id = result and result[1] or False
            # we read the act window
            result = act_obj.read(cr, uid, id, context=context)
            # we add the new invoices into domain list
            invoice_domain = eval(result['domain'])
            invoice_domain.append(('id', 'in', created_inv))
            result['domain'] = invoice_domain
            """
            return True

    @api.multi
    def invoice_debit(self):
        #ids = self._context('active_ids')
        #id_inv = self._context.get('active_ids')
        return self.compute_debit()

I expect to read the invoice to create a copy with some changed values, so i forced a raise error to make sure that is gonna be created.

First you used api.model means you are using new API. I'm confused about this line:

 for form in self.browse(self):

with api.model self is always an empty set a never tried this I wonder why you are in the loop in the first play.

I think you need to change this to api.multi and remove the context parameter in the new api the parameter is in the self it's self.

    self._context  or self.env.context

try this but this a simple explanation how new API work you don't have to pass cr, ids, context each time

@api.multi
def compute_debit(self):


     for form in self: # you don't have to browse self it's all read a Recordset
         .....
         .....
         .....

         for inv in inv_obj.browse(record): # this is okay because it's a list of ids you should browse to convert to recrodset
             # here you don't have to pass the id in the new api 
             invoice = inv.read(['name', 'type', 'number', 'reference',
                                    'comment', 'date_due', 'partner_id',
                                    'partner_insite', 'partner_contact',
                                    'partner_ref', 'payment_term',
                                    'account_id', 'currency_id',
                                    'invoice_line', 'tax_line',
                                    'journal_id', 'period_id'])

you are mixing new api with old api ?!! a lot in your code you should use one of the two. you will have a lot of problem with code good luck.

like for example

   inv._refund_cleanup_lines(
                cr, uid, invoice_lines, context=context)

I don't see any variable or argument cr or uid you get the idea

for example instead of reading the fields and calling the method like this what you had to do is:

       # no read at all you all ready have acces to fields
       inv._refund_cleanup_lines(inv.invoice_line)

Hope you get the idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM