From b605b689fd88bde4270ddf6200387f81aa8625f3 Mon Sep 17 00:00:00 2001 From: Kazem Alghasi Date: Sat, 8 Aug 2026 03:49:46 +0330 Subject: [PATCH] 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 --- 01_Documents/STATUS.md | 17 + 03_WordPress/test-plugin.php | 62 +++ .../ifnex-bridge/assets/css/ifnex-bridge.css | 384 ++++++++++++++++++ .../plugins/ifnex-bridge/ifnex-bridge.php | 14 + .../ifnex-bridge/includes/shortcodes.php | 103 +++++ .../ifnex-bridge/includes/tracking-form.php | 93 +++++ .../ifnex-bridge/includes/user-bridge.php | 221 ++++++++++ 7 files changed, 894 insertions(+) create mode 100644 03_WordPress/test-plugin.php create mode 100644 03_WordPress/wp-content/plugins/ifnex-bridge/assets/css/ifnex-bridge.css create mode 100644 03_WordPress/wp-content/plugins/ifnex-bridge/includes/user-bridge.php diff --git a/01_Documents/STATUS.md b/01_Documents/STATUS.md index c60a26e..660cbfe 100644 --- a/01_Documents/STATUS.md +++ b/01_Documents/STATUS.md @@ -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 diff --git a/03_WordPress/test-plugin.php b/03_WordPress/test-plugin.php new file mode 100644 index 0000000..8c9c6b7 --- /dev/null +++ b/03_WordPress/test-plugin.php @@ -0,0 +1,62 @@ +تست پلاگین IFNEX Bridge + +

1. فرم رهگیری مرسوله

+[ifnex_tracking_form title="رهگیری مرسوله IFNEX" placeholder="شماره بارنامه را وارد کنید" button_text="جستجو"] + +

2. موجودی کیف پول

+[ifnex_wallet_balance show_details="yes"] + +

3. لیست تراکنش‌ها

+[ifnex_transactions per_page="5" show_pagination="yes"] + +

4. وضعیت مستقیم مرسوله

+[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"; diff --git a/03_WordPress/wp-content/plugins/ifnex-bridge/assets/css/ifnex-bridge.css b/03_WordPress/wp-content/plugins/ifnex-bridge/assets/css/ifnex-bridge.css new file mode 100644 index 0000000..6326345 --- /dev/null +++ b/03_WordPress/wp-content/plugins/ifnex-bridge/assets/css/ifnex-bridge.css @@ -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; +} diff --git a/03_WordPress/wp-content/plugins/ifnex-bridge/ifnex-bridge.php b/03_WordPress/wp-content/plugins/ifnex-bridge/ifnex-bridge.php index e5638fb..b6df2c9 100644 --- a/03_WordPress/wp-content/plugins/ifnex-bridge/ifnex-bridge.php +++ b/03_WordPress/wp-content/plugins/ifnex-bridge/ifnex-bridge.php @@ -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() { diff --git a/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php b/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php index d9f5651..09ca608 100644 --- a/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php +++ b/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php @@ -86,3 +86,106 @@ function ifnex_tracking_status_shortcode($atts) { برای مشاهده موجودی باید وارد شوید.

'; + } + + $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 '

' . esc_html($balance->get_error_message()) . '

'; + } + + ob_start(); + ?> +
+
+ موجودی کیف پول: + ریال +
+ +
+

مجموع واریزی: ریال

+

مجموع برداشت: ریال

+ +

⚠️ کیف پول شما مسدود است.

+ +
+ +
+ برای مشاهده تراکنش‌ها باید وارد شوید.

'; + } + + $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 '

' . esc_html($transactions->get_error_message()) . '

'; + } + + if (empty($transactions['transactions'])) { + return '

هنوز تراکنشی ثبت نشده است.

'; + } + + ob_start(); + ?> +
+

تاریخچه تراکنش‌ها

+
+ +
+
+ + + + + = 0 ? '+' : ''; ?> + ریال + +
+
+

+
+ + +
+ +

کد پیگیری:

+ +
+
+ +
+ 1): ?> +
+ +
+ +
+ 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' => '

هنوز تراکنشی ثبت نشده است.

', + )); + return; + } + + ob_start(); + ?> +
+ +
+
+ + + + + = 0 ? '+' : ''; ?> + ریال + +
+
+

+
+ + +
+ +

کد پیگیری:

+ +
+
+ +
+ true, + 'html' => $html, + )); +} diff --git a/03_WordPress/wp-content/plugins/ifnex-bridge/includes/user-bridge.php b/03_WordPress/wp-content/plugins/ifnex-bridge/includes/user-bridge.php new file mode 100644 index 0000000..c0ffa6b --- /dev/null +++ b/03_WordPress/wp-content/plugins/ifnex-bridge/includes/user-bridge.php @@ -0,0 +1,221 @@ +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; + } +}