WalletService.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <?php
  2. namespace App\Services\Coach;
  3. use App\Models\MemberUser;
  4. use App\Models\WalletTransRecord;
  5. use Illuminate\Support\Facades\Log;
  6. class WalletService
  7. {
  8. /**
  9. * 获取技师钱包信息
  10. *
  11. * @param int $userId 技师用户ID
  12. */
  13. public function getWallet(int $userId): array
  14. {
  15. try {
  16. // 加载用户和技师信息
  17. $user = MemberUser::with(['coach', 'coach.wallet'])->findOrFail($userId);
  18. abort_if(! $user->coach, 404, '技师信息不存在');
  19. // 获取技师钱包
  20. $wallet = $user->coach->wallet;
  21. // 获取钱包流水统计
  22. $statistics = $this->getWalletStatistics($wallet->id);
  23. return [
  24. 'available_balance' => number_format($wallet->available_balance, 2, '.', ''), // 可用余额
  25. 'frozen_amount' => number_format($wallet->frozen_amount, 2, '.', ''), // 冻结金额
  26. 'total_income' => number_format($statistics['total_income'], 2, '.', ''), // 累计收入
  27. 'total_withdraw' => number_format($statistics['total_withdraw'], 2, '.', ''), // 累计支出
  28. 'today_income' => number_format($statistics['today_income'], 2, '.', ''), // 今日收入
  29. 'month_income' => number_format($statistics['month_income'], 2, '.', ''), // 本月收入
  30. 'last_month_income' => number_format($statistics['last_month_income'], 2, '.', ''), // 上月收入
  31. ];
  32. } catch (\Exception $e) {
  33. Log::error('获取技师钱包信息失败', [
  34. 'user_id' => $userId,
  35. 'error' => $e->getMessage(),
  36. 'file' => $e->getFile(),
  37. 'line' => $e->getLine(),
  38. ]);
  39. throw $e;
  40. }
  41. }
  42. /**
  43. * 获取钱包流水记录
  44. *
  45. * @param int $userId 技师用户ID
  46. * @param array $params 查询参数
  47. */
  48. public function getWalletRecords(int $userId, array $params): array
  49. {
  50. try {
  51. // 加载用户和技师信息(优化关联加载)
  52. $user = MemberUser::with(['coach', 'coach.wallet'])->findOrFail($userId);
  53. abort_if(! $user->coach, 404, '技师信息不存在');
  54. abort_if(! $user->coach->wallet, 404, '钱包信息不存在');
  55. // 构建查询
  56. $query = WalletTransRecord::where('wallet_id', $user->coach->wallet->id)
  57. // 修复参数名称错误
  58. ->when(isset($params['type']), function ($query) use ($params) {
  59. return $query->where('trans_type', $params['type']);
  60. })
  61. // 优化日期查询
  62. ->when(isset($params['start_date']), function ($query) use ($params) {
  63. return $query->whereDate('created_at', '>=', $params['start_date']);
  64. })
  65. ->when(isset($params['end_date']), function ($query) use ($params) {
  66. return $query->whereDate('created_at', '<=', $params['end_date']);
  67. })
  68. // 添加金额范围筛选
  69. ->when(isset($params['min_amount']), function ($query) use ($params) {
  70. return $query->where('amount', '>=', $params['min_amount']);
  71. })
  72. ->when(isset($params['max_amount']), function ($query) use ($params) {
  73. return $query->where('amount', '<=', $params['max_amount']);
  74. })
  75. // 添加交易状态筛选
  76. ->when(isset($params['status']), function ($query) use ($params) {
  77. return $query->where('status', $params['status']);
  78. })
  79. // 添加排序选项
  80. ->when(
  81. isset($params['sort_field']) && isset($params['sort_order']),
  82. function ($query) use ($params) {
  83. return $query->orderBy(
  84. $params['sort_field'],
  85. $params['sort_order'] === 'desc' ? 'desc' : 'asc'
  86. );
  87. },
  88. function ($query) {
  89. return $query->orderBy('created_at', 'desc');
  90. }
  91. );
  92. // 分页获取数据(添加字段选择)
  93. $records = $query->paginate(
  94. $params['per_page'] ?? 10,
  95. [
  96. 'id',
  97. 'trans_no',
  98. 'trans_type',
  99. 'amount',
  100. 'balance',
  101. 'owner_type',
  102. 'owner_id',
  103. 'remark',
  104. 'status',
  105. 'created_at',
  106. ],
  107. 'page',
  108. $params['page'] ?? 1
  109. );
  110. // TODO: 处理格式化数据存在的枚举映射
  111. // 格式化数据
  112. $items = collect($records->items())->map(function ($record) {
  113. return [
  114. 'id' => $record->id,
  115. 'trans_no' => $record->trans_no,
  116. 'trans_type' => $this->formatTransType($record->trans_type),
  117. 'amount' => number_format($record->amount, 2, '.', ''),
  118. 'balance' => number_format($record->balance, 2, '.', ''),
  119. 'owner_type' => $this->formatOwnerType($record->owner_type),
  120. 'owner_id' => $record->owner_id,
  121. 'remark' => $record->remark,
  122. 'status' => $this->formatStatus($record->status),
  123. 'created_at' => $record->created_at->format('Y-m-d H:i:s'),
  124. ];
  125. });
  126. // 添加汇总信息
  127. $summary = [
  128. 'total_income' => $query->where('amount', '>', 0)->sum('amount'),
  129. 'total_expense' => abs($query->where('amount', '<', 0)->sum('amount')),
  130. 'record_count' => $records->total(),
  131. ];
  132. return [
  133. 'items' => $items,
  134. 'total' => $records->total(),
  135. 'summary' => $summary,
  136. ];
  137. } catch (\Exception $e) {
  138. Log::error('获取钱包流水记录失败', [
  139. 'user_id' => $userId,
  140. 'params' => $params,
  141. 'error' => $e->getMessage(),
  142. 'file' => $e->getFile(),
  143. 'line' => $e->getLine(),
  144. ]);
  145. throw $e;
  146. }
  147. }
  148. /**
  149. * 格式化交易类型
  150. */
  151. private function formatTransType(int $type): string
  152. {
  153. return match ($type) {
  154. 1 => '收入',
  155. 2 => '支出',
  156. default => '未知',
  157. };
  158. }
  159. /**
  160. * 格式化来源类型
  161. */
  162. private function formatOwnerType(string $type): string
  163. {
  164. return match ($type) {
  165. 'order' => '订单',
  166. 'withdraw' => '提现',
  167. 'refund' => '退款',
  168. 'system' => '系统',
  169. default => '其他',
  170. };
  171. }
  172. /**
  173. * 格式化状态
  174. */
  175. private function formatStatus(int $status): string
  176. {
  177. return match ($status) {
  178. 1 => '成功',
  179. 2 => '处理中',
  180. 3 => '失败',
  181. default => '未知',
  182. };
  183. }
  184. /**
  185. * 获取钱包流水统计
  186. *
  187. * @param int $walletId 钱包ID
  188. */
  189. private function getWalletStatistics(int $walletId): array
  190. {
  191. try {
  192. // 计算总收入和总支出
  193. $totals = WalletTransRecord::where('wallet_id', $walletId)
  194. ->selectRaw('
  195. SUM(CASE WHEN amount > 0 THEN amount ELSE 0 END) as total_income,
  196. ABS(SUM(CASE WHEN amount < 0 THEN amount ELSE 0 END)) as total_withdraw
  197. ')
  198. ->first();
  199. // 计算今日收入
  200. $todayIncome = WalletTransRecord::where('wallet_id', $walletId)
  201. ->where('amount', '>', 0)
  202. ->whereDate('created_at', today())
  203. ->sum('amount');
  204. // 计算本月收入
  205. $monthIncome = WalletTransRecord::where('wallet_id', $walletId)
  206. ->where('amount', '>', 0)
  207. ->whereYear('created_at', now()->year)
  208. ->whereMonth('created_at', now()->month)
  209. ->sum('amount');
  210. // 计算上月收入
  211. $lastMonthIncome = WalletTransRecord::where('wallet_id', $walletId)
  212. ->where('amount', '>', 0)
  213. ->whereYear('created_at', now()->subMonth()->year)
  214. ->whereMonth('created_at', now()->subMonth()->month)
  215. ->sum('amount');
  216. return [
  217. 'total_income' => $totals->total_income ?? 0,
  218. 'total_withdraw' => $totals->total_withdraw ?? 0,
  219. 'today_income' => $todayIncome,
  220. 'month_income' => $monthIncome,
  221. 'last_month_income' => $lastMonthIncome,
  222. ];
  223. } catch (\Exception $e) {
  224. Log::error('获取钱包统计信息失败', [
  225. 'wallet_id' => $walletId,
  226. 'error' => $e->getMessage(),
  227. ]);
  228. return [
  229. 'total_income' => 0,
  230. 'total_withdraw' => 0,
  231. 'today_income' => 0,
  232. 'month_income' => 0,
  233. 'last_month_income' => 0,
  234. ];
  235. }
  236. }
  237. }