mirror of
https://github.com/myronblair/tomsjavajive
synced 2026-07-27 16:52:36 -05:00
Add in-admin refund processing via Square RefundPayment API
admin/order.php previously had no real refund action - the "refunded" status option was purely cosmetic, only setting order_status without touching payment_status or calling any payment API. Adds a Refund card (full or partial amount, optional reason) that calls the real Square Refunds API for orders paid via Square, updates payment_status (refunded/partially_refunded) and order_status, logs the refund ID as an order note, and restores any wallet_amount_used back to the customer wallet on a full refund (mirroring how it was deducted on payment success in markSquarePaymentResult). Also fixed the Payment sidebar card to display square_payment_id (it only ever showed the old stripe_payment_intent field, even for Square orders). Tested in sandbox: full refund (wallet restore verified), and confirmed Squares own over-refund rejection surfaces cleanly as a flash error rather than a crash.
This commit is contained in:
+137
-21
@@ -5,6 +5,7 @@
|
|||||||
ob_start();
|
ob_start();
|
||||||
$pageTitle = 'Order Details';
|
$pageTitle = 'Order Details';
|
||||||
require_once __DIR__ . '/includes/header.php';
|
require_once __DIR__ . '/includes/header.php';
|
||||||
|
require_once __DIR__ . '/../includes/square.php';
|
||||||
|
|
||||||
$orderId = $_GET['id'] ?? '';
|
$orderId = $_GET['id'] ?? '';
|
||||||
|
|
||||||
@@ -24,41 +25,116 @@ if (!$order) {
|
|||||||
// Handle status update
|
// Handle status update
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$action = $_POST['action'] ?? '';
|
$action = $_POST['action'] ?? '';
|
||||||
|
|
||||||
if ($action === 'update_status') {
|
if ($action === 'update_status') {
|
||||||
$status = $_POST['status'] ?? '';
|
$status = $_POST['status'] ?? '';
|
||||||
$trackingNumber = $_POST['tracking_number'] ?? '';
|
$trackingNumber = $_POST['tracking_number'] ?? '';
|
||||||
|
|
||||||
$updateData = ['order_status' => $status];
|
$updateData = ['order_status' => $status];
|
||||||
if ($trackingNumber) {
|
if ($trackingNumber) {
|
||||||
$updateData['tracking_number'] = $trackingNumber;
|
$updateData['tracking_number'] = $trackingNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
db()->update('orders', $updateData, 'order_id = :id', ['id' => $orderId]);
|
db()->update('orders', $updateData, 'order_id = :id', ['id' => $orderId]);
|
||||||
setFlash('success', 'Order status updated');
|
setFlash('success', 'Order status updated');
|
||||||
header('Location: /admin/order.php?id=' . $orderId);
|
header('Location: /admin/order.php?id=' . $orderId);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($action === 'add_note') {
|
if ($action === 'add_note') {
|
||||||
$note = trim($_POST['note'] ?? '');
|
$note = trim($_POST['note'] ?? '');
|
||||||
if ($note) {
|
if ($note) {
|
||||||
$existingNotes = $order['notes'] ?? '';
|
$existingNotes = $order['notes'] ?? '';
|
||||||
$newNote = '[' . date('M j, Y g:i A') . '] ' . $note;
|
$newNote = '[' . date('M j, Y g:i A') . '] ' . $note;
|
||||||
$allNotes = $existingNotes ? $existingNotes . "\n" . $newNote : $newNote;
|
$allNotes = $existingNotes ? $existingNotes . "\n" . $newNote : $newNote;
|
||||||
|
|
||||||
db()->update('orders', ['notes' => $allNotes], 'order_id = :id', ['id' => $orderId]);
|
db()->update('orders', ['notes' => $allNotes], 'order_id = :id', ['id' => $orderId]);
|
||||||
setFlash('success', 'Note added');
|
setFlash('success', 'Note added');
|
||||||
header('Location: /admin/order.php?id=' . $orderId);
|
header('Location: /admin/order.php?id=' . $orderId);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($action === 'process_refund') {
|
||||||
|
$refundAmount = (float) ($_POST['refund_amount'] ?? 0);
|
||||||
|
$reason = trim($_POST['refund_reason'] ?? '');
|
||||||
|
|
||||||
|
if ($order['payment_method'] !== 'square' || empty($order['square_payment_id'])) {
|
||||||
|
setFlash('error', 'This order has no Square payment to refund.');
|
||||||
|
header('Location: /admin/order.php?id=' . $orderId);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if ($order['payment_status'] !== 'paid' && $order['payment_status'] !== 'partially_refunded') {
|
||||||
|
setFlash('error', 'Only paid orders can be refunded.');
|
||||||
|
header('Location: /admin/order.php?id=' . $orderId);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if ($refundAmount <= 0 || $refundAmount > (float) $order['total']) {
|
||||||
|
setFlash('error', 'Invalid refund amount.');
|
||||||
|
header('Location: /admin/order.php?id=' . $orderId);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = squareRefundPayment($order['square_payment_id'], $refundAmount, $reason ?: ('Order #' . $order['order_number']));
|
||||||
|
$refund = $result['refund'] ?? [];
|
||||||
|
$refundStatus = $refund['status'] ?? '';
|
||||||
|
|
||||||
|
if (in_array($refundStatus, ['PENDING', 'COMPLETED'], true)) {
|
||||||
|
$isFullRefund = $refundAmount >= (float) $order['total'];
|
||||||
|
$newPaymentStatus = $isFullRefund ? 'refunded' : 'partially_refunded';
|
||||||
|
|
||||||
|
db()->update('orders',
|
||||||
|
['payment_status' => $newPaymentStatus, 'order_status' => $isFullRefund ? 'refunded' : $order['order_status']],
|
||||||
|
'order_id = :id',
|
||||||
|
['id' => $orderId]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Restore any wallet credit that was applied, proportionally on a full refund
|
||||||
|
if ($isFullRefund && !empty($order['wallet_amount_used']) && (float) $order['wallet_amount_used'] > 0 && !empty($order['customer_id'])) {
|
||||||
|
$walletAmount = (float) $order['wallet_amount_used'];
|
||||||
|
$cust = db()->fetch("SELECT wallet_balance FROM customers WHERE customer_id = :id", ['id' => $order['customer_id']]);
|
||||||
|
if ($cust) {
|
||||||
|
$newBalance = (float) $cust['wallet_balance'] + $walletAmount;
|
||||||
|
db()->update('customers', ['wallet_balance' => $newBalance], 'customer_id = :id', ['id' => $order['customer_id']]);
|
||||||
|
db()->insert('wallet_transactions', [
|
||||||
|
'transaction_id' => generateId('wt_'),
|
||||||
|
'customer_id' => $order['customer_id'],
|
||||||
|
'amount' => $walletAmount,
|
||||||
|
'balance_after' => $newBalance,
|
||||||
|
'type' => 'refund',
|
||||||
|
'description' => 'Refund for Order #' . $order['order_number'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$existingNotes = $order['notes'] ?? '';
|
||||||
|
$newNote = '[' . date('M j, Y g:i A') . '] Refunded ' . formatCurrency($refundAmount)
|
||||||
|
. ' via Square (refund ID: ' . ($refund['id'] ?? 'unknown') . ')'
|
||||||
|
. ($reason ? ' — ' . $reason : '');
|
||||||
|
$allNotes = $existingNotes ? $existingNotes . "\n" . $newNote : $newNote;
|
||||||
|
db()->update('orders', ['notes' => $allNotes], 'order_id = :id', ['id' => $orderId]);
|
||||||
|
|
||||||
|
setFlash('success', formatCurrency($refundAmount) . ' refunded successfully.');
|
||||||
|
} else {
|
||||||
|
setFlash('error', 'Refund did not complete (status: ' . $refundStatus . ').');
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
setFlash('error', 'Refund failed: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Location: /admin/order.php?id=' . $orderId);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$items = json_decode($order['items'], true) ?? [];
|
$items = json_decode($order['items'], true) ?? [];
|
||||||
$shippingAddress = json_decode($order['shipping_address'], true) ?? [];
|
$shippingAddress = json_decode($order['shipping_address'], true) ?? [];
|
||||||
|
|
||||||
$statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded'];
|
$statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded'];
|
||||||
|
$canRefund = $order['payment_method'] === 'square'
|
||||||
|
&& !empty($order['square_payment_id'])
|
||||||
|
&& in_array($order['payment_status'], ['paid', 'partially_refunded'], true);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
@@ -81,6 +157,9 @@ $statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'canc
|
|||||||
<?php if (hasFlash('success')): ?>
|
<?php if (hasFlash('success')): ?>
|
||||||
<div class="alert alert-success"><i class="fas fa-check-circle"></i> <?= getFlash('success') ?></div>
|
<div class="alert alert-success"><i class="fas fa-check-circle"></i> <?= getFlash('success') ?></div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
<?php if (hasFlash('error')): ?>
|
||||||
|
<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> <?= getFlash('error') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 1.5rem;">
|
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 1.5rem;">
|
||||||
<!-- Main Column -->
|
<!-- Main Column -->
|
||||||
@@ -141,6 +220,12 @@ $statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'canc
|
|||||||
<td style="text-align: right; color: var(--admin-success);">-<?= formatCurrency($order['discount']) ?></td>
|
<td style="text-align: right; color: var(--admin-success);">-<?= formatCurrency($order['discount']) ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
<?php if (($order['wallet_amount_used'] ?? 0) > 0): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3" style="text-align: right;">Wallet / Gift Card</td>
|
||||||
|
<td style="text-align: right; color: var(--admin-success);">-<?= formatCurrency($order['wallet_amount_used']) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
<tr style="font-size: 1.125rem; font-weight: 600;">
|
<tr style="font-size: 1.125rem; font-weight: 600;">
|
||||||
<td colspan="3" style="text-align: right;">Total</td>
|
<td colspan="3" style="text-align: right;">Total</td>
|
||||||
<td style="text-align: right;"><?= formatCurrency($order['total']) ?></td>
|
<td style="text-align: right;"><?= formatCurrency($order['total']) ?></td>
|
||||||
@@ -149,7 +234,7 @@ $statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'canc
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Notes -->
|
<!-- Notes -->
|
||||||
<div class="admin-card">
|
<div class="admin-card">
|
||||||
<div class="admin-card-header">
|
<div class="admin-card-header">
|
||||||
@@ -161,7 +246,7 @@ $statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'canc
|
|||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<p class="text-muted" style="margin-bottom: 1rem;">No notes yet.</p>
|
<p class="text-muted" style="margin-bottom: 1rem;">No notes yet.</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<input type="hidden" name="action" value="add_note">
|
<input type="hidden" name="action" value="add_note">
|
||||||
<div class="form-group mb-0">
|
<div class="form-group mb-0">
|
||||||
@@ -173,8 +258,34 @@ $statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'canc
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?php if ($canRefund): ?>
|
||||||
|
<!-- Refund -->
|
||||||
|
<div class="admin-card">
|
||||||
|
<div class="admin-card-header">
|
||||||
|
<h3 class="admin-card-title">Process Refund</h3>
|
||||||
|
</div>
|
||||||
|
<div class="admin-card-body">
|
||||||
|
<form method="POST" onsubmit="return confirm('Refund ' + document.getElementById('refund_amount').value + ' via Square? This cannot be undone.');">
|
||||||
|
<input type="hidden" name="action" value="process_refund">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Amount</label>
|
||||||
|
<input type="number" step="0.01" min="0.01" max="<?= $order['total'] ?>" name="refund_amount" id="refund_amount" class="form-input" value="<?= $order['total'] ?>" required>
|
||||||
|
<small class="text-muted">Up to <?= formatCurrency($order['total']) ?> (full order total). Enter a lower amount for a partial refund.</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Reason (optional)</label>
|
||||||
|
<input type="text" name="refund_reason" class="form-input" placeholder="e.g. damaged item, customer request">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-secondary btn-block">
|
||||||
|
<i class="fas fa-undo"></i> Refund via Square
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div>
|
<div>
|
||||||
<!-- Status -->
|
<!-- Status -->
|
||||||
@@ -185,7 +296,7 @@ $statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'canc
|
|||||||
<div class="admin-card-body">
|
<div class="admin-card-body">
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<input type="hidden" name="action" value="update_status">
|
<input type="hidden" name="action" value="update_status">
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">Status</label>
|
<label class="form-label">Status</label>
|
||||||
<select name="status" class="form-select">
|
<select name="status" class="form-select">
|
||||||
@@ -196,17 +307,17 @@ $statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'canc
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">Tracking Number</label>
|
<label class="form-label">Tracking Number</label>
|
||||||
<input type="text" name="tracking_number" class="form-input" value="<?= htmlspecialchars($order['tracking_number'] ?? '') ?>">
|
<input type="text" name="tracking_number" class="form-input" value="<?= htmlspecialchars($order['tracking_number'] ?? '') ?>">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary btn-block">Update Status</button>
|
<button type="submit" class="btn btn-primary btn-block">Update Status</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Customer -->
|
<!-- Customer -->
|
||||||
<div class="admin-card">
|
<div class="admin-card">
|
||||||
<div class="admin-card-header">
|
<div class="admin-card-header">
|
||||||
@@ -218,7 +329,7 @@ $statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'canc
|
|||||||
<?php if ($order['customer_phone']): ?>
|
<?php if ($order['customer_phone']): ?>
|
||||||
<p><?= htmlspecialchars($order['customer_phone']) ?></p>
|
<p><?= htmlspecialchars($order['customer_phone']) ?></p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if ($order['customer_id']): ?>
|
<?php if ($order['customer_id']): ?>
|
||||||
<a href="/admin/customers.php?id=<?= $order['customer_id'] ?>" class="btn btn-sm btn-secondary mt-1">
|
<a href="/admin/customers.php?id=<?= $order['customer_id'] ?>" class="btn btn-sm btn-secondary mt-1">
|
||||||
View Customer
|
View Customer
|
||||||
@@ -226,7 +337,7 @@ $statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'canc
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Shipping Address -->
|
<!-- Shipping Address -->
|
||||||
<?php if (!empty($shippingAddress) && ($shippingAddress['type'] ?? '') !== 'pickup'): ?>
|
<?php if (!empty($shippingAddress) && ($shippingAddress['type'] ?? '') !== 'pickup'): ?>
|
||||||
<div class="admin-card">
|
<div class="admin-card">
|
||||||
@@ -236,14 +347,14 @@ $statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'canc
|
|||||||
<div class="admin-card-body">
|
<div class="admin-card-body">
|
||||||
<p>
|
<p>
|
||||||
<?= htmlspecialchars($shippingAddress['address'] ?? '') ?><br>
|
<?= htmlspecialchars($shippingAddress['address'] ?? '') ?><br>
|
||||||
<?= htmlspecialchars($shippingAddress['city'] ?? '') ?>,
|
<?= htmlspecialchars($shippingAddress['city'] ?? '') ?>,
|
||||||
<?= htmlspecialchars($shippingAddress['state'] ?? '') ?>
|
<?= htmlspecialchars($shippingAddress['state'] ?? '') ?>
|
||||||
<?= htmlspecialchars($shippingAddress['zip'] ?? '') ?>
|
<?= htmlspecialchars($shippingAddress['zip'] ?? '') ?>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<!-- Payment -->
|
<!-- Payment -->
|
||||||
<div class="admin-card">
|
<div class="admin-card">
|
||||||
<div class="admin-card-header">
|
<div class="admin-card-header">
|
||||||
@@ -260,13 +371,18 @@ $statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'canc
|
|||||||
$paymentClass = match($order['payment_status']) {
|
$paymentClass = match($order['payment_status']) {
|
||||||
'paid' => 'success',
|
'paid' => 'success',
|
||||||
'failed' => 'error',
|
'failed' => 'error',
|
||||||
'refunded' => 'warning',
|
'refunded', 'partially_refunded' => 'warning',
|
||||||
default => 'primary'
|
default => 'primary'
|
||||||
};
|
};
|
||||||
?>
|
?>
|
||||||
<span class="badge badge-<?= $paymentClass ?>"><?= ucfirst($order['payment_status']) ?></span>
|
<span class="badge badge-<?= $paymentClass ?>"><?= ucfirst(str_replace('_', ' ', $order['payment_status'])) ?></span>
|
||||||
</div>
|
</div>
|
||||||
<?php if ($order['stripe_payment_intent']): ?>
|
<?php if (!empty($order['square_payment_id'])): ?>
|
||||||
|
<div style="display: flex; justify-content: space-between;">
|
||||||
|
<span>Square Payment ID</span>
|
||||||
|
<span class="text-muted" style="font-size: 0.8rem;"><?= htmlspecialchars(substr($order['square_payment_id'], 0, 20)) ?></span>
|
||||||
|
</div>
|
||||||
|
<?php elseif ($order['stripe_payment_intent']): ?>
|
||||||
<div style="display: flex; justify-content: space-between;">
|
<div style="display: flex; justify-content: space-between;">
|
||||||
<span>Stripe ID</span>
|
<span>Stripe ID</span>
|
||||||
<span class="text-muted" style="font-size: 0.8rem;"><?= htmlspecialchars(substr($order['stripe_payment_intent'], 0, 20)) ?>...</span>
|
<span class="text-muted" style="font-size: 0.8rem;"><?= htmlspecialchars(substr($order['stripe_payment_intent'], 0, 20)) ?>...</span>
|
||||||
@@ -274,7 +390,7 @@ $statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'canc
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Timeline -->
|
<!-- Timeline -->
|
||||||
<div class="admin-card">
|
<div class="admin-card">
|
||||||
<div class="admin-card-header">
|
<div class="admin-card-header">
|
||||||
|
|||||||
@@ -73,6 +73,21 @@ function squareGetPayment(string $paymentId): array {
|
|||||||
return squareApi('GET', '/payments/' . $paymentId);
|
return squareApi('GET', '/payments/' . $paymentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function squareRefundPayment(string $paymentId, float $amount, string $reason = ''): array {
|
||||||
|
$body = [
|
||||||
|
'idempotency_key' => 'refund_' . $paymentId . '_' . bin2hex(random_bytes(6)),
|
||||||
|
'amount_money' => [
|
||||||
|
'amount' => (int) round($amount * 100),
|
||||||
|
'currency' => 'USD',
|
||||||
|
],
|
||||||
|
'payment_id' => $paymentId,
|
||||||
|
];
|
||||||
|
if ($reason) {
|
||||||
|
$body['reason'] = substr($reason, 0, 192);
|
||||||
|
}
|
||||||
|
return squareApi('POST', '/refunds', $body);
|
||||||
|
}
|
||||||
|
|
||||||
function isSquareConfigured(): bool {
|
function isSquareConfigured(): bool {
|
||||||
return defined('SQUARE_ACCESS_TOKEN') && defined('SQUARE_APP_ID') && defined('SQUARE_LOCATION_ID')
|
return defined('SQUARE_ACCESS_TOKEN') && defined('SQUARE_APP_ID') && defined('SQUARE_LOCATION_ID')
|
||||||
&& !empty(SQUARE_ACCESS_TOKEN) && !empty(SQUARE_APP_ID) && !empty(SQUARE_LOCATION_ID)
|
&& !empty(SQUARE_ACCESS_TOKEN) && !empty(SQUARE_APP_ID) && !empty(SQUARE_LOCATION_ID)
|
||||||
|
|||||||
Reference in New Issue
Block a user