make_post_sell/templates/cart_checkout.j2
- Added "Save PayPal for faster checkout" checkbox
- Shows "PayPal saved" status for returning users
- Sends save_paypal parameter to backend
make_post_sell/templates/billing.j2
- Added PayPal management section
- Shows connected status with PayPal logo
- Added "Disconnect PayPal" button
This commit is contained in:
parent
4a6f7ebb3a
commit
e8e0e52f40
2 changed files with 176 additions and 0 deletions
|
|
@ -38,6 +38,38 @@
|
|||
|
||||
</section>
|
||||
|
||||
{# PayPal Saved Payment Method Section #}
|
||||
{% if paypal_enabled and paypal_user_shop %}
|
||||
<section class="well" style="margin-top: 20px;">
|
||||
<h3>PayPal Payment Method</h3>
|
||||
|
||||
{% if paypal_user_shop.has_saved_payment_method %}
|
||||
<div style="padding: 15px; background-color: #f0f7ff; border-left: 4px solid #0070ba; border-radius: 4px; margin-top: 10px;">
|
||||
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 8px;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="#0070ba">
|
||||
<path d="M20.067 8.478c.492.88.556 2.014.3 3.327-.74 3.806-3.276 5.12-6.514 5.12h-.5a.805.805 0 00-.794.68l-.04.22-.63 3.993-.032.17a.804.804 0 01-.794.679H7.72a.483.483 0 01-.477-.558L9.01 8.975a.964.964 0 01.951-.814h2.053c3.893 0 6.535 1.62 7.055 6.317z"/>
|
||||
<path d="M10.964 8.975a.964.964 0 00-.95.814L8.247 21.891a.483.483 0 00.476.558h3.344c.336 0 .622-.243.678-.574l.028-.15.63-3.994.04-.218a.805.805 0 01.795-.68h.5c3.238 0 5.774-1.314 6.514-5.12.256-1.313.192-2.447-.3-3.327a3.918 3.918 0 00-1.172-1.241c-.67-.437-1.53-.695-2.527-.827-.27-.036-.549-.063-.837-.083h-.18z" opacity=".7"/>
|
||||
</svg>
|
||||
<span style="font-weight: 500; font-size: 16px;">PayPal Account Connected</span>
|
||||
</div>
|
||||
<p style="margin: 0 0 12px 0; color: #666; font-size: 14px;">
|
||||
Your PayPal account is saved for quick checkout. Click the PayPal button at checkout to complete your purchase.
|
||||
</p>
|
||||
<form method="POST" action="/billing/disconnect-paypal" style="margin: 0;">
|
||||
<input type="hidden" name="csrf_token" value="{{ request.session.get_csrf_token() }}">
|
||||
<button type="submit" style="padding: 8px 16px; background-color: #fff; border: 1px solid #ccc; border-radius: 4px; cursor: pointer; font-size: 14px; color: #333;">
|
||||
Disconnect PayPal
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{% else %}
|
||||
<p style="color: #666; margin-top: 10px;">
|
||||
No PayPal account connected. Check the "Save PayPal" box during checkout to save your PayPal account for faster future purchases.
|
||||
</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
<center>
|
||||
<a href="/cart" class="product-new-button mps-button">Review Order</a>
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,150 @@
|
|||
</form>
|
||||
{% endif %}
|
||||
|
||||
{# PayPal checkout button #}
|
||||
{% if paypal_enabled and request.shop and request.shop.is_paypal_ready and cart.requires_payment %}
|
||||
<br/>
|
||||
|
||||
{# Saved PayPal status or save checkbox #}
|
||||
{% if paypal_user_shop and paypal_user_shop.has_saved_payment_method %}
|
||||
{# User has PayPal saved #}
|
||||
<div style="margin-bottom: 15px; padding: 12px; background-color: #f0f7ff; border-left: 4px solid: #0070ba; border-radius: 4px;">
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<span style="font-size: 20px;">✓</span>
|
||||
<span style="font-weight: 500; color: #0070ba;">PayPal saved for quick checkout</span>
|
||||
</div>
|
||||
<small style="display: block; margin-top: 4px; color: #666;">
|
||||
Click the PayPal button below to complete your purchase
|
||||
</small>
|
||||
</div>
|
||||
{% else %}
|
||||
{# User does not have PayPal saved - show checkbox #}
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
|
||||
<input type="checkbox" id="save-paypal-checkbox" name="save_paypal" value="true" style="cursor: pointer;">
|
||||
<span>💾 Save PayPal for faster checkout next time</span>
|
||||
</label>
|
||||
<small style="display: block; margin-left: 24px; color: #666; margin-top: 4px;">
|
||||
You can manage saved payment methods in your account settings
|
||||
</small>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div id="paypal-button-container"></div>
|
||||
<script src="https://www.paypal.com/sdk/js?client-id={{ request.shop.paypal_client_id }}¤cy=USD"></script>
|
||||
<script>
|
||||
// Store all order IDs for multi-shop support
|
||||
var allPayPalOrderIds = [];
|
||||
|
||||
// Double-click protection flags
|
||||
var isCreatingOrder = false;
|
||||
var isProcessingApproval = false;
|
||||
|
||||
paypal.Buttons({
|
||||
style: {
|
||||
layout: 'vertical',
|
||||
color: 'gold',
|
||||
shape: 'rect',
|
||||
label: 'paypal'
|
||||
},
|
||||
createOrder: function(data, actions) {
|
||||
// Prevent duplicate order creation
|
||||
if (isCreatingOrder) {
|
||||
console.warn('PayPal order creation already in progress');
|
||||
return Promise.reject(new Error('Order creation already in progress'));
|
||||
}
|
||||
|
||||
isCreatingOrder = true;
|
||||
|
||||
// Check if user wants to save PayPal for future use
|
||||
var savePayPalCheckbox = document.getElementById('save-paypal-checkbox');
|
||||
var savePayPal = savePayPalCheckbox ? savePayPalCheckbox.checked : false;
|
||||
|
||||
return fetch("{{ request.route_url('paypal_create_order', cart_id=cart.id) }}?save_paypal=" + (savePayPal ? 'true' : 'false'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': '{{ request.session.get_csrf_token() }}'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
alert('Error creating PayPal order: ' + data.error);
|
||||
isCreatingOrder = false;
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
// Handle both single order_id (old format) and order_ids array (new format)
|
||||
if (data.order_ids) {
|
||||
allPayPalOrderIds = data.order_ids;
|
||||
isCreatingOrder = false;
|
||||
// Return first order ID for PayPal SDK to process
|
||||
return data.order_ids[0];
|
||||
} else if (data.order_id) {
|
||||
allPayPalOrderIds = [data.order_id];
|
||||
isCreatingOrder = false;
|
||||
return data.order_id;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
isCreatingOrder = false;
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
onApprove: function(data, actions) {
|
||||
// Prevent duplicate submission after approval
|
||||
if (isProcessingApproval) {
|
||||
console.warn('PayPal approval already being processed');
|
||||
return Promise.reject(new Error('Approval already being processed'));
|
||||
}
|
||||
|
||||
isProcessingApproval = true;
|
||||
|
||||
// For multi-shop carts, we have multiple order IDs
|
||||
// PayPal SDK only handles the first one, so we pass all IDs to backend
|
||||
var orderIdsToSubmit = allPayPalOrderIds.join(',');
|
||||
|
||||
// Create form to submit PayPal order ID(s)
|
||||
var form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = '{{ request.route_url('paypal_complete_checkout', cart_id=cart.id) }}';
|
||||
|
||||
var csrfInput = document.createElement('input');
|
||||
csrfInput.type = 'hidden';
|
||||
csrfInput.name = 'csrf_token';
|
||||
csrfInput.value = '{{ request.session.get_csrf_token() }}';
|
||||
form.appendChild(csrfInput);
|
||||
|
||||
var orderIdInput = document.createElement('input');
|
||||
orderIdInput.type = 'hidden';
|
||||
orderIdInput.name = 'paypal_order_id';
|
||||
orderIdInput.value = orderIdsToSubmit;
|
||||
form.appendChild(orderIdInput);
|
||||
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
|
||||
// Note: We don't reset isProcessingApproval because the page will redirect
|
||||
// If form.submit() fails, the page stays and user can't retry anyway
|
||||
},
|
||||
onError: function(err) {
|
||||
console.error('PayPal error:', err);
|
||||
alert('PayPal payment failed. Please try again or use another payment method.');
|
||||
// Reset flags on error so user can retry
|
||||
isCreatingOrder = false;
|
||||
isProcessingApproval = false;
|
||||
},
|
||||
onCancel: function(data) {
|
||||
// Reset flags if user cancels PayPal flow
|
||||
console.log('PayPal payment cancelled by user');
|
||||
isCreatingOrder = false;
|
||||
isProcessingApproval = false;
|
||||
}
|
||||
}).render('#paypal-button-container');
|
||||
</script>
|
||||
{% endif %}{# End PayPal enabled check #}
|
||||
|
||||
{# For free checkouts (e.g., with coupons), provide a simple confirmation button #}
|
||||
{% if not cart.requires_payment %}
|
||||
<form method="POST" action="{{ request.route_url('user_cart_complete_checkout', cart_id=cart.id) }}">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue