first(); } /** * 进行回水操作 * @param $id * @return bool * @throws Exception */ public static function grant($id): bool { return RewardGrantService::grant('backflow', (int) $id, (string) (request()->user->username ?? 'system')); } /** * 记录本期充值/提现供列表展示,回水金额按分类亏损和规则计算。 * @param $memberId string 会员ID * @param $changeAmount float 充值或提现金额 * @return Backflow */ public static function updateOrCreate(string $memberId, float $changeAmount): Backflow { $date = BackflowPeriod::forDate(Carbon::now(BackflowPeriod::TIMEZONE)->toDateString(), BackflowPeriod::dailyFrom()); $field = $changeAmount > 0 ? 'recharge_amount' : 'withdrawal_amount'; $query = static::$MODEL::query(); if (strlen($date) === 10) $query->where('daily_date', $date); $backflow = $query->firstOrCreate(['date' => $date, 'member_id' => $memberId]); static::$MODEL::whereKey($backflow->id)->whereIn('status', Backflow::OPEN_STATUSES)->increment($field, $changeAmount); return $backflow->refresh(); } /** 已发放 / 待发放 / 是否可发放 */ public static function grantFields(array $row, ?string $dailyFrom = null, bool $hasUnsettled = false): array { $amount = bcadd((string) ($row['amount'] ?? 0), '0', 2); $granted = bcadd((string) ($row['granted_amount'] ?? 0), '0', 2); $open = in_array((int) ($row['status'] ?? 0), Backflow::OPEN_STATUSES, true); $pending = $open && bccomp($amount, $granted, 2) > 0 ? bcsub($amount, $granted, 2) : '0.00'; $period = (string) ($row['date'] ?? ''); $today = Carbon::now(BackflowPeriod::TIMEZONE)->toDateString(); [, $end] = $period !== '' ? BackflowPeriod::bounds($period, $dailyFrom) : ['', $today]; $closed = $period !== '' && $today >= $end; $waiting = $closed && $hasUnsettled && BackflowPeriod::waitsForSettlement($period, $dailyFrom); return [ 'amount' => $amount, 'granted_amount' => $granted, 'pending_amount' => $pending, 'can_grant' => $open && !$waiting && ($closed || bccomp($pending, '0', 2) > 0), 'status_text' => [Backflow::STATUS_PENDING => '未发放', Backflow::STATUS_GRANTED => '已发放', Backflow::STATUS_PARTIAL => '部分发放'][(int) ($row['status'] ?? 0)] ?? '', ]; } public static function getWhere(array $search = []): array { $where = []; if (isset($search['id']) && !empty($search['id'])) { $where[] = ['backflow.id', '=', $search['id']]; } if (isset($search['member_id']) && !empty($search['member_id'])) { $where[] = ['backflow.member_id', '=', $search['member_id']]; } if (isset($search['date']) && !empty($search['date'])) { $period = $search['date']; $where[] = strlen($period) === 7 ? ['backflow.date', 'like', $period . '%'] : ['backflow.date', '=', $period]; } if (isset($search['status']) && $search['status'] != '') { $where[] = ['backflow.status', '=', $search['status']]; } if (!empty($search['account'])) { $where[] = ['users.account', 'like', '%' . trim((string)$search['account']) . '%']; } if (!empty($search['first_name'])) { $where[] = ['users.first_name','like', '%'.$search['first_name'].'%']; } return $where; } public static function paginate(array $search = []): array { $today = Carbon::now(BackflowPeriod::TIMEZONE)->toDateString(); $dailyFrom = BackflowPeriod::dailyFrom(); $query = static::$MODEL::join('users', 'users.member_id', '=', 'backflow.member_id') ->where(static::getWhere($search)) ->where('backflow.date', '<=', $today); \App\Support\MemberAudience::visibleUsers($query, 'users'); // 后台模拟会员只在模拟管理里出现 $paginator = $query->select("backflow.*", "users.first_name", "users.account", "users.admin_note as user_admin_note")->orderByDesc('date')->orderBy('status') ->paginate($search['limit']); // 未结清的记录按最新注单和当前规则实时重算(规则修改后存储值可能过期),与点“发放”时的计算一致 $tiers = $labels = null; foreach ($paginator->items() as $item) { $hasUnsettled = false; if (in_array((int) $item->status, Backflow::OPEN_STATUSES, true)) { $tiers ??= RewardRuleService::tiers('backflow'); $labels ??= RewardRuleService::categories('backflow'); $user = RewardBasisService::user((string) $item->member_id); $basis = $user ? RewardBasisService::backflowBasis($user, (string) $item->date, $dailyFrom) : []; $live = RewardBasisService::backflowReward($basis, $tiers, $labels); $hasUnsettled = $live['has_unsettled']; $item['amount'] = $live['amount']; $item['loss_amount'] = $live['loss_amount']; $item['need_flow'] = $live['need_flow']; $item['details'] = $live['details']; } foreach (self::grantFields($item->toArray(), $dailyFrom, $hasUnsettled) as $field => $value) $item[$field] = $value; } // $count = $query->count(); // $query->with(['user'])->orderByDesc('date')->orderBy('status'); // $list = $query->forPage($search['page'], $search['limit'])->get()->toArray(); // return ['total' => $count, 'data' => $list]; return ['total' => $paginator->total(), 'data' => $paginator->items()]; } }