Production readiness hardening and ops tooling
This commit is contained in:
@ -133,27 +133,27 @@
|
||||
</div>
|
||||
</div>
|
||||
<nav class="flex-1 flex flex-col gap-1">
|
||||
<a class="flex items-center gap-3 px-4 py-3 text-secondary dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-xl transition-all font-label-md text-label-md" href="#">
|
||||
<a class="flex items-center gap-3 px-4 py-3 text-secondary dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-xl transition-all font-label-md text-label-md" href="/ui/admin-reconciliation-management">
|
||||
<span class="material-symbols-outlined" data-icon="account_balance_wallet">account_balance_wallet</span>
|
||||
<span>Reconciliation</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-4 py-3 text-secondary dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-xl transition-all font-label-md text-label-md" href="#">
|
||||
<a class="flex items-center gap-3 px-4 py-3 text-secondary dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-xl transition-all font-label-md text-label-md" href="/ui/admin-dashboard-overview">
|
||||
<span class="material-symbols-outlined" data-icon="security">security</span>
|
||||
<span>Audit Logs</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-4 py-3 text-secondary dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-xl transition-all font-label-md text-label-md" href="#">
|
||||
<a class="flex items-center gap-3 px-4 py-3 text-secondary dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-xl transition-all font-label-md text-label-md" href="/ui/admin-dashboard-overview">
|
||||
<span class="material-symbols-outlined" data-icon="payments">payments</span>
|
||||
<span>Fee Management</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-4 py-3 bg-secondary-container dark:bg-on-secondary-fixed-variant text-on-secondary-container dark:text-on-secondary-fixed rounded-xl font-bold font-label-md text-label-md" href="#">
|
||||
<a class="flex items-center gap-3 px-4 py-3 bg-secondary-container dark:bg-on-secondary-fixed-variant text-on-secondary-container dark:text-on-secondary-fixed rounded-xl font-bold font-label-md text-label-md" href="/ui/merchant-settlement-history">
|
||||
<span class="material-symbols-outlined" data-icon="receipt_long">receipt_long</span>
|
||||
<span>Settlements</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-4 py-3 text-secondary dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-xl transition-all font-label-md text-label-md" href="#">
|
||||
<a class="flex items-center gap-3 px-4 py-3 text-secondary dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-xl transition-all font-label-md text-label-md" href="/ui/device-technical-detail">
|
||||
<span class="material-symbols-outlined" data-icon="router">router</span>
|
||||
<span>Device Health</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-4 py-3 text-secondary dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-xl transition-all font-label-md text-label-md" href="#">
|
||||
<a class="flex items-center gap-3 px-4 py-3 text-secondary dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-xl transition-all font-label-md text-label-md" href="/ui/hub">
|
||||
<span class="material-symbols-outlined" data-icon="contact_support">contact_support</span>
|
||||
<span>Support</span>
|
||||
</a>
|
||||
@ -163,10 +163,10 @@
|
||||
<span class="material-symbols-outlined" data-icon="add_chart">add_chart</span>
|
||||
Generate Report
|
||||
</button>
|
||||
<a class="flex items-center gap-3 px-4 py-3 text-secondary dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-xl transition-all font-label-md text-label-md" href="#">
|
||||
<button id="merchant-logout" class="w-full flex items-center gap-3 px-4 py-3 text-secondary dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-xl transition-all font-label-md text-label-md">
|
||||
<span class="material-symbols-outlined" data-icon="logout">logout</span>
|
||||
<span>Logout</span>
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
<!-- Main Content Area -->
|
||||
@ -184,6 +184,10 @@
|
||||
<div class="flex items-center gap-4">
|
||||
<span class="material-symbols-outlined text-on-surface-variant cursor-pointer hover:text-primary transition-colors" data-icon="notifications">notifications</span>
|
||||
<span class="material-symbols-outlined text-on-surface-variant cursor-pointer hover:text-primary transition-colors" data-icon="settings">settings</span>
|
||||
<div class="text-right">
|
||||
<p id="merchant-session-name" class="text-[12px] font-bold text-on-surface leading-tight">Merchant User</p>
|
||||
<p id="merchant-session-role" class="text-[11px] text-slate-500 leading-tight">session</p>
|
||||
</div>
|
||||
<div class="h-10 w-10 rounded-full bg-slate-200 overflow-hidden border border-slate-300">
|
||||
<img alt="Administrator Avatar" class="w-full h-full object-cover" data-alt="A professional headshot of a smiling fintech administrator in a bright, modern corporate office. High-key lighting highlights the reliable and expert persona, matching a clean light-mode aesthetic with soft blue and grey tones." src="https://lh3.googleusercontent.com/aida-public/AB6AXuAULoyxr37TXy6dAfagS4FSEQl7UpTG5XXKiqbc3Lt55-L4oWWcAjgJSHLfIRx3w_TYphBzQLrW9XdgtYvGMwDlsGslyaOunv0ANbViiiH0eSWWUrweqkulmIFSgKdqKoxSKdQ8L5ouHalFrIJtx0Lff4GQ-YmlbRwDJAfjaYzNFCucdQ4X7Dt7iIx83NWQ0Mf6PlAchGv7WoVm7K3TI8C6HkpMzpYhiphfN1LYtRDR4i-kW-Uk8Gcv2tPYheVSH_5-r9spt16EOl4"/>
|
||||
</div>
|
||||
@ -199,7 +203,7 @@
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<p class="font-label-md text-label-md text-slate-500 mb-1">Available Balance</p>
|
||||
<h3 class="font-metric-lg text-metric-lg text-on-background">$12,480.50</h3>
|
||||
<h3 id="merchant-pending-payout" class="font-metric-lg text-metric-lg text-on-background">Rp0</h3>
|
||||
</div>
|
||||
<div class="w-10 h-10 bg-primary-container/10 rounded-lg flex items-center justify-center text-primary">
|
||||
<span class="material-symbols-outlined" data-icon="account_balance">account_balance</span>
|
||||
@ -218,14 +222,14 @@
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<p class="font-label-md text-label-md text-slate-500 mb-1">Next Payout Date</p>
|
||||
<h3 class="font-metric-lg text-metric-lg text-on-background">Oct 24, 2023</h3>
|
||||
<h3 id="merchant-next-payout-date" class="font-metric-lg text-metric-lg text-on-background">-</h3>
|
||||
</div>
|
||||
<div class="w-10 h-10 bg-warning/10 rounded-lg flex items-center justify-center text-warning">
|
||||
<span class="material-symbols-outlined" data-icon="event">event</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<p class="font-label-md text-label-md text-slate-400">Estimated: <span class="text-on-surface font-semibold">$3,150.00</span></p>
|
||||
<p class="font-label-md text-label-md text-slate-400">Estimated: <span id="merchant-next-payout-amount" class="text-on-surface font-semibold">Rp0</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Total Settled MTD -->
|
||||
@ -233,18 +237,18 @@
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<p class="font-label-md text-label-md text-slate-500 mb-1">Total Settled (MTD)</p>
|
||||
<h3 class="font-metric-lg text-metric-lg text-on-background">$45,210.00</h3>
|
||||
<h3 id="merchant-paid-payout" class="font-metric-lg text-metric-lg text-on-background">Rp0</h3>
|
||||
</div>
|
||||
<div class="w-10 h-10 bg-success/10 rounded-lg flex items-center justify-center text-success">
|
||||
<span class="material-symbols-outlined" data-icon="payments">payments</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 flex items-center gap-2">
|
||||
<span class="text-success font-metric-sm text-metric-sm flex items-center">
|
||||
<span class="material-symbols-outlined text-[16px]" data-icon="trending_up">trending_up</span>
|
||||
12.5%
|
||||
<span id="merchant-adjustment-amount" class="text-slate-500 font-metric-sm text-metric-sm flex items-center">
|
||||
<span class="material-symbols-outlined text-[16px]" data-icon="balance">balance</span>
|
||||
Adj Rp0
|
||||
</span>
|
||||
<span class="text-slate-400 font-label-md text-label-md">vs last month</span>
|
||||
<span class="text-slate-400 font-label-md text-label-md">included</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -262,11 +266,11 @@
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-label-md text-label-md text-slate-500 whitespace-nowrap">Status:</span>
|
||||
<select class="border-slate-200 rounded-lg text-body-md focus:ring-primary focus:border-primary py-1 px-3">
|
||||
<select id="merchant-settlement-status-filter" class="border-slate-200 rounded-lg text-body-md focus:ring-primary focus:border-primary py-1 px-3">
|
||||
<option>All Statuses</option>
|
||||
<option>Processed</option>
|
||||
<option>Pending</option>
|
||||
<option>Failed</option>
|
||||
<option value="paid">Paid</option>
|
||||
<option value="created">Pending</option>
|
||||
<option value="failed">Failed</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@ -296,7 +300,7 @@
|
||||
<th class="px-6 font-label-md text-label-md text-slate-500 uppercase tracking-wider text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-100">
|
||||
<tbody id="merchant-settlement-rows" class="divide-y divide-slate-100">
|
||||
<!-- Row 1: Processed -->
|
||||
<tr class="hover:bg-slate-50 transition-colors h-row-height group">
|
||||
<td class="px-6 font-label-md text-label-md font-semibold text-primary">SET-902341</td>
|
||||
@ -394,7 +398,7 @@
|
||||
</div>
|
||||
<!-- Pagination -->
|
||||
<div class="px-6 py-4 flex items-center justify-between border-t border-slate-100 bg-white">
|
||||
<p class="font-label-md text-label-md text-slate-500">Showing <span class="font-semibold text-on-surface">1 - 5</span> of <span class="font-semibold text-on-surface">124</span> disbursements</p>
|
||||
<p id="merchant-settlement-summary" class="font-label-md text-label-md text-slate-500">Loading settlement batches...</p>
|
||||
<div class="flex gap-2">
|
||||
<button class="p-2 border border-slate-200 rounded-lg text-slate-400 hover:text-primary hover:bg-slate-50 transition-all">
|
||||
<span class="material-symbols-outlined text-[20px]" data-icon="chevron_left">chevron_left</span>
|
||||
@ -529,8 +533,8 @@
|
||||
<div class="space-y-6">
|
||||
<div class="p-4 bg-slate-50 rounded-xl">
|
||||
<p class="font-label-md text-label-md text-slate-500">Net Amount Paid</p>
|
||||
<p class="font-metric-lg text-metric-lg text-primary">$2,401.00</p>
|
||||
<span class="inline-flex items-center mt-2 px-2.5 py-0.5 rounded-full text-xs font-medium bg-success/10 text-success">
|
||||
<p id="drawer-net-amount" class="font-metric-lg text-metric-lg text-primary">Rp0</p>
|
||||
<span id="drawer-status-badge" class="inline-flex items-center mt-2 px-2.5 py-0.5 rounded-full text-xs font-medium bg-success/10 text-success">
|
||||
Successful Transfer
|
||||
</span>
|
||||
</div>
|
||||
@ -538,19 +542,19 @@
|
||||
<h4 class="font-label-md text-label-md font-bold uppercase text-slate-400">Breakdown</h4>
|
||||
<div class="flex justify-between items-center py-2 border-b border-slate-100">
|
||||
<span class="text-body-md text-slate-600">Gross Processing Volume</span>
|
||||
<span class="font-metric-sm text-metric-sm">$2,450.00</span>
|
||||
<span id="drawer-gross-amount" class="font-metric-sm text-metric-sm">Rp0</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center py-2 border-b border-slate-100">
|
||||
<span class="text-body-md text-slate-600">Platform Fees (2%)</span>
|
||||
<span class="font-metric-sm text-metric-sm text-danger">-$49.00</span>
|
||||
<span class="text-body-md text-slate-600">Platform Fees</span>
|
||||
<span id="drawer-fee-amount" class="font-metric-sm text-metric-sm text-danger">Rp0</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center py-2 border-b border-slate-100">
|
||||
<span class="text-body-md text-slate-600">Adjustment/Refunds</span>
|
||||
<span class="font-metric-sm text-metric-sm">$0.00</span>
|
||||
<span id="drawer-adjustment-amount" class="font-metric-sm text-metric-sm">Rp0</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center py-2">
|
||||
<span class="text-body-md font-bold">Total Disbursed</span>
|
||||
<span class="font-metric-sm text-metric-sm font-bold text-primary">$2,401.00</span>
|
||||
<span id="drawer-total-amount" class="font-metric-sm text-metric-sm font-bold text-primary">Rp0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4 pt-6">
|
||||
@ -560,14 +564,14 @@
|
||||
<span class="material-symbols-outlined text-slate-500" data-icon="account_balance">account_balance</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-label-md text-label-md font-bold">HDFC Bank India</p>
|
||||
<p class="text-body-md text-slate-500">Checking Account •••• 4492</p>
|
||||
<p class="font-label-md text-label-md font-bold">Settlement Account</p>
|
||||
<p id="drawer-destination" class="text-body-md text-slate-500">-</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4 pt-6">
|
||||
<h4 class="font-label-md text-label-md font-bold uppercase text-slate-400">Transfer Log</h4>
|
||||
<div class="relative pl-6 space-y-6 before:absolute before:left-2 before:top-2 before:bottom-2 before:w-0.5 before:bg-slate-200">
|
||||
<div id="drawer-event-log" class="relative pl-6 space-y-6 before:absolute before:left-2 before:top-2 before:bottom-2 before:w-0.5 before:bg-slate-200">
|
||||
<div class="relative">
|
||||
<div class="absolute -left-[22px] top-1 w-4 h-4 rounded-full bg-success ring-4 ring-white"></div>
|
||||
<p class="font-label-md text-label-md font-bold">Transfer Initiated</p>
|
||||
@ -586,7 +590,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-8 flex flex-col gap-3">
|
||||
<button class="w-full bg-primary text-on-primary py-3 px-4 rounded-xl font-bold flex items-center justify-center gap-2">
|
||||
<button id="drawer-download-report" class="w-full bg-primary text-on-primary py-3 px-4 rounded-xl font-bold flex items-center justify-center gap-2">
|
||||
<span class="material-symbols-outlined" data-icon="download">download</span>
|
||||
Download Proof of Transfer
|
||||
</button>
|
||||
@ -599,7 +603,161 @@
|
||||
<!-- Overlay for drawer -->
|
||||
<div class="fixed inset-0 bg-slate-900/40 backdrop-blur-sm z-[90] hidden opacity-0 transition-opacity duration-300" id="drawerOverlay" onclick="toggleDrawer(false)"></div>
|
||||
</main>
|
||||
<script src="/ui/shared/merchant-api.js"></script>
|
||||
<script>
|
||||
const MerchantSettlementUI = (() => {
|
||||
const api = window.MerchantUIAPI;
|
||||
const rowsEl = document.getElementById('merchant-settlement-rows');
|
||||
const statusFilter = document.getElementById('merchant-settlement-status-filter');
|
||||
const summaryEl = document.getElementById('merchant-settlement-summary');
|
||||
const downloadBtn = document.getElementById('drawer-download-report');
|
||||
const logoutBtn = document.getElementById('merchant-logout');
|
||||
let activeBatchId = null;
|
||||
let activeBatchCode = '';
|
||||
|
||||
const normalize = (value) => String(value || '').toLowerCase();
|
||||
const money = (value) => api.formatMoney(value);
|
||||
const dt = (value) => api.formatDateTime(value);
|
||||
const setText = (id, value) => {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.textContent = value || '-';
|
||||
};
|
||||
const statusClass = (status) => {
|
||||
if (status === 'paid') return 'bg-success/10 text-success';
|
||||
if (status === 'failed' || status === 'cancelled') return 'bg-danger/10 text-danger';
|
||||
return 'bg-warning/10 text-warning';
|
||||
};
|
||||
const statusLabel = (status) => status === 'created' ? 'PENDING' : String(status || '-').toUpperCase();
|
||||
|
||||
const renderRows = (batches, merchant) => {
|
||||
if (!rowsEl) return;
|
||||
if (!batches.length) {
|
||||
rowsEl.innerHTML = '<tr><td colspan="7" class="px-6 py-10 text-center text-slate-500">No settlement batches available.</td></tr>';
|
||||
if (summaryEl) summaryEl.textContent = 'Showing 0 disbursements';
|
||||
return;
|
||||
}
|
||||
rowsEl.innerHTML = batches.map((batch) => `
|
||||
<tr class="hover:bg-slate-50 transition-colors h-row-height group cursor-pointer" data-batch-id="${batch.id}">
|
||||
<td class="px-6 font-label-md text-label-md font-semibold text-primary">${batch.batch_code}</td>
|
||||
<td class="px-6 font-body-md text-body-md text-on-surface">${dt(batch.paid_at || batch.created_at)}</td>
|
||||
<td class="px-6 font-body-md text-body-md text-slate-500">${merchant.settlement_account_reference || '-'}</td>
|
||||
<td class="px-6 font-body-md text-body-md text-right tabular-nums">${money(batch.gross_amount)}</td>
|
||||
<td class="px-6 font-body-md text-body-md text-right tabular-nums font-semibold">${money(batch.net_payable_amount)}</td>
|
||||
<td class="px-6"><span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${statusClass(batch.status)}">${statusLabel(batch.status)}</span></td>
|
||||
<td class="px-6 text-right">
|
||||
<button class="text-primary hover:underline font-label-md text-label-md flex items-center gap-1 ml-auto group-hover:opacity-100 opacity-0 transition-opacity">
|
||||
<span class="material-symbols-outlined text-[16px]" data-icon="visibility">visibility</span>
|
||||
Detail
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
rowsEl.querySelectorAll('tr[data-batch-id]').forEach((row) => {
|
||||
row.addEventListener('click', () => openDrawer(row.dataset.batchId, merchant));
|
||||
});
|
||||
if (summaryEl) summaryEl.textContent = `Showing ${batches.length} disbursement(s)`;
|
||||
};
|
||||
|
||||
const renderEvents = (events) => {
|
||||
const host = document.getElementById('drawer-event-log');
|
||||
if (!host) return;
|
||||
const rows = Array.isArray(events) ? events : [];
|
||||
if (!rows.length) {
|
||||
host.innerHTML = '<div class="relative"><div class="absolute -left-[22px] top-1 w-4 h-4 rounded-full bg-slate-300 ring-4 ring-white"></div><p class="font-label-md text-label-md font-bold">No payout events yet</p><p class="text-xs text-slate-400">-</p></div>';
|
||||
return;
|
||||
}
|
||||
host.innerHTML = rows.map((event) => {
|
||||
const label = String(event.event_type || '').replace(/_/g, ' ').toUpperCase();
|
||||
const actor = `${event.actor_type || 'system'}${event.actor_id ? ` · ${event.actor_id}` : ''}`;
|
||||
return `
|
||||
<div class="relative">
|
||||
<div class="absolute -left-[22px] top-1 w-4 h-4 rounded-full bg-success ring-4 ring-white"></div>
|
||||
<p class="font-label-md text-label-md font-bold">${label}</p>
|
||||
<p class="text-xs text-slate-400">${dt(event.created_at)} · ${actor}</p>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
};
|
||||
|
||||
const openDrawer = async (batchId, merchant) => {
|
||||
const payload = await api.getSettlementBatch(batchId);
|
||||
const batch = payload.batch;
|
||||
const metadata = batch.metadata_json || {};
|
||||
const adjustmentAmount = Array.isArray(payload.adjustments)
|
||||
? payload.adjustments
|
||||
.filter((item) => (item.approval_status || 'approved') === 'approved')
|
||||
.reduce((sum, item) => sum + Number(item.signed_amount || 0), 0)
|
||||
: Number(metadata.total_adjustment_amount || 0);
|
||||
const adjustedNetAmount = Number(batch.net_payable_amount || 0) + adjustmentAmount;
|
||||
activeBatchId = batch.id;
|
||||
activeBatchCode = batch.batch_code;
|
||||
setText('drawer-net-amount', money(adjustedNetAmount));
|
||||
setText('drawer-gross-amount', money(batch.gross_amount));
|
||||
setText('drawer-fee-amount', `-${money(batch.platform_fee_amount)}`);
|
||||
setText('drawer-adjustment-amount', money(adjustmentAmount));
|
||||
setText('drawer-total-amount', money(adjustedNetAmount));
|
||||
setText('drawer-destination', merchant.settlement_account_reference || '-');
|
||||
const badge = document.getElementById('drawer-status-badge');
|
||||
if (badge) {
|
||||
badge.textContent = statusLabel(batch.status);
|
||||
badge.className = `inline-flex items-center mt-2 px-2.5 py-0.5 rounded-full text-xs font-medium ${statusClass(batch.status)}`;
|
||||
}
|
||||
renderEvents(payload.events || []);
|
||||
toggleDrawer(true);
|
||||
};
|
||||
|
||||
const downloadActiveCsv = async () => {
|
||||
if (!activeBatchId) return;
|
||||
const { token, merchantId } = api.requireSession();
|
||||
const response = await fetch(`/merchant/settlement-batches/${encodeURIComponent(activeBatchId)}/export.csv`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'X-Merchant-Id': merchantId
|
||||
}
|
||||
});
|
||||
if (!response.ok) throw new Error(`CSV export failed: ${response.status}`);
|
||||
const blob = await response.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `${activeBatchCode || activeBatchId}-merchant-payout-report.csv`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
const load = async () => {
|
||||
api.requireSession();
|
||||
const [profile, summary, batches] = await Promise.all([
|
||||
api.getProfile(),
|
||||
api.getSettlementSummary(),
|
||||
api.listSettlementBatches({
|
||||
limit: 100,
|
||||
status: statusFilter?.value && statusFilter.value !== 'All Statuses' ? statusFilter.value : undefined
|
||||
})
|
||||
]);
|
||||
const merchant = profile?.merchant || profile;
|
||||
const user = profile?.user || api.getSessionUser?.();
|
||||
setText('merchant-session-name', user?.name || merchant.brand_name || merchant.legal_name || 'Merchant User');
|
||||
setText('merchant-session-role', user?.role_name ? `${String(user.role_name).toUpperCase()} · ${api.getAuthMode?.() || 'session'}` : api.getAuthMode?.() || 'session');
|
||||
setText('merchant-pending-payout', money(summary.pending_amount));
|
||||
setText('merchant-paid-payout', money(summary.adjusted_paid_amount ?? summary.paid_amount));
|
||||
setText('merchant-adjustment-amount', `Adj ${money(summary.adjustment_amount || 0)}`);
|
||||
setText('merchant-next-payout-amount', money(summary.pending_amount));
|
||||
setText('merchant-next-payout-date', Number(summary.created_batches || 0) > 0 ? 'On next payout run' : '-');
|
||||
renderRows(batches || [], merchant);
|
||||
};
|
||||
|
||||
statusFilter?.addEventListener('change', load);
|
||||
downloadBtn?.addEventListener('click', downloadActiveCsv);
|
||||
logoutBtn?.addEventListener('click', () => {
|
||||
api.clearSession();
|
||||
window.location.href = '/ui/merchant-login';
|
||||
});
|
||||
return { load };
|
||||
})();
|
||||
|
||||
function toggleDrawer(isOpen) {
|
||||
const drawer = document.getElementById('detailDrawer');
|
||||
const overlay = document.getElementById('drawerOverlay');
|
||||
@ -615,10 +773,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Simulating row click for detail view
|
||||
document.querySelectorAll('tbody tr').forEach(row => {
|
||||
row.style.cursor = 'pointer';
|
||||
row.addEventListener('click', () => toggleDrawer(true));
|
||||
MerchantSettlementUI.load().catch((error) => {
|
||||
console.error('[merchant-settlement] failed loading data', error);
|
||||
});
|
||||
</script>
|
||||
<!-- ui-nav -->
|
||||
@ -630,4 +786,4 @@
|
||||
<a href="/ui/admin-dashboard-overview" style="margin-right:0;color:#2563eb;text-decoration:none;font-weight:600">Dashboard</a>
|
||||
</div>
|
||||
'
|
||||
</body></html>
|
||||
</body></html>
|
||||
|
||||
Reference in New Issue
Block a user