PiPiPen 工作任务确认业务逻辑分析文档
概述
本文档详细分析了 WorkTaskController::confrimStageWorkStatus 方法中 CNY 和非 CNY 两种不同货币的业务逻辑和资金流转过程。该方法处理工作任务完成时的资金结算,涉及多币种转换、平台费抵扣、以及复杂的钱包体系设计。
核心逻辑分支
CNY 收款分支($workTask->currency->isCNY):
- 使用 aliPayWallet 单钱包架构
- 直接以 CNY 币种进行所有计算
- $totalAmount = $workTask->price 已包含 CreditWallet 抵扣金额
- 艺术家收入 = $totalAmount - $payFee - $platFee
非 CNY 收款分支(! $workTask->currency->isCNY):
- 使用 stripeFullWallet + stripeRecipientWallet 双钱包架构
- 涉及汇率转换和零小数货币处理
- 需要单独补偿 CreditWallet 抵扣金额
- 复杂的多币种费用计算和补偿机制
核心业务场景
CNY 收款场景
当工作任务的货币是CNY时,系统采用支付宝(aliPay)生态进行资金处理,使用单一钱包架构。
非 CNY 收款场景
当工作任务的货币不是CNY时(如USD、JPY、EUR等),系统采用 Stripe 支付生态进行资金处理,使用双钱包架构。
关键代码位置
- 文件:
app/Http/Controllers/Api/User/WorkTaskController.php - 方法:
confrimStageWorkStatus - CNY 逻辑分支:
$workTask->currency->isCNY(第245-358行) - 非 CNY 逻辑分支:
! $workTask->currency->isCNY(第359-474行)
重要安全特性
- 幂等性保护:第187-189行检查工作任务状态,防止重复执行
- 并发安全:使用分布式锁(第162-165行)和数据库锁(第182行)
- 异常处理:完善的 try-catch-finally 结构确保事务一致性和锁释放(第168-492行)
钱包体系设计
设计架构对比
CNY 收款架构:单一钱包系统
- 使用 aliPayWallet 进行所有资金处理
- 直接以 CNY 币种进行计算,无需汇率转换
- CreditWallet 抵扣已包含在
$totalAmount中
非 CNY 收款架构:三钱包系统
- stripeFullWallet:记录 Stripe 实际到账净收入
- stripeRecipientWallet:补偿各种抵扣和费用
- platFeeWallet:平台费抵扣福利钱包
CNY 收款钱包设计
aliPayWallet(支付宝钱包)
- 币种:CNY(人民币)
- 用途:CNY 收款的唯一钱包,处理所有资金流转
- 资金来源:用户支付的完整订单金额
- 关键特点:
- $totalAmount = $workTask->price(已包含所有费用和抵扣)
- 不需要单独的 CreditWallet 补偿机制
- 艺术家最终收入 = $totalAmount - $payFee - $platFee
- 钱包类型:
WalletUsage::Deposit+WalletDepositType::Alipay - 安全特性:使用
firstOrFail()确保钱包存在(第246-251行)
核心设计原则(非 CNY 收款)
在修复 bug 过程中,我们确认了三钱包体系的精确设计原则:
1. stripeFullWallet(Stripe全功能钱包)
- 币种:与 workTask 币种一致(如 JPY、EUR 等)
- 数据存储:零小数货币以"分"为单位存储(如100日元存储为10000)
- 用途:记录从 Stripe Connect 账户实际到账的净收入
- 资金来源:
balance_transaction['net'](扣除 Stripe 手续费后的净额) - 钱包类型:
WalletUsage::Deposit+WalletDepositType::StripeFull - 安全特性:使用
firstOrFail()确保钱包存在(第353-355行)
2. stripeRecipientWallet(补差钱包)
- 币种:固定为 USD(存储为美分)
- 用途:确保艺术家获得完整收入的补偿钱包
- 补偿内容:
- 用户使用 CreditWallet 抵现的金额(USD,不需要零小数货币转换)
- platFeeWallet 抵扣的平台费用(USD)
- 钱包类型:
WalletUsage::Deposit+WalletDepositType::StripeRecipient - 安全特性:使用
firstOrFail()确保钱包存在(第357-361行)
3. platFeeWallet(平台费抵扣钱包)
- 币种:固定为 USD(存储为美分)
- 性质:平台发放给艺术家的福利钱包
- 用途:专门用于抵扣平台收取的手续费
- 使用规则:只能用于抵扣,不能提现
- 钱包类型:
WalletUsage::PlatFee - 重要逻辑:通过
PlatFeeWalletService处理复杂的汇率转换和余额扣除
CNY 收款业务流程分析
业务场景举例(CNY 收款)
假设条件:
- 用户订单:1000 CNY
- 用户使用 CreditWallet 抵扣:200 CNY
- 用户实际支付:800 CNY
- 平台费率:10%
- 支付手续费:30 CNY
重要理解:
$totalAmount = $workTask->price = 1000 CNY(包含 CreditWallet 抵扣)- 用户实际支付 + CreditWallet 抵扣 = 总订单金额
- 800 CNY(实际支付)+ 200 CNY(CreditWallet)= 1000 CNY(总订单)
第一步:获取 aliPayWallet 钱包(第246-251行)
关键设计:
- 使用
firstOrFail()确保钱包存在 - 数据库锁确保并发安全
- 单一钱包处理所有 CNY 资金流转
第二步:设置基础金额(第253-256行)
关键理解:
$totalAmount直接使用$workTask->price,不是从 Stripe 获取的balance_transaction['net']- 这个金额已经包含了 CreditWallet 抵扣的部分
- 不需要像非 CNY 那样单独补偿 CreditWallet
第三步:处理订单费用信息(第258-282行)
处理结果:
$payFee = 30 CNY(支付手续费)$userDeductionAmount = 200 CNY(CreditWallet 抵扣,用于记录)- 抵扣记录状态更新为已处理
第四步:计算平台费(第283-305行)
平台费处理场景:
- 如果 platFeeWallet 有足够余额:
$platFee减少到 0 或更低 - 如果 platFeeWallet 余额不足:
$platFee部分减少 - 如果 platFeeWallet 无余额:
$platFee保持原值
第五步:计算艺术家收入(第307-310行)
计算示例:
- 假设 platFeeWallet 完全抵扣了平台费($platFee = 0):
$amount = 1000 - 30 - 0 = 970 CNY
- 假设 platFeeWallet 无余额($platFee = 100):
$amount = 1000 - 30 - 100 = 870 CNY
第六步:更新 aliPayWallet 余额(第311-358行)
CNY 与非 CNY 业务逻辑对比
核心差异总结
关键理解:CreditWallet 处理差异
CNY 收款:
$totalAmount = $workTask->price(1000 CNY)- 这个金额已经包含了 CreditWallet 的抵扣部分
- 用户实际支付 800 CNY + CreditWallet 抵扣 200 CNY = 1000 CNY
- 艺术家收入基于完整的 1000 CNY 计算
- 不需要额外补偿
非 CNY 收款:
$totalAmount来自 Stripe 的balance_transaction['net']- 这个金额是用户实际支付的净到账金额
- 不包含 CreditWallet 抵扣部分
- 需要单独补偿 CreditWallet 到 stripeRecipientWallet
- 需要额外补偿机制
业务逻辑完整性
CNY 收款的设计优势:
- 简化的单钱包架构
- 避免复杂的汇率转换
- CreditWallet 补偿天然内置
- 计算逻辑更加直观
非 CNY 收款的设计复杂性:
- 需要处理多币种和汇率
- 零小数货币的特殊处理
- 多钱包协调工作
- 复杂的补偿机制
这两种设计反映了不同支付生态(支付宝 vs Stripe)的特点和限制,CNY 收款利用了支付宝的简化支付流程,而非 CNY 收款则需要适应 Stripe Connect 的复杂架构。
详细业务流程分析(非 CNY 收款)
业务场景举例
假设条件:
- 用户支付:1000 JPY
- 平台费:100 JPY
- platFeeWallet 余额:50 USD
- 当前汇率:1 USD = 150 JPY
第一步:数据验证和安全检查(第362-385行)
重要发现:
$userDeductionAmount始终为 USD 币种,因为来自walletDeductionRecords- 添加了负数验证,防止 Stripe 异常数据导致系统问题
解析结果:
$totalAmount:实际到账净额(JPY)$payFee:Stripe 手续费(JPY)$platFee:平台应用费(JPY)$userDeductionAmount:用户礼品卡抵扣金额(JPY)
第二步:零小数货币处理(第387-392行)
重要澄清:
- 零小数货币列表:JPY、KRW、VND、BIF、CLP等
- 数据存储规则:零小数货币在数据库中以"分"为单位存储(100日元存储为10000)
- 为什么 userDeductionAmount 不转换:它来自 USD 的
walletDeductionRecords,与 workTask 币种无关
第三步:钱包余额更新和交易记录(第394-421行)
修复关键点:
- 在执行
increment()前保存原始余额 - 确保交易记录中的
before_balance和after_balance准确无误
结果:记录 Stripe 实际到账的净收入
第四步:补偿用户礼品卡抵扣(第409-421行)
结果:补偿用户使用礼品卡抵扣的金额(USD)
第五步:平台费抵扣与汇率计算(第424-456行)
重大修复:此步骤在原实现中有严重的逻辑错误,经过多次 bug 修复已完全纠正
5.1 调用 PlatFeeWalletService 处理
PlatFeeWalletService::minus 内部逻辑:
- 获取 platFeeWallet(USD钱包)余额
- 将 USD 余额转换为 workTask 币种进行比较
- 计算实际可抵扣金额
- 将抵扣金额转换回 USD 进行钱包操作
5.2 计算 platFeeWallet 等值金额
计算结果:50 USD × 150 = 7500 JPY(向下取整)
5.3 判断抵扣逻辑
场景A:platFeeWallet 余额充足(7500 JPY > 100 JPY)
场景B:platFeeWallet 余额不足 假设 platFeeWallet 只有 0.5 USD(等值75 JPY):
5.4 更新 platFeeWallet(修复后的正确实现)
重要修复点:
- 之前的错误:使用
increment()错误地增加 platFeeWallet 余额 - 修复后:使用
decrement()正确地减少 platFeeWallet 余额 - 数据一致性:before_balance 和 after_balance 现在准确记录
5.5 stripeRecipientWallet 补偿平台费
汇率处理的关键设计
汇率舍入策略
- 扣除时向上取整(ceil):确保平台费完全覆盖,保护平台利益
- 兑换时向下取整(floor):防止超额扣除用户钱包,保护用户利益
币种转换流程
- 输入:平台费以 workTask 币种计算(如 100 JPY)
- 转换:将 platFeeWallet 的 USD 余额转换为 workTask 币种进行比较
- 扣除:将需要抵扣的 workTask 币种金额转换为 USD 进行钱包操作
- 输出:两个 USD 钱包的余额变动
不同场景的处理结果
场景1:platFeeWallet 余额充足
- 输入:100 JPY 平台费,50 USD platFeeWallet
- 处理:
- platFeeWallet:50 USD → 49 USD(扣除1 USD)
- stripeRecipientWallet:+1 USD
- 结果:艺术家实际承担平台费:0 JPY
场景2:platFeeWallet 余额不足
- 输入:100 JPY 平台费,0.5 USD platFeeWallet
- 处理:
- 0.5 USD 等值:75 JPY
- platFeeWallet:0.5 USD → 0 USD(全部扣除)
- stripeRecipientWallet:+0.5 USD
- 结果:艺术家实际承担平台费:25 JPY
场景3:platFeeWallet 余额为0
- 输入:100 JPY 平台费,0 USD platFeeWallet
- 处理:不进行任何抵扣操作
- 结果:艺术家承担全部平台费:100 JPY
最终资金流向总结
以 1000 JPY 支付为例:
资金分配
- Stripe 手续费:自动扣除(如 30 JPY)
- 平台应用费:100 JPY
- 净到账金额:870 JPY
钱包变动
- stripeFullWallet:+870 JPY(实际到账金额)
- platFeeWallet:-1 USD(抵扣平台费)
- stripeRecipientWallet:+1 USD(补偿平台费)+ 其他补偿
艺术家收入
- 总收入:stripeFullWallet + stripeRecipientWallet(按汇率折算)
- 实际效果:获得完整的预期收入,平台费被 USD 钱包抵扣
安全特性与错误处理
1. 并发安全机制
- 分布式锁:使用 Redis 缓存锁防止同一工作任务的并发处理
- 数据库锁:
lockForUpdate()确保数据一致性 - 锁超时设置:10秒超时防止死锁
2. 幂等性保护
- 状态检查:防止重复执行已完成的工作任务
- 早期返回:已完成的任务直接返回成功
3. 数据验证与安全检查
- 金额有效性验证:防止 Stripe 返回负数或异常数据
- 钱包存在性检查:使用
firstOrFail()确保钱包存在 - 空值安全检查:防止关联对象为空导致的错误
4. 完善的异常处理
- 统一异常处理:try-catch-finally 结构
- 事务回滚:确保数据一致性
- 锁释放保证:finally 块确保锁被正确释放
- 详细错误日志:记录完整的错误信息和堆栈跟踪
5. 数据一致性保证
- 正确的余额记录:before_balance 和 after_balance 准确记录
- 交易记录完整性:所有钱包操作都有对应的交易记录
- 操作原子性:所有相关操作在同一事务中完成
技术特点与优势
1. 多币种支持
- 任意币种支持:支持所有 Stripe 支持的货币
- 智能汇率转换:自动处理汇率转换和舍入
- 零小数货币处理:正确处理 JPY、KRW 等货币的存储格式
2. 风险控制
- 多层并发保护:分布式锁 + 数据库锁
- 汇率舍入策略:向上取整保护平台,向下取整保护用户
- 完整的审计追踪:详细的交易记录确保可追溯性
- 输入验证:全面的数据验证和安全检查
3. 用户体验
- 平台费抵扣:减少艺术家负担的福利机制
- 透明的费用计算:清晰的费用分解和记录
- 灵活的补偿机制:确保艺术家获得完整收入
4. 业务灵活性
- 动态费用政策:通过调整 platFeeWallet 余额来调节费用政策
- 复杂业务场景支持:支持多币种、多阶段的复杂委托
- 模块化服务设计:便于维护和扩展
5. 系统稳定性
- 幂等性设计:防止重复操作的副作用
- 故障恢复:完善的异常处理和事务回滚
- 监控友好:详细的日志记录便于问题排查
相关代码文件
核心控制器
app/Http/Controllers/Api/User/WorkTaskController.php
服务类
app/Service/Wallet/PlatFeeWalletService.phpapp/Service/RateService.phpapp/Service/Stripe/Amount.php
模型类
app/Models/WorkTask.phpapp/Models/Wallet.phpapp/Models/Currency.phpapp/Models/Order.php
枚举类
app/Enums/WalletUsage.phpapp/Enums/WalletDepositType.phpapp/Enums/WalletTransactionAction.phpapp/Enums/WalletTransactionBizType.php
总结
这套业务逻辑设计巧妙地处理了 CNY 和非 CNY 两种不同收款环境下的复杂费用结算问题。通过在 bug 修复过程中的深入分析和多次迭代,我们完善了整个系统的设计,实现了:
1. 双架构设计精髓
CNY 收款架构:
- 单一钱包设计:aliPayWallet 处理所有资金流转
- 天然补偿机制:CreditWallet 抵扣已包含在 $totalAmount 中
- 简化计算流程:艺术家收入 = 订单总额 - 支付费用 - 平台费
- 直接费用处理:无需复杂的汇率转换和多钱包协调
非 CNY 收款架构:
- 三钱包协作:stripeFullWallet + stripeRecipientWallet + platFeeWallet
- 精确补偿机制:单独补偿 CreditWallet 和平台费抵扣
- 复杂汇率处理:多币种环境下的精确计算和舍入策略
- 零小数货币支持:特殊处理 JPY、KRW 等货币格式
2. 业务逻辑完整性
CNY 收款的核心优势:
- 利用支付宝生态的简化支付流程
- CreditWallet 补偿天然内置,无需额外处理
- 计算逻辑直观,维护成本低
- 适应中国市场的支付习惯
非 CNY 收款的技术复杂性:
- 适应 Stripe Connect 的复杂架构
- 处理全球多币种和汇率波动
- 零小数货币的特殊存储和计算
- 多钱包协调确保资金流转准确性
3. 完善的三钱包架构(非 CNY)
- 收入记录:stripeFullWallet 准确记录 Stripe 实际到账的净收入
- 费用抵扣:platFeeWallet 提供平台费抵扣的福利机制
- 收入补偿:stripeRecipientWallet 确保艺术家获得完整收入
4. 健壮的安全保障(通用)
- 并发安全:多层锁机制防止数据竞争
- 数据一致性:正确的余额记录和交易追踪
- 异常恢复:完善的错误处理和事务回滚
- 输入验证:全面的数据验证和安全检查
- 幂等性保护:防止重复操作的副作用
5. 精确的业务逻辑(通用)
- 汇率处理:合理的舍入策略保护各方利益
- 币种支持:正确处理零小数货币的特殊格式
- 费用计算:透明准确的费用分解和处理
- 状态管理:完整的任务状态流转控制
6. 关键技术特点对比
CNY 收款的技术特点:
- 单一数据源:$totalAmount 直接来自 $workTask->price
- 内置补偿:CreditWallet 抵扣天然包含在总金额中
- 简化交易记录:详细的 detail 数组记录所有费用分解
- 直接费用扣除:所有费用直接从 CNY 总额中扣除
非 CNY 收款的技术特点:
- 多数据源协调:从 Stripe balance_transaction 获取净收入
- 显式补偿机制:单独补偿 CreditWallet 和平台费抵扣
- 复杂汇率计算:多币种转换和精确舍入策略
- 多钱包同步:确保三个钱包的数据一致性
7. 关键修复成果
在 bug 修复过程中,我们解决了多个关键问题:
- 平台费抵扣逻辑:修复了 increment/decrement 操作方向错误
- 数据一致性:确保 before_balance 和 after_balance 的准确记录
- 零小数货币处理:澄清了 userDeductionAmount 的正确处理方式
- 异常处理:完善了锁释放和错误恢复机制
- 安全检查:增加了空值验证和金额有效性检查
8. 架构设计价值
统一的设计哲学:
- 不同支付生态采用最适合的架构设计
- CNY 利用支付宝的简化流程,非 CNY 适应 Stripe 的复杂架构
- 两种架构都确保艺术家获得完整的预期收入
- 平台费抵扣机制在两种架构中都得到了良好实现
业务灵活性:
- CNY 收款:适应中国市场的支付习惯和监管要求
- 非 CNY 收款:支持全球多币种的复杂国际支付场景
- 统一接口:对上层业务逻辑提供一致的处理接口
9. 生产就绪特性(通用)
- 可扩展性:模块化的服务设计支持功能扩展
- 可维护性:清晰的代码结构和详细的日志记录
- 可监控性:完整的交易记录支持业务监控和审计
- 国际化支持:多币种和多语言的完整支持
10. 核心业务价值
用户体验:
- CNY 用户享受简化的支付流程
- 非 CNY 用户获得全球化的支付体验
- 平台费抵扣减少艺术家负担
- 透明的费用计算和记录
业务扩展性:
- 支持中国和国际两个市场的不同支付生态
- 复杂的费用政策和抵扣机制
- 完整的合规性和审计追踪
- 灵活的汇率和费用管理
这个双架构系统在保证财务准确性和系统稳定性的同时,充分适应了不同市场的支付特点,提供了良好的用户体验和业务灵活性。CNY 收款的简化设计和非 CNY 收款的复杂架构,都是针对具体业务场景的最优解决方案。通过多次 bug 修复和优化,两套代码都已达到生产可用的高质量标准。
文档创建时间:2025-01-11
最后更新时间:2025-01-11
版本:3.0 - 已整合 CNY 和非 CNY 收款业务逻辑分析
状态:已完成双架构业务逻辑分析和技术特性文档化

