供需撮合
受众:开发者、平台管理员 摘要:Marketplace 模块用于承载供需发布、撮合订单和撮合结算。它不替代商城交易,也不承载商品库存、支付和售后。
模块边界
spring-open-module-marketplace 面向供需信息流和轻量撮合流程:
- API 前缀:
/api/v1/marketplace/**。 - 管理 API 前缀:
/api/v1/admin/marketplace/**。 - 配置前缀:
spring.open.marketplace.*。 - 数据库表前缀:
marketplace_。 - 权限码前缀:
marketplace:*。
Marketplace 保存撮合相关标量 ID,不直接依赖 Mall 商品、库存、订单、支付或售后实体。结算打款通过 Money 提现流水记录打款引用,后续对账和外部支付状态再通过 Money / Cashier 的稳定 contract 衔接。
供需信息管理
后台供需信息入口基于 marketplace_listing 表提供首段管理 contract:
| 能力 | 接口 |
|---|---|
| 分页查询 | GET /api/v1/admin/marketplace/listings |
| 查询详情 | GET /api/v1/admin/marketplace/listings/{id} |
| 查询推广运营统计 | GET /api/v1/admin/marketplace/listings/promotion-statistics |
| 审核通过并发布 | POST /api/v1/admin/marketplace/listings/{id}/review/approve |
| 驳回审核 | POST /api/v1/admin/marketplace/listings/{id}/review/reject |
| 调整展示状态 | PUT /api/v1/admin/marketplace/listings/{id}/status |
分页支持按编号 / 标题关键字、供需类型、分类、地区、发布者、展示状态和审核状态筛选。展示状态当前使用 draft、published、offline、closed;审核状态使用 pending、approved、rejected。审核通过会将供需信息推进到 published 并补齐发布时间;驳回只写审核状态,已发布记录被驳回时会下线为 offline。
供需信息查询需要 marketplace:listing:view;审核和状态调整需要 marketplace:listing:review。
撮合订单
后台订单入口基于 marketplace_order 表提供管理 contract:
| 能力 | 接口 |
|---|---|
| 分页查询 | GET /api/v1/admin/marketplace/orders |
| 查询详情 | GET /api/v1/admin/marketplace/orders/{id} |
| 查询撮合运营统计 | GET /api/v1/admin/marketplace/settlements/statistics |
| 批准退款申请 | POST /api/v1/admin/marketplace/orders/{id}/refund/approve |
| 驳回退款申请 | POST /api/v1/admin/marketplace/orders/{id}/refund/reject |
| 执行已批准退款 | POST /api/v1/admin/marketplace/orders/{id}/refund/execute |
| 同步退款状态 | POST /api/v1/admin/marketplace/orders/{id}/refund/compensate |
分页支持按订单编号 / 支付引用关键字、供需信息 ID、买方 ID、卖方 ID 和订单状态筛选。当前订单状态使用 created、paid、confirmed、cancelled、refunded。
撮合订单查询和详情需要 marketplace:order:view。撮合运营统计需要 marketplace:settlement:view,会聚合当前订单、退款、结算、风险复核、对账状态和结算金额,供 Admin 订单页顶部展示待处理退款、待审结算、复核超时和对账异常。退款申请审核、退款执行和退款状态同步需要 marketplace:order:refund-review。Admin 退款审核只处理用户提交的 refundStatus=requested 申请,把 approved / rejected、审核人、审核时间和审核备注写回订单扩展 JSON。退款执行只允许 approved 或 execute_failed 状态进入,使用订单 paymentRefId 查找 Cashier 支付单,通过 Payment refund contract 调用支付 Provider,并用稳定 refundNo=marketplace-refund-{orderNo} 做幂等;Provider 返回已退款 / 成功时同步 Cashier refundedAmount 和支付单状态,Marketplace 订单推进到 refunded,执行人、执行时间、退款单号、Provider 状态、交易号和 trace 写入订单扩展 JSON。Provider 异步退款通知进入 Cashier 后,Marketplace 会按 Cashier outTradeNo 反查订单 paymentRefId,仅在退款已批准、执行中或执行失败的状态机内幂等推进 refunded,不会处理无关 Cashier 退款。退款状态同步只允许 executing / execute_failed 进入,不会重复调用 refund,只通过 Payment query 查询 Provider 状态;只有查询结果明确为已退款时才补偿 Cashier 和 Marketplace 状态,否则仅记录同步人、同步时间、同步 trace、Provider 状态和消息。Marketplace 不私改 Money 账户余额或账本。
用户侧订单入口基于当前登录用户参与关系隔离查询,只返回买方或卖方与自己相关的撮合订单:
| 能力 | 接口 |
|---|---|
| 查询我的撮合订单 | GET /api/v1/marketplace/orders |
| 查询我的撮合订单详情 | GET /api/v1/marketplace/orders/{id} |
| 买方确认已支付订单 | POST /api/v1/marketplace/orders/{id}/confirm |
| 取消创建态订单 | POST /api/v1/marketplace/orders/{id}/cancel |
| 买方提交退款申请 | POST /api/v1/marketplace/orders/{id}/refund-request |
用户侧订单返回体会附带退款申请、退款执行、退款同步和结算摘要字段:refundStatus、refundReason、refundRequestedAt、refundReviewedBy、refundReviewedAt、refundReviewRemark、refundExecutedBy、refundExecutedAt、refundExecutionRemark、refundNo、refundAmount、refundPaymentOutTradeNo、refundProvider、refundProviderStatus、refundProviderCode、refundProviderMessage、refundTransactionId、refundTraceId、refundCompensatedBy、refundCompensatedAt、refundCompensationRemark、refundCompensationTraceId、refundCompensationStatus、refundCompensationCode、refundCompensationMessage、settlementNo、settlementStatus、settleAmount、settlementCurrency、settlementPaidAt。退款申请仅买方可对 paid / confirmed 订单提交,状态写入订单扩展 JSON 并保持幂等;Admin 可审核为 approved / rejected,批准后由后台执行退款入口承接 Cashier / Payment 资金动作。买方确认 paid 订单为 confirmed 后,系统会按订单号生成 SETTLE-{orderNo} 的 pending 结算单,后续审核、拆账、打款和对账继续走后台结算 contract。
用户侧供需信息
用户侧供需信息入口复用 marketplace_listing,只暴露已发布、审核通过且未过期的公开信息:
| 能力 | 接口 |
|---|---|
| 分页浏览公开供需信息 | GET /api/v1/marketplace/listings |
| 查看公开供需详情 | GET /api/v1/marketplace/listings/{id} |
| 登录用户提交供需信息 | POST /api/v1/marketplace/listings |
公开分页支持按编号 / 标题关键字、供需类型、分类和地区筛选,但会忽略调用方传入的展示状态与审核状态,只返回 published + approved 且 expiredAt 为空或未到期的数据。提交接口要求登录,listingType 仅支持 supply 和 demand;提交后记录进入 draft + pending,由后台审核通过后才会公开展示。
App 端入口为 marketplace/index 和 marketplace/detail,支持公开列表、详情和轻量发布表单。PC 端入口为 /marketplace 和 /marketplace/{id},支持筛选、分页、公开详情和发布审核提交。页面只展示当前已落地的供需信息 contract,不伪造撮合订单或结算状态。
供需刷新和置顶推广
登录发布者可以对自己已发布、审核通过且未过期的供需信息执行刷新或置顶推广:
| 能力 | 接口 |
|---|---|
| 查询公开推广定价 | GET /api/v1/marketplace/promotion/pricing |
| 查询后台推广定价 | GET /api/v1/admin/marketplace/promotion/pricing |
| 保存后台推广定价 | PUT /api/v1/admin/marketplace/promotion/pricing |
| 查询后台会员推广额度 | GET /api/v1/admin/marketplace/promotion/quota |
| 查询后台推广运营统计 | GET /api/v1/admin/marketplace/listings/promotion-statistics |
| 刷新或置顶供需信息 | POST /api/v1/marketplace/listings/{id}/promotion |
请求体使用 promotionType 指定推广动作,当前支持 refresh 和 pin;使用 fulfillmentType 指定履约方式,当前支持 entitlement 和 paid。客户端不传价格、币种、Provider 或置顶时长,后端始终读取 spring.open.marketplace.promotion.* 配置创建 Cashier 订单和计算置顶时长;remark 会写入供需信息扩展快照。
推广定价配置项:
| 配置项 | 默认值 | 说明 |
|---|---|---|
spring.open.marketplace.promotion.refresh-amount | 9.90 | 刷新展示的付费金额 |
spring.open.marketplace.promotion.pin-amount | 19.90 | 置顶推广的付费金额 |
spring.open.marketplace.promotion.currency | CNY | 付费推广订单币种 |
spring.open.marketplace.promotion.provider | mock | 付费推广订单默认支付 Provider |
spring.open.marketplace.promotion.pin-duration-hours | 24 | 单次置顶生效小时数 |
spring.open.marketplace.promotion.max-pin-duration-hours | 720 | 置顶时长安全上限 |
spring.open.marketplace.settlement.commission-rate-bps | 0 | 撮合订单平台佣金费率,单位 bps,10000 表示 100% |
spring.open.marketplace.settlement.risk-review-amount-threshold | 0 | 撮合订单触发人工风险复核的成交额阈值,单位为最小货币单位,0 表示关闭 |
spring.open.marketplace.settlement.risk-review-receiver-daily-amount-threshold | 0 | 同一收款用户当日累计成交额触发人工风险复核的阈值,单位为最小货币单位,0 表示关闭 |
spring.open.marketplace.settlement.risk-review-receiver-daily-order-count-threshold | 0 | 同一收款用户当日结算笔数触发人工风险复核的阈值,0 表示关闭 |
Entitlement 履约会即时消费额度并生效:refresh 默认消费额度项 marketplace.listing.refresh,pin 默认消费额度项 marketplace.listing.pin,consumer 为 marketplace,scope 为 listing,period 为 once,单次消耗 1。后台推广额度接口会返回这些固定 contract 和幂等键模板,Admin 供需信息页同步展示,方便运营在会员套餐里配置对应额度项。Paid 履约会创建 Cashier 支付订单,支付场景为 marketplace-listing-promotion,订单属性写入供需 ID、供需编号、发布者、推广类型和置顶时长;Cashier 支付成功回调后由 Marketplace 幂等生效推广,幂等字段为 lastPromotionOrderNo。
App marketplace/detail 和 PC /marketplace/{id} 已读取公开推广定价并提供付费刷新、付费置顶入口。页面只负责展示服务端定价、创建推广订单,拿到 outTradeNo 后跳转统一收银台;法币和 Web3 代币等支付方式由 Cashier 根据当前环境、Provider 配置和支付订单状态统一呈现,不在 Marketplace 页面单独拆支付入口。Admin 供需信息页展示当前刷新 / 置顶价格、Provider、置顶时长和推广运营快照,并支持直接编辑推广定价;保存后写入配置中心 spring.open.marketplace.promotion.*,后端推广下单通过 ConfigManager 运行期读取,不需要重启应用。运营快照基于当前 marketplace_listing 字段统计总供需、已推广供需、已刷新供需、置顶供需、有效置顶、付费推广订单和最近推广时间,不伪造历史趋势。
刷新会更新 lastRefreshedAt,公开分页会在有效置顶之后按最近刷新时间排序。置顶会写入 pinnedUntil,如果原置顶仍有效,会从原置顶截止时间继续延长。
撮合结算
后台结算入口基于 marketplace_settlement 表提供首段管理 contract:
| 能力 | 接口 |
|---|---|
| 分页查询 | GET /api/v1/admin/marketplace/settlements |
| 查询详情 | GET /api/v1/admin/marketplace/settlements/{id} |
| 查询拆分账本 | GET /api/v1/admin/marketplace/settlements/{id}/ledger |
| 汇总统计 | GET /api/v1/admin/marketplace/settlements/summary |
| 风险审计摘要 | GET /api/v1/admin/marketplace/settlements/risk-audit |
| 风险复核明细 | GET /api/v1/admin/marketplace/settlements/risk-review-report |
| 补偿计划 | GET /api/v1/admin/marketplace/settlements/compensation-plan |
| 审核通过 | POST /api/v1/admin/marketplace/settlements/{id}/review/approve |
| 驳回 | POST /api/v1/admin/marketplace/settlements/{id}/review/reject |
| 记录风险复核 | POST /api/v1/admin/marketplace/settlements/{id}/risk-review |
| 标记打款 | POST /api/v1/admin/marketplace/settlements/{id}/pay |
| 重试打款 | POST /api/v1/admin/marketplace/settlements/{id}/retry-payout |
| 同步打款结果 | POST /api/v1/admin/marketplace/settlements/{id}/sync-payout |
| 回写对账结果 | POST /api/v1/admin/marketplace/settlements/{id}/reconciliation |
分页支持按结算编号关键字、订单 ID、收款用户 ID、状态和是否需要风险复核筛选。结算返回体会解析扩展快照中的 riskReviewRequired、riskReviewReason 和 commissionRateBps,并根据 spring.open.marketplace.settlement.risk-review-sla-hours 计算 riskReviewDueAt、riskReviewOverdue 和 riskReviewSlaHours。后台可使用“仅需复核”开关形成待人工复核队列,并在状态列和详情抽屉展示风险原因、复核截止时间、超时标识和佣金费率。汇总返回待审核、已审核、已打款、已驳回数量,以及总金额、佣金、结算金额、待打款金额和已打款金额。
买方确认撮合订单后,Marketplace 会幂等创建 pending 结算单:收款方为卖方,成交总额来自订单金额,平台佣金按 spring.open.marketplace.settlement.commission-rate-bps 计算,默认 0,应结算金额为成交总额扣减平台佣金后的金额。成交额达到 spring.open.marketplace.settlement.risk-review-amount-threshold、同一收款用户当日累计成交额达到 spring.open.marketplace.settlement.risk-review-receiver-daily-amount-threshold,或同一收款用户当日结算笔数达到 spring.open.marketplace.settlement.risk-review-receiver-daily-order-count-threshold 时,结算单扩展快照会标记 riskReviewRequired=true,并写入 riskReviewReason / riskReviewReasons 供后台人工复核;该标记不新增状态机,审核 / 驳回仍走既有结算审核入口。结算佣金、风险复核阈值和复核 SLA 均优先读取配置中心,@ConfigurationProperties 只作为运行期配置不可用时的兜底。拆分账本接口读取 marketplace_settlement_ledger,用于后台追踪同一结算单的成交总额、平台佣金、收款方应结算额和收款方打款记录。审核通过时写入三条 booked 账本:gross_amount、platform_commission 和 receiver_settle_amount;标记打款或失败重试打款成功创建新提现流水时写入 receiver_payout 账本。账本使用 ledgerKey 幂等,避免重复审核、同步或重试链路造成重复分账记录。
风险复核处理入口只允许操作待审核且已标记需复核的结算单。请求体使用 decision 记录复核结论,当前支持 approved、need_more_info 和 reject_recommended;使用 action 记录处理建议,当前支持 continue、hold 和 reject。该入口会把复核结论、处理建议、复核备注、处理人和处理时间写入结算扩展快照,供 Admin 详情抽屉审计展示;它不会直接改变结算状态,真正审核通过或驳回仍必须走结算审核状态机。
风险审计摘要会直接读取当前结算单和扩展快照,聚合需复核、已处理、待处理、超时、对账异常、人工对账和缺少打款 Provider 的数量,并按风险原因、复核动作、对账状态和打款 Provider 输出分桶。该接口只用于后台运营审计和跨渠道结算排查,不新增报表表、不修改结算状态、不触发 Money / Cashier 写入;Admin 结算页会在列表上方展示这些指标,帮助运营定位高额复核、对账异常和打款渠道缺失。
风险复核明细接口会返回最近 50 条需复核结算单,按复核超时优先、未处理优先和创建时间稳定排序,包含结算编号、订单、收款人、应结金额、复核原因、处理结论、处理建议、处理人、处理时间、复核截止时间、对账状态和打款 Provider。该接口只读复用 marketplace_settlement.extra_json,不新增报表表、不修改结算状态、不触发 Money / Cashier / Payment 写入;Admin 结算页会在风险审计卡片中展示明细,方便运营从摘要指标下钻到具体结算单。
补偿计划接口会筛选待打款、Money 提现仍在处理、提现状态失败 / 驳回 / 取消、对账不匹配、人工对账、以及已打款但缺少 Provider / 提现 / 交易号引用的结算单,并给出 execute-payout、sync-payout、retry-payout、reconcile-difference、manual-review-compensation 或 register-payout-reference 建议动作。该接口只读返回运营提示,不直接触发出款、不补写 Money / Cashier / Payment 状态;实际处理仍需通过既有打款、同步、重试和对账入口完成。
标记打款接口兼容旧的 { "remark": "..." } 请求体,也支持携带 Money 打款信息:
| 字段 | 含义 |
|---|---|
provider | 打款 Provider;为空时使用 Money 手工打款 Provider。 |
destinationType | 收款目标类型;为空时使用 Money 手工收款目标。 |
payeeName | 收款人名称。 |
payeeAccount | 收款账号。 |
transactionId | 外部打款交易号。 |
remark | 打款备注。 |
Money 提现服务可用时,Marketplace 会用 marketplace:settlement:payout:{settlementNo} 作为幂等键创建提现流水,并在结算单记录 payoutWithdrawId、payoutWithdrawNo、payoutProvider 和 payoutTransactionId,方便后台详情和后续对账追踪。
重试打款接口用于 Money 提现状态已进入 failed、rejected 或 canceled 的结算单。结算单处于 approved 或 paid 都可以发起重试,接口会先读取原提现流水;如果原提现仍在 processing,会先通过 Money syncPayout 查询外部状态。确认原提现失败后,Marketplace 使用 marketplace:settlement:payout:{settlementNo}:retry:{oldWithdrawNo} 作为新幂等键重新创建提现流水,并把结算单的提现引用切换到新流水,避免和上一笔失败提现共用幂等键。若原提现已成功支付,接口只同步成功结果,不会重复创建打款流水。
同步打款结果接口从 Money 提现流水读取当前状态:
- Money 提现仍为
processing时,Marketplace 会先调用 MoneysyncPayout,由 Money 的 Payment / Cashier 打款 Provider 查询外部打款状态,再使用查询后的提现状态回写结算单。 - Money 提现为
paid时,Marketplace 结算单回写为paid,并同步paidAt、Provider 和外部交易号。 - Money 提现为
failed、rejected或canceled时,Marketplace 结算单回滚为approved,清空paidAt,保留提现流水引用用于追踪和重试。 - 同步快照会写入
extra_json,包含提现单号、提现状态、Provider、交易号、traceId、同步时间和必要的回滚状态。
Money 提现状态也是 Provider 异步打款回调的事实入口。Payment / Cashier / 银行转账 / Web3 放款等 Provider 把结果同步到 Money 提现单后,Money 会通过提现状态处理器通知业务模块;Marketplace 只消费已经写入本结算单的 payoutWithdrawId 或 payoutWithdrawNo,并复用上面的 paid / failed / rejected / canceled 状态规则同步结算结果。未关联 Marketplace 结算的 Money 提现会被跳过,业务处理器异常不会回滚 Money 提现状态。
对账结果回写接口只允许操作已打款结算单。请求体中的 status 支持 matched、mismatched 和 manual_review;当状态为 matched 且请求携带 amount 或 currency 时,金额和币种必须与结算单一致。系统会把对账状态、对账 Provider、外部交易号、对账参考号、金额、币种、原因、备注和回写时间写入 extra_json,同时在结算单缺少打款 Provider 或外部交易号时补齐对应展示字段。这个接口只负责回写 Marketplace 对账快照,不替代 Money / Cashier 的提现状态同步、真实支付流水或补偿流程。
状态机
撮合结算单当前使用四个状态:
| 状态 | 含义 | 可执行动作 |
|---|---|---|
pending | 待审核 | 审核通过、驳回 |
approved | 已审核,待打款 | 标记打款、失败后重试打款 |
rejected | 已驳回 | 无 |
paid | 已打款 | 同步打款结果、回写对账结果 |
审核可携带 remark,系统会写入 extra_json 的 remark 字段。标记打款和同步打款结果会在 extra_json 中记录备注、打款引用和同步快照,保持扩展字段为 JSON 语义。
权限
结算查询、详情、汇总、风险审计摘要、风险复核明细和补偿计划需要 marketplace:settlement:view。
审核通过、驳回、标记打款、重试打款、同步打款结果和回写对账结果需要 marketplace:settlement:review。
后台页面
Admin 当前已补齐 Marketplace 菜单种子对应的页面入口:
| 页面 | 状态 |
|---|---|
marketplace/listings/index | 已接入供需信息分页、详情、审核通过、驳回、展示状态调整、推广定价、会员推广额度和推广运营统计展示 contract。 |
marketplace/orders/index | 已接入撮合订单分页、详情、状态筛选、运营统计、退款申请状态展示、退款申请审核、已批准退款执行和退款状态同步 contract。 |
marketplace/settlements/index | 已接入结算分页、风险复核队列筛选、汇总、风险审计摘要、风险复核明细、补偿计划、详情、拆分账本、审核、打款、重试打款、同步打款结果和对账回写 contract。 |
用户侧页面
| 页面 | 状态 |
|---|---|
App marketplace/index | 已接入公开供需分页、类型筛选、关键词搜索、加载更多、提交审核表单、用户撮合订单和结算详情展开。 |
App marketplace/detail | 已接入公开供需详情、服务端推广定价、付费刷新和付费置顶,推广订单统一跳转 Cashier。 |
PC /marketplace | 已接入公开供需分页、类型筛选、关键词搜索、分页、提交审核表单、用户撮合订单和结算详情展开。 |
PC /marketplace/{id} | 已接入公开供需详情、服务端推广定价、付费刷新和付费置顶,推广订单统一跳转 Cashier。 |
App marketplace/index 和 PC /marketplace 同时展示“我的撮合订单”,已接入用户订单分页、确认、创建态取消、退款申请、退款申请状态、结算摘要和结算详情展开;Admin 批准、驳回、执行退款或同步退款补偿后,用户侧可查看对应状态线索,并且不再重复展示申请退款按钮。
后续边界
当前结算 contract 已完成 Marketplace 自身后台管理闭环,并衔接 Money 提现流水引用。后续扩展仍必须保持 Marketplace 只承载供需撮合、结算审计和运营复核,不把 Mall 商品交易、库存、支付和售后逻辑搬入 Marketplace。