{% extends 'wfbo/_layout.html.twig' %} {% block title %}{{ subject.firstName }} {{ subject.lastName }} — Transactions{% endblock %} {% block wfbo_title %}User Transactions{% endblock %} {% block wfbo_content %} {% for flash in app.flashes('success') %} {% endfor %} {% for flash in app.flashes('error') %} {% endfor %} {# ── User header ── #}
← Back to Users
{{ subject.firstName|first|upper }}{{ subject.lastName|first|upper }}

{{ subject.firstName }} {{ subject.lastName }} {% if subject.isHouseAgent %} House Agent {% endif %}

{{ subject.userIdentifier }}

{# Wallet balance badge #}

Wallet Balance

₱{{ subject.walletBalance|number_format(2) }}

{# Actions dropdown #} {% if is_granted('ROLE_ADMIN') or is_granted('ROLE_SUPER_ADMIN') %} {% set isPlainUser = 'ROLE_MASTER_AGENT' not in subject.roles and 'ROLE_AGENT' not in subject.roles and 'ROLE_ADMIN' not in subject.roles and 'ROLE_SUPER_ADMIN' not in subject.roles and 'ROLE_FINANCE' not in subject.roles and 'ROLE_OPERATIONS' not in subject.roles and 'ROLE_AUDITOR' not in subject.roles %} {# Hidden forms — triggered by dropdown items #} {% if 'ROLE_ADMIN' not in subject.roles and 'ROLE_SUPER_ADMIN' not in subject.roles %} {% else %} {% endif %} {% if 'ROLE_FINANCE' not in subject.roles %} {% else %} {% endif %} {% if 'ROLE_OPERATIONS' not in subject.roles %} {% else %} {% endif %} {% if 'ROLE_AUDITOR' not in subject.roles %} {% else %} {% endif %} {% if is_granted('ROLE_SUPER_ADMIN') %} {% endif %} {# Dropdown trigger #} {% endif %}
{# ── Upline family tree ── #} {% if treeUplineChain|length > 0 or isAgent %}

Agents

{% for uplineUser in treeUplineChain %} {% set uIsMaster = 'ROLE_MASTER_AGENT' in uplineUser.roles %} {% set uIsAgent = 'ROLE_AGENT' in uplineUser.roles %}
{% if uIsMaster %} Master Agent {% elseif uIsAgent %} Agent {% endif %}
{{ uplineUser.firstName }} {{ uplineUser.lastName }}
{% endfor %} {% set subjectIsMaster = 'ROLE_MASTER_AGENT' in subject.roles %} {% set subjectIsAgent = 'ROLE_AGENT' in subject.roles %}
{% if subjectIsMaster %} Master Agent {% elseif subjectIsAgent %} Agent {% else %} Player {% endif %} {{ subject.firstName }} {{ subject.lastName }} viewing
{% endif %} {# ── System Adjustment form (ROLE_AUDITOR only) ── #} {% if is_granted('ROLE_AUDITOR') %}

System Adjustment

Auditor only — credit or debit this player's wallet.

{% endif %} {# ── Period filter (scopes the stat cards below only, not the tables) ── #} {% set periodPresets = [ {key: 'today', label: 'Today'}, {key: 'yesterday', label: 'Yesterday'}, {key: 'this_month', label: 'This Month'}, {key: 'last_month', label: 'Last Month'}, {key: 'this_year', label: 'This Year'}, {key: 'last_year', label: 'Last Year'}, ] %}
{% for p in periodPresets %} {{ p.label }} {% endfor %} ↻ Refresh
{# ── Stats row ── #} {% set colClass = 'col-12 col-sm-6 col-lg-3' %}

Total Deposited

₱{{ totalDeposited|number_format(2) }}

Total Bonus Received

₱{{ totalBonusReceived|number_format(2) }}

Total Bet Amount

₱{{ totalBetAmount|number_format(2) }}

Total Win Amount

₱{{ totalWinAmount|number_format(2) }}

{% if isAgent %}

Total Commission

₱{{ totalCommissionAmount|number_format(2) }}

Direct Referrals

{{ directReferralCount }}

Players Logged In · {{ periodLabel }}

{{ playersLoggedIn }}

Active Players · {{ periodLabel }}

{{ activePlayers }}

{% if 'ROLE_MASTER_AGENT' in subject.roles %}

Referrals from Agents

{{ subAgentReferralCount }}

{% endif %}

Total Player Bet Amount

₱{{ totalPlayerBetAmount|number_format(2) }}

Total Player Win Amount

₱{{ totalPlayerWinAmount|number_format(2) }}

Total Win Rate

{{ totalPlayerWinRate|number_format(2) }}%

Total Revenue Collected

₱{{ totalPlayerRevenue|number_format(2) }}

{% endif %}
{# ── Type tabs ── #}
Deposits ({{ depositCount }}) Withdrawals ({{ withdrawalCount }}) Bets ({{ betCount }}) Adjustments ({{ adjustmentCount }}) Bonuses ({{ bonusCount }}) Wallet ({{ walletCount }}) Activity ({{ activityCount }}) {% if isAgent %} Commissions ({{ commissionCount }}) Players ({{ playerCount }}) Agents ({{ agentCount }}) Player Bets ({{ playerBetCount }}) By Event / Race ({{ commEventCount }}) {% endif %}
{# ── Deposits table (Deposit entities directly - every status, not just approved) ── #} {% if currentType == 'deposits' %}
{% for deposit in deposits %} {% else %} {% endfor %}
Date Amount Sent To Ref. No. Status

{{ deposit.createdAt|date('M d, Y') }}

{{ deposit.createdAt|date('h:i A') }}

₱{{ deposit.amount|number_format(2) }}

{% if deposit.approvedAmount is not null %}

Approved: ₱{{ deposit.approvedAmount|number_format(2) }}

{% endif %}
{% if deposit.paymentDetail %}

{{ deposit.paymentDetail.label }}

{{ deposit.paymentDetail.bankName }}

{{ deposit.paymentDetail.accountNumber }}

{% else %} — {% endif %}
{{ deposit.transactionReference ?? '—' }} {% if deposit.status == 'pending' %} Pending {% elseif deposit.status == 'approved' %} Approved {% if deposit.reviewNote %}

{{ deposit.reviewNote }}

{% endif %} {% else %} Rejected {% if deposit.reviewNote %}

{{ deposit.reviewNote }}

{% endif %} {% endif %}
No deposits found for this user.
{% endif %} {# ── Unified transactions table (withdrawals/adjustments) ── #} {% if currentType in ['withdrawals', 'adjustments', 'bonuses', 'wallet'] %} {% if currentType == 'wallet' %}
{% if currentTxType %} Clear {% endif %} {{ total }} transaction{{ total != 1 ? 's' : '' }}
{% endif %}
{% if currentType == 'withdrawals' %}{% endif %} {% if currentType == 'wallet' %}{% endif %} {% if currentType == 'wallet' %}{% endif %} {% for tx in transactions %} {% if currentType == 'withdrawals' %} {% endif %} {% if currentType == 'wallet' %} {% endif %} {% if currentType == 'wallet' %} {% endif %} {% else %} {% endfor %}
Date Type DescriptionBank DetailsReferenceAmountBalance Before{{ currentType == 'wallet' ? 'Balance After' : 'Balance' }}

{{ tx.createdAt|date('M d, Y') }}

{{ tx.createdAt|date('h:i A') }}

{% if tx.type == 'deposit' %} Deposit {% elseif tx.type == 'withdrawal' %} Withdrawal {% elseif tx.type == 'bet' %} Bet {% elseif tx.type == 'win' %} Win {% elseif tx.type == 'bonus' %} Bonus {% if tx.referenceType == 'deposit_campaign_award' %}

Deposit Promo

{% elseif tx.referenceType == 'player_bonus' %}

Claimed Bonus

{% endif %} {% elseif tx.type == 'adjustment' %} Adjustment {% elseif tx.type == 'refund' %} Refund {% elseif tx.type == 'commission' %} Commission {% else %} {{ tx.type|capitalize }} {% endif %}
{{ tx.description ?? '—' }} {% set w = withdrawalsByReferenceId[tx.referenceId] ?? null %} {% if w %}

{{ w.bankName }}

{{ w.bankAccountName }}

{{ w.bankAccountNumber }}

{% else %} — {% endif %}
{% set refLabels = { 'race_bet': 'Race bet', 'high_low_bet': 'High-Low bet', 'mines_game': 'Mines game', 'color_game_bet': 'Color Game bet', 'fruit_king_bet': 'Fruit King bet', 'pachinko_bet': 'Pachinko bet', 'spin_win_bet': 'Spin & Win bet', 'pusoy_bet': 'Pusoy Dos hand', 'live_racing_bet': 'Live Racing bet', 'event': 'LR event', } %} {{ tx.referenceType ? (refLabels[tx.referenceType] ?? tx.referenceType) ~ (tx.referenceId ? ' #' ~ tx.referenceId : '') : '—' }} {% set absAmount = tx.absoluteAmount %} {% if tx.amount > 0 %}

+₱{{ absAmount|number_format(2) }}

{% else %}

-₱{{ absAmount|number_format(2) }}

{% endif %}
₱{{ tx.balanceBefore|number_format(2) }} ₱{{ tx.balanceAfter|number_format(2) }}
No {{ currentType == 'wallet' ? 'wallet transactions' : currentType }} found for this user.
{% endif %} {# ── Bets table (real per-game bet entities via WfboController::betUnion) ── #} {% if currentType == 'bets' %}
{% if currentSearch %} Clear {{ total }} match{{ total != 1 ? 'es' : '' }} for "{{ currentSearch }}" {% endif %}
{% if is_granted('ROLE_SUPER_ADMIN') %} {% endif %} {% for bet in bets %} {{ _self.bet_cells(bet, lrBetSummaries, lrNoteByRef, is_granted('ROLE_SUPER_ADMIN'), subject.mobileNumber) }} {% else %} {% endfor %}
Date Game Ref # Detail Bet Payout OutcomeAction
No bets found for this user.
{% endif %} {# Shared per-game bet cells (Date/Game/Ref/Detail/Bet/Payout/Outcome), used by the Bets panel and the Player Bets panel. #} {% macro bet_cells(bet, lrBetSummaries, lrNoteByRef, showActions, playerMobile) %}

{{ bet.created_at|date('M d, Y') }}

{{ bet.created_at|date('h:i A') }}

{% if bet.game == 'vk' %} Video Karera {% elseif bet.game == 'high-low' %} Pataasan {% elseif bet.game == 'mines' %} Mines {% elseif bet.game == 'fk' %} Fruit King {% elseif bet.game == 'pk' %} Pachinko {% elseif bet.game == 'sw' %} Spin & Win {% elseif bet.game == 'pd' %} Pusoy Dos {% elseif bet.game == 'lr' %} Live Racing {% elseif bet.game == 'cg' %} Color Game {% else %} {% endif %} #{{ bet.ref_id }} {% if bet.game == 'high-low' %} {% if bet.round_cards is defined and bet.round_cards is not null %} {% set cards = bet.round_cards|split('|') %} {% set winnerCard = bet.round_result in ['card1', 'card2'] ? attribute({card1: cards[0], card2: cards[1]}, bet.round_result) : null %}
Bet: Card {{ bet.description|slice(4) }} {% if bet.round_result is defined and bet.round_result is not null %} Result: Card {{ bet.round_result|slice(4) }} ↑ {% if winnerCard %} {% endif %} {% endif %}
{% else %}
Bet: Card {{ bet.description|slice(4) }}
{% endif %} {% elseif bet.game == 'cg' %} {% set dice = bet.round_result ? bet.round_result|split(',') : [] %} {% set cgDiceBg = {'yellow':'#F4B942','white':'#F5F5F5','pink':'#FF3E9A','blue':'#3D87E8','red':'#E63946','green':'#3FB65D'} %} {% set cgDiceFg = {'yellow':'#3a2606','white':'#1a1330','pink':'#ffffff','blue':'#ffffff','red':'#ffffff','green':'#ffffff'} %}
{{ bet.description }} {% if dice|length == 3 %}
{% for d in dice %} {{ d|slice(0, 1) }} {% endfor %}
{% endif %}
{% elseif bet.game == 'mines' %} {{ bet.description|replace({'_': ' '})|capitalize }} — {{ bet.round_result }} tile{{ bet.round_result == '1' ? '' : 's' }} revealed {% elseif bet.game == 'fk' %} Bet: {{ bet.description|capitalize }}{% if bet.round_result %} — Landed: {{ bet.round_result|capitalize }}{% endif %} {% elseif bet.game == 'pk' or bet.game == 'sw' %} {{ bet.description }} {% elseif bet.game == 'pd' %} {{ bet.description }}{% if bet.round_result %} — finished {{ bet.round_result }}{% endif %} {% elseif bet.game == 'lr' %} {# The per-leg candidate breakdown is precomputed in PHP (WfboController::resolveLrSelectionSummaries) - a boxed ticket can carry 900+ combos and doing this in Twig blew the request memory limit. #} {{ bet.description|title }}{% if lrBetSummaries[bet.id] is defined and lrBetSummaries[bet.id] %} — {{ lrBetSummaries[bet.id] }}{% endif %}{% if bet.combo_count is defined and bet.combo_count > 1 %} (×{{ bet.combo_count }}){% endif %} {% else %} {{ bet.description }} {% endif %}

₱{{ bet.amount|number_format(2) }}

{% if (bet.status == 'won' or bet.status == 'mixed') and bet.payout and bet.payout > 0 %}

₱{{ bet.payout|number_format(2) }}

{% else %}

—

{% endif %} {% if bet.status == 'won' %} Won {% elseif bet.status == 'lost' %} Lose {% elseif bet.status == 'void' %} Void {% elseif bet.status == 'mixed' %} {% set counts = bet.status_counts is not null ? bet.status_counts|json_decode : null %} {% set mixedParts = [] %} {% if counts %} {% if counts.pending > 0 %}{% set mixedParts = mixedParts|merge([counts.pending ~ ' pending']) %}{% endif %} {% if counts.won > 0 %}{% set mixedParts = mixedParts|merge([counts.won ~ ' won']) %}{% endif %} {% if counts.lost > 0 %}{% set mixedParts = mixedParts|merge([counts.lost ~ ' lose']) %}{% endif %} {% if counts.void > 0 %}{% set mixedParts = mixedParts|merge([counts.void ~ ' void']) %}{% endif %} {% endif %} {{ mixedParts|length > 0 ? mixedParts|join(', ') : 'Mixed' }} {% else %} Pending {% endif %} {% if bet.game == 'lr' and lrNoteByRef is defined and lrNoteByRef[bet.ref_id] is defined and is_granted('ROLE_SUPER_ADMIN') %} note {% endif %} {% if showActions %} {% if bet.game == 'lr' and bet.status in ['pending', 'mixed'] and is_granted('ROLE_SUPER_ADMIN') %}
{% else %} — {% endif %} {% endif %} {% endmacro %} {# ── Player Bets table (agent downline) ── #} {% if currentType == 'playerbets' %}
{% if currentSearch %} Clear {% endif %}
{% for bet in bets %} {% set player = betPlayers[bet.bettor_id] ?? null %} {{ _self.bet_cells(bet, lrBetSummaries, {}, false) }} {% else %} {% endfor %}
Player Date Game Ref # Detail Bet Payout Outcome
{{ player ? player.firstName ~ ' ' ~ player.lastName : '#' ~ bet.bettor_id }}
No bets found for this agent's players.
{% endif %} {# ── Activity log table ── #} {% if currentType == 'activity' %}
{% for log in auditLogs %} {% else %} {% endfor %}
Date Action Performed By

{{ log.createdAt|date('M d, Y') }}

{{ log.createdAt|date('h:i A') }}

{{ log.action }} {% if log.actor %} {{ log.actor.firstName }} {{ log.actor.lastName }} {% else %} — {% endif %}
No activity recorded for this user.
{% endif %} {# ── Commissions table (agent/sub-agent users only) ── #} {% if currentType == 'commissions' %}
{% if currentCommEvent %} Clear Live Racing commissions only · {{ total }} entr{{ total == 1 ? 'y' : 'ies' }} {% endif %}
to
{% for commission in commissions %} {% if commission.bet is defined %} {# ── Live Racing commission (live_racing_commission) ── #} {% else %} {% set cb = commission.raceBet ?? commission.highLowBet ?? commission.colorGameBet ?? commission.minesGame ?? commission.fruitKingBet ?? commission.pachinkoBet ?? commission.spinWinBet ?? commission.pusoyBet %} {% endif %} {% else %} {% endfor %}
Date Player Mobile # Game Ref # Detail Bet Amount Commission Status

{{ commission.createdAt|date('M d, Y') }}

{{ commission.createdAt|date('h:i A') }}

{{ commission.sourcePlayer.firstName }} {{ commission.sourcePlayer.lastName }} {{ commission.sourcePlayer.userIdentifier }} Live Racing {{ commission.bet.referenceNumber }} {{ commission.bet.betTypeKey|replace({'_': ' '})|title }} · {{ commission.role|capitalize }} {% set meta = lrCommissionMeta[commission.id] ?? null %} {% if meta %} {{ meta.eventLabel }}{% if meta.raceNumbers is not empty %} · R{{ meta.raceNumbers|join(', R') }}{% endif %} {% endif %}

₱{{ commission.bet.amount|number_format(2) }}

₱{{ commission.amount|number_format(2) }}

{% if commission.bet.status == 'won' %} Won {% elseif commission.bet.status == 'lost' %} Lose {% elseif commission.bet.status == 'void' %} Void {% else %} Processing {% endif %}

{{ commission.createdAt|date('M d, Y') }}

{{ commission.createdAt|date('h:i A') }}

{{ commission.sourcePlayer.firstName }} {{ commission.sourcePlayer.lastName }} {{ commission.sourcePlayer.userIdentifier }} {% if commission.raceBet %} Video Karera {% elseif commission.highLowBet %} Pataasan {% elseif commission.colorGameBet %} Color Game {% elseif commission.fruitKingBet %} Fruit King {% elseif commission.pachinkoBet %} Pachinko {% elseif commission.spinWinBet %} Spin & Win {% elseif commission.pusoyBet %} Pusoy Dos {% else %} Mines {% endif %} {% if commission.raceBet %} #{{ commission.raceBet.race.id }} {% elseif commission.highLowBet %} #{{ commission.highLowBet.round.id }} {% else %} #{{ cb.id }} {% endif %} {% if commission.raceBet %} {{ commission.raceBet.firstHorse }}-{{ commission.raceBet.secondHorse }} {% elseif commission.highLowBet %} {% if commission.highLowBet.prediction == 'card1' %} Card 1 {% else %} Card 2 {% endif %} {% elseif commission.colorGameBet %} {{ commission.colorGameBet.color|capitalize }} · {{ commission.colorGameBet.matchCount }} match {% elseif commission.fruitKingBet %} {{ commission.fruitKingBet.symbol|capitalize }}{% if commission.fruitKingBet.resultSymbol %} — {{ commission.fruitKingBet.resultSymbol|capitalize }}{% if commission.fruitKingBet.resultTier == 'triple' %} (triple){% endif %}{% endif %} {% elseif commission.pachinkoBet %} {{ commission.pachinkoBet.multiplier }}× {% elseif commission.pusoyBet %} {{ commission.pusoyBet.hand.tier|capitalize }}{% if commission.pusoyBet.placement %} — #{{ commission.pusoyBet.placement }}{% endif %} {% else %} {{ commission.minesGame.tier|replace({'_': ' '})|capitalize }} — {{ commission.minesGame.tilesRevealed }} tile{{ commission.minesGame.tilesRevealed == 1 ? '' : 's' }} revealed {% endif %}

₱{{ cb.amount|number_format(2) }}

₱{{ commission.amount|number_format(2) }}

{% if cb.status == 'won' or cb.status == 'cashed_out' %} Won {% elseif cb.status == 'lost' or cb.status == 'busted' %} Lose {% else %} Processing {% endif %}
No commissions found for this agent.
{% endif %} {# ── Commission by event / race (Live Racing, agent/sub-agent only) ── #} {% if currentType == 'commissions-by-race' %}

Commission from a multi-race bet is attributed to its last leg — the race it settles against. Click a race to see its entries.

{% if currentCommEvent is null %}

Select an event above to see its per-race commission breakdown.

{% else %}
{% for r in commRaceRows %} {% else %} {% endfor %} {% if commRaceUnattributed != '0.00' %} {% endif %} {% if commRaceTotal %} {% endif %}
Race Losing Bets Commission
Race {{ r.raceNumber }} {{ r.betCount }} ₱{{ r.commission|number_format(2) }}
No Live Racing commissions for this event.
Unattributed — ₱{{ commRaceUnattributed|number_format(2) }}
Total {{ commRaceTotal.betCount }} ₱{{ commRaceTotal.commission|number_format(2) }}
{% endif %}
{% endif %} {# ── Players table ── #} {% if currentType == 'players' %}
{% for player in referredPlayers %} {% else %} {% endfor %}
# Player Name Mobile Joined Last Seen Last Bet
{{ loop.index }} {{ player.firstName }} {{ player.lastName }} {{ player.mobileNumber }} {{ player.createdAt|date('M d, Y') }} {{ player.lastSeenAt ? player.lastSeenAt|date('M d, H:i') : '—' }} {% set lb = latestBetByPlayer[player.id] ?? null %} {% if lb %}{{ lb.placedAt|date('M d, H:i') }} · {{ lb.game }}{% else %}—{% endif %}
No referred players found.
{% endif %} {# ── Agents table ── #} {% if currentType == 'agents' %}
{% for agent in downlineAgents %} {% set isSub = 'ROLE_SUB_AGENT' in agent.roles %} {% else %} {% endfor %}
# Agent Name Mobile Role Joined
{{ loop.index }} {{ agent.firstName }} {{ agent.lastName }} {{ agent.mobileNumber }} {% if isSub %} Sub-Agent {% elseif 'ROLE_AGENT' in agent.roles %} Agent {% else %} Master Agent {% endif %} {{ agent.createdAt|date('M d, Y') }}
No agents found under this account.
{% endif %} {# ── Pagination ── #} {% if totalPages > 1 %}

Page {{ currentPage }} of {{ totalPages }}  ·  {{ total }} total

{% set pageParams = {id: subject.id, type: currentType} %} {% if currentSearch %}{% set pageParams = pageParams|merge({search: currentSearch}) %}{% endif %} {% if currentCommEvent %}{% set pageParams = pageParams|merge({event: currentCommEvent}) %}{% endif %} {% if currentCommRace %}{% set pageParams = pageParams|merge({race: currentCommRace}) %}{% endif %} {% if currentTxType %}{% set pageParams = pageParams|merge({txType: currentTxType}) %}{% endif %} {% if currentPage > 1 %} ← Previous {% endif %} {% if currentPage < totalPages %} Next → {% endif %}
{% endif %} {% if currentType == 'bets' and is_granted('ROLE_SUPER_ADMIN') %} {% endif %} {% endblock %} {% block javascripts %} {{ parent() }} {% if is_granted('ROLE_ADMIN') %} {# ── Change Agent Modal ── #} {# ── House Win Rate Modal ── #} {# ── Change Name Modal (super admin only) ── #} {% endif %} {# ── Reset Password Result Modal ── #} {% set resetPwd = _flashes['reset_password_value'] ?? [] %} {% set resetName = _flashes['reset_password_name'] ?? [] %} {% if resetPwd %} {% endif %} {# ── Generic Confirmation Modal ── #} {% if is_granted('ROLE_ADMIN') %} {% endif %} {% if currentType == 'bets' and is_granted('ROLE_SUPER_ADMIN') %} {% endif %} {% endblock %}