TransferOrder.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <?php
  2. namespace App\Module\Transfer\Models;
  3. use App\Module\Transfer\Casts\TransferOrderCast;
  4. use App\Module\Transfer\Casts\CallbackDataCast;
  5. use App\Module\Transfer\Enums\TransferStatus;
  6. use App\Module\Transfer\Enums\TransferType;
  7. use UCore\ModelCore;
  8. /**
  9. * 划转订单模型
  10. *
  11. * field start
  12. * @property int $id 主键ID
  13. * @property int $transfer_app_id 划转应用ID
  14. * @property int $out_id 外部应用ID
  15. * @property string $out_order_id 外部订单ID
  16. * @property string $out_user_id 外部用户ID
  17. * @property int $user_id 内部用户ID
  18. * @property int $currency_id 货币类型ID
  19. * @property int $fund_id 资金账户类型ID
  20. * @property \App\Module\Transfer\Enums\TransferType $type 订单类型(1=转入,2=转出)
  21. * @property \App\Module\Transfer\Enums\TransferStatus $status 订单状态
  22. * @property float $out_amount 外部金额
  23. * @property float $amount 内部金额
  24. * @property float $exchange_rate 使用汇率
  25. * @property \App\Module\Transfer\Casts\CallbackDataCast $callback_data 回调数据
  26. * @property string $error_message 错误信息
  27. * @property string $remark 备注信息
  28. * @property \Carbon\Carbon $processed_at 处理时间
  29. * @property \Carbon\Carbon $callback_at 回调时间
  30. * @property \Carbon\Carbon $completed_at 完成时间
  31. * @property \Carbon\Carbon $created_at 创建时间
  32. * @property \Carbon\Carbon $updated_at 更新时间
  33. * @property \Carbon\Carbon $deleted_at 删除时间
  34. * @property float $fee_rate 使用的手续费率
  35. * @property float $fee_amount 手续费金额
  36. * @property float $actual_amount 实际到账金额(扣除手续费后)
  37. * field end
  38. */
  39. class TransferOrder extends ModelCore
  40. {
  41. /**
  42. * 数据表名
  43. */
  44. protected $table = 'transfer_orders';
  45. // attrlist start
  46. protected $fillable = [
  47. 'id',
  48. 'transfer_app_id',
  49. 'out_id',
  50. 'out_order_id',
  51. 'out_user_id',
  52. 'user_id',
  53. 'currency_id',
  54. 'fund_id',
  55. 'type',
  56. 'status',
  57. 'out_amount',
  58. 'amount',
  59. 'exchange_rate',
  60. 'callback_data',
  61. 'error_message',
  62. 'remark',
  63. 'processed_at',
  64. 'callback_at',
  65. 'completed_at',
  66. 'fee_rate',
  67. 'fee_amount',
  68. 'actual_amount',
  69. ];
  70. // attrlist end
  71. /**
  72. * 属性类型转换
  73. */
  74. protected $casts = [
  75. 'id' => 'integer',
  76. 'transfer_app_id' => 'integer',
  77. 'out_id' => 'integer',
  78. 'user_id' => 'integer',
  79. 'currency_id' => 'integer',
  80. 'fund_id' => 'integer',
  81. 'type' => TransferType::class,
  82. 'status' => TransferStatus::class,
  83. 'out_amount' => 'decimal:10',
  84. 'amount' => 'decimal:10',
  85. 'exchange_rate' => 'decimal:4',
  86. 'fee_rate' => 'decimal:4',
  87. 'fee_amount' => 'decimal:4',
  88. 'actual_amount' => 'decimal:4',
  89. 'callback_data' => CallbackDataCast::class,
  90. 'processed_at' => 'datetime',
  91. 'callback_at' => 'datetime',
  92. 'completed_at' => 'datetime',
  93. 'created_at' => 'datetime',
  94. 'updated_at' => 'datetime',
  95. 'deleted_at' => 'datetime',
  96. ];
  97. /**
  98. * 软删除
  99. */
  100. protected $dates = ['deleted_at'];
  101. /**
  102. * 隐藏字段
  103. */
  104. protected $hidden = [];
  105. /**
  106. * 关联划转应用
  107. */
  108. public function transferApp()
  109. {
  110. return $this->belongsTo(TransferApp::class, 'transfer_app_id');
  111. }
  112. /**
  113. * 获取类型文本
  114. */
  115. public function getTypeTextAttribute(): string
  116. {
  117. return $this->type->getDescription();
  118. }
  119. /**
  120. * 获取状态文本
  121. */
  122. public function getStatusTextAttribute(): string
  123. {
  124. return $this->status->getDescription();
  125. }
  126. /**
  127. * 获取状态颜色
  128. */
  129. public function getStatusColorAttribute(): string
  130. {
  131. return $this->status->getColor();
  132. }
  133. /**
  134. * 获取类型颜色
  135. */
  136. public function getTypeColorAttribute(): string
  137. {
  138. return $this->type->getColor();
  139. }
  140. /**
  141. * 判断是否为转入订单
  142. */
  143. public function isTransferIn(): bool
  144. {
  145. return $this->type === TransferType::IN;
  146. }
  147. /**
  148. * 判断是否为转出订单
  149. */
  150. public function isTransferOut(): bool
  151. {
  152. return $this->type === TransferType::OUT;
  153. }
  154. /**
  155. * 判断是否为最终状态
  156. */
  157. public function isFinalStatus(): bool
  158. {
  159. return $this->status->isFinal();
  160. }
  161. /**
  162. * 判断是否可以重试
  163. */
  164. public function canRetry(): bool
  165. {
  166. return $this->status->canRetry();
  167. }
  168. /**
  169. * 更新状态
  170. */
  171. public function updateStatus(TransferStatus $status, string $message = null): bool
  172. {
  173. $data = ['status' => $status];
  174. if ($message) {
  175. $data['error_message'] = $message;
  176. }
  177. // 设置时间戳
  178. switch ($status) {
  179. case TransferStatus::PROCESSING:
  180. $data['processed_at'] = now();
  181. break;
  182. case TransferStatus::CALLBACK:
  183. $data['callback_at'] = now();
  184. break;
  185. case TransferStatus::COMPLETED:
  186. case TransferStatus::FAILED:
  187. $data['completed_at'] = now();
  188. break;
  189. }
  190. return $this->update($data);
  191. }
  192. /**
  193. * 判断是否收取了手续费
  194. */
  195. public function hasFee(): bool
  196. {
  197. return $this->fee_amount > 0;
  198. }
  199. /**
  200. * 获取手续费率百分比文本
  201. */
  202. public function getFeeRatePercentAttribute(): string
  203. {
  204. return number_format($this->fee_rate * 100, 2) . '%';
  205. }
  206. /**
  207. * 获取手续费金额格式化文本
  208. */
  209. public function getFeeAmountTextAttribute(): string
  210. {
  211. return number_format($this->fee_amount, 4);
  212. }
  213. /**
  214. * 获取实际到账金额格式化文本
  215. */
  216. public function getActualAmountTextAttribute(): string
  217. {
  218. return number_format($this->actual_amount, 4);
  219. }
  220. /**
  221. * 设置手续费信息
  222. *
  223. * @param float $feeRate 手续费率
  224. * @param string $feeAmount 手续费金额
  225. * @param string $actualAmount 实际到账金额
  226. */
  227. public function setFeeInfo(float $feeRate, string $feeAmount, string $actualAmount): void
  228. {
  229. $this->fee_rate = $feeRate;
  230. $this->fee_amount = $feeAmount;
  231. $this->actual_amount = $actualAmount;
  232. }
  233. /**
  234. * 计算手续费信息(基于关联的应用配置)
  235. */
  236. public function calculateFeeFromApp(): array
  237. {
  238. if (!$this->transferApp) {
  239. return [
  240. 'fee_rate' => 0.0000,
  241. 'fee_amount' => '0.0000',
  242. 'actual_amount' => $this->amount,
  243. ];
  244. }
  245. if ($this->isTransferIn()) {
  246. return $this->transferApp->calculateInFee($this->amount);
  247. } else {
  248. return $this->transferApp->calculateOutFee($this->amount);
  249. }
  250. }
  251. }