
Spree 6.1 B2B 订单文档体系Documents 区域、装箱清单与付款指示打印设计全解析【免费下载链接】spreeOpen Source eCommerce Platform for B2B, Marketplace, and Enterprise. REST API, TypeScript SDK, and production-ready Next.js storefront. Self-host it. Own your stack. No vendor lock-in. Zero platform fees.项目地址: https://gitcode.com/GitHub_Trending/sp/spree导读B2B 订单在成交前后会积累大量纸质文档——采购方的采购订单PO、报价单、装箱清单、发货文件这些在今天的 Spree 中只能散落在邮件线程里。本文基于docs/plans/6.1-b2b-order-documents.md设计计划系统讲解 Spree 6.1 如何为订单引入一个Documents 文档区域上传文件、私有存储、按文档粒度的客户可见性、买家订单视图展示并扩展 Dashboard 已有的客户端打印路径新增箱级装箱清单与付款指示单两类可打印文档。读完本文你将掌握Spree::OrderDocument的数据模型、私有附件与可见性设计、两类打印文档的数据来源freight summary 与 payment terms以及本计划与 PO 编号、批发运输、付款条款等上游计划的衔接方式并理解为什么发票与 PDF 服务端渲染被刻意排除在 6.1 的 OSS 范围之外。背景B2B 订单的纸质文档困局批发与 B2B 采购和零售完全不同一单生意在真正发货前双方往往已经交换了采购订单、报价、装箱说明、运输文件等大量资料。这些资料是订单的事实档案——买方财务部门几年后对账时依赖它们海关与货运代理也需要它们。但当前 Spree 中订单模型只承载结构化数据纸质文件的唯一去向是邮件线程这带来两个问题文档与订单脱钩文件存在收发双方的邮箱里无法按订单检索无法控制谁能看到什么打印输出能力有限Dashboard 已有装箱单packing slip的客户端打印实现但批发场景需要的箱级装箱清单cartons/pallets/CBM/毛重和付款指示单terms 银行转账信息 付款参考号尚无输出载体。该计划docs/plans/6.1-b2b-order-documents.md正是为了补齐这两块一个订单级的文档存储区域以及两类数据已就绪但尚无出口的生成式打印文档。它同时明确划定了边界——真正的发票带编号的 proforma 与商业发票、PDF 生成、法定编号不在 6.1 范围内那属于 Enterprise 的 terms/invoicing 产品线。核心设计决策Key Decisions计划的开篇以不得偏离的强约束列出四条关键决策它们是整个设计的骨架。1.Spree::OrderDocument是上传文件行不是生成流水线这是最重要的一条决策文档区域是一个附件行模型而不是服务器端文档生成管线。每行文档记录包含order_id归属订单label文档标签如装箱清单扫描件customer_visible客户可见性默认false内部文书保持内部私有存储附件使用防伪造spoofing-protected校验沿用 seller-submission / tax-certificate 先例uploaded_by多态关联记录上传者是员工还是客户——买家可以通过账户订单视图自行上传自己的文件。计划中的po_document来自 6.0-b2b-customer-po-numbers.md保留其专属槽位——因为它有语义强制必填检查——但 Documents 区域会把它与通用文档行并列展示。2. 生成式文档继续走客户端 HTML 打印6.1 中两类生成文档装箱清单、付款指示单沿用已发布的 packing-slip 模式刻意做成打印窗口而非 admin 路由因为订单页面已经加载了所需全部数据。装箱清单从冻结的 freight summary 中取出 carton/pallet/CBM 区块付款指示单渲染 terms 计划表 银行偏好 付款参考号。两者都不自称发票、不带发票编号、不产生存储工件。3. 核心不带 PDF 栈计划明确当未来需要服务端渲染时它将随 Enterprise 发票产品一起到来OSS 的打印与上传永远不会引入 PDF 依赖。这让 OSS 维护成本保持可控同时把法定编号 PDF划给商业产品线。4. 客户可见性按文档粒度默认私有内部文书保持内部买家的订单视图只列出customer_visible: true的文档并通过带过期时间的签名 URL私有存储读取模式访问。Spree::OrderDocument模型设计计划给出了模型的骨架代码class Spree::OrderDocument Spree.base_class belongs_to :order, class_name: Spree::Order belongs_to :uploaded_by, polymorphic: true, optional: true has_one_attached :file, service: Spree.private_storage_service_name validates :label, presence: true # customer_visible boolean, default false, null: false end这个模型的设计可以在仓库现有的附件先例中找到完整的实现依据私有存储服务Spree.private_storage_service_name是核心中处理机密文件的统一入口。Spree::TaxExemptionCertificate#documenttax_exemption_certificate.rb与Spree::SellerRequirementSubmission#fileseller_requirement_submission.rb都通过它挂载附件注释明确说明原因Confidential, so the private service rather than the public one that serves product images。OrderDocument#file沿用同一模式——买家的 PO 里带着价格、条款和内部成本代码只能通过认证的下载动作访问。防伪造内容校验Spree::SellerRequirementSubmission中的做法是让字节决定文件是什么而不是上传者发送的 headerSpree::AttachmentContentTypeValidatorSpree::Purchase::PurchaseOrder模块purchase_order.rb则给出了更具体的清单application/pdf、image/jpeg、image/png、image/heic、image/webp、Word 文档等并限制单文件 10 MB——计划中的OrderDocument附件应沿用同一套校验思路。有界上传TaxExemptionCertificate::MAX_DOCUMENT_SIZE 10.megabytes的注释解释了原因the download action reads the whole blob into memory to serve it, so an unbounded upload would be an unbounded allocation per request。PurchaseOrder还进一步实现了磁盘上实际尺寸校验分块下载测量防止上传者虚报byte_size绕过校验这些约束都是OrderDocument的私有附件应当继承的安全基线。API 表面Admin 与 Store 两条链路计划为文档区域规划了两条 API 链路分工清晰Admin API嵌套 CRUD 直传nested /admin/orders/:id/documentsCRUD上传走signed blob 直传direct upload与服务端转存相比可避免大文件占满请求线程。Store API买家视角的文档索引与上传账户订单视图上的documents index只暴露customer_visible的文档create买家上传自己的文件永远对自己可见并为员工标记为买家提供buyer-supplied。这一可见性过滤 买家可写的组合正是文档区域的差异化价值员工上传的内部核对单不会泄漏给买家而买家补传的 PO 修订版又能立即回到员工视野。Dashboard 与 Storefront 的呈现Dashboard订单页 Documents 卡片订单页面新增 Documents 卡片提供四类操作上传upload可见性开关visibility toggle——对应customer_visible字段下载download——走签名 URL 私有读取删除带确认delete-with-confirm打印动作紧挨现有 packing slip 按钮排列即订单页同时具备装箱单 / 装箱清单 / 付款指示单三类打印入口。Storefront完整的买家订单视图Storefront 订单页新增文档列表与 6.1 另外两个计划组合成买家的完整视图订单阶段 预计就绪日期6.1-order-stages.md付款计划表6.0-6.1-b2b-payment-terms.md发货 / freight summary文档列表。两类生成式打印文档的数据来源6.1 扩展的是 Dashboard 现有的客户端打印路径因此理解先例至关重要。先例packing-slip 的客户端打印模式仓库中已实现的原型是 packing-slip.ts。它的核心模式值得细读从Fulfillment与Order数据构建行生成完整 HTML含内联 CSS写入printWindow.document然后window.open新窗口并调用print()刻意不是 admin 路由——注释写明the admin shell (sidebar, top bar) would print with an in-app page, and everything the slip needs is already loaded on the order screen不含价格——a packing slip says what is in the box, not what it cost所有用户文本经escapeHtml转义防止订单数据注入打印 HTML。6.1 的两类新打印将复用这一整套模式。装箱清单Carton-Level Packing List装箱清单在 packing slip 的基础上叠加物流区块数据来自冻结的 freight summary单位数units箱数cartons托盘数pallets毛重gross weight体积 CBM外加 PO 编号与订单号。这里的冻结语义来自批发运输计划6.0-b2b-wholesale-shipping.mdfreight summary 在估价时由 freight provider 计算并持久化到所选DeliveryRate#metadatajsonb订单面读取一律来自那里绝不从活跃商品目录重新推导——与 duty snapshot 的 doctrine 一致。仓库中 freight_summary.rb 的实现给出了这个数据结构的完整形态build从库存包装内容沿Unit → Carton → Pallet → CBM/Weight链条汇总total_units、total_cartons、total_pallets仅当所有箱级行都声明了cartons_per_pallet时非 nil、total_volumeCBM、total_weightkg以及complete?标志——当某行缺少箱数据时退回单位体积/重量并标记不完整让数字保持可用同时如实告知部分数据来自未测量的目录。as_json的输出形状就是装箱清单打印区块直接消费的数据。付款指示单Payment-Instructions Sheet付款指示单渲染的是付款条款计划6.0-6.1-b2b-payment-terms.md中的数据订单号 PO 引用条款快照terms snapshotkindprepaid | deposit、deposit_percentage、balance_due_label如Before shipping现在应付金额amount due now银行转账信息bank transfer details付款参考号payment reference关键点条款快照在订单成交时冻结与议价价格同理公司后续条款变更不影响已成交订单打印读取的始终是订单快照而非重新解析付款参考号是 6.1 存储的、可 ransack 搜索的reference列RF/ISO 11649 结构化债权人参考风格校验位基于付款的 prefixed id保证银行对账单的一行能精确对应一笔付款。而派生编号R1001-P1明确不作为对账标识——兄弟记录被删除时派生编号会漂移这正是付款条款计划记录在案的教训。计划还规定当 PO 编号与付款参考号存在时打印必须渲染它们PO 计划中的文档约束同样适用。与上游计划的衔接本计划的三大依赖计划在头部声明了三个依赖理解它们才能理解文档区域的数据从何而来依赖一Customer PO Numbers6.0-b2b-customer-po-numbers.md已实现po_document是订单的第一个附件也是本计划模型的原型。它实现为Spree::Purchase::PurchaseOrderconcernCart 与 Order 共用包含po_number规范化、私有po_document附件防伪造 10 MB 上限、以及通过resolved_company读取的po_number_required?。PO 编号在成交时随购买字段复制到订单同一 blob 重新挂到订单blob 共享media-library 先例。本计划文档区域列出它时其必填语义保持专属槽位——通用文档行不承担必填检查。依赖二B2B Wholesale Shipping6.0-b2b-wholesale-shipping.md已实现freight summary 是装箱清单打印的数据源。批发运输计划还明确了一条与本计划相关的边界货运单据提单、托盘标牌、装箱清单绝不放进Spree::ShippingLabel那张表存放带成本和退款生命周期的承运商标签而是进入Spree::OrderDocument或本计划的客户端打印。仓库中 freight 数据已落地于 freight.rb、delivery_rate.rb、delivery_rate_provider/freight.rb 等文件。依赖三B2B Payment Terms6.0-6.1-b2b-payment-terms.md草稿中条款快照与银行参考喂给付款指示单。该计划同时预告了PaymentMethod::BankTransfer6.1加入核心、每笔付款生成存储型reference、以及 storefront pay-balance 路由——付款指示单正是把这些信息落到可打印载体的出口。迁移路径三阶段落地计划给出的落地顺序清晰且明确Nothing to migrate——没有数据迁移需求Schema model admin 嵌套 CRUD dashboard 卡片先打通存储与管理面Store 表面文档列表 买家上传打通买家可见性链路两类打印装箱清单区块、付款指示单最后补上输出面。由于 6.0 的 PO 文档po_document与 freight summary 已实现、payment terms 仍在草稿付款指示单的实际数据依赖会随 payment-terms 计划的推进而就绪。约束与边界Constraints on Current Work计划对后续实现设定了三条硬约束值得任何计划读者铭记订单面向的文件必须走OrderDocument或专属语义槽位如po_document——绝不允许在其他模型上挂松散附件。这是架构纪律附件必须可检索、可控制可见性而不是散落在任意模型上。OSS 中禁用发票词汇——任何模型、编号或文档都不得命名为 invoice付款文档只能叫payment instructions付款指示。这既是合规谨慎也是产品边界法定编号是 Enterprise terms/invoicing 的领域。打印必须渲染po_number与付款参考号存在时——PO 计划确立的文档约束在此延续保证会计人员无论手拿哪个参考号都能对上同一笔交易。刻意不做的事与开放问题计划的Open Questions 为空但有一项刻意的取舍值得强调不把生成的打印自动附加为存储文档。理由是——a print is a view of live data; a stored artifact is an invoicing feature打印是对实时数据的视图条款或物流数据变了打印跟着变而存储工件属于发票产品线。这一区分贯穿全计划6.1 的文档区域只处理上传的真实文件打印只是实时数据的输出窗口两者不混为一谈。总结6.1-b2b-order-documents.md为 Spree 的 B2B 能力补齐了最后一块订单拼图通过Spree::OrderDocument让纸质文档获得订单归属、私有存储与细粒度可见性通过两类客户端打印箱级装箱清单、付款指示单让 freight summary 与 payment terms 这些已就绪的数据获得出口。整个设计遵循四条一贯原则附件归口单一模型、打印不产生存储工件、OSS 不引入 PDF 与发票词汇、数据读取以冻结快照为准。它同时为 Enterprise 的 terms/invoicing 产品留下清晰的挂载点——未来若需服务端 PDF 渲染与法定编号将在商业产品线中到来OSS 的上传与打印路径无需为此改动。延伸阅读上游依赖docs/plans/6.0-b2b-customer-po-numbers.md、docs/plans/6.0-b2b-wholesale-shipping.md、docs/plans/6.0-6.1-b2b-payment-terms.md相邻计划docs/plans/6.1-order-stages.md买家订单视图的阶段与预计日期、docs/plans/6.0-document-numbers.md编号机制核心从不承诺法定编号打印先例packages/dashboard/src/lib/packing-slip.ts客户端 HTML 打印的完整实现附件先例spree/core/app/models/spree/tax_exemption_certificate.rb私有附件 10 MB 上限、spree/core/app/models/spree/seller_requirement_submission.rb防伪造内容类型校验、spree/core/app/models/concerns/spree/purchase/purchase_order.rbPO 文档的完整实现物流数据来源spree/core/app/models/spree/freight_summary.rb装箱清单打印区块消费的数据结构【免费下载链接】spreeOpen Source eCommerce Platform for B2B, Marketplace, and Enterprise. REST API, TypeScript SDK, and production-ready Next.js storefront. Self-host it. Own your stack. No vendor lock-in. Zero platform fees.项目地址: https://gitcode.com/GitHub_Trending/sp/spree创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考