Skip to content

概述

续租是租赁订单在租期到期前(或逾期后)由用户端(小程序/H5/App)管理后台发起的延长租期操作。续租会在原订单上追加新的分期账单(eb_store_order_installment),更新订单租赁信息(总天数/总期数/结束时间/总租金),并同步支付宝侧(交易组件 / 租赁行业交易)的租期计划。

取消续租仅管理后台支持,用户端不允许取消续租route/api.php 无取消续租接口)。

功能入口

入口位置说明
发起续租用户端view/uniapp/pages/goods/lease_order_xuzu/index.vue订单详情/列表页「续租」按钮进入,选择天数后刷脸(e签宝)或静默签署(爱签)
发起续租管理后台view/admin/src/pages/order/leaseOrderList/components/rentDetailModal.vue(租金账单页右上「续租」按钮)输入续租天数(最多补足 90 天)与续租金额,无需人脸与合同
取消续租管理后台rentDetailModal.vue 租金账单操作栏「取消续租」(仅续租账期 & 未支付 & 最新续租批次)选择取消原因后提交

接口清单

用户端(route/api.php

方法路径控制器说明
POSTorder/relet_lease/:idapp\controller\api\v1\order\StoreOrder::reletLease发起续租($uid>0,需人脸/合同)
POSTorder/relet_price/:idapp\controller\api\v1\order\StoreOrder::getReletPrice查询续租价格

前端封装:view/uniapp/api/leaseOrder.jsreletLease() / getReletMoney()

reletLease 参数:

参数类型必填说明
daysint续租天数
providerstring人脸认证 provider,默认 mpalipay
product_idint商品信息ID(自定义租期走斜率公式计价时必传)

管理后台(route/admin.php

方法路径控制器说明
POSTorder/relet_orderv1.order.StoreOrder/reletOrderapp\common\controller\Lease后台续租($uid=0,无合同)
POSTorder/cancel_relet_appendv1.order.StoreOrder/cancelReletAppendapp\common\controller\Lease取消续租

前端封装:view/admin/src/api/leaseOrder.jsxuzuRent() / cancelReletAppend()

reletOrder 参数: oid(订单ID)、days(续租天数)、relet_money(续租金额,可选,不传按日租金计算)

cancelReletAppend 参数:

参数类型必填说明
oidint订单ID
numint取消起始期数(该期及以后同批次续租分期一并删除)
reason_codestring取消原因代码(固定枚举,见下)
reason_descstring取消原因描述,不传则取代码对应文案

reason_code 枚举app/services/alipay/CommerceRentServices.php::$cancelReasonCode):

代码文案
USER_PLAN_CHANGE用户租赁计划有变
USER_OVERDUE_PAYMENT用户超期支付自动取消
OUT_OF_STOCK无库存取消
OTHER其他

核心流程

用户端续租

用户端「续租」页
  ├─ 查询续租价格 getReletPrice
  │    ├─ 斜率公式计价(product_id):QuickOrderServices::caculatePriceBySlopeFormula
  │    ├─ 租期折扣:StoreProductLeaseDiscountAuxServices::getBestDiscount
  │    ├─ SVIP 订单叠加计算
  │    └─ 返回 origin_price / discount_price / promotions_price

  └─ 发起续租 reletLease → StoreOrderServices::reletLeaseOrder($oid, $uid>0, ...)
       ├─ 1. 参数与状态校验(见「校验规则」)
       ├─ 2. 计算续租天数→期数(≤30天=1期,>30天=每30天1期)
       ├─ 3. 续租后总天数 > 90 天:抛「后台操作暂不支持续长租」(长租续租暂禁用,
       │       longReletLeaseOrder 生成 type=13 新订单的代码保留但不可达)
       ├─ 4. 分支:
       │     ├─ 爱签(contract_sign=2):
       │     │     ├─ 缓存续租参数 reletLeaseOrder_{oid}_{uid}(60分钟)
       │     │     ├─ StoreOrderInstallmentServices::createReletData 直接生成续租账单
       │     │     └─ SystemContractServices::asignReletFlow 静默签署续租合同(复用首次人脸)
       │     └─ e签宝:
       │           ├─ EsignServices::persons_verify 发起人脸认证(返回 apply.originalUrl/faceToken)
       │           └─ 缓存续租参数 reletLeaseOrder_{oid}_{uid}(60分钟),待认证回调
       └─ 5. e签宝认证回调链路:
             verify_callback(app/controller/api/v2/user/Esign.php)
               → 记录 face_auth_detail.relet_{n},face_auth_status=2
               → OrderCreateAfterJob::afterEsignPersonsVerify($oid, $relet_times)
                    → createReletData 生成续租账单
                    → generateEsignContract 创建填充续租合同
                    → esign3PersonSign 用户静默签署

管理后台续租

管理后台租金账单页「续租」→ xuzuRent({oid, days, relet_money})
  → StoreOrderServices::reletLeaseOrder($oid, $uid=0, ...)
      ├─ 同样的状态校验(无用户归属校验)
      ├─ 缓存续租参数 reletLeaseOrder_{oid}_{uid}(仅5秒,防并发)
      └─ 直接 createReletData:无需人脸与合同,追加租期

取消续租(仅管理后台)

管理后台租金账单操作栏「取消续租」(row.relet_times>0 && row.status==0 && 最新续租批次)
  → cancelReletAppend({oid, num, reason_code, reason_desc})
  → StoreOrderServices::cancelReletAppend
      ├─ 1. 校验:订单存在 / 有续租记录 / 仅允许取消最新续租批次(该期 relet_times == 订单 relet_times)
      ├─ 2. 事务内:
      │     ├─ 取出 relet_times 相同且 num >= 传入 num 的所有分期,逐一校验 status==0(未支付)
      │     ├─ 物理删除这些分期
      │     ├─ 回滚订单:total_price 减、lease_days/end_time/lease_num 回退
      │     └─ CommerceRentServices::cancelReletAppend
      │           → rentplaninfoAppend(..., 'CANCEL_APPEND') 同步支付宝取消追加租期计划
      └─ 3. OrderstatusJob 记录订单状态日志(msg: 取消续租: 第X期,原因:...)

核心代码位置

职责文件方法
续租主入口(校验/分支)app/services/order/StoreOrderServices.phpreletLeaseOrder()
长租续租(新订单,暂不可达)同上longReletLeaseOrder()
续租价格查询app/services/order/StoreOrderInstallmentServices.phpgetReletPrice()
生成续租分期账单同上createReletData()
取消续租(回滚+同步支付宝)app/services/order/StoreOrderServices.phpcancelReletAppend()
支付宝侧续租追加/取消app/services/alipay/CommerceRentServices.phpreletAppend() / cancelReletAppend()
爱签续租合同静默签署app/services/other/SystemContractServices.phpasignReletFlow()
e签宝人脸认证回调app/controller/api/v2/user/Esign.phpverify_callback()
人脸认证后生成账单/合同app/jobs/order/OrderCreateAfterJob.phpafterEsignPersonsVerify() / esign3PersonSign()
用户端控制器app/controller/api/v1/order/StoreOrder.phpreletLease() / getReletPrice()
后台控制器app/common/controller/Lease.phpreletOrder() / cancelReletAppend()
后台前端view/admin/src/pages/order/leaseOrderList/components/rentDetailModal.vue续租/取消续租弹窗
用户端前端view/uniapp/pages/goods/lease_order_xuzu/index.vue续租页

校验规则(reletLeaseOrder)

以下任一不满足即抛异常:

  1. 订单存在且未被取消
  2. 用户端:uid > 0 时校验 订单.uid == uid(订单归属)
  3. 订单租赁信息 is_relet == 1(商品支持续租)
  4. 订单 status >= 2(已确认收货)、status != 6(未完结)
  5. lease_status ∈ [1 租用中, 2 逾期中, 5 待归还, 6 待接收]
  6. 无未完成的买断支付订单
  7. 非子订单(pid == 0
  8. 无未完结租期(lease_num_paid == lease_num
  9. order_lease.relet_times 字段存在
  10. 用户端逾期订单(end_time < 当前时间)放行(校验已注释)
  11. 续租金额 ≤ 剩余预授权金额(rest_amount
  12. 非蚂蚁森林订单(active_tag != 'mysl'
  13. days > 0
  14. check_type ∈ [1 芝麻免押, 3 新租赁行业交易](代扣方式不支持续租)
  15. 0元租包:续租到期不超过会员有效期;SVIP:会员到期校验
  16. 续租后总天数 ≤ 90 天(长租续租暂禁用)

数据表字段

eb_store_order_lease(订单租赁信息)

字段说明
is_relet订单是否允许续租(下单时快照商品配置,1=是)
relet_times已续租次数(每次续租 +1)
relet_days续租累计总天数
lease_days租赁总天数(原 + 续租)
lease_num租赁总期数(原 + 续租新增期数)
end_time租期结束时间(每次续租向后顺延)

eb_store_order_installment(分期账单)

字段说明
relet_times该期所属续租批次(0=原始租期,1=第一次续租,以此类推);管理后台据此识别续租账期并展示「续租」标签

eb_store_product(商品)

字段说明
is_relet商品是否支持续租(1=是)
day_price每日租金(续租默认计价基准)

续租账单生成规则(createReletData)

  • 从 Redis 缓存 reletLeaseOrder_{oid}_{uid} 读取续租参数(天数/日租金/总租金)
    • 用户端 e签宝/爱签:缓存 60 分钟(等待人脸/签署完成)
    • 后台:仅缓存 5 秒(直接使用)
  • 续租新增期数:lease_num + 1 起,relet_times 标记为本批次
  • 每期金额 = 续租总额 / 期数(余数计入首期);续租折扣(getBestDiscount)与 SVIP 差价逻辑与价格查询一致
  • 同步更新:total_price(订单总租金累加)、lease_status=1lease_dayslease_numend_timerelet_days
  • 同步支付宝:
    • check_type=1(芝麻免押):TradeComponentServices::orderModify 交易组件追加租期
    • check_type=3(租赁行业交易):CommerceRentServices::reletAppend 追加分期计划
  • 推送订阅消息 order_relet
  • 记录订单状态日志(OrderstatusJob,msg:用户/后台申请短租续租: X天

注意事项与限制

  1. 取消续租仅后台:用户端无取消续租接口;管理后台仅允许取消最新续租批次relet_times == 订单.order_lease.relet_times)中未支付status==0)的分期,且从所选期数起该批次后续分期一并删除。
  2. 长租续租暂禁用:续租后总租期超过 90 天直接抛异常;longReletLeaseOrder(生成 type=13 续租新订单)代码保留但当前不可达。
  3. 后台续租免合同$uid=0 走「无需人脸及合同,直接追加租期」分支;用户端必须完成人脸认证(e签宝)或静默签署(爱签)后才生成账单。
  4. 并发保护:续租入口用 CacheService::lock(3秒)防重复提交;createReletData 依赖 Redis 缓存中的续租参数,缓存缺失时抛「续租操作失败,请重试」。
  5. 取消续租为物理删除:续租分期记录直接从 eb_store_order_installment 删除(非状态标记),同时回滚订单租赁数据,并同步支付宝 CANCEL_APPEND

承信租多门店租赁商城系统官方文档