Files
mp-pilates/docs/membership-contract.md
2026-10-29 17:34:28 +08:00

8.9 KiB
Raw Blame History

会员卡合同签署

适用范围

  • 月卡(DURATION)与多次卡(TIMES 且课时 > 1 或不限次)必须签署;单次卡、体验卡不签。判定函数为 shared 的 requiresMembershipContract。
  • 每笔支付订单对应一份合同(orderId 唯一)。次卡续费并入原会员卡时,续费订单单独签署续购合同。
  • 存量会员卡:仍在有效期且有可用权益、但没有合同覆盖的卡,按未覆盖的已支付订单金额自动生成「存量会员补签」合同;后台直接开通、没有订单的卡,由馆主在「会员合同」页填写实付金额后发起。邀请奖励赠课卡不补签。

流程

  1. 购卡确认弹窗勾选「已阅读并同意《会员卡服务合同》」,可预览合同范本;勾选时间写入 orders.contract_accepted_at。
  2. 微信支付回调在发卡事务内签发合同(PENDING_SIGN),交易事实冻结在 terms。
  3. 支付确认后跳转签署页:确认真实姓名与手机号 → 阅读全文至底部并勾选条款、健康声明 → 手写签名 → 提交。
  4. 服务端重新渲染合同并比对 SHA-256,一致才签署;同时冻结正文、学员签名、乙方签名快照、签署 IP、UA 和设备信息,并记录 contract_events。
  5. 个人中心「我的合同」查看状态、全文和双方签名,已签署合同可导出 PDF(文件内含合同编号与内容摘要)。

新购合同未签署前,学员不能用该卡自助预约(馆主代约不拦截);存量补签只提醒、不拦截。馆主可作废合同(如已线下签纸质合同、已退费),作废后解除预约拦截。

合同条款要点

条款由 server/src/contract/contract-template.ts 按卡种动态生成,模板版本 2026-10-v2。依据《消费者权益保护法实施条例》第 22 条及《最高人民法院关于审理预付式消费民事纠纷案件适用法律若干问题的解释》(2025-05-01 施行):

  • 付款 7 日内且未上课,全额退款(续费同样适用)。
  • 学员原因退费:实付 − 已用课时 × 单节标准课价,结果小于零按零,不收手续费;不限次卡按剩余天数比例退。
  • 场馆原因退费:按本卡实付单价折算已用课时,并依法计息。
  • 允许整体转让、免费延期 1 次(≤ 30 天)、伤病孕期可暂停;停业或迁址提前 30 日公告。
  • 月卡到期后可联系馆主补差升级同类课程多次卡:按本期月卡实付且未退还的金额抵扣,已用课时计入目标次卡已用课时,新有效期从补款及双方书面确认均完成之日起算;升级不影响依法退费的权利。
  • 删除了模板中「最终解释权归场馆」「到期不退任何费用」「转卡收 10%」等可能被认定无效的格式条款;与学员重大利害相关的条款加粗提示。

单节标准课价在「合同签署设置」中配置,未配置时取在售单次卡价格。

月卡到期补差升级(2026-10-29)

  • 第二条新增月卡专属条款,并在到期、合同终止条款中保留升级及依法结算的权利,不再使用「到期一律不退费」表述。
  • 目标为升级时在售的同类课程多次卡,以办理时公示售价计算差价,售价不低于可抵扣金额、总课时多于原月卡已用课时;不另收升级手续费,同一期月卡金额不得重复抵扣。
  • 示例:月卡实付 1,000 元、已用 3 节,升级售价 2,000 元的 10 次卡,补款 1,000 元,剩余 7 节。不是另赠一张完整的 10 次卡。
  • 办理前须书面确认原月卡/合同、目标次卡、抵扣与补款金额、已用及剩余课时、有效期起止;原月卡权益并入次卡,不重复使用。本次只更新合同文本,不新增自动补款、改卡或合同补充协议功能;馆主实际办理时应留存双方书面确认及收款凭证。

仅更新本次条款的发布范围

  • 合同功能已上线时,只需构建并发布 server;无 shared 类型、接口、小程序界面及数据库变更,无需为本次条款重新发布小程序。首次上线合同功能仍需完成下方原有迁移和小程序发布步骤。
  • 购卡范本、新合同及已有待签合同再次加载时使用新版正文;若用户停留在旧正文,签署时的 SHA-256 校验会拒绝提交,需重新加载阅读后签署。
  • 签署时同步保存实际正文的模板版本,避免旧待签记录仍标记 v1、正文却为 v2。已签合同的正文、版本、摘要及 PDF 保持签署时快照,不自动追加条款;如需适用于已签合同,双方另行书面确认补充约定。

配置与发布

  1. 应用迁移 20261028090000_membership_contracts(仅新增表与 orders.contract_accepted_at 列),生成 Prisma Client,再发布 shared/server。
  2. 新增依赖 pdfkit;中文字体随服务端发布在 packages/server/assets/fonts/NotoSansSC-Regular.otf(SIL OFL)。可用环境变量 CONTRACT_PDF_FONT_PATH 指向其他字体。
  3. 小程序后台「开发管理 - 服务器域名」需将 API 域名加入 downloadFile 合法域名,否则无法导出 PDF。
  4. 发布前由馆主在「管理中心 - 合同签署设置」填写经营者名称、统一社会信用代码、经营者、联系电话、经营场所。默认合同专用章见下方,经营者手写签名选填。未完善基本信息时学员可查看但不能签署。
  5. 发布新版小程序。旧版小程序购卡不会勾选同意,但仍会生成待签合同,并在新版个人中心提示签署。

默认乙方合同章

  • 场馆提供的原图保存在 packages/server/assets/contracts/party-b-seal.jpg,发布服务端时须连同 assets/ 一起部署(与 PDF 字体一致)。无需新增环境变量或数据库迁移。
  • 合同设置显示默认章;购买前范本、待签合同及签署阅读页在乙方签章区展示,经营者手写签名仍可选填并同时展示。
  • 签署时合同章以 data URI 写入合同正文 document.partyBSeal,纳入 SHA-256 校验并冻结;详情和 PDF 只使用该快照。替换默认图片后,仅影响未签合同,已签旧合同不追补印章。

回退

  • 服务端回退到上一版本即可,新增表保留不影响旧代码;不要删除 membership_contracts、contract_events,它们是签署凭证。
  • 若需临时关闭预约拦截,可在后台作废对应待签合同,或回退 booking.service.ts 中的合同检查。

风险提示

  • 自建手写签名属于一般电子签名,依靠微信身份、手机号、内容摘要、签名留存和审计日志形成证据链;如需 CA 认证的可靠电子签名,可后续接入第三方电子签服务。
  • 部分城市(如上海)对单张预付卡金额(5000 元)、资金存管和备案另有规定,请按工作室所在地核实。合同正式使用前建议请律师审阅。

验证(2026-10-28)

  • 服务端全量测试通过:38 个套件、605 项测试;新增合同模板、合同服务及预约拦截用例。
  • shared/server 构建、小程序类型检查与微信小程序生产构建通过;本地生成样例 PDF 并逐页检查排版。
  • 未在本地连接数据库做端到端验证(本地 .env 指向生产库),需在部署后按上述流程真机验收。

条款更新验证(2026-10-29)

  • 服务端 38 个测试套件、610 项测试通过,服务端构建通过。
  • 覆盖有限次/不限次月卡升级条款、到期权利保留、旧待签合同签署时保存新版版本,以及已签旧版正文和 PDF 不受模板更新影响。
  • 实现阶段未连接数据库;生产发布及只读核验结果见下方记录。

条款更新生产发布(2026-10-29)

  • 代码提交:20ef49d(feat(contract): 支持月卡到期补差升级次卡条款),已同步并保留此前合同专用章与筛选修复。
  • 发布前 shared/server 构建通过,完整服务端 38 个套件、612 项测试通过。
  • 北京时间 17:34 完成发布,线上模板版本为 2026-10-v2;仅替换合同模板、合同服务的 JS 及 source map 共 4 个运行文件,其他 server/shared 构建及资源均与发布包一致(共核对 325 个文件)。
  • 未执行数据库迁移,生产 .env、Prisma schema、依赖配置保持原样;PM2 沿用原进程配置重启并保存。
  • 内网与公网 HTTPS /api/health 均返回正常,线上运行文件生成的月卡正文包含实付抵扣及已用课时承接条款。
  • 备份、发布包、文件清单及核验记录位于服务器私有目录 /usr/local/web/releases/contract-upgrade-20261029-20ef49d/;发布包 SHA-256 为 ad0ab2491c4988266e9beb633a0c67b85f90214de0081188fce6f38763358da9。
  • 如需回退,恢复该目录 previous-build.tgz 中的运行文件后重启 mp-pilates-server;不要覆盖生产数据库或已签合同。
  • 本次未发布小程序、未创建测试订单或签署记录;实际会员端预览及签署仍需通过本人账号确认。