You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Odoo调用action_post()报Expected singleton: res.company()错误解决

Odoo调用account.move.action_post()时触发Expected singleton: res.company()错误

问题场景

开发API用于搜索并冲销account.move模型条目,已成功找到目标条目并通过refund_moves()完成冲销,但调用action_post()确认冲销条目时,抛出Expected singleton: res.company()错误。此前在sale.order/account.move等其他模型中调用action_post()均正常。

相关代码

API路由及核心逻辑

@http.route('/update_invoice', website="false", auth='custom_auth', type='json', methods=['POST'])
def update_invoice(self, **kwargs):
    # 搜索目标条目
    invoice = request.env['account.move'].sudo().search([
        ('matter_id','=',matterID),
        ('account_id','=',accountID),
        ('move_type','=','out_invoice'),
        ('company_id','=',creditor.id)
    ])
    if invoice:
        # 创建冲销记录
        move_reversal = request.env['account.move.reversal'].with_context(
            active_model="account.move", 
            active_ids=invoice.id
        ).sudo().create({
            'date': intakeDate,
            'reason': 'Balance Adjustment',
            'journal_id': invoice.journal_id.id,
        })

        # 执行冲销
        move_reversal.refund_moves()
        
        # 搜索生成的冲销条目
        refundInvoice = request.env['account.move'].sudo().search([
            ('name','=',"/"),
            ('company_id','=',creditor.id),
            ('move_type','=','out_refund')
        ])

        if refundInvoice:
            _logger.info("Refund Invoice Found")

            # 此处触发错误
            refundInvoice.action_post()

自定义授权逻辑

@classmethod
def _auth_method_custom_auth(cls):
    access_token = request.httprequest.headers.get('Authorization')
    _logger.info(access_token)
    
    if not access_token:
        _logger.info('Access Token Missing')
        raise BadRequest('Missing Access Token')
    
    if access_token.startswith('Bearer '):
        access_token = access_token[7:]
        _logger.info(access_token)
        
    
    user_id = request.env["res.users.apikeys"]._check_credentials(scope='odoo.restapi', key=access_token)
    if not user_id:
        _logger.info('No user with api key found')
        raise BadRequest('Access token Invalid')

    request.update_env(user=user_id)

报错栈

Traceback (most recent call last):
  File "/home/odoo/src/odoo/odoo/models.py", line 5841, in ensure_one
    _id, = self._ids
ValueError: not enough values to unpack (expected 1, got 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/odoo/src/odoo/odoo/http.py", line 2189, in __call__
    response = request._serve_db()
  File "/home/odoo/src/odoo/odoo/http.py", line 1765, in _serve_db
    return service_model.retrying(self._serve_ir_http, self.env)
  File "/home/odoo/src/odoo/odoo/service/model.py", line 133, in retrying
    result = func()
  File "/home/odoo/src/odoo/odoo/http.py", line 1792, in _serve_ir_http
    response = self.dispatcher.dispatch(rule.endpoint, args)
  File "/home/odoo/src/odoo/odoo/http.py", line 1996, in dispatch
    result = self.request.registry['ir.http']._dispatch(endpoint)
  File "/home/odoo/src/odoo/addons/website/models/ir_http.py", line 235, in _dispatch
    response = super()._dispatch(endpoint)
  File "/home/odoo/src/odoo/odoo/addons/base/models/ir_http.py", line 222, in _dispatch
    result = endpoint(**request.params)
  File "/home/odoo/src/odoo/odoo/http.py", line 722, in route_wrapper
    result = endpoint(self, *args, **params_ok)
  File "/home/odoo/src/user/account_ext/controllers/main.py", line 411, in update_invoice
    refundInvoice.action_post()
  File "/home/odoo/src/odoo/addons/sale/models/account_move.py", line 63, in action_post
    res = super(AccountMove, self).action_post()
  File "/home/odoo/src/enterprise/account_accountant/models/account_move.py", line 76, in action_post
    res = super().action_post()
  File "/home/odoo/src/odoo/addons/account/models/account_move.py", line 4072, in action_post
    other_moves._post(soft=False)
  File "/home/odoo/src/enterprise/sale_subscription/models/account_move.py", line 13, in _post
    posted_moves = super()._post(soft=soft)
  File "/home/odoo/src/enterprise/account_asset/models/account_move.py", line 109, in _post
    posted = super()._post(soft)
  File "/home/odoo/src/odoo/addons/sale/models/account_move.py", line 99, in _post
    posted = super()._post(soft)
  File "/home/odoo/src/enterprise/account_reports/models/account_move.py", line 48, in _post
    return super()._post(soft)
  File "/home/odoo/src/enterprise/account_avatax/models/account_move.py", line 15, in _post
    res = super()._post(soft=soft)
  File "/home/odoo/src/enterprise/account_invoice_extract/models/account_invoice.py", line 262, in _post
    posted = super()._post(soft)
  File "/home/odoo/src/enterprise/account_inter_company_rules/models/account_move.py", line 14, in _post
    posted = super()._post(soft)
  File "/home/odoo/src/enterprise/account_external_tax/models/account_move.py", line 53, in _post
    return super()._post(soft=soft)
  File "/home/odoo/src/enterprise/account_accountant/models/account_move.py", line 68, in _post
    posted = super()._post(soft)
  File "/home/odoo/src/odoo/addons/account/models/account_move.py", line 3876, in _post
    draft_reverse_moves.reversed_entry_id._reconcile_reversed_moves(draft_reverse_moves, self._context.get('move_reverse_cancel', False))
  File "/home/odoo/src/odoo/addons/account/models/account_move.py", line 3694, in _reconcile_reversed_moves
    lines.with_context(move_reverse_cancel=move_reverse_cancel).reconcile()
  File "/home/odoo/src/odoo/addons/account/models/account_move_line.py", line 2935, in reconcile
    return self._reconcile_plan([self])
  File "/home/odoo/src/odoo/addons/account/models/account_move_line.py", line 2345, in _reconcile_plan
    self._reconcile_plan_with_sync(plan_list, all_amls)
  File "/home/odoo/src/odoo/addons/account/models/account_move_line.py", line 2492, in _reconcile_plan_with_sync
    exchange_diff_values = exchange_lines_to_fix._prepare_exchange_difference_move_vals(
  File "/home/odoo/src/odoo/addons/account/models/account_move_line.py", line 2603, in _prepare_exchange_difference_move_vals
    accounting_exchange_date = journal.with_context(move_date=exchange_date).accounting_date
  File "/home/odoo/src/odoo/odoo/fields.py", line 1207, in __get__
    self.compute_value(recs)
  File "/home/odoo/src/odoo/odoo/fields.py", line 1389, in compute_value
    records._compute_field_value(self)
  File "/home/odoo/src/odoo/addons/mail/models/mail_thread.py", line 424, in _compute_field_value
    return super()._compute_field_value(field)
  File "/home/odoo/src/odoo/odoo/models.py", line 4867, in _compute_field_value
    fields.determine(field.compute, self)
  File "/home/odoo/src/odoo/odoo/fields.py", line 102, in determine
    return needle(*args)
  File "/home/odoo/src/odoo/addons/account/models/account_journal.py", line 366, in _compute_accounting_date
    journal.accounting_date = temp_move._get_accounting_date(move_date, has_tax)
  File "/home/odoo/src/odoo/addons/account/models/account_move.py", line 4358, in _get_accounting_date
    lock_dates = self._get_violated_lock_dates(invoice_date, has_tax)
  File "/home/odoo/src/odoo/addons/account/models/account_move.py", line 4389, in _get_violated_lock_dates
    return self.company_id._get_violated_lock_dates(invoice_date, has_tax)
  File "/home/odoo/src/odoo/addons/account/models/company.py", line 369, in _get_violated_lock_dates
    self.ensure_one()
  File "/home/odoo/src/odoo/odoo/models.py", line 5844, in ensure_one
    raise ValueError("Expected singleton: %s" % self)
ValueError: Expected singleton: res.company()

解决方案

通过在调用action_post()时使用with_company()明确指定公司上下文,解决了该问题:

refundInvoice.with_company(invoice.company_id).action_post()

内容的提问来源于stack exchange,提问作者Brandon Huynh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 00:42:05