feat: Complete WordPress customer portal
This commit is contained in:
parent
aa8fb17230
commit
bac2a7bb25
@ -212,3 +212,162 @@
|
|||||||
background: #fff; padding: 40px; border-radius: var(--ifnex-radius);
|
background: #fff; padding: 40px; border-radius: var(--ifnex-radius);
|
||||||
border: 1px solid var(--ifnex-border);
|
border: 1px solid var(--ifnex-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ═══ Payment Page ═══ */
|
||||||
|
.ifnex-payment-page { max-width: 700px; margin: 0 auto; padding: 20px 0; }
|
||||||
|
.ifnex-payment-card {
|
||||||
|
background: #fff; border-radius: var(--ifnex-radius);
|
||||||
|
border: 1px solid var(--ifnex-border); padding: 32px;
|
||||||
|
}
|
||||||
|
.ifnex-payment-card h2 { margin-top: 0; color: var(--ifnex-dark); }
|
||||||
|
|
||||||
|
.ifnex-order-summary {
|
||||||
|
background: var(--ifnex-light); border-radius: 8px;
|
||||||
|
padding: 20px; margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
.ifnex-summary-row {
|
||||||
|
display: flex; justify-content: space-between; padding: 8px 0;
|
||||||
|
border-bottom: 1px dashed var(--ifnex-border);
|
||||||
|
}
|
||||||
|
.ifnex-summary-row:last-child { border-bottom: none; }
|
||||||
|
.ifnex-summary-row.total {
|
||||||
|
font-size: 18px; font-weight: 700; color: var(--ifnex-primary-dark);
|
||||||
|
padding-top: 12px; margin-top: 8px; border-top: 2px solid var(--ifnex-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ifnex-payment-methods { display: grid; gap: 16px; }
|
||||||
|
.ifnex-payment-option {
|
||||||
|
border: 2px solid var(--ifnex-border); border-radius: 8px;
|
||||||
|
padding: 20px; transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.ifnex-payment-option:hover { border-color: var(--ifnex-primary); }
|
||||||
|
.ifnex-payment-option.disabled { opacity: 0.5; pointer-events: none; }
|
||||||
|
.ifnex-payment-option h3 { margin-top: 0; color: var(--ifnex-dark); }
|
||||||
|
.ifnex-payment-option p { color: var(--ifnex-gray); margin: 8px 0 16px; }
|
||||||
|
|
||||||
|
.ifnex-warning {
|
||||||
|
background: #fef3c7; color: #92400e; padding: 10px;
|
||||||
|
border-radius: 6px; font-size: 13px; margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ifnex-payment-footer {
|
||||||
|
margin-top: 24px; padding-top: 20px;
|
||||||
|
border-top: 1px solid var(--ifnex-border); text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ═══ Order Detail Page ═══ */
|
||||||
|
.ifnex-order-detail { max-width: 900px; margin: 0 auto; padding: 20px 0; }
|
||||||
|
|
||||||
|
.ifnex-detail-header {
|
||||||
|
display: flex; justify-content: space-between; align-items: center;
|
||||||
|
margin-bottom: 20px; flex-wrap: wrap; gap: 12px;
|
||||||
|
}
|
||||||
|
.ifnex-detail-title { display: flex; align-items: center; gap: 12px; }
|
||||||
|
.ifnex-detail-title h2 { margin: 0; color: var(--ifnex-dark); }
|
||||||
|
.ifnex-awb-code {
|
||||||
|
background: var(--ifnex-dark); color: #fff; padding: 6px 12px;
|
||||||
|
border-radius: 6px; font-size: 14px; font-weight: 700;
|
||||||
|
}
|
||||||
|
.ifnex-badge-lg { padding: 8px 20px; font-size: 14px; }
|
||||||
|
|
||||||
|
.ifnex-detail-actions {
|
||||||
|
display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 24px;
|
||||||
|
padding: 16px; background: var(--ifnex-light); border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ifnex-detail-section {
|
||||||
|
background: #fff; border: 1px solid var(--ifnex-border);
|
||||||
|
border-radius: var(--ifnex-radius); padding: 24px; margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.ifnex-detail-section h3 {
|
||||||
|
margin-top: 0; color: var(--ifnex-dark); padding-bottom: 12px;
|
||||||
|
border-bottom: 1px solid var(--ifnex-border); margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ifnex-route-detail {
|
||||||
|
display: flex; align-items: center; gap: 20px; padding: 20px;
|
||||||
|
}
|
||||||
|
.ifnex-route-point {
|
||||||
|
flex: 1; text-align: center; padding: 20px;
|
||||||
|
background: var(--ifnex-light); border-radius: 8px;
|
||||||
|
}
|
||||||
|
.ifnex-point-label {
|
||||||
|
font-size: 12px; color: var(--ifnex-gray); text-transform: uppercase;
|
||||||
|
letter-spacing: 1px; margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.ifnex-point-country {
|
||||||
|
font-size: 20px; font-weight: 700; color: var(--ifnex-dark);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.ifnex-point-iso {
|
||||||
|
font-size: 13px; color: var(--ifnex-gray); font-weight: 600;
|
||||||
|
}
|
||||||
|
.ifnex-route-line {
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
flex: 0.5;
|
||||||
|
}
|
||||||
|
.ifnex-plane-icon { font-size: 32px; }
|
||||||
|
|
||||||
|
.ifnex-info-grid {
|
||||||
|
display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px;
|
||||||
|
}
|
||||||
|
.ifnex-info-item.full { grid-column: 1 / -1; }
|
||||||
|
.ifnex-info-label {
|
||||||
|
display: block; font-size: 12px; color: var(--ifnex-gray);
|
||||||
|
text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.ifnex-info-value { font-size: 15px; color: var(--ifnex-dark); font-weight: 500; }
|
||||||
|
|
||||||
|
.ifnex-price-breakdown { padding: 8px 0; }
|
||||||
|
.ifnex-price-row {
|
||||||
|
display: flex; justify-content: space-between; padding: 10px 0;
|
||||||
|
border-bottom: 1px dashed var(--ifnex-border); font-size: 14px;
|
||||||
|
}
|
||||||
|
.ifnex-price-row:last-child { border-bottom: none; }
|
||||||
|
.ifnex-price-row.total {
|
||||||
|
font-size: 18px; font-weight: 800; color: var(--ifnex-primary-dark);
|
||||||
|
padding-top: 16px; margin-top: 8px; border-top: 2px solid var(--ifnex-primary);
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ifnex-text-success { color: var(--ifnex-success); font-weight: 600; }
|
||||||
|
.ifnex-text-warning { color: var(--ifnex-warning); font-weight: 600; }
|
||||||
|
|
||||||
|
/* Timeline */
|
||||||
|
.ifnex-timeline { position: relative; padding-right: 20px; }
|
||||||
|
.ifnex-timeline::before {
|
||||||
|
content: ''; position: absolute; right: 8px; top: 0; bottom: 0;
|
||||||
|
width: 2px; background: var(--ifnex-border);
|
||||||
|
}
|
||||||
|
.ifnex-timeline-item {
|
||||||
|
position: relative; padding-right: 32px; padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
.ifnex-timeline-item:last-child { padding-bottom: 0; }
|
||||||
|
.ifnex-timeline-dot {
|
||||||
|
position: absolute; right: -20px; top: 4px;
|
||||||
|
width: 16px; height: 16px; border-radius: 50%;
|
||||||
|
background: var(--ifnex-primary); border: 3px solid #fff;
|
||||||
|
box-shadow: 0 0 0 2px var(--ifnex-border);
|
||||||
|
}
|
||||||
|
.ifnex-timeline-content {
|
||||||
|
background: var(--ifnex-light); padding: 12px 16px;
|
||||||
|
border-radius: 8px; border-right: 3px solid var(--ifnex-primary);
|
||||||
|
}
|
||||||
|
.ifnex-timeline-header {
|
||||||
|
display: flex; justify-content: space-between; flex-wrap: wrap;
|
||||||
|
gap: 8px; margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.ifnex-timeline-date { font-size: 12px; color: var(--ifnex-gray); }
|
||||||
|
.ifnex-timeline-location { font-size: 13px; color: var(--ifnex-gray); }
|
||||||
|
.ifnex-empty-timeline { color: var(--ifnex-gray); font-style: italic; }
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.ifnex-route-detail { flex-direction: column; }
|
||||||
|
.ifnex-route-line { transform: rotate(90deg); }
|
||||||
|
.ifnex-info-grid { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
.ifnex-detail-actions { display: none !important; }
|
||||||
|
.ifnex-order-detail { max-width: 100%; }
|
||||||
|
}
|
||||||
@ -39,11 +39,13 @@ function ifnex_settings_page_html() {
|
|||||||
if (isset($_POST['ifnex_api_url']) && check_admin_referer('ifnex_settings_save')) {
|
if (isset($_POST['ifnex_api_url']) && check_admin_referer('ifnex_settings_save')) {
|
||||||
update_option('ifnex_api_url', sanitize_url($_POST['ifnex_api_url']));
|
update_option('ifnex_api_url', sanitize_url($_POST['ifnex_api_url']));
|
||||||
update_option('ifnex_api_key', sanitize_text_field($_POST['ifnex_api_key']));
|
update_option('ifnex_api_key', sanitize_text_field($_POST['ifnex_api_key']));
|
||||||
|
update_option('ifnex_bridge_api_key', sanitize_text_field($_POST['ifnex_bridge_api_key'] ?? ''));
|
||||||
echo '<div class="notice notice-success"><p>تنظیمات ذخیره شد.</p></div>';
|
echo '<div class="notice notice-success"><p>تنظیمات ذخیره شد.</p></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$api_url = get_option('ifnex_api_url', 'http://localhost:8000/api/v1');
|
$api_url = get_option('ifnex_api_url', 'http://localhost:8000/api/v1');
|
||||||
$api_key = get_option('ifnex_api_key', '');
|
$api_key = get_option('ifnex_api_key', '');
|
||||||
|
$bridge_api_key = get_option('ifnex_bridge_api_key', '');
|
||||||
?>
|
?>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<h1>تنظیمات IFNEX Logistics Bridge</h1>
|
<h1>تنظیمات IFNEX Logistics Bridge</h1>
|
||||||
@ -52,15 +54,36 @@ function ifnex_settings_page_html() {
|
|||||||
<table class="form-table">
|
<table class="form-table">
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row"><label for="ifnex_api_url">API URL</label></th>
|
<th scope="row"><label for="ifnex_api_url">API URL</label></th>
|
||||||
<td><input type="text" id="ifnex_api_url" name="ifnex_api_url" value="<?php echo esc_attr($api_url); ?>" class="regular-text" placeholder="http://localhost:8000/api/v1"></td>
|
<td>
|
||||||
|
<input type="text" id="ifnex_api_url" name="ifnex_api_url" value="<?php echo esc_attr($api_url); ?>" class="regular-text" placeholder="http://localhost:8000/api/v1">
|
||||||
|
<p class="description">آدرس پایه API لاراول</p>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row"><label for="ifnex_api_key">API Key</label></th>
|
<th scope="row"><label for="ifnex_api_key">API Key (عمومی)</label></th>
|
||||||
<td><input type="text" id="ifnex_api_key" name="ifnex_api_key" value="<?php echo esc_attr($api_key); ?>" class="regular-text"></td>
|
<td>
|
||||||
|
<input type="text" id="ifnex_api_key" name="ifnex_api_key" value="<?php echo esc_attr($api_key); ?>" class="regular-text">
|
||||||
|
<p class="description">برای APIهای عمومی مثل Tracking</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr style="background: #fff3cd;">
|
||||||
|
<th scope="row"><label for="ifnex_bridge_api_key">🔐 Bridge API Key</label></th>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="ifnex_bridge_api_key" name="ifnex_bridge_api_key" value="<?php echo esc_attr($bridge_api_key); ?>" class="regular-text">
|
||||||
|
<p class="description"><strong>مهم:</strong> باید با مقدار <code>IFNEX_BRIDGE_API_KEY</code> در فایل <code>.env</code> لاراول یکسان باشد.</p>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<?php submit_button('ذخیره تنظیمات'); ?>
|
<?php submit_button('ذخیره تنظیمات'); ?>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2>راهنمای راهاندازی</h2>
|
||||||
|
<ol>
|
||||||
|
<li>در فایل <code>.env</code> لاراول، خط <code>IFNEX_BRIDGE_API_KEY=your-secret-key</code> را تنظیم کنید</li>
|
||||||
|
<li>همان مقدار را در فیلد "Bridge API Key" بالا وارد کنید</li>
|
||||||
|
<li>کاربران وردپرس باید در لاراول با همان ایمیل موجود باشند (از <code>php artisan ifnex:sync-wp-users</code> استفاده کنید)</li>
|
||||||
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
@ -393,7 +393,7 @@ function ifnex_orders_list_shortcode($atts) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ifnex-order-actions">
|
<div class="ifnex-order-actions">
|
||||||
<a href="<?php echo esc_url(home_url('/order-detail/' . $order['id'] . '/')); ?>"
|
<a href="<?php echo esc_url(home_url('/order-detail/?order_id=' . $order['id'])); ?>"
|
||||||
class="ifnex-btn ifnex-btn-sm ifnex-btn-info">
|
class="ifnex-btn ifnex-btn-sm ifnex-btn-info">
|
||||||
👁️ جزئیات
|
👁️ جزئیات
|
||||||
</a>
|
</a>
|
||||||
@ -406,8 +406,8 @@ function ifnex_orders_list_shortcode($atts) {
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (!$order['status']['is_paid']): ?>
|
<?php if (!$order['status']['is_paid']): ?>
|
||||||
<a href="<?php echo esc_url(home_url('/payment/' . $order['id'] . '/')); ?>"
|
<a href="<?php echo esc_url(home_url('/order-payment/?order_id=' . $order['id'])); ?>"
|
||||||
class="ifnex-btn ifnex-btn-sm ifnex-btn-success">
|
class="ifnex-btn ifnex-btn-sm ifnex-btn-success">
|
||||||
💳 پرداخت
|
💳 پرداخت
|
||||||
</a>
|
</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@ -605,3 +605,495 @@ function ifnex_order_form_shortcode($atts) {
|
|||||||
<?php
|
<?php
|
||||||
return ob_get_clean();
|
return ob_get_clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
// شورتکد صفحه پرداخت سفارش
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
add_shortcode('ifnex_order_payment', 'ifnex_order_payment_shortcode');
|
||||||
|
|
||||||
|
function ifnex_order_payment_shortcode($atts) {
|
||||||
|
if (!is_user_logged_in()) {
|
||||||
|
return '<p class="ifnex-error">برای پرداخت، باید وارد شوید.</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$atts = shortcode_atts(array('order_id' => ''), $atts);
|
||||||
|
|
||||||
|
// دریافت order_id از URL parameter
|
||||||
|
$order_id = $atts['order_id'] ?: ($_GET['order_id'] ?? 0);
|
||||||
|
|
||||||
|
if (!$order_id) {
|
||||||
|
return '<p class="ifnex-error">شناسه سفارش مشخص نشده است.</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$bridge = new IFNEX_User_Bridge();
|
||||||
|
$user_id = get_current_user_id();
|
||||||
|
|
||||||
|
$order = $bridge->get_customer_order($user_id, $order_id);
|
||||||
|
|
||||||
|
if (is_wp_error($order)) {
|
||||||
|
return '<p class="ifnex-error">' . esc_html($order->get_error_message()) . '</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $order['data'];
|
||||||
|
|
||||||
|
// بررسی وضعیت
|
||||||
|
if ($data['status']['value'] !== 'pending_payment') {
|
||||||
|
return '<div class="ifnex-success-box">
|
||||||
|
<h3>✅ این سفارش قبلاً پرداخت شده است</h3>
|
||||||
|
<p>وضعیت: ' . esc_html($data['status']['label']) . '</p>
|
||||||
|
<a href="' . esc_url(home_url('/my-orders/')) . '" class="ifnex-btn ifnex-btn-primary">بازگشت به سفارشات</a>
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$balance = $bridge->get_wallet_balance($user_id);
|
||||||
|
$wallet_balance = is_wp_error($balance) ? 0 : ($balance['balance'] ?? 0);
|
||||||
|
$can_pay_wallet = $wallet_balance >= $data['total_fee'];
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
?>
|
||||||
|
<div class="ifnex-payment-page">
|
||||||
|
<div class="ifnex-payment-card">
|
||||||
|
<h2>💳 پرداخت سفارش</h2>
|
||||||
|
|
||||||
|
<div class="ifnex-order-summary">
|
||||||
|
<div class="ifnex-summary-row">
|
||||||
|
<span>شماره پیگیری:</span>
|
||||||
|
<strong><?php echo esc_html($data['awb_no']); ?></strong>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-summary-row">
|
||||||
|
<span>مسیر:</span>
|
||||||
|
<strong><?php echo esc_html($data['from_country']['name']); ?> → <?php echo esc_html($data['to_country']['name']); ?></strong>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-summary-row total">
|
||||||
|
<span>مبلغ قابل پرداخت:</span>
|
||||||
|
<strong><?php echo number_format($data['total_fee']); ?> ریال</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ifnex-payment-methods">
|
||||||
|
<!-- پرداخت از کیف پول -->
|
||||||
|
<div class="ifnex-payment-option <?php echo $can_pay_wallet ? '' : 'disabled'; ?>">
|
||||||
|
<h3>💰 پرداخت از کیف پول</h3>
|
||||||
|
<p>موجودی فعلی: <strong><?php echo number_format($wallet_balance); ?> ریال</strong></p>
|
||||||
|
<?php if ($can_pay_wallet): ?>
|
||||||
|
<button class="ifnex-btn ifnex-btn-success ifnex-pay-wallet" data-order-id="<?php echo esc_attr($order_id); ?>">
|
||||||
|
پرداخت فوری از کیف پول
|
||||||
|
</button>
|
||||||
|
<?php else: ?>
|
||||||
|
<p class="ifnex-warning">⚠️ موجودی کافی نیست. لطفاً ابتدا کیف پول خود را شارژ کنید.</p>
|
||||||
|
<a href="<?php echo esc_url(home_url('/wallet/')); ?>" class="ifnex-btn ifnex-btn-info">شارژ کیف پول</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- پرداخت از درگاه -->
|
||||||
|
<div class="ifnex-payment-option">
|
||||||
|
<h3>🏦 پرداخت از درگاه بانکی</h3>
|
||||||
|
<p>انتقال به درگاه پرداخت امن (زرینپال)</p>
|
||||||
|
<button class="ifnex-btn ifnex-btn-primary ifnex-pay-gateway" data-order-id="<?php echo esc_attr($order_id); ?>">
|
||||||
|
انتقال به درگاه بانکی
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="ifnex-payment-message" style="display:none; margin-top:20px;"></div>
|
||||||
|
|
||||||
|
<div class="ifnex-payment-footer">
|
||||||
|
<a href="<?php echo esc_url(home_url('/my-orders/')); ?>" class="ifnex-btn ifnex-btn-sm">
|
||||||
|
← بازگشت به سفارشات
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
// پرداخت از کیف پول
|
||||||
|
$('.ifnex-pay-wallet').on('click', function() {
|
||||||
|
if (!confirm('آیا از پرداخت از کیف پول اطمینان دارید؟')) return;
|
||||||
|
|
||||||
|
var btn = $(this);
|
||||||
|
var orderId = btn.data('order-id');
|
||||||
|
|
||||||
|
console.log('═══════════════════════════════════════');
|
||||||
|
console.log('🚀 Starting wallet payment');
|
||||||
|
console.log('Order ID:', orderId);
|
||||||
|
console.log('AJAX URL:', ifnex_ajax.ajax_url);
|
||||||
|
console.log('Nonce:', ifnex_ajax.nonce);
|
||||||
|
console.log('═══════════════════════════════════════');
|
||||||
|
|
||||||
|
btn.prop('disabled', true).text('در حال پرداخت...');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: ifnex_ajax.ajax_url,
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
action: 'ifnex_pay_order_wallet',
|
||||||
|
order_id: orderId,
|
||||||
|
nonce: ifnex_ajax.nonce
|
||||||
|
},
|
||||||
|
beforeSend: function() {
|
||||||
|
console.log('📤 Sending AJAX request...');
|
||||||
|
},
|
||||||
|
success: function(res) {
|
||||||
|
console.log('📥 Response received:', res);
|
||||||
|
console.log('Success:', res.success);
|
||||||
|
console.log('Data:', res.data);
|
||||||
|
|
||||||
|
if (res.success) {
|
||||||
|
console.log('✅ Payment successful!');
|
||||||
|
console.log('New status:', res.data?.status?.value);
|
||||||
|
console.log('Transaction ID:', res.data?.transaction_id);
|
||||||
|
|
||||||
|
$('#ifnex-payment-message')
|
||||||
|
.removeClass('ifnex-error-box')
|
||||||
|
.addClass('ifnex-success-box')
|
||||||
|
.html('✅ پرداخت با موفقیت انجام شد! در حال انتقال...')
|
||||||
|
.show();
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
window.location.href = ifnex_ajax.orders_url + '?t=' + Date.now();
|
||||||
|
}, 2000);
|
||||||
|
} else {
|
||||||
|
console.error('❌ Payment failed:', res.data);
|
||||||
|
btn.prop('disabled', false).text('پرداخت فوری از کیف پول');
|
||||||
|
$('#ifnex-payment-message')
|
||||||
|
.addClass('ifnex-error-box')
|
||||||
|
.text('خطا: ' + (res.data || 'نامشخص'))
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('═══════════════════════════════════════');
|
||||||
|
console.error('❌ AJAX ERROR');
|
||||||
|
console.error('Status:', status);
|
||||||
|
console.error('Error:', error);
|
||||||
|
console.error('Response Code:', xhr.status);
|
||||||
|
console.error('Response Text:', xhr.responseText);
|
||||||
|
console.error('═══════════════════════════════════════');
|
||||||
|
|
||||||
|
btn.prop('disabled', false).text('پرداخت فوری از کیف پول');
|
||||||
|
$('#ifnex-payment-message')
|
||||||
|
.addClass('ifnex-error-box')
|
||||||
|
.html('خطا در ارتباط با سرور<br><small>' + error + '</small>')
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// پرداخت از درگاه
|
||||||
|
$('.ifnex-pay-gateway').on('click', function() {
|
||||||
|
var btn = $(this);
|
||||||
|
var orderId = btn.data('order-id');
|
||||||
|
|
||||||
|
btn.prop('disabled', true).text('در حال اتصال به درگاه...');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: ifnex_ajax.ajax_url,
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
action: 'ifnex_pay_order_gateway',
|
||||||
|
order_id: orderId,
|
||||||
|
callback_url: window.location.href,
|
||||||
|
nonce: ifnex_ajax.nonce
|
||||||
|
},
|
||||||
|
success: function(res) {
|
||||||
|
if (res.success && res.data.payment_url) {
|
||||||
|
window.location.href = res.data.payment_url;
|
||||||
|
} else {
|
||||||
|
btn.prop('disabled', false).text('انتقال به درگاه بانکی');
|
||||||
|
$('#ifnex-payment-message')
|
||||||
|
.addClass('ifnex-error-box')
|
||||||
|
.text('خطا: ' + (res.data || 'خطا در اتصال به درگاه'))
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
btn.prop('disabled', false).text('انتقال به درگاه بانکی');
|
||||||
|
$('#ifnex-payment-message')
|
||||||
|
.addClass('ifnex-error-box')
|
||||||
|
.text('خطا در ارتباط با سرور')
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
// شورتکد جزئیات سفارش
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
add_shortcode('ifnex_order_detail', 'ifnex_order_detail_shortcode');
|
||||||
|
|
||||||
|
function ifnex_order_detail_shortcode($atts) {
|
||||||
|
if (!is_user_logged_in()) {
|
||||||
|
return '<p class="ifnex-error">برای مشاهده جزئیات، باید وارد شوید.</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$atts = shortcode_atts(array('order_id' => ''), $atts);
|
||||||
|
$order_id = $atts['order_id'] ?: ($_GET['order_id'] ?? 0);
|
||||||
|
|
||||||
|
// اگر از URL pretty استفاده شده (order-detail/14/)
|
||||||
|
if (!$order_id && isset($_SERVER['REQUEST_URI'])) {
|
||||||
|
if (preg_match('/order-detail\/(\d+)/', $_SERVER['REQUEST_URI'], $matches)) {
|
||||||
|
$order_id = $matches[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$order_id) {
|
||||||
|
return '<p class="ifnex-error">شناسه سفارش مشخص نشده است.</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$bridge = new IFNEX_User_Bridge();
|
||||||
|
$user_id = get_current_user_id();
|
||||||
|
|
||||||
|
$order = $bridge->get_customer_order($user_id, $order_id);
|
||||||
|
|
||||||
|
if (is_wp_error($order)) {
|
||||||
|
return '<p class="ifnex-error">' . esc_html($order->get_error_message()) . '</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $order['data'];
|
||||||
|
$status = $data['status'];
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
?>
|
||||||
|
<div class="ifnex-order-detail">
|
||||||
|
<!-- هدر با وضعیت -->
|
||||||
|
<div class="ifnex-detail-header">
|
||||||
|
<div class="ifnex-detail-title">
|
||||||
|
<h2>📦 جزئیات سفارش</h2>
|
||||||
|
<code class="ifnex-awb-code"><?php echo esc_html($data['awb_no']); ?></code>
|
||||||
|
</div>
|
||||||
|
<span class="ifnex-badge ifnex-badge-<?php echo esc_attr($status['color']); ?> ifnex-badge-lg">
|
||||||
|
<?php echo esc_html($status['label']); ?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- دکمههای عملیاتی -->
|
||||||
|
<div class="ifnex-detail-actions">
|
||||||
|
<a href="<?php echo esc_url(home_url('/my-orders/')); ?>" class="ifnex-btn ifnex-btn-sm">
|
||||||
|
← بازگشت به سفارشات
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<?php if (!$status['is_paid']): ?>
|
||||||
|
<a href="<?php echo esc_url(home_url('/order-payment/?order_id=' . $order_id)); ?>"
|
||||||
|
class="ifnex-btn ifnex-btn-sm ifnex-btn-success">
|
||||||
|
💳 پرداخت
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($status['can_cancel']): ?>
|
||||||
|
<button class="ifnex-btn ifnex-btn-sm ifnex-btn-danger ifnex-cancel-order-detail"
|
||||||
|
data-order-id="<?php echo esc_attr($order_id); ?>">
|
||||||
|
❌ لغو سفارش
|
||||||
|
</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<button onclick="window.print()" class="ifnex-btn ifnex-btn-sm ifnex-btn-info">
|
||||||
|
🖨️ چاپ
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- مسیر ارسال -->
|
||||||
|
<div class="ifnex-detail-section">
|
||||||
|
<h3>🗺️ مسیر ارسال</h3>
|
||||||
|
<div class="ifnex-route-detail">
|
||||||
|
<div class="ifnex-route-point from">
|
||||||
|
<div class="ifnex-point-label">از</div>
|
||||||
|
<div class="ifnex-point-country">
|
||||||
|
<?php echo esc_html($data['from_country']['name'] ?? '—'); ?>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-point-iso">
|
||||||
|
<?php echo esc_html($data['from_country']['iso_code'] ?? ''); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-route-line">
|
||||||
|
<div class="ifnex-plane-icon">✈️</div>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-route-point to">
|
||||||
|
<div class="ifnex-point-label">به</div>
|
||||||
|
<div class="ifnex-point-country">
|
||||||
|
<?php echo esc_html($data['to_country']['name'] ?? '—'); ?>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-point-iso">
|
||||||
|
<?php echo esc_html($data['to_country']['iso_code'] ?? ''); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- اطلاعات مرسوله -->
|
||||||
|
<div class="ifnex-detail-section">
|
||||||
|
<h3>📦 اطلاعات مرسوله</h3>
|
||||||
|
<div class="ifnex-info-grid">
|
||||||
|
<div class="ifnex-info-item">
|
||||||
|
<span class="ifnex-info-label">نوع سرویس</span>
|
||||||
|
<span class="ifnex-info-value"><?php echo esc_html($data['type'] ?? '—'); ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-info-item">
|
||||||
|
<span class="ifnex-info-label">جهت ارسال</span>
|
||||||
|
<span class="ifnex-info-value">
|
||||||
|
<?php echo ($data['direction'] ?? '') === 'export' ? 'صادرات' : 'واردات'; ?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-info-item">
|
||||||
|
<span class="ifnex-info-label">وزن واقعی</span>
|
||||||
|
<span class="ifnex-info-value"><?php echo esc_html($data['weight'] ?? '—'); ?> kg</span>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-info-item">
|
||||||
|
<span class="ifnex-info-label">وزن قابل محاسبه</span>
|
||||||
|
<span class="ifnex-info-value"><?php echo esc_html($data['chargeable_weight'] ?? '—'); ?> kg</span>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-info-item">
|
||||||
|
<span class="ifnex-info-label">تاریخ ثبت</span>
|
||||||
|
<span class="ifnex-info-value"><?php echo esc_html($data['created_at_jalali'] ?? '—'); ?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- اطلاعات مالی -->
|
||||||
|
<div class="ifnex-detail-section">
|
||||||
|
<h3>💰 اطلاعات مالی</h3>
|
||||||
|
<div class="ifnex-price-breakdown">
|
||||||
|
<div class="ifnex-price-row">
|
||||||
|
<span>مبلغ خالص (درهم):</span>
|
||||||
|
<span><?php echo number_format($data['net_dirham'] ?? 0); ?> AED</span>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-price-row">
|
||||||
|
<span>مبلغ خالص (ریال):</span>
|
||||||
|
<span><?php echo number_format($data['net_rial'] ?? 0); ?> ریال</span>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-price-row total">
|
||||||
|
<span>مبلغ کل:</span>
|
||||||
|
<span><?php echo number_format($data['total_fee'] ?? 0); ?> ریال</span>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-price-row">
|
||||||
|
<span>وضعیت پرداخت:</span>
|
||||||
|
<span class="<?php echo $status['is_paid'] ? 'ifnex-text-success' : 'ifnex-text-warning'; ?>">
|
||||||
|
<?php echo $status['is_paid'] ? '✅ پرداخت شده' : '⏳ در انتظار پرداخت'; ?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- اطلاعات فرستنده -->
|
||||||
|
<?php if (!empty($data['sender_name']) || !empty($data['sender_phone'])): ?>
|
||||||
|
<div class="ifnex-detail-section">
|
||||||
|
<h3>👤 اطلاعات فرستنده</h3>
|
||||||
|
<div class="ifnex-info-grid">
|
||||||
|
<div class="ifnex-info-item">
|
||||||
|
<span class="ifnex-info-label">نام</span>
|
||||||
|
<span class="ifnex-info-value"><?php echo esc_html($data['sender_name'] ?? '—'); ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-info-item">
|
||||||
|
<span class="ifnex-info-label">تلفن</span>
|
||||||
|
<span class="ifnex-info-value"><?php echo esc_html($data['sender_phone'] ?? '—'); ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-info-item full">
|
||||||
|
<span class="ifnex-info-label">آدرس</span>
|
||||||
|
<span class="ifnex-info-value"><?php echo esc_html($data['sender_address'] ?? '—'); ?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<!-- اطلاعات گیرنده -->
|
||||||
|
<?php if (!empty($data['receiver_name']) || !empty($data['receiver_phone'])): ?>
|
||||||
|
<div class="ifnex-detail-section">
|
||||||
|
<h3>📮 اطلاعات گیرنده</h3>
|
||||||
|
<div class="ifnex-info-grid">
|
||||||
|
<div class="ifnex-info-item">
|
||||||
|
<span class="ifnex-info-label">نام</span>
|
||||||
|
<span class="ifnex-info-value"><?php echo esc_html($data['receiver_name'] ?? '—'); ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-info-item">
|
||||||
|
<span class="ifnex-info-label">تلفن</span>
|
||||||
|
<span class="ifnex-info-value"><?php echo esc_html($data['receiver_phone'] ?? '—'); ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="ifnex-info-item full">
|
||||||
|
<span class="ifnex-info-label">آدرس</span>
|
||||||
|
<span class="ifnex-info-value"><?php echo esc_html($data['receiver_address'] ?? '—'); ?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<!-- Timeline رهگیری -->
|
||||||
|
<?php if (!empty($data['tracking_events'])): ?>
|
||||||
|
<div class="ifnex-detail-section">
|
||||||
|
<h3>📍 تاریخچه رهگیری</h3>
|
||||||
|
<div class="ifnex-timeline">
|
||||||
|
<?php foreach ($data['tracking_events'] as $event): ?>
|
||||||
|
<div class="ifnex-timeline-item">
|
||||||
|
<div class="ifnex-timeline-dot"></div>
|
||||||
|
<div class="ifnex-timeline-content">
|
||||||
|
<div class="ifnex-timeline-header">
|
||||||
|
<strong><?php echo esc_html($event['event_description'] ?? ''); ?></strong>
|
||||||
|
<span class="ifnex-timeline-date">
|
||||||
|
<?php echo esc_html($event['event_date'] ?? ''); ?>
|
||||||
|
<?php if (!empty($event['event_time'])): ?>
|
||||||
|
- <?php echo esc_html($event['event_time']); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<?php if (!empty($event['location'])): ?>
|
||||||
|
<div class="ifnex-timeline-location">
|
||||||
|
📍 <?php echo esc_html($event['location']); ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="ifnex-detail-section">
|
||||||
|
<h3>📍 تاریخچه رهگیری</h3>
|
||||||
|
<p class="ifnex-empty-timeline">هنوز رویدادی ثبت نشده است.</p>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
$('.ifnex-cancel-order-detail').on('click', function() {
|
||||||
|
if (!confirm('آیا از لغو این سفارش اطمینان دارید؟')) return;
|
||||||
|
|
||||||
|
var btn = $(this);
|
||||||
|
var orderId = btn.data('order-id');
|
||||||
|
|
||||||
|
btn.prop('disabled', true).text('در حال لغو...');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: ifnex_ajax.ajax_url,
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
action: 'ifnex_cancel_order',
|
||||||
|
order_id: orderId,
|
||||||
|
nonce: ifnex_ajax.nonce
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
alert('سفارش با موفقیت لغو شد.');
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
alert('خطا: ' + response.data);
|
||||||
|
btn.prop('disabled', false).text('❌ لغو سفارش');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
alert('خطا در ارتباط با سرور.');
|
||||||
|
btn.prop('disabled', false).text('❌ لغو سفارش');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
@ -18,22 +18,29 @@ class IFNEX_User_Bridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* دریافت توکن Sanctum برای کاربر وردپرس
|
* دریافت توکن Sanctum از لاراول برای کاربر وردپرس
|
||||||
*/
|
*/
|
||||||
public function get_user_token($user_id) {
|
public function get_user_token($user_id) {
|
||||||
$token = get_user_meta($user_id, 'ifnex_laravel_token', true);
|
$token = get_user_meta($user_id, 'ifnex_laravel_token', true);
|
||||||
$token_expiry = get_user_meta($user_id, 'ifnex_laravel_token_expiry', true);
|
$token_expiry = get_user_meta($user_id, 'ifnex_laravel_token_expiry', true);
|
||||||
|
|
||||||
|
// اگر توکن معتبر وجود دارد، از آن استفاده کن
|
||||||
if ($token && $token_expiry && strtotime($token_expiry) > time()) {
|
if ($token && $token_expiry && strtotime($token_expiry) > time()) {
|
||||||
return $token;
|
return $token;
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = get_userdata($user_id);
|
// دریافت اطلاعات کاربر وردپرس
|
||||||
if (!$user) {
|
$wp_user = get_userdata($user_id);
|
||||||
|
if (!$wp_user) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$token = $this->request_token($user->user_email, $this->generate_temp_password($user_id));
|
// درخواست توکن از Bridge endpoint (جدید)
|
||||||
|
$token = $this->request_bridge_token(
|
||||||
|
$user_id,
|
||||||
|
$wp_user->user_email,
|
||||||
|
$wp_user->display_name
|
||||||
|
);
|
||||||
|
|
||||||
if ($token) {
|
if ($token) {
|
||||||
update_user_meta($user_id, 'ifnex_laravel_token', $token);
|
update_user_meta($user_id, 'ifnex_laravel_token', $token);
|
||||||
@ -43,13 +50,18 @@ class IFNEX_User_Bridge {
|
|||||||
return $token;
|
return $token;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* درخواست توکن از لاراول
|
* درخواست توکن از Bridge endpoint جدید
|
||||||
|
* این روش نیازی به رمز عبور ندارد و از API Key مشترک استفاده میکند
|
||||||
*/
|
*/
|
||||||
private function request_token($email, $password) {
|
private function request_bridge_token($wp_user_id, $email, $name) {
|
||||||
//$url = $this->api_url . '/sanctum/token';
|
$url = $this->api_url . '/bridge/login';
|
||||||
|
$bridge_key = get_option('ifnex_bridge_api_key', '');
|
||||||
|
|
||||||
$url = $this->api_url . '/auth/login';
|
if (empty($bridge_key)) {
|
||||||
|
error_log('IFNEX: Bridge API Key is not configured in WordPress settings');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$args = array(
|
$args = array(
|
||||||
'headers' => array(
|
'headers' => array(
|
||||||
@ -57,8 +69,10 @@ class IFNEX_User_Bridge {
|
|||||||
'Accept' => 'application/json',
|
'Accept' => 'application/json',
|
||||||
),
|
),
|
||||||
'body' => json_encode(array(
|
'body' => json_encode(array(
|
||||||
'email' => $email,
|
'bridge_api_key' => $bridge_key,
|
||||||
'password' => $password,
|
'wp_user_id' => $wp_user_id,
|
||||||
|
'wp_user_email' => $email,
|
||||||
|
'wp_user_name' => $name,
|
||||||
'token_name' => 'wordpress-bridge-' . get_current_blog_id(),
|
'token_name' => 'wordpress-bridge-' . get_current_blog_id(),
|
||||||
)),
|
)),
|
||||||
'timeout' => 30,
|
'timeout' => 30,
|
||||||
@ -67,6 +81,7 @@ class IFNEX_User_Bridge {
|
|||||||
$response = wp_remote_post($url, $args);
|
$response = wp_remote_post($url, $args);
|
||||||
|
|
||||||
if (is_wp_error($response)) {
|
if (is_wp_error($response)) {
|
||||||
|
error_log('IFNEX Bridge Error: ' . $response->get_error_message());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,25 +92,12 @@ class IFNEX_User_Bridge {
|
|||||||
return $data['token'];
|
return $data['token'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error_log('IFNEX Bridge Token Error: ' . ($data['message'] ?? 'Unknown error'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* تولید رمز عبور موقت برای کاربر وردپرس
|
* ارسال درخواست احراز هویتشده به API لاراول
|
||||||
*/
|
|
||||||
private function generate_temp_password($user_id) {
|
|
||||||
$temp_pass = get_user_meta($user_id, 'ifnex_temp_password', true);
|
|
||||||
|
|
||||||
if (!$temp_pass) {
|
|
||||||
$temp_pass = wp_generate_password(32, true, true);
|
|
||||||
update_user_meta($user_id, 'ifnex_temp_password', $temp_pass);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $temp_pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ارسال درخواست احراز هویت به API لاراول
|
|
||||||
*/
|
*/
|
||||||
public function authenticated_request($user_id, $endpoint, $method = 'GET', $data = array()) {
|
public function authenticated_request($user_id, $endpoint, $method = 'GET', $data = array()) {
|
||||||
$token = $this->get_user_token($user_id);
|
$token = $this->get_user_token($user_id);
|
||||||
@ -105,6 +107,7 @@ class IFNEX_User_Bridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$url = $this->api_url . $endpoint;
|
$url = $this->api_url . $endpoint;
|
||||||
|
$method = strtoupper($method);
|
||||||
|
|
||||||
$args = array(
|
$args = array(
|
||||||
'headers' => array(
|
'headers' => array(
|
||||||
@ -113,16 +116,16 @@ class IFNEX_User_Bridge {
|
|||||||
'Content-Type' => 'application/json',
|
'Content-Type' => 'application/json',
|
||||||
),
|
),
|
||||||
'timeout' => 30,
|
'timeout' => 30,
|
||||||
|
'method' => $method, // ✅ همیشه متد درخواستی استفاده شود
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($method === 'POST' && !empty($data)) {
|
// ✅ اصلاح: بر اساس متد، data را اضافه کن
|
||||||
$args['body'] = json_encode($data);
|
if (in_array($method, ['POST', 'PUT', 'PATCH'])) {
|
||||||
$args['method'] = 'POST';
|
// حتی اگر data خالی باشد، body را خالی بفرست
|
||||||
} else {
|
$args['body'] = json_encode($data ?: new \stdClass());
|
||||||
$args['method'] = 'GET';
|
} elseif ($method === 'GET' && !empty($data)) {
|
||||||
if (!empty($data)) {
|
// برای GET، data را به URL اضافه کن
|
||||||
$url = add_query_arg($data, $url);
|
$url = add_query_arg($data, $url);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = wp_remote_request($url, $args);
|
$response = wp_remote_request($url, $args);
|
||||||
@ -132,13 +135,22 @@ class IFNEX_User_Bridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$body = wp_remote_retrieve_body($response);
|
$body = wp_remote_retrieve_body($response);
|
||||||
|
$code = wp_remote_retrieve_response_code($response);
|
||||||
$data = json_decode($body, true);
|
$data = json_decode($body, true);
|
||||||
|
|
||||||
if ($response['response']['code'] === 401) {
|
// لاگ برای دیباگ
|
||||||
|
error_log("IFNEX API [{$method}] {$endpoint} => Status: {$code}");
|
||||||
|
|
||||||
|
if ($code === 401) {
|
||||||
$this->invalidate_token(get_current_user_id());
|
$this->invalidate_token(get_current_user_id());
|
||||||
return new WP_Error('token_expired', 'توکن منقضی شده است. لطفاً دوباره وارد شوید.');
|
return new WP_Error('token_expired', 'توکن منقضی شده است. لطفاً دوباره وارد شوید.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// اگر پاسخ JSON نیست
|
||||||
|
if (!is_array($data)) {
|
||||||
|
return new WP_Error('invalid_response', 'پاسخ نامعتبر از سرور: ' . substr($body, 0, 200));
|
||||||
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,10 +439,12 @@ function ifnex_enqueue_order_assets() {
|
|||||||
global $post;
|
global $post;
|
||||||
if (!is_a($post, 'WP_Post')) return;
|
if (!is_a($post, 'WP_Post')) return;
|
||||||
|
|
||||||
$has_order_shortcodes =
|
$has_order_shortcodes =
|
||||||
has_shortcode($post->post_content, 'ifnex_orders_list') ||
|
has_shortcode($post->post_content, 'ifnex_orders_list') ||
|
||||||
has_shortcode($post->post_content, 'ifnex_order_form') ||
|
has_shortcode($post->post_content, 'ifnex_order_form') ||
|
||||||
has_shortcode($post->post_content, 'ifnex_user_profile');
|
has_shortcode($post->post_content, 'ifnex_user_profile') ||
|
||||||
|
has_shortcode($post->post_content, 'ifnex_order_payment') ||
|
||||||
|
has_shortcode($post->post_content, 'ifnex_order_detail');
|
||||||
|
|
||||||
if ($has_order_shortcodes) {
|
if ($has_order_shortcodes) {
|
||||||
// ✅ اصلاح: dirname(__FILE__) یک سطح بالاتر میرود
|
// ✅ اصلاح: dirname(__FILE__) یک سطح بالاتر میرود
|
||||||
@ -462,3 +476,75 @@ function ifnex_enqueue_order_assets() {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
// AJAX Handlers برای پرداخت سفارش
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
add_action('wp_ajax_ifnex_pay_order_wallet', 'ifnex_pay_order_wallet_ajax');
|
||||||
|
function ifnex_pay_order_wallet_ajax() {
|
||||||
|
check_ajax_referer('ifnex_ajax_nonce', 'nonce');
|
||||||
|
if (!is_user_logged_in()) wp_send_json_error('باید وارد شوید.');
|
||||||
|
|
||||||
|
$order_id = intval($_POST['order_id'] ?? 0);
|
||||||
|
if (!$order_id) wp_send_json_error('شناسه سفارش نامعتبر است.');
|
||||||
|
|
||||||
|
$bridge = new IFNEX_User_Bridge();
|
||||||
|
$result = $bridge->authenticated_request(
|
||||||
|
get_current_user_id(),
|
||||||
|
"/customer/orders/{$order_id}/pay-wallet",
|
||||||
|
'POST'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (is_wp_error($result)) wp_send_json_error($result->get_error_message());
|
||||||
|
if (isset($result['success']) && !$result['success']) {
|
||||||
|
wp_send_json_error($result['message'] ?? 'خطا در پرداخت');
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_send_json_success($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_action('wp_ajax_ifnex_pay_order_gateway', 'ifnex_pay_order_gateway_ajax');
|
||||||
|
function ifnex_pay_order_gateway_ajax() {
|
||||||
|
check_ajax_referer('ifnex_ajax_nonce', 'nonce');
|
||||||
|
if (!is_user_logged_in()) wp_send_json_error('باید وارد شوید.');
|
||||||
|
|
||||||
|
$order_id = intval($_POST['order_id'] ?? 0);
|
||||||
|
$callback_url = sanitize_url($_POST['callback_url'] ?? '');
|
||||||
|
|
||||||
|
if (!$order_id) wp_send_json_error('شناسه سفارش نامعتبر است.');
|
||||||
|
if (!$callback_url) wp_send_json_error('آدرس بازگشت نامعتبر است.');
|
||||||
|
|
||||||
|
$bridge = new IFNEX_User_Bridge();
|
||||||
|
$result = $bridge->authenticated_request(
|
||||||
|
get_current_user_id(),
|
||||||
|
"/customer/orders/{$order_id}/pay-gateway",
|
||||||
|
'POST',
|
||||||
|
['frontend_callback' => $callback_url]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (is_wp_error($result)) wp_send_json_error($result->get_error_message());
|
||||||
|
if (isset($result['success']) && !$result['success']) {
|
||||||
|
wp_send_json_error($result['message'] ?? 'خطا در اتصال به درگاه');
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_send_json_success($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enqueue برای صفحه پرداخت
|
||||||
|
add_action('wp_enqueue_scripts', 'ifnex_enqueue_payment_assets');
|
||||||
|
function ifnex_enqueue_payment_assets() {
|
||||||
|
global $post;
|
||||||
|
if (!is_a($post, 'WP_Post')) return;
|
||||||
|
|
||||||
|
if (has_shortcode($post->post_content, 'ifnex_order_payment')) {
|
||||||
|
$plugin_url = plugin_dir_url(dirname(__FILE__));
|
||||||
|
wp_enqueue_style('ifnex-orders-css', $plugin_url . 'assets/css/ifnex-orders.css', array(), '1.3.0');
|
||||||
|
wp_enqueue_script('jquery');
|
||||||
|
wp_localize_script('jquery', 'ifnex_ajax', array(
|
||||||
|
'ajax_url' => admin_url('admin-ajax.php'),
|
||||||
|
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
|
||||||
|
'orders_url' => home_url('/my-orders/'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user