Odoo 怎么接入 Peppol 网络收发 BIS Billing 3.0 格式的发票
【免费下载链接】odooOdoo. Open Source Apps To Grow Your Business.项目地址: https://gitcode.com/GitHub_Trending/od/odoo
如果你的公司在 PEPPOL_LIST 列出的欧洲国家(奥地利、比利时、瑞士、捷克、德国、丹麦、爱沙尼亚、西班牙、芬兰、法国、爱尔兰、冰岛、立陶宛、卢森堡、拉脱维亚、马耳他、荷兰、挪威、瑞典、斯洛文尼亚等,见 addons/account/manifest.py 同级的addons/account/models/company.py中PEPPOL_DEFAULT_COUNTRIES),需要向商业伙伴电子发票,Odoo 的account_peppol模块可以让发票以 Peppol BIS Billing 3.0(UBL,EN 16931)格式通过 Peppol 网络发送和接收。完成接入后,你在 Odoo 中点一次“Send”,发票就会以Peppol BIS Billing UBL Invoice V3这类文档标识(urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1,见 res_company.py 的_peppol_modules_document_types)发出;对方回传的电子发票会自动落入你配置的采购日记账。
安装模块与依赖
模块定义见 addons/account_peppol/manifest.py,关键事实:
- 模块名
Peppol,摘要为 “This module is used to send/receive documents with PEPPOL”,version为1.2; - 依赖
account_edi_proxy_client和account_edi_ubl_cii(即会计应用及 UBL/CII EDI 模块),这两个会随安装自动带上; - Python 外部依赖为
phonenumbers,系统包对应python3-phonenumbers(apt 名)。模块用phonenumbers解析并校验注册时填写的手机号码,缺失时注册向导会直接报 “Please install the phonenumbers library.”(见 res_company.py 的_check_phonenumbers_import); auto_install配置:当account_edi_ubl_cii已安装、且数据库中至少有一家公司位于上述国家列表时,该模块会自动安装。
因此最短准备路径是:确认已安装 Odoo 会计(account+account_edi_ubl_cii),在公司设置里把公司所在国家设为支持的国家之一,然后安装account_peppol;若手动安装,先保证phonenumbers库可用。
在设置中注册为 Peppol 参与者
入口在 Odoo 设置(General Settings → Accounting)中由该模块提供的 Peppol 区块(res_config_settings_views.xml):
- 未注册时(状态
not_registered)显示 “Activate Peppol” 按钮,点击后打开 “Activate Electronic Invoicing (via Peppol)” 注册向导(模型peppol.registration,实现见 peppol_registration.py); - 已注册后,同一区块显示你的 Peppol ID(
EAS:endpoint,即account_peppol_edi_identification)、非生产模式时附带的模式标签(DEMO/TEST)、Peppol Contact Email,以及 “Disconnect Peppol” 按钮。
向导中必须填的字段由_ensure_mandatory_fields校验:
- 公司已选择国家(会计国家);
- 联系人邮箱与手机号都必填。手机号需符合国际格式,例如
+32123456789(+32为区号),格式错误会报 “Please enter the mobile number in the correct international format.”; - Peppol Address = EAS(电子地址规范代码,下拉选择)+ Endpoint(编号,只保留字母数字字符)。部分 EAS 的编号有格式规则,如
0007(10 位瑞典组织号)、0184(8 位丹麦 CVR)、0192(9 位挪威组织号)、0208(10 位)、0088(EAN),不符合会报 “The Peppol endpoint identification number is not correct.”(规则表PEPPOL_ENDPOINT_RULES见 res_company.py); - 分支公司不能使用与总公司完全相同的 Peppol ID(“Peppol ID should be different from main company.”)。
向导中的 “Register as a receiver” 选项决定注册角色:Odoo 会查询 SMP 目录判断你的公司是否已在 Peppol 网络上有注册——如果尚未注册,勾选该项会走 SMP 注册(即同时获得接收能力);如果已在某 Access Point 注册过接收,向导会提示 “Your company is already registered on an Access Point (…) for receiving invoices. We will register you on Odoo as a sender only.”
提交后(可能弹出一次身份验证,如 itsme/generic 登录),_create_connection会生成 RSA 密钥对、向 Peppol 代理服务发起连接并创建account_edi_proxy_client.user记录,然后按最终状态给出三种成功通知:
- 仅发送(
sender):“You can now send electronic invoices via Peppol.”; - SMP 注册中(
smp_registration):“Your Peppol registration will be activated soon. You can already send invoices.”(设置页会提示 “Your registration should be activated within a day.”); - 可收可发(
receiver):“You can now send and receive electronic invoices via Peppol”。
状态字段account_peppol_proxy_state的取值是后续所有判断的基础:not_registered/sender(可发不可收)/smp_registration(可发,接收注册待激活)/receiver(可发可收)/rejected。注册被拒时会收到 “Registration rejected.” 通知,设置页也会说明拒绝原因已发送邮件。
法国公司属于特例:向导会把 EAS 固定为0225,但_ensure_pdp_not_sent_through_peppol会拦截通过 Peppol 发送法国发票的路径,要求改用 “France - E-Invoicing (Approved Platform)” 模块l10n_fr_pdp(通过 PDP 发送)。如果你的公司是法国主体,这里应走 PDP 模块而不是本文主路径。
配置接收:入账日记账与 Webhook
要接收发票(参与角色为 Sending & Receiving),设置页会要求必填Incoming Accounting Journal:必须是采购类型(purchase)日记账,选错会报 “A purchase journal must be used to receive Peppol documents.”(res_company.py 的_check_peppol_purchase_journal_id)。未指定时系统默认取该公司第一个采购日记账。
接收依赖两条链路,都在 data/cron.xml 和 controllers/webhooks.py 中定义:
- 定时任务
PEPPOL: retrieve new documents每 4 小时拉取一次新文档(_cron_peppol_get_new_documents); - Webhook 路由
/peppol/webhook/new-message(公开 POST,带 token 校验)会在 Access Point 推送新消息时立即触发上述任务;另有/peppol/webhook/message-state-update与/peppol/webhook/user-state-update分别触发消息状态、参与者状态更新。
Webhook 地址由系统基于服务器 Base URL 拼接(/peppol/webhook,见_get_peppol_webhook_endpoint),所以要求 Odoo 实例有公网可达的 Base URL 注册时才会生效;没有 Webhook 时,4 小时一次的拉取任务仍能兜底收到发票。消息状态更新由PEPPOL: update message status任务每日执行一次。
发送一张 BIS Billing 3.0 发票
发送路径就在发票表单上(account_move_send.py):
- 确认商业伙伴的 Peppol 状态。伙伴模型上有
peppol_verification_state(not_verified/not_valid/not_valid_format/valid),填写或修改伙伴的peppol_eas+peppol_endpoint时会自动执行 SMP 目录校验(button_account_peppol_check_partner_endpoint)。只有valid(伙伴在 Peppol 上且能收该格式)才能走 Peppol 通道;not_valid_format会在发送向导中产生告警 “Customer is on Peppol but did not enable receiving documents.” - 客户所在国家在
PEPPOL_DEFAULT_COUNTRIES内时,peppol会默认加入发送方式,你在 “Send and Print” / 发送向导中确认即可;比利时伙伴(EAS0208/9925)在一种格式校验失败时会自动尝试另一种 EAS 组合。 - 发送前提由
_is_applicable_to_move逐条检查:伙伴国家在PEPPOL_LIST、公司account_peppol_proxy_state不是not_registered/rejected(且_compute_peppol_can_send为真)、伙伴校验状态valid、发票能生成 UBL/CII XML。 - 发送时
_get_peppol_document_params组装{'receiver': '<EAS:endpoint>', 'ubl': base64(XML)}文档并调用 Peppol 代理的1/send_document接口。XML 超过约 64 MB 会报 “Invoice … exceeds the size limit of 64 MB to be sent via Peppol.”
若公司尚未注册或状态不允许发送,点击发送会直接打开上文那个注册向导(_do_peppol_pre_send),注册完成后可继续发送。
验证发送与接收结果
发送侧——发票上的PEPPOL status字段(peppol_move_state)是核对依据,取值链路为:
ready(已发布发票且公司可发送、伙伴校验valid时自动置为 Ready to send)→to_send(Queued,提交时置位)→processing(Pending Reception,代理返回消息 UUID 后写入peppol_message_uuid并置位)→done(Done);- 失败则进入
error(Error),错误标题记录在发送数据中,例如参与者未就绪等错误经get_peppol_error_message转成可读信息; - 状态进入
processing后,系统会把PEPPOL: update message status定时任务提前到 5 分钟后触发一次(ir_cron_peppol_get_message_status的_trigger),以尽快把网络回执同步回来。发票一旦peppol_is_sent(即状态离开 ready/to_send/error/skipped),就不能再取消或退回草稿(“Cannot cancel an entry that has already been sent to PEPPOL”),草稿态发票可先改回再处理。
接收侧——新发票经拉取或 Webhook 触发创建后,会计日志标题为 “Peppol invoice received”,并携带 “Peppol document UUID: …” 行(account_edi_common.py 的_log_import_invoice_ubl_cii)。收到来自 Peppol 的发票在约束上更严格:客户方与公司方的EndpointID都必须存在(PEPPOL-EN16931-R010 / R020,见 account_edi_xml_ubl_bis3.py),缺失时导入会报对应约束错误。入账位置即上文配置的采购日记账。
故障与边界情况
设置页有一个专门的失步告警(account_is_token_out_of_sync为真时显示):“Disconnected from Peppol! Your database is not linked to Peppol anymore. This might be due to a database duplication or restoration.” 此时提供两个按钮:
- Reconnect this database:把当前数据库重新绑定到 Peppol 连接(
_peppol_out_of_sync_reconnect_this_database); - Disconnect this database:只断开当前数据库,不影响 IAP 侧连接本身(不要用它来注销参与者)。
其余需要留意的限制:
- 退出网络用设置页的 “Disconnect Peppol”(
button_peppol_deregister),或 “Re-register” 流程(先注销再重新打开注册向导); - 分支公司可借用总公司的连接(设置页显示 “You are sending from ”),此时 Peppol ID、角色配置随母公司,可单独 “Disconnect” 断开借用关系;
- 同一公司已存在其他 EDI 代理连接时,注册会报 “A connection to ' ' already exists.”,不能并行两条通道;
- 若 Peppol 返回
rejected,设置页会显示 “You registration has been rejected, the reason has been sent to you via email.”,需要联系支持。
完成以上步骤后,判断接入是否成功的标准就是:设置页 Peppol ID 显示且状态为receiver(或smp_registration一天内转为可接收)、测试发票的 PEPPOL status 走到done、接收的发票出现在采购日记账且日志中带 Peppol 消息 UUID。
【免费下载链接】odooOdoo. Open Source Apps To Grow Your Business.项目地址: https://gitcode.com/GitHub_Trending/od/odoo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考