资讯动态

Mailchimp Open Commerce 履约体系详解:api-plugin-fulfillment 基础插件如何构建 Fulfillment Type / Method 扩展框架

发布时间:2026/10/14 3:15:03 来源:尧图企业网站定制
后端电商【免费下载链接】reactionProject has been discontinued ////// Mailchimp Open Commerce is an API-first, headless commerce platform built using Node.js, React, GraphQL. Deployed via Docker and Kubernetes.项目地址https://gitcode.com/gh_mirrors/re/reaction点击查看免费下载本篇围绕仓库中 packages/api-plugin-fulfillment/README.md 文档展开讲解 Mailchimp Open CommerceReaction中履约Fulfillment基础插件的定位与实现它本身不实现任何具体履约方式而是为 shipping、pickup、digital 等履约类型插件以及 flatRate、store pickup 等履约方式插件提供统一的注册机制、数据模型、GraphQL API 与报价quotes流程。读完本文你可以理解如何基于这套框架编写自己的履约类型插件和履约方式插件并清楚从「购物车请求报价」到「用户选中履约方式」的完整调用链。一、基础插件的角色README 核心观点的源码印证README 的核心论点可以归纳为三句话这是一个基础履约插件其作用是让其他履约类型shipping、pickup、digital 等与履约方式shipping、store、download 等能够以各自独立的插件形式被引入系统它提供实现履约所需的通用能力collections、GraphQL schema、queries/mutations、schema 扩展、报价分发等每个新引入的履约类型插件其对应的具体履约方式也必须作为独立的插件添加。例如pickup类型下可以有store pickup和curb-side pickup两种方式每一种都是一个单独插件。仓库的目录结构与这一设计完全对应层级插件包职责基础层api-plugin-fulfillment通用模型、API、注册机制类型层api-plugin-fulfillment-type-shipping、api-plugin-fulfillment-type-pickup注册履约类型枚举值并在 startup 时创建类型根记录方式层api-plugin-fulfillment-method-shipping-flat-rate、api-plugin-fulfillment-method-shipping-dynamic-rate、api-plugin-fulfillment-method-pickup-store实现具体报价逻辑向类型下注入方法记录应用侧的插件装配关系可以直接在 apps/reaction/plugins.json 中看到fulfillment、fulfillmentTypeShipping、fulfillmentTypePickup、fulfillmentMethodShippingFlatRate、fulfillmentMethodShippingDynamicRate、fulfillmentMethodPickupStore被分别独立列出并加载。二、插件注册一个插件声明了什么入口是 src/index.js 中导出的register(app)函数它通过app.registerPlugin声明了基础插件的全部能力逐项来看collections注册Fulfillment与FulfillmentRestrictions两个 MongoDB 集合并声明索引Fulfillmentname: 1、shopId: 1—— 履约类型按店铺隔离一条文档代表一个店铺下的一种履约类型其methods数组内嵌该类型下的所有履约方式FulfillmentRestrictionsmethodIds: 1—— 履约限制规则集合按方法 ID 索引。graphQL注入 schema.graphql 与 resolvers。queries / mutations注入内部查询与变更函数见第五节。functionsByTyperegisterPluginHandler: [registerPluginHandlerForFulfillmentTypes]—— 供子插件注册履约类型名preStartup/startup—— 启动钩子见第七节。contextAdditions向请求上下文注入fulfillment对象见下节。simpleSchemas注册MethodEmptyData。shopSettingsConfig注册店铺设置项baseFulfillmentTypesForShop字符串数组可选控制「每个新建商品默认附加哪些履约类型」编辑权限为reaction:legacy:fulfillmentTypes/update:settings。2.1 注册处理器子插件如何「登记」履约类型src/registration.js 维护一个全局对象export const fulfillment { registeredFulfillmentTypes: [undecided] }; export function registerPluginHandlerForFulfillmentTypes({ registeredFulfillmentTypes }) { if (registeredFulfillmentTypes) { fulfillment.registeredFulfillmentTypes fulfillment.registeredFulfillmentTypes.concat(registeredFulfillmentTypes); } FulfillmentTypeDeclaration.validate(fulfillment); }基础插件自身只预置undecided这一兜底类型对应 GraphQL 枚举中的默认值。类型插件则通过插件描述里的registeredFulfillmentTypes字段向该数组追加自己的类型。以 api-plugin-fulfillment-type-pickup/src/index.js 为例await app.registerPlugin({ label: Fulfillment Type Pickup, name: fulfillment-type-pickup, ... functionsByType: { startup: [startup] }, registeredFulfillmentTypes: [pickup] });registerPluginHandlerForFulfillmentTypes正是框架在加载插件时按functionsByType.registerPluginHandler类型回调的钩子完成「类型名登记」这一动作。三、数据模型SimpleSchema 定义与跨插件 Schema 扩展3.1 核心 Schemasrc/simpleSchemas.js 定义了本插件的文档模型FulfillmentTypeSchemaFulfillment集合的文档结构字段类型说明nameString履约类型显示名用户可编辑shopIdString所属店铺 IDproviderProviderSchema内嵌对象enabled(Boolean)、label(String)、name(String)fulfillmentTypeString类型标识如shipping、pickup应用使用、用户不可编辑displayMessageTypeString?特定于该类型的 UI 附加提示methodsFulfillmentMethodSchema[]?该类型下的履约方式数组createdAt/updatedAtDate时间戳必填FulfillmentMethodSchema内嵌于类型的methods数组字段类型说明costNumber?可选成本fulfillmentTypesString[] (minCount 1)适用类型向后兼容字段groupString方法所属分组handlingNumber手续费enabledBoolean是否启用labelStringUI 显示名nameString方法唯一标识用户可编辑名fulfillmentMethodString?应用内部用的方法名如flatRate用户不可编辑displayMessageMethodString?特定于该方法的 UI 附加提示rateNumber费率UserEditableFulfillmentMethodSchema只保留了cost、handling、enabled、label、displayMessageMethod、rate六个可编辑字段用于updateFulfillmentMethod的入参校验。MethodEmptyData定义了一个空占位对象gqlType: String 可选emptyData: Boolean作为methodAdditionalData的默认形态。3.2 extendFulfillmentSchemas把「类型白名单」注入其他插件extendFulfillmentSchemas(schemas, allFulfillmentTypesArray)是本插件preStartup阶段调用的关键函数。它用SimpleSchema.extend把「所有已注册履约类型组成的白名单数组」写入其他插件的 schema 定义中涉及Product/CatalogProduct的supportedFulfillmentTypes.$allowedValuesShipment的typeCartItem的selectedFulfillmentType与supportedFulfillmentTypes.$CommonOrder的fulfillmentTypeorderFulfillmentGroupInputSchema/OrderFulfillmentGroup的type同时向SelectedFulfillmentOption和ShippingMethod追加methodAdditionalData字段SimpleSchema.oneOf(MethodEmptyData)可选为方式插件扩展自己的附加数据结构预留扩展点。也就是说基础插件是全局履约字段校验规则的中枢类型插件只负责登记类型名商品、购物车条目、发货单上的履约类型字段合法性则由这里统一收口。3.3 GraphQL 层的数据类型schemas/schema.graphql 定义了完整的对外模型enum FulfillmentType基础插件只声明undecided一个值其余枚举值如shipping、pickup由类型插件的 schema 追加扩展源码注释写明 extended by fulfillment-type pluginstype EmptyDataunion AdditionalData EmptyData方法附加数据的多态容器resolvers/index.js 中的AdditionalData.__resolveType依据obj.gqlType做类型解析方式插件会以相同模式追加 union 成员。例如 api-plugin-fulfillment-method-pickup-store/src/preStartup.js 会在preStartup阶段把自己的 MethodStoreData含storeId、storeAddress、storeTiming等门店字段extend 进ShippingMethod与SelectedFulfillmentOption的methodAdditionalData定义type FulfillmentMethodObj方法根对象cost、handling、rate、enabled、label、name、fulfillmentMethod、group、fulfillmentTypestype CustomFulfillmentMethodObj在方法对象上额外带出fulfillmentTypeId与shopId供按类型分页查询方法时使用type FulfillmentTypeObj/ProviderInfo类型根对象与供应商信息Relay 风格的 Connection 分页类型FulfillmentTypeObjConnection、FulfillmentMethodObjConnection及对应 Edge。四、GraphQL 查询与变更 API4.1 Queryschema.graphql 暴露三个查询Resolver 实现分别位于fulfillmentType(fulfillmentTypeId, shopId)src/queries/fulfillmentType.js先校验reaction:legacy:fulfillmentTypes/read权限再按_id shopId查询fulfillmentTypes(shopId, after/before/first/last/offset)src/queries/fulfillmentTypes.js返回Fulfillment.find({ shopId })游标fulfillmentMethods(shopId, fulfillmentTypeId, after/before/first/last/offset)src/queries/fulfillmentMethods.js 使用聚合管道先把匹配的Fulfillment文档$unwind: $methods再$replaceRoot合并出fulfillmentTypeId与shopId——因为方法是以数组形式内嵌在类型文档里的聚合是把它「拍平」为独立节点的必要手段。另外ShopSettings被扩展了baseFulfillmentTypesForShop: [FulfillmentType]字段同时扩展了ShopSettingsUpdatesinput语义是「将添加到每个新建商品上的默认履约类型列表」。4.2 MutationGraphQL 层只暴露两个面向管理端的变更schema.graphql而内部 mutations 更完整src/mutations/index.jsMutation说明updateFulfillmentType(input)更新类型的name、enabled、label、displayMessageType实现见 src/mutations/updateFulfillmentType.js校验reaction:legacy:fulfillmentTypes/update权限后按_id shopId执行$setupdateFulfillmentMethod(input)更新方法的可编辑字段入参UpdateFulfillmentMethodInfo需给出shopId、fulfillmentTypeId、methodId与UserEditableMethodInputlabel/displayMessageMethod/cost/handling/rate/enabled均可选selectFulfillmentOptionForGroup内部 mutation由 GraphQL resolver 层调用从购物车的shipmentQuotes中选出指定fulfillmentMethodId的报价写入该组的shipmentMethod并saveCart见 src/mutations/selectFulfillmentOptionForGroup.jsupdateFulfillmentOptionsForGroup内部 mutation重新拉取某履约组的报价quotes并回写购物车见 src/mutations/updateFulfillmentOptionsForGroup.js4.3 关键 mutation 的实现细节createFulfillmentTypesrc/mutations/createFulfillmentType.js用FulfillmentTypeSchema.clean(input)清洗入参并把provider.name强制对齐为name明确「虽然 schema 允许methods但创建类型时不允许同时携带方法」——方法应由方式插件通过createFulfillmentMethod注入这一点直接呼应了 README 中「方式必须是独立插件」的设计幂等处理若{ shopId, fulfillmentType }已存在则仅Logger.warn并直接返回不抛错新插入前校验reaction:legacy:fulfillmentTypes/create权限用Random.id()生成_id。对应的测试 src/mutations/createFulfillmentType.test.js 覆盖了三个路径缺少必填字段报Name is required、类型已存在时跳过权限校验直接返回、以及正常插入。createFulfillmentMethodsrc/mutations/createFulfillmentMethod.js校验reaction:legacy:fulfillmentMethods/create权限后先确认目标类型存在若该类型下已有同fulfillmentMethod名的方法则幂等返回否则为方法生成_id、自动把fulfillmentTypes设为[该类型的 fulfillmentType]再用$addToSet: { methods: method }追加到类型文档的methods数组。五、报价流程fulfillmentMethodsWithQuotes 的分发机制这是基础插件「通用能力」中最核心的一环src/queries/fulfillmentMethodsWithQuotes.js。流程可以拆解为前置检查commonOrder.items为空直接返回空数组调用 extendCommonOrder 把订单条目用 Catalog 中真实的商品/变体数据而非客户端数据合并补全并串联执行所有addShippingRestrictionCustomAttributes类型的函数以收集限制所需的标签与自定义属性按类型分发commonOrder.fulfillmentType指定本次要报价的履约类型基础插件从context.getFunctionsOfType(fulfillmentMethodsWithQuotes)中筛选func.key fulfillmentTypeInGroup的所有 handler 并行执行Promise.all失败重试一次各方式插件会把处理失败的请求登记进retrialTargets首轮结束后若非空则整体重试一轮仍失败则Logger.warn记录出错的 package返回所有方式插件写入rates的报价数组。方式插件正是通过functionsByType.fulfillmentMethodsWithQuotes挂载自己的 handler。以 api-plugin-fulfillment-method-shipping-flat-rate/src/index.js 为例functionsByType: { preStartup: [fulfillmentMethodShippingFlatRatePreStartup], validateOrderMethods: [{ key: flatRate, handler: validateOrderMethodsFlatRate, name: validateOrderMethodsFlatRate }], fulfillmentMethodsWithQuotes: [ { key: shipping, handler: fulfillmentMethodsWithQuotesShippingFlatRate, name: fulfillmentMethodsWithQuotesShippingFlatRate } ] }key: shipping即声明「我负责 shipping 类型下的报价」与类型插件登记的registeredFulfillmentTypes形成闭环。此外 src/queries/getFulfillmentMethodsWithQuotes.js 是 5.0 起标记为 deprecated 的别名直接转发给fulfillmentMethodsWithQuotes仅为向后兼容保留。购物车侧的完整链路在 src/mutations/updateFulfillmentOptionsForGroup.js 中体现取出购物车 →removeMissingItemsFromCart清理失效商品 →getCommonOrderForCartGroup构造该履约组的 CommonOrder → 调用fulfillmentMethodsWithQuotes拿到 rates → 用getShipmentQuotesQueryStatus归一化出shipmentQuotes与shipmentQuotesQueryStatus区分pending/success/error三种状态→ 仅当报价或状态有变化时saveCart。随后用户在结算页做选择走selectFulfillmentOptionForGroup校验所选fulfillmentMethodId必须存在于当前组的shipmentQuotes中防止选择已被刷新掉的报价再把对应option.method写入组的shipmentMethod。六、启动流程与数据库迁移6.1 preStartup版本检查 Schema 扩展src/preStartup.js 做两件事通过reactioncommerce/db-version-check校验reaction_api_plugin_fulfillment命名空间的数据库版本是否为期望的2setToExpectedIfMissing回调中只有当Fulfillment与FulfillmentRestrictions两个集合均为空或不存在时才把版本直接置为期望值避免对已有数据误判从context.fulfillment.registeredFulfillmentTypes此时已由各类型插件填好取值调用extendFulfillmentSchemas完成上一节所述的白名单注入。6.2 startupundecided 兜底类型src/startup.js 监听appEvents的afterShopCreate事件每个新店铺创建后若Fulfillment集合中不存在{ fulfillmentType: undecided, shopId }记录则自动插入一条name: Undecided Type、provider 为{ enabled: true, label: Undecided, name: undecided }的根记录作为用户在尚未选定履约类型时的占位。类型插件遵循同一模式api-plugin-fulfillment-type-pickup/src/checkAndCreateFulfillmentType.js 在 startup 时为每个店铺幂等创建pickup类型记录方式插件同理api-plugin-fulfillment-method-pickup-store/src/startup.js 遍历所有店铺每个店铺一个事务确保门店自提方法存在并监听afterShopCreate覆盖新店铺。6.3 迁移从 Shipping 到 Fulfillment 的更名migrations/2.js注册于 migrations/index.js记录了这套模型从「shipping 专用」到「通用履约」的演进up用聚合把旧Shipping集合整体$out复制为新Fulfillment集合、FlatRateFulfillmentRestrictions复制为FulfillmentRestrictions为缺失fulfillmentType的文档补写fulfillmentType: shipping用arrayFilters为已有methods批量补写fulfillmentMethod: flatRate并把 Groups 中的旧权限reaction:legacy:shippingMethods/*、shippingRestrictions/*映射替换为reaction:legacy:fulfillmentTypes/*、fulfillmentMethods/*、fulfillmentRestrictions/*down从受影响 Groups 中pullAll新权限并 drop 两个新集合。这也解释了为何 GraphQL schema 中仍保留Shipment、ShippingMethod等命名源码注释中多处提到 retained for backward compatibility。七、不透明 ID 与工具src/xforms/id.js 定义了reaction/shop、reaction/cart、reaction/fulfillmentGroup、reaction/fulfillmentMethod四个命名空间的 opaque id 编解码函数其中FulfillmentMethod._id的 resolversrc/resolvers/FulfillmentMethod/index.js即用encodeFulfillmentMethodOpaqueId把内部 ID 包装为不透明 ID 输出给客户端。八、本地开发与测试按 package.json 的声明该包要求 Node14.18.1、npm7依赖simpl-schema、lodash与同仓库的api-utils、reaction-error、random、db-version-check等包。常用脚本# 在 packages/api-plugin-fulfillment 目录下 npm test # 运行 jest npm run lint # eslint测试集中在每个 mutation 同目录的*.test.js如 createFulfillmentType.test.js、selectFulfillmentOptionForGroup.test.js通过reactioncommerce/api-utils/tests/mockContext.js与mockCollection构造 mock 上下文与集合分别验证必填校验、幂等返回、正常写入三类行为src/tests/factory.js 则提供了测试用的工厂数据。九、小结三层插件架构的完整图景把 README 的设计主张与源码对照可以得到这张扩展地图基础插件本文主角提供Fulfillment/FulfillmentRestrictions集合、SimpleSchema 模型与全局白名单扩展、GraphQL 查询/变更、registerPluginHandlerForFulfillmentTypes登记机制、fulfillmentMethodsWithQuotes报价分发、购物车选择/刷新报价 mutation以及undecided兜底类型的 startup 逻辑类型插件如 fulfillment-type-shipping / fulfillment-type-pickup只需通过registeredFulfillmentTypes登记类型名、追加 GraphQL 枚举值并在 startup 时为店铺创建类型根记录方式插件如 fulfillment-method-shipping-flat-rate / fulfillment-method-pickup-store通过functionsByType.fulfillmentMethodsWithQuotes按类型 key挂载报价实现、通过createFulfillmentMethod注入方法记录、通过preStartup把自己的MethodXxxData扩展进methodAdditionalData并可追加validateOrderMethods校验器。对要扩展新履约能力例如 digital 下载方式或 curb-side pickup的开发者而言正确的落点正是 README 所强调的新建类型插件登记类型名 新建方式插件实现报价与附加数据而不是修改基础插件本身。赞分享后端电商【免费下载链接】reactionProject has been discontinued ////// Mailchimp Open Commerce is an API-first, headless commerce platform built using Node.js, React, GraphQL. Deployed via Docker and Kubernetes.项目地址https://gitcode.com/gh_mirrors/re/reaction点击查看免费下载相关推荐ReactionMailchimp Open Commerce中 shipping 履约类型的注册与初始化机制api-plugin-fulfillment-type-shipping 源码解析ReactionMailchimp Open Commerce中 shipping 履约类型的注册与初始化机制api plugin fulfillment后端电商Reaction Commerce pickup 履约类型插件api-plugin-fulfillment-type-pickup 的实现与运行机制解析Reaction Commerce pickup 履约类型插件api plugin fulfillment type pickup 的实现与运行机制解析 本文后端电商Reaction 门店自提履约方法插件实现解析api-plugin-fulfillment-method-pickup-storeReaction 门店自提履约方法插件实现解析api plugin fulfillment method pickup store 本篇技术指南围绕 Reac后端电商上一篇SkillOpt-Sleep 接入 Codex用 AGENTS Skills 给本地 Codex Agent 搭建夜间自我进化Sleep Cycle实战指南下一篇react-admin 锁机制实战useLockOnMount 实现记录级并发编辑保护创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑