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

Odoo前端附件无法同步至后端问题求助

问题排查与解决方案

核心问题原因

  1. 前端请求方式错误:使用ajax.jsonRpc传递FormData是无效的——jsonRpc会自动将参数序列化为JSON格式,而FormData无法被JSON序列化,导致文件数据根本没传到后端。
  2. 后端路由类型不匹配:路由设置为type='json'时,Odoo不会解析multipart/form-data格式请求中的文件,request.httprequest.files始终为空。
  3. 参数传递逻辑混乱:前端将普通字段与FormData分开传递,后端无法同时接收两种格式的参数。

修正方案

1. 前端代码调整

改用ajax.post发送multipart/form-data请求,将所有字段(文本+文件)统一放入FormData:

odoo.define('test_payment.payment', function(require) {
    "use strict";
    var ajax = require('web.ajax');
    $(document).ready(function() {
        'use strict';
        $('button[name="o_payment_submit_button"]').bind("click", function(ev) {
            ev.preventDefault(); // 阻止按钮默认提交行为,避免页面跳转
            
            var formData = new FormData();
            // 添加文本字段
            formData.append('comment', $('#customer_comment').val());
            formData.append('client_order_ref', $('#customer_po').val());
            // 添加文件字段
            var files = $('#customer_documents')[0].files;
            for (var i = 0; i < files.length; i++) {
                formData.append('customer_documents', files[i]);
            }
            
            // 发送multipart请求
            ajax.post('/shop/customer_comment', formData, {
                contentType: false,
                processData: false,
            }).then(function(res) {
                console.log('数据提交成功:', res);
                // 这里可以继续执行原有的支付流程
            }).fail(function(err) {
                console.error('提交失败:', err);
            });
        });
    });
});

2. 后端代码调整

修改路由类型为http,适配multipart/form-data请求,同时修正附件存储的编码逻辑:

"""Add Customer comment functions to the website_sale controller."""
from odoo import http
from odoo.http import request

class WebsiteSale(http.Controller):
    @http.route(['/shop/customer_comment'], type='http', auth="public", methods=['POST'], website=True, csrf=True)
    def customer_comment(self, **post):
        """Add comment and attachments to sale order when clicking 'pay now'"""
        comment = post.get('comment')
        client_order_ref = post.get('client_order_ref')
        
        if comment:
            order = request.website.sale_get_order()
            redirection = self.checkout_redirection(order)
            if redirection:
                return redirection
            
            if order and order.id:
                # 更新订单文本字段
                order.write({
                    'customer_comment': comment,
                    'client_order_ref': client_order_ref,
                })
                
                # 处理上传文件
                customer_documents = request.httprequest.files.getlist('customer_documents')
                attachment_ids = []
                for doc in customer_documents:
                    if doc.filename:  # 跳过空文件
                        attachment_data = {
                            'name': doc.filename,
                            'type': 'binary',
                            'res_model': 'sale.order',
                            'res_id': order.id,
                            'datas': doc.read().encode('base64'),  # Odoo要求附件数据为base64编码
                            'mimetype': doc.content_type,
                        }
                        attachment = request.env['ir.attachment'].sudo().create(attachment_data)
                        attachment_ids.append(attachment.id)
                
                # 有附件才发送消息
                if attachment_ids:
                    order.message_post(attachment_ids=attachment_ids)
        
        # 返回JSON格式响应
        return request.make_json_response({'success': True})

关键说明

  • 前端必须用ajax.post而非jsonRpc,因为jsonRpc仅支持JSON格式参数,无法处理文件上传。
  • 后端路由type改为http后,Odoo会自动解析multipart/form-data中的表单字段和文件。
  • ir.attachment的datas字段要求存储base64编码的二进制数据,所以需要对文件内容做encode('base64')处理。
  • 添加csrf=True是Odoo网站路由的安全规范,避免跨站请求伪造。

内容的提问来源于stack exchange,提问作者Bishal Ghimire

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 05:46:06