mirror of
https://github.com/myronblair/tomtomgames
synced 2026-06-30 17:51:08 -05:00
Auto-debit platform credits when purchase is approved
When a pending purchase is resolved as completed: - Inserts a debit row into platform_credits for the matching platform (joins token_purchases.platform_id slug → platforms.id) - Debit notes include purchase #, player name, username, token count, amount, method - Total shown in credit modal now subtracts debits from credits (net balance) Credit history table updates: - CREDIT/DEBIT type badges, debit rows tinted red with − prefix - Debit rows show "Purchase #X ↗" button that closes modal, jumps to the Purchases section (all tab), and highlights that purchase row - Edit/delete buttons hidden on auto-generated debit rows Also fixes: resolve_purchase was echoing $sent (undefined variable bug) Also fixes: purchaseCard div now has id="pr-N" so jump-highlight works Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+43
-12
@@ -1228,7 +1228,7 @@ function purchaseCard(p, showActions=true) {
|
||||
'<button class="btn btn-red" data-pid="'+p.id+'" onclick="resolvePurchase(this.dataset.pid,"failed")" style="width:100%;font-size:15px;padding:10px">✗ Reject</button></div>'
|
||||
: (p.admin_note ? '<div style="font-size:14px;color:var(--gold);padding:6px 8px;background:rgba(240,192,64,.07);border-radius:6px;margin-top:4px">📝 '+escHtmlA(p.admin_note)+'</div>' : '');
|
||||
|
||||
return '<div class="card" style="margin-bottom:10px;'+(isPending?'border-color:rgba(240,192,64,.25);background:rgba(240,192,64,.02)':'')+'">'+
|
||||
return '<div class="card" id="pr-'+p.id+'" style="margin-bottom:10px;'+(isPending?'border-color:rgba(240,192,64,.25);background:rgba(240,192,64,.02)':'')+'">'+
|
||||
'<div style="display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap">'+
|
||||
'<div style="flex:1;min-width:180px">'+
|
||||
'<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:4px">'+
|
||||
@@ -3173,22 +3173,37 @@ async function loadCreditEntries() {
|
||||
list.innerHTML = `<table style="width:100%;border-collapse:collapse;font-size:14px">
|
||||
<thead><tr style="border-bottom:1px solid var(--border)">
|
||||
<th style="padding:8px 6px;text-align:left;color:var(--text2);font-size:12px;font-weight:700;letter-spacing:.5px">DATE</th>
|
||||
<th style="padding:8px 6px;text-align:right;color:var(--text2);font-size:12px;font-weight:700;letter-spacing:.5px">CREDITS</th>
|
||||
<th style="padding:8px 6px;text-align:left;color:var(--text2);font-size:12px;font-weight:700;letter-spacing:.5px">TYPE</th>
|
||||
<th style="padding:8px 6px;text-align:right;color:var(--text2);font-size:12px;font-weight:700;letter-spacing:.5px">AMOUNT</th>
|
||||
<th style="padding:8px 6px;text-align:left;color:var(--text2);font-size:12px;font-weight:700;letter-spacing:.5px">METHOD</th>
|
||||
<th style="padding:8px 6px;text-align:left;color:var(--text2);font-size:12px;font-weight:700;letter-spacing:.5px">NOTES</th>
|
||||
<th style="padding:8px 6px;width:80px"></th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
${d.credits.map(c=>`<tr style="border-bottom:1px solid rgba(255,255,255,0.05)">
|
||||
<td style="padding:9px 6px;color:var(--text)">${escHtmlA(c.credit_date)}</td>
|
||||
<td style="padding:9px 6px;text-align:right;font-family:'Exo 2',sans-serif;font-weight:700;color:var(--cyan)">${parseFloat(c.credits_purchased).toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2})}</td>
|
||||
<td style="padding:9px 6px;color:var(--text2)">${escHtmlA(c.payment_method||'—')}</td>
|
||||
<td style="padding:9px 6px;color:var(--text2);font-size:13px;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${escHtmlA(c.notes||'')}</td>
|
||||
<td style="padding:9px 6px;text-align:right;white-space:nowrap">
|
||||
<button onclick="editCreditEntry(${c.id})" style="background:rgba(0,229,255,.08);border:1px solid rgba(0,229,255,.2);color:var(--cyan);border-radius:5px;padding:3px 8px;font-size:13px;cursor:pointer;margin-right:4px">✏️</button>
|
||||
<button onclick="deleteCreditEntry(${c.id})" style="background:rgba(255,68,68,.08);border:1px solid rgba(255,68,68,.2);color:var(--red);border-radius:5px;padding:3px 8px;font-size:13px;cursor:pointer">🗑</button>
|
||||
</td>
|
||||
</tr>`).join('')}
|
||||
${d.credits.map(c=>{
|
||||
const isDebit = c.type === 'debit';
|
||||
const amtColor = isDebit ? 'var(--red)' : 'var(--cyan)';
|
||||
const amtPrefix = isDebit ? '−' : '+';
|
||||
const rowBg = isDebit ? 'background:rgba(255,68,68,.03)' : '';
|
||||
const typeBadge = isDebit
|
||||
? '<span style="background:rgba(255,68,68,.15);color:var(--red);font-size:11px;font-weight:700;padding:2px 7px;border-radius:10px;letter-spacing:.3px">DEBIT</span>'
|
||||
: '<span style="background:rgba(0,229,255,.12);color:var(--cyan);font-size:11px;font-weight:700;padding:2px 7px;border-radius:10px;letter-spacing:.3px">CREDIT</span>';
|
||||
const refLink = (isDebit && c.purchase_ref_id)
|
||||
? `<button onclick="jumpToPurchase(${c.purchase_ref_id})" style="background:rgba(240,192,64,.1);border:1px solid rgba(240,192,64,.25);color:var(--gold);border-radius:5px;padding:3px 8px;font-size:12px;cursor:pointer;font-family:'Exo 2',sans-serif;font-weight:700;white-space:nowrap">Purchase #${c.purchase_ref_id} ↗</button>`
|
||||
: '';
|
||||
const editDel = !isDebit
|
||||
? `<button onclick="editCreditEntry(${c.id})" style="background:rgba(0,229,255,.08);border:1px solid rgba(0,229,255,.2);color:var(--cyan);border-radius:5px;padding:3px 8px;font-size:13px;cursor:pointer;margin-right:4px">✏️</button>
|
||||
<button onclick="deleteCreditEntry(${c.id})" style="background:rgba(255,68,68,.08);border:1px solid rgba(255,68,68,.2);color:var(--red);border-radius:5px;padding:3px 8px;font-size:13px;cursor:pointer">🗑</button>`
|
||||
: '';
|
||||
return `<tr style="border-bottom:1px solid rgba(255,255,255,0.05);${rowBg}">
|
||||
<td style="padding:9px 6px;color:var(--text)">${escHtmlA(c.credit_date)}</td>
|
||||
<td style="padding:9px 6px">${typeBadge}</td>
|
||||
<td style="padding:9px 6px;text-align:right;font-family:'Exo 2',sans-serif;font-weight:700;color:${amtColor}">${amtPrefix}${parseFloat(c.credits_purchased).toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2})}</td>
|
||||
<td style="padding:9px 6px;color:var(--text2)">${escHtmlA(c.payment_method||'—')}</td>
|
||||
<td style="padding:9px 6px;color:var(--text2);font-size:13px;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="${escHtmlA(c.notes||'')}">${escHtmlA(c.notes||'')}</td>
|
||||
<td style="padding:9px 6px;text-align:right;white-space:nowrap">${refLink}${editDel}</td>
|
||||
</tr>`;
|
||||
}).join('')}
|
||||
</tbody></table>`;
|
||||
}
|
||||
|
||||
@@ -3249,6 +3264,22 @@ async function deleteCreditEntry(id) {
|
||||
else toast(d.error||'Error','err');
|
||||
}
|
||||
|
||||
async function jumpToPurchase(purchaseId) {
|
||||
closeCreditModal();
|
||||
showSec('purchases');
|
||||
document.querySelectorAll('#section-purchases .ftab').forEach(b=>b.classList.remove('active'));
|
||||
const allTab = document.querySelector('#section-purchases .ftab[onclick*="\'all\'"]');
|
||||
if (allTab) allTab.classList.add('active');
|
||||
await loadPurchases('all');
|
||||
const el = document.getElementById('pr-' + purchaseId);
|
||||
if (el) {
|
||||
el.scrollIntoView({behavior:'smooth', block:'center'});
|
||||
el.style.outline = '2px solid var(--gold)';
|
||||
el.style.borderRadius = '12px';
|
||||
setTimeout(() => { el.style.outline = ''; el.style.borderRadius = ''; }, 2500);
|
||||
}
|
||||
}
|
||||
|
||||
// Sync hex input with color picker
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const picker = document.getElementById('gf-color');
|
||||
|
||||
Reference in New Issue
Block a user