'رهگیری مرسوله',
'placeholder' => 'شماره بارنامه را وارد کنید',
'button_text' => 'رهگیری',
), $atts);
// خواندن پارامتر awb از URL
$awb_from_url = isset($_GET['awb']) ? sanitize_text_field($_GET['awb']) : '';
ob_start();
?>
'',
), $atts);
if (empty($atts['awb'])) {
return 'شماره بارنامه وارد نشده است.
';
}
$client = new IFNEX_API_Client();
$result = $client->track_shipment($atts['awb']);
if (is_wp_error($result)) {
return '' . esc_html($result->get_error_message()) . '
';
}
ob_start();
?>
وضعیت مرسوله
نوع:
جهت:
فرستنده:
گیرنده:
برای مشاهده موجودی باید وارد شوید.';
}
$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();
?>
برای مشاهده پروفایل، باید وارد شوید.';
}
$atts = shortcode_atts(array(
'show_stats' => 'yes',
'show_wallet' => 'yes',
'show_recent_orders' => 'yes',
), $atts);
$bridge = new IFNEX_User_Bridge();
$user_id = get_current_user_id();
$profile = $bridge->get_customer_profile($user_id);
if (is_wp_error($profile)) {
return '' . esc_html($profile->get_error_message()) . '
';
}
ob_start();
?>
💰 وضعیت مالی
مانده حساب (موجودی منهای بدهیها)
ریال
0): ?>
⚠️ بدهی در انتظار پرداخت: ریال
🌍 بدهیهای چندارزی
ارز
مبلغ کل
تسویهشده
مانده
⚠️ بدهیهای بالا به ارز اصلی ثبت شدهاند و با نرخ روز تسویه میشوند.
🌍 بدهیهای چندارزی
ارز
مبلغ کل
تسویهشده
مانده
📊 آمار سفارشات
0): ?>
مجموع خرید:
ریال
برای مشاهده سفارشات، باید وارد شوید.';
}
$atts = shortcode_atts(array(
'per_page' => 10,
'status' => '',
), $atts);
$bridge = new IFNEX_User_Bridge();
$user_id = get_current_user_id();
$result = $bridge->get_customer_orders($user_id, intval($atts['per_page']), $atts['status']);
if (is_wp_error($result)) {
return '' . esc_html($result->get_error_message()) . '
';
}
$orders = $result['data'] ?? [];
$pagination = $result['pagination'] ?? [];
ob_start();
?>
وزن:
kg
مبلغ:
ریال
تاریخ:
1): ?>
🔐 ورود لازم است
برای ثبت سفارش، ابتدا باید وارد حساب کاربری خود شوید.
ورود به حساب
برای پرداخت، باید وارد شوید.';
}
$atts = shortcode_atts(array('order_id' => ''), $atts);
// دریافت order_id از URL parameter
$order_id = $atts['order_id'] ?: ($_GET['order_id'] ?? 0);
if (!$order_id) {
return 'شناسه سفارش مشخص نشده است.
';
}
$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 '' . esc_html($order->get_error_message()) . '
';
}
$data = $order['data'];
// بررسی وضعیت (فقط سفارشات تأیید شده قابل پرداخت هستند)
if ($data['status']['value'] !== 'approved') {
$message = 'این سفارش هنوز تأیید نشده است و قابل پرداخت نیست.';
if ($data['status']['value'] === 'pending_approval') {
$message = 'این سفارش در انتظار تأیید کارمند است. پس از تأیید، گزینه پرداخت فعال خواهد شد.';
} elseif ($data['status']['is_paid']) {
$message = 'این سفارش قبلاً پرداخت شده است.';
}
return '
⏳ ' . $message . '
وضعیت فعلی: ' . esc_html($data['status']['label']) . '
بازگشت به سفارشات
';
}
$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'];
// بررسی نتیجه پرداخت از درگاه (callback)
$payment_status = sanitize_text_field($_GET['status'] ?? '');
$payment_message = sanitize_text_field($_GET['message'] ?? '');
$payment_ref_id = sanitize_text_field($_GET['ref_id'] ?? '');
ob_start();
?>
💳 پرداخت سفارش
✅ پرداخت با موفقیت انجام شد!
کد پیگیری تراکنش:
مبلغ: ریال
سفارش شما در حال پردازش است.
مشاهده سفارشات
شماره پیگیری:
مسیر:
→
مبلغ قابل پرداخت:
ریال
💰 پرداخت از کیف پول
موجودی فعلی: ریال
پرداخت فوری از کیف پول
⚠️ موجودی کافی نیست. لطفاً ابتدا کیف پول خود را شارژ کنید.
شارژ کیف پول
🏦 پرداخت از درگاه بانکی
انتقال به درگاه پرداخت امن (زرینپال)
انتقال به درگاه بانکی
برای مشاهده جزئیات، باید وارد شوید.';
}
$atts = shortcode_atts(array('order_id' => ''), $atts);
$order_id = $atts['order_id'] ?: ($_GET['order_id'] ?? 0);
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 'شناسه سفارش مشخص نشده است.
';
}
// ⚠️ هندلر دانلودها (PDF و تعهدنامه) به template_redirect منتقل شده —
// اجرای آن داخل شورتکد یعنی بعد از چاپ HTML هدر قالب؛ خروجی باینری به
// HTML میچسبد و با Content-Length ناهمخوان، PDF نیمهتمام دانلود میشود.
$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 '' . esc_html($order->get_error_message()) . '
';
}
$data = $order['data'];
$status = $data['status'];
$awb = $data['awb_no'];
$oid = (int)$order_id;
$dl_base = home_url('/order-detail/?order_id=' . $oid . '&download=');
// مراحل پیشرفت
$status_val = $status['value'] ?? '';
$stage_order = ['pending_approval'=>1,'approved'=>2,'processed'=>3,'picked_up'=>4,'in_transit'=>5,'out_for_delivery'=>6,'delivered'=>7];
$current_stage = $stage_order[$status_val] ?? 0;
$stages = [
1 => 'ثبت', 2 => 'تأیید', 3 => 'پرداخت', 4 => 'جمعآوری',
5 => 'ارسال', 6 => 'تحویل'
];
ob_start();
?>
📦 اطلاعات مرسوله
نوع سرویس
جهت
وزن واقعی kg
وزن محاسبهای kg
تاریخ ثبت
📊 مراحل سفارش
$label):
$cls = $num <= $current_stage ? 'done' : ($num === $current_stage + 1 ? 'current' : 'pending');
$icon = $num <= $current_stage ? '✓' : $num;
?>
📍 تاریخچه رهگیری
هنوز رویدادی ثبت نشده است.
get_customer_order($user_id, $order_id);
if (is_wp_error($order)) wp_die('خطا: ' . $order->get_error_message());
$api_url = get_option('ifnex_api_url', 'http://localhost:8000/api/v1');
$download_url = rtrim($api_url, '/') . "/customer/orders/{$order_id}/pdf/{$download_type}";
$token = $bridge->get_user_token($user_id); // با تجدید خودکار در صورت انقضا/حذف
if (!$token) wp_die('توکن احراز هویت در دسترس نیست — لطفاً دوباره وارد شوید.');
$response = wp_remote_get($download_url, array(
'headers' => array(
'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/pdf',
),
'timeout' => 30,
));
if (is_wp_error($response)) wp_die('خطا در ارتباط با سرور.');
$status_code = wp_remote_retrieve_response_code($response);
if ($status_code !== 200) wp_die('خطا در دانلود فایل.');
$file_content = wp_remote_retrieve_body($response);
// پاسخ باید PDF خام باشد؛ وگرنه بهجای فایل خراب، پیام واضح نمایش بده
if (substr($file_content, 0, 4) !== '%PDF') {
wp_die('پاسخ سرور یک فایل PDF معتبر نبود — لطفاً دوباره تلاش کنید.');
}
$filename = strtoupper($download_type) . '-' . $order['data']['awb_no'] . '.pdf';
// پاکسازی همه بافرهای خروجی تا جریان فایل تمیز و همطول با Content-Length ارسال شود
while (ob_get_level()) { ob_end_clean(); }
nocache_headers();
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Length: ' . strlen($file_content));
echo $file_content;
exit;
}
// ══════════════════════════════════════════════════════════════
// پروکسی دانلود تعهدنامه (قالب خام یا فایل امضاشده) با توکن لاراول
// ══════════════════════════════════════════════════════════════
function ifnex_handle_commitment_download($order_id, $form_id, $type = 'template') {
$user_id = get_current_user_id();
if (!$user_id) wp_die('برای دانلود باید وارد شوید.');
$form_id = intval($form_id);
if (!$form_id) wp_die('شناسه فرم نامعتبر است.');
$bridge = new IFNEX_User_Bridge();
$order = $bridge->get_customer_order($user_id, $order_id);
if (is_wp_error($order)) wp_die('خطا: ' . $order->get_error_message());
$api_url = get_option('ifnex_api_url', 'http://localhost:8000/api/v1');
$endpoint = ($type === 'signed') ? 'download' : 'template';
$download_url = rtrim($api_url, '/') . "/customer/orders/{$order_id}/commitment-forms/{$form_id}/{$endpoint}";
$token = $bridge->get_user_token($user_id); // با تجدید خودکار در صورت انقضا/حذف
if (!$token) wp_die('توکن احراز هویت در دسترس نیست — لطفاً دوباره وارد شوید.');
$response = wp_remote_get($download_url, array(
'headers' => array(
'Authorization' => 'Bearer ' . $token,
'Accept' => '*/*',
),
'timeout' => 60,
));
if (is_wp_error($response)) wp_die('خطا در ارتباط با سرور.');
$status_code = wp_remote_retrieve_response_code($response);
if ($status_code !== 200) {
$body = wp_remote_retrieve_body($response);
$err = json_decode($body, true);
$msg = $err['message'] ?? ('خطا در دانلود فایل (کد: ' . $status_code . ')');
wp_die(esc_html($msg));
}
$file_content = wp_remote_retrieve_body($response);
// پاسخ باید فایل باینری باشد؛ شروع با '<' یعنی HTML/خطا برگشته
if ($file_content === '' || $file_content[0] === '<') {
wp_die('پاسخ سرور یک فایل معتبر نبود — لطفاً دوباره تلاش کنید.');
}
$awb = $order['data']['awb_no'] ?? ('order-' . $order_id);
// تشخیص نوع محتوا و نام فایل از روی هدر Laravel
$ctype = wp_remote_retrieve_header($response, 'content-type');
if (empty($ctype)) $ctype = 'application/octet-stream';
$disp = wp_remote_retrieve_header($response, 'content-disposition');
$filename = ($type === 'signed' ? 'signed-' : 'template-') . $form_id . '-' . $awb;
if ($disp && preg_match('/filename="?([^";]+)"?/i', $disp, $m)) {
$filename = trim($m[1]);
} else {
// fallback بر اساس content-type
$ext = (stripos($ctype, 'pdf') !== false) ? 'pdf'
: ((stripos($ctype, 'png') !== false) ? 'png'
: ((stripos($ctype, 'jpeg') !== false) ? 'jpg' : 'bin'));
$filename .= '.' . $ext;
}
// پاکسازی همه بافرهای خروجی تا جریان فایل تمیز و همطول با Content-Length ارسال شود
while (ob_get_level()) { ob_end_clean(); }
nocache_headers();
header('Content-Type: ' . $ctype);
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Length: ' . strlen($file_content));
echo $file_content;
exit;
}
function ifnex_icon($name, $size = 20) {
$icons = [
'dashboard' => ' ',
'orders' => ' ',
'plus' => ' ',
'wallet' => ' ',
'chart' => ' ',
'tracking' => ' ',
'user' => ' ',
'logout' => ' ',
'truck' => ' ',
'check' => ' ',
'clock' => ' ',
'bell' => ' ',
];
$path = $icons[$name] ?? $icons['dashboard'];
return '' . $path . ' ';
}
// ══════════════════════════════════════════════════════════════
// شورتکد پنل مشتری (Customer Dashboard)
// ══════════════════════════════════════════════════════════════
add_shortcode('ifnex_customer_dashboard', 'ifnex_customer_dashboard_shortcode');
function ifnex_customer_dashboard_shortcode($atts) {
if (!is_user_logged_in()) {
ob_start();
?>
🔐 ورود لازم است
برای دسترسی به پنل کاربری، ابتدا وارد حساب خود شوید.
ورود به حساب
get_customer_profile($user_id);
$wallet_balance = 0; $stats = [];
if (!is_wp_error($profile)) {
$wallet_balance = $profile['wallet']['balance'] ?? 0;
$stats = $profile['stats'] ?? [];
}
// تعداد اعلانهای خواندهنشده برای badge سایدبار
$unread_notifications = 0;
$notif_count_result = $bridge->get_notifications($user_id, 1);
if (!is_wp_error($notif_count_result) && isset($notif_count_result['unread_count'])) {
$unread_notifications = (int) $notif_count_result['unread_count'];
}
$recent_orders = [];
if ($tab === 'dashboard') {
$orders_result = $bridge->get_customer_orders($user_id, 3);
if (!is_wp_error($orders_result)) $recent_orders = $orders_result['data'] ?? [];
}
$base_url = get_permalink();
$menu_items = [
'dashboard' => ['icon' => 'dashboard', 'label' => 'داشبورد'],
'notifications'=> ['icon' => 'bell', 'label' => 'اعلانها'],
'orders' => ['icon' => 'orders', 'label' => 'سفارشات من'],
'new-order' => ['icon' => 'plus', 'label' => 'ثبت سفارش جدید'],
'wallet' => ['icon' => 'wallet', 'label' => 'کیف پول'],
'transactions' => ['icon' => 'chart', 'label' => 'تراکنشها'],
'tracking' => ['icon' => 'tracking', 'label' => 'رهگیری مرسوله'],
'profile' => ['icon' => 'user', 'label' => 'پروفایل'],
];
$tab_titles = [
'dashboard' => 'داشبورد', 'notifications' => 'اعلانها', 'orders' => 'سفارشات من', 'new-order' => 'ثبت سفارش جدید',
'wallet' => 'کیف پول', 'transactions' => 'تراکنشها', 'tracking' => 'رهگیری مرسوله', 'profile' => 'پروفایل',
];
ob_start();
?>
0): ?>
⚠️ بدهی در انتظار پرداخت
ریال
سفارش تأییدشده در انتظار پرداخت
🌍 بدهیهای چندارزی
ارز
مبلغ کل
تسویهشده
مانده بدهی
ℹ️ این بدهیها به ارز اصلی ثبت شدهاند و با نرخ روز تسویه میشوند.
برای تسویه با مدیر تماس بگیرید.
مانده حساب (موجودی منهای بدهیهای ریالی)
ریال
get_notifications($user_id);
$notifications = [];
if (!is_wp_error($notif_result)) {
$notifications = $notif_result['data'] ?? $notif_result ?? [];
if (!isset($notif_result['data']) && isset($notif_result[0])) {
$notifications = $notif_result;
}
}
$unread = 0;
foreach ($notifications as $n) {
if (empty($n['read_at'])) $unread++;
}
?>