123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- <?php
- namespace App\Services\Coach;
- use App\Models\Wallet;
- use App\Models\MemberUser;
- use App\Enums\WithdrawStatus;
- use App\Models\WalletTransRecord;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- use App\Models\WalletWithdrawRecord;
- class WalletService
- {
- /**
- * 获取技师钱包信息
- *
- * @param int $userId 技师用户ID
- */
- public function getWallet(int $userId): array
- {
- try {
- // 加载用户和技师信息
- $user = MemberUser::with(['coach', 'coach.wallet'])->findOrFail($userId);
- abort_if(! $user->coach, 404, '技师信息不存在');
- // 获取技师钱包
- $wallet = $user->coach->wallet;
- abort_if(! $wallet, 404, '钱包信息不存在');
- // 获取钱包流水统计
- $statistics = $this->getWalletStatistics($wallet->id);
- return [
- 'available_balance' => number_format($wallet->available_balance, 2, '.', ''), // 可用余额
- 'frozen_amount' => number_format($wallet->frozen_amount, 2, '.', ''), // 冻结金额
- 'total_income' => number_format($statistics['total_income'], 2, '.', ''), // 累计收入
- 'total_withdraw' => number_format($statistics['total_withdraw'], 2, '.', ''), // 累计支出
- 'today_income' => number_format($statistics['today_income'], 2, '.', ''), // 今日收入
- 'month_income' => number_format($statistics['month_income'], 2, '.', ''), // 本月收入
- 'last_month_income' => number_format($statistics['last_month_income'], 2, '.', ''), // 上月收入
- ];
- } catch (\Exception $e) {
- Log::error('获取技师钱包信息失败', [
- 'user_id' => $userId,
- 'error' => $e->getMessage(),
- 'file' => $e->getFile(),
- 'line' => $e->getLine(),
- ]);
- throw $e;
- }
- }
- /**
- * 获取钱包流水记录
- *
- * @param int $userId 技师用户ID
- * @param array $params 查询参数
- */
- public function getWalletRecords(int $userId, array $params): array
- {
- try {
- // 加载用户和技师信息(优化关联加载)
- $user = MemberUser::with(['coach', 'coach.wallet'])->findOrFail($userId);
- abort_if(! $user->coach, 404, '技师信息不存在');
- abort_if(! $user->coach->wallet, 404, '钱包信息不存在');
- // 构建查询
- $query = WalletTransRecord::where('wallet_id', $user->coach->wallet->id)
- // 修复参数名称错误
- ->when(isset($params['type']), function ($query) use ($params) {
- return $query->where('trans_type', $params['type']);
- })
- // 优化日期查询
- ->when(isset($params['start_date']), function ($query) use ($params) {
- return $query->whereDate('created_at', '>=', $params['start_date']);
- })
- ->when(isset($params['end_date']), function ($query) use ($params) {
- return $query->whereDate('created_at', '<=', $params['end_date']);
- })
- // 添加金额范围筛选
- ->when(isset($params['min_amount']), function ($query) use ($params) {
- return $query->where('amount', '>=', $params['min_amount']);
- })
- ->when(isset($params['max_amount']), function ($query) use ($params) {
- return $query->where('amount', '<=', $params['max_amount']);
- })
- // 添加交易状态筛选
- ->when(isset($params['status']), function ($query) use ($params) {
- return $query->where('state', $params['status']);
- })
- // 添加排序选项
- ->when(
- isset($params['sort_field']) && isset($params['sort_order']),
- function ($query) use ($params) {
- return $query->orderBy(
- $params['sort_field'],
- $params['sort_order'] === 'desc' ? 'desc' : 'asc'
- );
- },
- function ($query) {
- return $query->orderBy('created_at', 'desc');
- }
- );
- // 分页获取数据(添加字段选择)
- $records = $query->paginate(
- $params['per_page'] ?? 10,
- [
- 'id',
- 'trans_no',
- 'trans_type',
- 'amount',
- 'balance',
- 'owner_type',
- 'owner_id',
- 'remark',
- 'status',
- 'created_at',
- ],
- 'page',
- $params['page'] ?? 1
- );
- // TODO: 处理格式化数据存在的枚举映射
- // 格式化数据
- $items = collect($records->items())->map(function ($record) {
- return [
- 'id' => $record->id,
- 'trans_no' => $record->trans_no,
- 'trans_type' => $this->formatTransType($record->trans_type),
- 'amount' => number_format($record->amount, 2, '.', ''),
- 'balance' => number_format($record->balance, 2, '.', ''),
- 'owner_type' => $this->formatOwnerType($record->owner_type),
- 'owner_id' => $record->owner_id,
- 'remark' => $record->remark,
- 'state' => $this->formatStatus($record->state),
- 'created_at' => $record->created_at->format('Y-m-d H:i:s'),
- ];
- });
- // 添加汇总信息
- $summary = [
- 'total_income' => $query->where('amount', '>', 0)->sum('amount'),
- 'total_expense' => abs($query->where('amount', '<', 0)->sum('amount')),
- 'record_count' => $records->total(),
- ];
- return [
- 'items' => $items,
- 'total' => $records->total(),
- 'summary' => $summary,
- ];
- } catch (\Exception $e) {
- Log::error('获取钱包流水记录失败', [
- 'user_id' => $userId,
- 'params' => $params,
- 'error' => $e->getMessage(),
- 'file' => $e->getFile(),
- 'line' => $e->getLine(),
- ]);
- throw $e;
- }
- }
- /**
- * 技师钱包提现
- *
- * @param int $userId 技师用户ID
- * @param array $data 提现数据
- * @return array
- *
- * @throws \Exception
- */
- public function withdraw(int $userId, array $data)
- {
- return DB::transaction(function () use ($userId, $data) {
- try {
- // 获取用户和技师信息
- $user = MemberUser::with(['coach', 'coach.wallet'])->findOrFail($userId);
- abort_if(! $user->coach, 404, '技师信息不存在');
- abort_if(! $user->coach->wallet, 404, '钱包信息不存在');
- // 锁定钱包记录
- $wallet = Wallet::where('id', $user->coach->wallet->id)
- ->lockForUpdate()
- ->first();
- // TODO: 提现金额限制
- // 验证提现金额
- $amount = $data['amount'];
- abort_if($amount <= 100, 422, '提现金额必须大于100元');
- abort_if($amount > $wallet->available_balance, 422, '可提现余额不足');
- // 生成交易流水号
- $transNo = 'W' . date('YmdHis') . mt_rand(1000, 9999);
- // 创建提现记录
- $withdraw = WalletWithdrawRecord::create([
- 'wallet_id' => $wallet->id, // 钱包ID
- 'trans_no' => $transNo, // 交易流水号
- 'amount' => $amount, // 提现金额
- 'withdraw_type' => $data['withdraw_type'], // 提现方式(1:微信 2:支付宝 3:银行卡)
- 'withdraw_account' => $data['withdraw_account'], // 提现账号
- 'withdraw_account_name' => $data['withdraw_account_name'], // 提现账户名称
- 'state' => WithdrawStatus::PROCESSING, // 提现状态
- ]);
- // TODO: 创建交易记录字段需关联枚举
- // 创建交易记录
- $record = WalletTransRecord::create([
- 'wallet_id' => $wallet->id,
- 'trans_no' => $transNo,
- 'trans_type' => 2, // 支出
- 'amount' => -$amount,
- 'before_balance' => $wallet->available_balance,
- 'after_balance' => $wallet->available_balance - $amount,
- 'owner_type' => WalletWithdrawRecord::class,
- 'owner_id' => $withdraw->id,
- 'remark' => '提现申请',
- 'state' => 2, // 处理中
- ]);
- // 冻结提现金额
- $wallet->decrement('available_balance', $amount);
- $wallet->increment('frozen_amount', $amount);
- // 记录日志
- \Log::info('技师提现申请成功', [
- 'user_id' => $userId,
- 'coach_id' => $user->coach->id,
- 'trans_no' => $transNo,
- 'amount' => $amount,
- 'wallet_id' => $wallet->id,
- ]);
- return [
- 'message' => '提现申请已提交',
- 'trans_no' => $transNo,
- 'amount' => number_format($amount, 2, '.', ''),
- 'state' => '处理中',
- ];
- } catch (\Exception $e) {
- \Log::error('技师提现申请失败', [
- 'user_id' => $userId,
- 'data' => $data,
- 'error' => $e->getMessage(),
- 'file' => $e->getFile(),
- 'line' => $e->getLine(),
- ]);
- throw $e;
- }
- });
- }
- /**
- * 格式化交易类型
- */
- private function formatTransType(int $type): string
- {
- return match ($type) {
- 1 => '收入',
- 2 => '支出',
- default => '未知',
- };
- }
- /**
- * 格式化来源类型
- */
- private function formatOwnerType(string $type): string
- {
- return match ($type) {
- 'order' => '订单',
- 'withdraw' => '提现',
- 'refund' => '退款',
- 'system' => '系统',
- default => '其他',
- };
- }
- /**
- * 格式化状态
- */
- private function formatStatus(int $status): string
- {
- return match ($status) {
- 1 => '成功',
- 2 => '处理中',
- 3 => '失败',
- default => '未知',
- };
- }
- /**
- * 获取钱包流水统计
- *
- * @param int $walletId 钱包ID
- */
- private function getWalletStatistics(int $walletId): array
- {
- try {
- // 计算总收入和总支出
- $totals = WalletTransRecord::where('wallet_id', $walletId)
- ->selectRaw(expression: '
- SUM(CASE WHEN amount > 0 THEN amount ELSE 0 END) as total_income,
- ABS(SUM(CASE WHEN amount < 0 THEN amount ELSE 0 END)) as total_withdraw
- ')->first();
- // 计算今日收入
- $todayIncome = WalletTransRecord::where('wallet_id', $walletId)
- ->where('amount', '>', 0)
- ->whereDate('created_at', operator: today())
- ->sum('amount');
- // 计算本月收入
- $monthIncome = WalletTransRecord::where('wallet_id', $walletId)
- ->where('amount', '>', 0)
- ->whereYear('created_at', now()->year)
- ->whereMonth('created_at', now()->month)
- ->sum('amount');
- // 计算上月收入
- $lastMonthIncome = WalletTransRecord::where('wallet_id', $walletId)
- ->where('amount', '>', 0)
- ->whereYear('created_at', now()->subMonth()->year)
- ->whereMonth('created_at', now()->subMonth()->month)
- ->sum('amount');
- return [
- 'total_income' => $totals->total_income ?? 0,
- 'total_withdraw' => $totals->total_withdraw ?? 0,
- 'today_income' => $todayIncome,
- 'month_income' => $monthIncome,
- 'last_month_income' => $lastMonthIncome,
- ];
- } catch (\Exception $e) {
- Log::error('获取钱包统计信息失败', [
- 'wallet_id' => $walletId,
- 'error' => $e->getMessage(),
- ]);
- return [
- 'total_income' => 0,
- 'total_withdraw' => 0,
- 'today_income' => 0,
- 'month_income' => 0,
- 'last_month_income' => 0,
- ];
- }
- }
- }
|