mirror of
https://github.com/myronblair/tomsjavajive
synced 2026-07-27 16:52:36 -05:00
Wire up wallet balance and gift cards at checkout; fix Square gift card option; fix account/rewards.php CSS; fix real PDO/schema bugs found along the way
Feature: checkout.php now lets logged-in customers apply existing wallet balance or redeem a gift card code (which tops up wallet first, then applies) toward their order total. Deduction is deferred to payment success (markSquarePaymentResult in includes/square.php), never at order creation, so an abandoned checkout never loses real wallet money - mirrors how loyalty points already work here, unlike stock which is decremented eagerly. payment.php gains a second Square Gift Card tab (payments.giftCard() SDK method) alongside the card form, both hitting the same create-square-payment.php endpoint since Square treats both source types identically. New api/apply-wallet-credit.php validates/quotes an amount without writing anything - actual spend happens only via markSquarePaymentResult(). The gift-card-to-wallet transaction logic was extracted out of api/redeem-gift-card.php into a shared loyalty()->redeemGiftCardToWallet() so the Wallet page and checkout both call the same code. Also fixed three unrelated pre-existing bugs surfaced while testing this: - loyalty.php awardPoints() reused the same named PDO parameter (:points) twice in one UPDATE - fails under real prepared statements, meaning loyalty points (and the email sent right after them) were silently never awarded for any order tied to a logged-in customer. - redeemGiftCardToWallet (formerly inline in redeem-gift-card.php) referenced a gift_cards.updated_at column that does not exist in the schema, and used invalid enum values (gift_card_transactions.type=redeem, wallet_transactions.type=gift_card) that do not match the actual enum definitions - gift card redemption has likely never worked at all. - account/rewards.php was missing the line that loads account.css, unlike every other account/*.php page, so its sidebar/layout rendered unstyled.
This commit is contained in:
+100
-3
@@ -86,6 +86,15 @@ require_once __DIR__ . '/includes/header.php';
|
||||
</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<div class="payment-options mb-2" style="display: flex; gap: 0.5rem;">
|
||||
<button type="button" id="pay-tab-card" class="btn btn-primary" style="flex: 1;">
|
||||
<i class="fas fa-credit-card"></i> Card
|
||||
</button>
|
||||
<button type="button" id="pay-tab-giftcard" class="btn btn-secondary" style="flex: 1;">
|
||||
<i class="fas fa-gift"></i> Gift Card
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form id="payment-form">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Card Details</label>
|
||||
@@ -100,6 +109,21 @@ require_once __DIR__ . '/includes/header.php';
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<form id="gift-card-payment-form" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Square Gift Card</label>
|
||||
<div id="gift-card-element" style="padding: 0.75rem; border: 1px solid var(--color-border); border-radius: var(--radius-md);"></div>
|
||||
<div id="gift-card-errors" class="form-error" style="margin-top: 0.5rem;"></div>
|
||||
</div>
|
||||
|
||||
<button type="submit" id="gift-card-submit-button" class="btn btn-secondary btn-lg btn-block">
|
||||
<span id="gift-card-button-text">Pay <?= formatCurrency($total) ?></span>
|
||||
<span id="gift-card-spinner" style="display: none;">
|
||||
<span class="loading"></span> Processing...
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<?php if (!$stripeConfigured): ?>
|
||||
@@ -203,13 +227,86 @@ function wireDemoForm(endpoint) {
|
||||
wireDemoForm('/api/create-square-payment.php');
|
||||
<?php else: ?>
|
||||
// Square Web Payments SDK
|
||||
let squareCard;
|
||||
let squareCard, squareGiftCard;
|
||||
const squarePayments = window.Square.payments('<?= SQUARE_APP_ID ?>', '<?= SQUARE_LOCATION_ID ?>');
|
||||
(async function initSquare() {
|
||||
const payments = window.Square.payments('<?= SQUARE_APP_ID ?>', '<?= SQUARE_LOCATION_ID ?>');
|
||||
squareCard = await payments.card();
|
||||
squareCard = await squarePayments.card();
|
||||
await squareCard.attach('#card-element');
|
||||
})();
|
||||
|
||||
const cardTab = document.getElementById('pay-tab-card');
|
||||
const giftCardTab = document.getElementById('pay-tab-giftcard');
|
||||
const cardForm = document.getElementById('payment-form');
|
||||
const giftCardForm = document.getElementById('gift-card-payment-form');
|
||||
let giftCardInitialized = false;
|
||||
|
||||
cardTab.addEventListener('click', function() {
|
||||
cardTab.className = 'btn btn-primary';
|
||||
giftCardTab.className = 'btn btn-secondary';
|
||||
cardForm.style.display = '';
|
||||
giftCardForm.style.display = 'none';
|
||||
});
|
||||
|
||||
giftCardTab.addEventListener('click', async function() {
|
||||
cardTab.className = 'btn btn-secondary';
|
||||
giftCardTab.className = 'btn btn-primary';
|
||||
cardForm.style.display = 'none';
|
||||
giftCardForm.style.display = '';
|
||||
if (!giftCardInitialized) {
|
||||
giftCardInitialized = true;
|
||||
squareGiftCard = await squarePayments.giftCard();
|
||||
await squareGiftCard.attach('#gift-card-element');
|
||||
}
|
||||
});
|
||||
|
||||
giftCardForm.addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
const submitBtn = document.getElementById('gift-card-submit-button');
|
||||
const buttonText = document.getElementById('gift-card-button-text');
|
||||
const spinner = document.getElementById('gift-card-spinner');
|
||||
submitBtn.disabled = true;
|
||||
buttonText.style.display = 'none';
|
||||
spinner.style.display = 'inline';
|
||||
document.getElementById('gift-card-errors').textContent = '';
|
||||
|
||||
try {
|
||||
const tokenResult = await squareGiftCard.tokenize();
|
||||
if (tokenResult.status !== 'OK') {
|
||||
const msg = (tokenResult.errors && tokenResult.errors[0] && tokenResult.errors[0].message) || 'Gift card validation failed';
|
||||
document.getElementById('gift-card-errors').textContent = msg;
|
||||
submitBtn.disabled = false;
|
||||
buttonText.style.display = 'inline';
|
||||
spinner.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch('/api/create-square-payment.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ order_id: orderId, source_id: tokenResult.token })
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
if (data.error) {
|
||||
showMessage(data.error, 'error');
|
||||
submitBtn.disabled = false;
|
||||
buttonText.style.display = 'inline';
|
||||
spinner.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
if (data.success && data.redirect) {
|
||||
showMessage('Payment successful! Redirecting...', 'success');
|
||||
setTimeout(() => window.location.href = data.redirect, 1000);
|
||||
}
|
||||
} catch (err) {
|
||||
showMessage('Payment failed. Please try again.', 'error');
|
||||
console.error(err);
|
||||
submitBtn.disabled = false;
|
||||
buttonText.style.display = 'inline';
|
||||
spinner.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
const form = document.getElementById('payment-form');
|
||||
const submitButton = document.getElementById('submit-button');
|
||||
const buttonText = document.getElementById('button-text');
|
||||
|
||||
Reference in New Issue
Block a user