feat(wp-plugin): expand IFNEX Bridge with wallet and transaction support
Extend the WordPress bridge plugin to provide seamless integration with the backend wallet system. This update introduces user-specific functionality via shortcodes and AJAX. - feat(bridge): implement `IFNEX_User_Bridge` for Sanctum token management - feat(bridge): add `[ifnex_wallet_balance]` shortcode for balance display - feat(bridge): add `[ifnex_transactions]` shortcode for transaction history - feat(bridge): implement AJAX handlers for real-time balance and transaction updates - feat(bridge): add plugin-specific CSS assets and enqueueing logic - docs: update project status with new bridge capabilities - chore: add plugin testing utility and asset directory structure
This commit is contained in:
parent
e1c4385a9c
commit
b605b689fd
@ -261,6 +261,14 @@
|
||||
- [x] تستهای Unit/Feature برای Phase 2 (24 تست، 77 assertion)
|
||||
- [x] رفع باگ WalletController::balance()
|
||||
- [x] حذف PaymentGatewayService قدیمی (استفاده نمیشد)
|
||||
- [x] زیباسازی داشبورد و صفحه لاگین Filament
|
||||
- [x] گسترش پلاگین IFNEX Bridge برای وردپرس:
|
||||
- [x] ساخت `IFNEX_User_Bridge` برای مدیریت توکن Sanctum کاربران وردپرس
|
||||
- [x] اضافه کردن شورتکد `[ifnex_wallet_balance]`
|
||||
- [x] اضافه کردن شورتکد `[ifnex_transactions]`
|
||||
- [x] اضافه کردن AJAX handlers برای کیف پول و تراکنشها
|
||||
- [x] ساخت استایلهای CSS کامل برای تمام کامپوننتهای پلاگین
|
||||
- [x] ایجاد صفحه تست در وردپرس: http://localhost/ifnexwp/?page_id=16
|
||||
|
||||
---
|
||||
|
||||
@ -530,6 +538,15 @@ IFNEX-Logistics/
|
||||
- رفع باگ CHECK constraint در migration discount_codes (enum type: percent → percentage)
|
||||
- رفع باگ Wallet::isFrozen() — مدیریت null برای مقدار پیشفرض
|
||||
- بهروزرسانی STATUS.md با کارهای انجامشده Phase 2
|
||||
- گسترش پلاگین IFNEX Bridge:
|
||||
- ساخت `IFNEX_User_Bridge` برای مدیریت توکن Sanctum کاربران وردپرس
|
||||
- اضافه کردن شورتکد `[ifnex_wallet_balance]` با نمایش موجودی کیف پول
|
||||
- اضافه کردن شورتکد `[ifnex_transactions]` با لیست تراکنشهای کاربر
|
||||
- اضافه کردن AJAX handlers برای موجودی کیف پول و تراکنشها
|
||||
- ساخت استایلهای CSS کامل برای تمام کامپوننتهای پلاگین
|
||||
- ایجاد صفحه تست در وردپرس: http://localhost/ifnexwp/?page_id=16
|
||||
- رفع باگ صفحه لاگین Filament (MethodNotAllowed)
|
||||
- حذف فایلهای سفارشی لاگین و بازگشت به پیشفرض Filament
|
||||
|
||||
|
||||
|
||||
|
||||
62
03_WordPress/test-plugin.php
Normal file
62
03_WordPress/test-plugin.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
// Test script for IFNEX Bridge plugin
|
||||
// This creates a test page in WordPress with all shortcodes
|
||||
|
||||
require_once('wp-load.php');
|
||||
|
||||
// Check if user is logged in as admin
|
||||
if (!is_user_logged_in() || !current_user_can('manage_options')) {
|
||||
die('Admin access required');
|
||||
}
|
||||
|
||||
// Create test page content
|
||||
$page_content = '
|
||||
<h1>تست پلاگین IFNEX Bridge</h1>
|
||||
|
||||
<h2>1. فرم رهگیری مرسوله</h2>
|
||||
[ifnex_tracking_form title="رهگیری مرسوله IFNEX" placeholder="شماره بارنامه را وارد کنید" button_text="جستجو"]
|
||||
|
||||
<h2>2. موجودی کیف پول</h2>
|
||||
[ifnex_wallet_balance show_details="yes"]
|
||||
|
||||
<h2>3. لیست تراکنشها</h2>
|
||||
[ifnex_transactions per_page="5" show_pagination="yes"]
|
||||
|
||||
<h2>4. وضعیت مستقیم مرسوله</h2>
|
||||
[ifnex_tracking_status awb="980100010"]
|
||||
';
|
||||
|
||||
// Check if test page already exists
|
||||
$test_page = get_page_by_title('تست IFNEX Bridge', OBJECT, 'page');
|
||||
|
||||
if (!$test_page) {
|
||||
// Create test page
|
||||
$page_id = wp_insert_post(array(
|
||||
'post_title' => 'تست IFNEX Bridge',
|
||||
'post_content' => $page_content,
|
||||
'post_status' => 'publish',
|
||||
'post_type' => 'page',
|
||||
'post_author' => 1,
|
||||
));
|
||||
|
||||
if ($page_id) {
|
||||
echo "✅ صفحه تست ایجاد شد: " . get_permalink($page_id) . "\n";
|
||||
} else {
|
||||
echo "❌ خطا در ایجاد صفحه تست\n";
|
||||
}
|
||||
} else {
|
||||
// Update existing test page
|
||||
$test_page->post_content = $page_content;
|
||||
wp_update_post($test_page);
|
||||
echo "✅ صفحه تست بهروز شد: " . get_permalink($test_page->ID) . "\n";
|
||||
}
|
||||
|
||||
echo "\n📋 اطلاعات اتصال:\n";
|
||||
echo "API URL: " . get_option('ifnex_api_url', 'http://localhost:8000/api/v1') . "\n";
|
||||
echo "API Key: " . (get_option('ifnex_api_key', '') ? 'تنظیم شده' : 'تنظیم نشده') . "\n";
|
||||
|
||||
echo "\n🔧 مراحل بعدی:\n";
|
||||
echo "1. مطمئن شوید لاراول در حال اجرا است: cd 04_Laravel && php artisan serve\n";
|
||||
echo "2. وارد صفحه تست شوید: http://localhost/ifnexwp/?page_id=" . ($test_page ? $test_page->ID : $page_id) . "\n";
|
||||
echo "3. ابتدا وارد وردپرس شوید (admin / admin)\n";
|
||||
echo "4. صفحه تست را باز کنید و عملکرد شورتکدها را بررسی کنید\n";
|
||||
@ -0,0 +1,384 @@
|
||||
/**
|
||||
* IFNEX Bridge Styles
|
||||
* استایلهای پلاگین IFNEX Logistics Bridge
|
||||
*/
|
||||
|
||||
/* Wallet Balance */
|
||||
.ifnex-wallet-balance {
|
||||
background: #f9fafb;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
margin: 15px 0;
|
||||
font-family: inherit;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.ifnex-balance-main {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.ifnex-balance-label {
|
||||
font-size: 14px;
|
||||
color: #6b7280;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.ifnex-balance-amount {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.ifnex-balance-details {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.ifnex-balance-details p {
|
||||
margin: 5px 0;
|
||||
font-size: 14px;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.ifnex-balance-details strong {
|
||||
color: #6b7280;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.ifnex-wallet-frozen {
|
||||
color: #dc2626;
|
||||
font-weight: 600;
|
||||
margin-top: 10px;
|
||||
padding: 8px 12px;
|
||||
background: #fee2e2;
|
||||
border-radius: 6px;
|
||||
border-right: 3px solid #dc2626;
|
||||
}
|
||||
|
||||
/* Transactions */
|
||||
.ifnex-transactions {
|
||||
margin: 15px 0;
|
||||
font-family: inherit;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.ifnex-transactions h3 {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid #f59e0b;
|
||||
}
|
||||
|
||||
.ifnex-transactions-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.ifnex-transaction-item {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 10px;
|
||||
padding: 16px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.ifnex-transaction-item:hover {
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
border-color: #f59e0b;
|
||||
}
|
||||
|
||||
.ifnex-transaction-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.ifnex-transaction-type {
|
||||
display: inline-block;
|
||||
padding: 4px 10px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
background: #dbeafe;
|
||||
color: #1e40af;
|
||||
}
|
||||
|
||||
.ifnex-transaction-type.deposit {
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
}
|
||||
|
||||
.ifnex-transaction-type.withdrawal {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.ifnex-transaction-type.order_payment {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
}
|
||||
|
||||
.ifnex-transaction-type.refund {
|
||||
background: #e0e7ff;
|
||||
color: #3730a3;
|
||||
}
|
||||
|
||||
.ifnex-transaction-amount {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
font-family: 'Vazirmatn', 'IranYekan', sans-serif;
|
||||
}
|
||||
|
||||
.ifnex-transaction-amount.positive {
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.ifnex-transaction-amount.negative {
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.ifnex-transaction-details {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.ifnex-transaction-description {
|
||||
color: #4b5563;
|
||||
font-size: 14px;
|
||||
margin: 0 0 6px 0;
|
||||
}
|
||||
|
||||
.ifnex-transaction-meta {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.ifnex-transaction-status {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
background: #f3f4f6;
|
||||
color: #374151;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.ifnex-transaction-status.completed {
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
}
|
||||
|
||||
.ifnex-transaction-status.pending {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
}
|
||||
|
||||
.ifnex-transaction-status.failed {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.ifnex-transaction-ref {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/* Tracking Status */
|
||||
.ifnex-tracking-container {
|
||||
max-width: 700px;
|
||||
margin: 20px auto;
|
||||
padding: 24px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 12px;
|
||||
font-family: inherit;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.ifnex-tracking-container h2 {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid #f59e0b;
|
||||
}
|
||||
|
||||
.ifnex-tracking-form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ifnex-form-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.ifnex-form-group input {
|
||||
flex: 1;
|
||||
padding: 12px 16px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
font-size: 15px;
|
||||
font-family: inherit;
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.ifnex-form-group input:focus {
|
||||
outline: none;
|
||||
border-color: #f59e0b;
|
||||
box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1);
|
||||
}
|
||||
|
||||
.ifnex-form-group button {
|
||||
padding: 12px 24px;
|
||||
background: #f59e0b;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
font-family: inherit;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.ifnex-form-group button:hover {
|
||||
background: #d97706;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.ifnex-form-group button:disabled {
|
||||
background: #9ca3af;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.ifnex-tracking-result {
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
background: #f9fafb;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.ifnex-error {
|
||||
color: #dc2626;
|
||||
font-weight: 500;
|
||||
padding: 10px;
|
||||
background: #fee2e2;
|
||||
border-radius: 6px;
|
||||
border-right: 3px solid #dc2626;
|
||||
}
|
||||
|
||||
.ifnex-tracking-status h3 {
|
||||
margin-top: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.ifnex-status-badge {
|
||||
display: inline-block;
|
||||
padding: 6px 14px;
|
||||
background: #f59e0b;
|
||||
color: white;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 12px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.ifnex-status-badge.delivered {
|
||||
background: #059669;
|
||||
}
|
||||
|
||||
.ifnex-status-badge.failed {
|
||||
background: #dc2626;
|
||||
}
|
||||
|
||||
.ifnex-status-badge.in_transit {
|
||||
background: #2563eb;
|
||||
}
|
||||
|
||||
.ifnex-tracking-details {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.ifnex-tracking-details p {
|
||||
margin: 6px 0;
|
||||
font-size: 14px;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.ifnex-tracking-details strong {
|
||||
color: #374151;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.ifnex-timeline {
|
||||
margin-top: 20px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.ifnex-timeline h4 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.ifnex-timeline ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ifnex-timeline li {
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid #f3f4f6;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.ifnex-timeline li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.ifnex-timeline li strong {
|
||||
color: #f59e0b;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.ifnex-timeline li span {
|
||||
color: #4b5563;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.ifnex-timeline li small {
|
||||
color: #9ca3af;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@ -12,9 +12,23 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
|
||||
// لود کردن فایلهای پلاگین
|
||||
require_once plugin_dir_path( __FILE__ ) . 'includes/api-client.php';
|
||||
require_once plugin_dir_path( __FILE__ ) . 'includes/user-bridge.php';
|
||||
require_once plugin_dir_path( __FILE__ ) . 'includes/shortcodes.php';
|
||||
require_once plugin_dir_path( __FILE__ ) . 'includes/tracking-form.php';
|
||||
|
||||
// لود کردن استایلهای پلاگین
|
||||
add_action('wp_enqueue_scripts', 'ifnex_enqueue_scripts');
|
||||
function ifnex_enqueue_scripts() {
|
||||
global $post;
|
||||
if (is_a($post, 'WP_Post') &&
|
||||
(has_shortcode($post->post_content, 'ifnex_tracking_form') ||
|
||||
has_shortcode($post->post_content, 'ifnex_wallet_balance') ||
|
||||
has_shortcode($post->post_content, 'ifnex_transactions') ||
|
||||
has_shortcode($post->post_content, 'ifnex_tracking_status'))) {
|
||||
wp_enqueue_style('ifnex-bridge-css', plugin_dir_url(__FILE__) . 'assets/css/ifnex-bridge.css', array(), '1.0.0');
|
||||
}
|
||||
}
|
||||
|
||||
// اضافه کردن لینک به منوی پیشخوان وردپرس
|
||||
add_action( 'admin_menu', 'ifnex_plugin_setup_menu' );
|
||||
function ifnex_plugin_setup_menu() {
|
||||
|
||||
@ -86,3 +86,106 @@ function ifnex_tracking_status_shortcode($atts) {
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
// شورتکد موجودی کیف پول
|
||||
add_shortcode('ifnex_wallet_balance', 'ifnex_wallet_balance_shortcode');
|
||||
|
||||
function ifnex_wallet_balance_shortcode($atts) {
|
||||
if (!is_user_logged_in()) {
|
||||
return '<p class="ifnex-error">برای مشاهده موجودی باید وارد شوید.</p>';
|
||||
}
|
||||
|
||||
$atts = shortcode_atts(array(
|
||||
'show_details' => 'no',
|
||||
), $atts);
|
||||
|
||||
$bridge = new IFNEX_User_Bridge();
|
||||
$balance = $bridge->get_wallet_balance(get_current_user_id());
|
||||
|
||||
if (is_wp_error($balance)) {
|
||||
return '<p class="ifnex-error">' . esc_html($balance->get_error_message()) . '</p>';
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="ifnex-wallet-balance">
|
||||
<div class="ifnex-balance-main">
|
||||
<span class="ifnex-balance-label">موجودی کیف پول:</span>
|
||||
<span class="ifnex-balance-amount"><?php echo number_format($balance['balance']); ?> ریال</span>
|
||||
</div>
|
||||
<?php if ($atts['show_details'] === 'yes'): ?>
|
||||
<div class="ifnex-balance-details">
|
||||
<p><strong>مجموع واریزی:</strong> <?php echo number_format($balance['total_deposited']); ?> ریال</p>
|
||||
<p><strong>مجموع برداشت:</strong> <?php echo number_format($balance['total_withdrawn']); ?> ریال</p>
|
||||
<?php if ($balance['is_frozen']): ?>
|
||||
<p class="ifnex-wallet-frozen">⚠️ کیف پول شما مسدود است.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
// شورتکد لیست تراکنشها
|
||||
add_shortcode('ifnex_transactions', 'ifnex_transactions_shortcode');
|
||||
|
||||
function ifnex_transactions_shortcode($atts) {
|
||||
if (!is_user_logged_in()) {
|
||||
return '<p class="ifnex-error">برای مشاهده تراکنشها باید وارد شوید.</p>';
|
||||
}
|
||||
|
||||
$atts = shortcode_atts(array(
|
||||
'per_page' => 10,
|
||||
'show_pagination' => 'no',
|
||||
), $atts);
|
||||
|
||||
$bridge = new IFNEX_User_Bridge();
|
||||
$transactions = $bridge->get_transactions(get_current_user_id(), intval($atts['per_page']));
|
||||
|
||||
if (is_wp_error($transactions)) {
|
||||
return '<p class="ifnex-error">' . esc_html($transactions->get_error_message()) . '</p>';
|
||||
}
|
||||
|
||||
if (empty($transactions['transactions'])) {
|
||||
return '<p>هنوز تراکنشی ثبت نشده است.</p>';
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="ifnex-transactions">
|
||||
<h3>تاریخچه تراکنشها</h3>
|
||||
<div class="ifnex-transactions-list">
|
||||
<?php foreach ($transactions['transactions'] as $transaction): ?>
|
||||
<div class="ifnex-transaction-item">
|
||||
<div class="ifnex-transaction-header">
|
||||
<span class="ifnex-transaction-type <?php echo esc_attr($transaction['type']); ?>">
|
||||
<?php echo esc_html($transaction['type']); ?>
|
||||
</span>
|
||||
<span class="ifnex-transaction-amount <?php echo $transaction['amount'] >= 0 ? 'positive' : 'negative'; ?>">
|
||||
<?php echo $transaction['amount'] >= 0 ? '+' : ''; ?>
|
||||
<?php echo number_format($transaction['amount']); ?> ریال
|
||||
</span>
|
||||
</div>
|
||||
<div class="ifnex-transaction-details">
|
||||
<p class="ifnex-transaction-description"><?php echo esc_html($transaction['description']); ?></p>
|
||||
<div class="ifnex-transaction-meta">
|
||||
<span class="ifnex-transaction-status"><?php echo esc_html($transaction['status']); ?></span>
|
||||
<span class="ifnex-transaction-date"><?php echo esc_html($transaction['created_at_jalali']); ?></span>
|
||||
</div>
|
||||
<?php if (!empty($transaction['reference_id'])): ?>
|
||||
<p class="ifnex-transaction-ref">کد پیگیری: <?php echo esc_html($transaction['reference_id']); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if ($atts['show_pagination'] === 'yes' && $transactions['last_page'] > 1): ?>
|
||||
<div class="ifnex-pagination">
|
||||
<!-- Pagination can be added here -->
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
@ -204,3 +204,96 @@ function ifnex_track_shipment_ajax() {
|
||||
|
||||
wp_send_json(array('success' => true, 'html' => $html));
|
||||
}
|
||||
|
||||
// AJAX Handler: موجودی کیف پول
|
||||
add_action('wp_ajax_ifnex_get_wallet_balance', 'ifnex_get_wallet_balance_ajax');
|
||||
add_action('wp_ajax_nopriv_ifnex_get_wallet_balance', 'ifnex_get_wallet_balance_ajax');
|
||||
|
||||
function ifnex_get_wallet_balance_ajax() {
|
||||
if (!is_user_logged_in()) {
|
||||
wp_send_json(array('success' => false, 'message' => 'برای مشاهده موجودی باید وارد شوید.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$bridge = new IFNEX_User_Bridge();
|
||||
$balance = $bridge->get_wallet_balance(get_current_user_id());
|
||||
|
||||
if (is_wp_error($balance)) {
|
||||
wp_send_json(array('success' => false, 'message' => $balance->get_error_message()));
|
||||
return;
|
||||
}
|
||||
|
||||
wp_send_json(array(
|
||||
'success' => true,
|
||||
'balance' => $balance['balance'],
|
||||
'formatted_balance' => number_format($balance['balance']) . ' ریال',
|
||||
'total_deposited' => number_format($balance['total_deposited']) . ' ریال',
|
||||
'total_withdrawn' => number_format($balance['total_withdrawn']) . ' ریال',
|
||||
'is_frozen' => $balance['is_frozen'],
|
||||
));
|
||||
}
|
||||
|
||||
// AJAX Handler: لیست تراکنشها
|
||||
add_action('wp_ajax_ifnex_get_transactions', 'ifnex_get_transactions_ajax');
|
||||
add_action('wp_ajax_nopriv_ifnex_get_transactions', 'ifnex_get_transactions_ajax');
|
||||
|
||||
function ifnex_get_transactions_ajax() {
|
||||
if (!is_user_logged_in()) {
|
||||
wp_send_json(array('success' => false, 'message' => 'برای مشاهده تراکنشها باید وارد شوید.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$per_page = isset($_POST['per_page']) ? intval($_POST['per_page']) : 10;
|
||||
|
||||
$bridge = new IFNEX_User_Bridge();
|
||||
$transactions = $bridge->get_transactions(get_current_user_id(), $per_page);
|
||||
|
||||
if (is_wp_error($transactions)) {
|
||||
wp_send_json(array('success' => false, 'message' => $transactions->get_error_message()));
|
||||
return;
|
||||
}
|
||||
|
||||
// ساخت HTML لیست تراکنشها
|
||||
if (empty($transactions['transactions'])) {
|
||||
wp_send_json(array(
|
||||
'success' => true,
|
||||
'html' => '<p>هنوز تراکنشی ثبت نشده است.</p>',
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="ifnex-transactions-list">
|
||||
<?php foreach ($transactions['transactions'] as $transaction): ?>
|
||||
<div class="ifnex-transaction-item">
|
||||
<div class="ifnex-transaction-header">
|
||||
<span class="ifnex-transaction-type">
|
||||
<?php echo esc_html($transaction['type']); ?>
|
||||
</span>
|
||||
<span class="ifnex-transaction-amount <?php echo $transaction['amount'] >= 0 ? 'positive' : 'negative'; ?>">
|
||||
<?php echo $transaction['amount'] >= 0 ? '+' : ''; ?>
|
||||
<?php echo number_format($transaction['amount']); ?> ریال
|
||||
</span>
|
||||
</div>
|
||||
<div class="ifnex-transaction-details">
|
||||
<p class="ifnex-transaction-description"><?php echo esc_html($transaction['description']); ?></p>
|
||||
<div class="ifnex-transaction-meta">
|
||||
<span class="ifnex-transaction-status"><?php echo esc_html($transaction['status']); ?></span>
|
||||
<span class="ifnex-transaction-date"><?php echo esc_html($transaction['created_at_jalali']); ?></span>
|
||||
</div>
|
||||
<?php if (!empty($transaction['reference_id'])): ?>
|
||||
<p class="ifnex-transaction-ref">کد پیگیری: <?php echo esc_html($transaction['reference_id']); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php
|
||||
$html = ob_get_clean();
|
||||
|
||||
wp_send_json(array(
|
||||
'success' => true,
|
||||
'html' => $html,
|
||||
));
|
||||
}
|
||||
|
||||
@ -0,0 +1,221 @@
|
||||
<?php
|
||||
/**
|
||||
* IFNEX User Bridge
|
||||
* مدیریت ارتباط کاربران وردپرس با لاراول
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class IFNEX_User_Bridge {
|
||||
private $api_url;
|
||||
private $api_key;
|
||||
|
||||
public function __construct() {
|
||||
$this->api_url = rtrim(get_option('ifnex_api_url', 'http://localhost:8000/api/v1'), '/');
|
||||
$this->api_key = get_option('ifnex_api_key', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* دریافت توکن Sanctum برای کاربر وردپرس
|
||||
*/
|
||||
public function get_user_token($user_id) {
|
||||
$token = get_user_meta($user_id, 'ifnex_laravel_token', true);
|
||||
$token_expiry = get_user_meta($user_id, 'ifnex_laravel_token_expiry', true);
|
||||
|
||||
if ($token && $token_expiry && strtotime($token_expiry) > time()) {
|
||||
return $token;
|
||||
}
|
||||
|
||||
$user = get_userdata($user_id);
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$token = $this->request_token($user->user_email, $this->generate_temp_password($user_id));
|
||||
|
||||
if ($token) {
|
||||
update_user_meta($user_id, 'ifnex_laravel_token', $token);
|
||||
update_user_meta($user_id, 'ifnex_laravel_token_expiry', date('Y-m-d H:i:s', strtotime('+30 days')));
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* درخواست توکن از لاراول
|
||||
*/
|
||||
private function request_token($email, $password) {
|
||||
$url = $this->api_url . '/sanctum/token';
|
||||
|
||||
$args = array(
|
||||
'headers' => array(
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
),
|
||||
'body' => json_encode(array(
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
'token_name' => 'wordpress-bridge-' . get_current_blog_id(),
|
||||
)),
|
||||
'timeout' => 30,
|
||||
);
|
||||
|
||||
$response = wp_remote_post($url, $args);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
$data = json_decode($body, true);
|
||||
|
||||
if (isset($data['token'])) {
|
||||
return $data['token'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* تولید رمز عبور موقت برای کاربر وردپرس
|
||||
*/
|
||||
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()) {
|
||||
$token = $this->get_user_token($user_id);
|
||||
|
||||
if (!$token) {
|
||||
return new WP_Error('no_token', 'توکن احراز هویت یافت نشد.');
|
||||
}
|
||||
|
||||
$url = $this->api_url . $endpoint;
|
||||
|
||||
$args = array(
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $token,
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
'timeout' => 30,
|
||||
);
|
||||
|
||||
if ($method === 'POST' && !empty($data)) {
|
||||
$args['body'] = json_encode($data);
|
||||
$args['method'] = 'POST';
|
||||
} else {
|
||||
$args['method'] = 'GET';
|
||||
if (!empty($data)) {
|
||||
$url = add_query_arg($data, $url);
|
||||
}
|
||||
}
|
||||
|
||||
$response = wp_remote_request($url, $args);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
$data = json_decode($body, true);
|
||||
|
||||
if ($response['response']['code'] === 401) {
|
||||
$this->invalidate_token(get_current_user_id());
|
||||
return new WP_Error('token_expired', 'توکن منقضی شده است. لطفاً دوباره وارد شوید.');
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* باطل کردن توکن
|
||||
*/
|
||||
public function invalidate_token($user_id) {
|
||||
delete_user_meta($user_id, 'ifnex_laravel_token');
|
||||
delete_user_meta($user_id, 'ifnex_laravel_token_expiry');
|
||||
}
|
||||
|
||||
/**
|
||||
* دریافت موجودی کیف پول کاربر
|
||||
*/
|
||||
public function get_wallet_balance($user_id) {
|
||||
$result = $this->authenticated_request($user_id, '/wallet/balance');
|
||||
|
||||
if (is_wp_error($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return array(
|
||||
'balance' => $result['balance'] ?? 0,
|
||||
'total_deposited' => $result['total_deposited'] ?? 0,
|
||||
'total_withdrawn' => $result['total_withdrawn'] ?? 0,
|
||||
'is_frozen' => $result['is_frozen'] ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* دریافت تراکنشهای کاربر
|
||||
*/
|
||||
public function get_transactions($user_id, $per_page = 15) {
|
||||
$result = $this->authenticated_request($user_id, '/wallet/transactions', 'GET', array(
|
||||
'per_page' => $per_page,
|
||||
));
|
||||
|
||||
if (is_wp_error($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* رهگیری مرسوله
|
||||
*/
|
||||
public function track_shipment($awb_no) {
|
||||
if (empty($this->api_key)) {
|
||||
return new WP_Error('no_api_key', 'API Key تنظیم نشده است.');
|
||||
}
|
||||
|
||||
$url = $this->api_url . '/track/' . urlencode($awb_no);
|
||||
|
||||
$args = array(
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $this->api_key,
|
||||
'Accept' => 'application/json',
|
||||
),
|
||||
'timeout' => 30,
|
||||
);
|
||||
|
||||
$response = wp_remote_get($url, $args);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
$data = json_decode($body, true);
|
||||
|
||||
if ($response['response']['code'] === 404) {
|
||||
return new WP_Error('not_found', 'مرسولهای با این کد پیدا نشد.');
|
||||
}
|
||||
|
||||
if ($response['response']['code'] !== 200) {
|
||||
return new WP_Error('api_error', 'خطا در ارتباط با API: ' . ($data['message'] ?? 'Unknown error'));
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user