From 1e4a8532fa8b3b7f1a53ac5033a92d2bf7145270 Mon Sep 17 00:00:00 2001 From: Kazem Alghasi Date: Sat, 29 Aug 2026 07:33:28 +0330 Subject: [PATCH] - Phase 3.5.1: Multi-Package support in order form - Phase 3.5.2: Invoice items form (PARCEL only) - ShipmentPackage model and migration - Updated CustomerOrderController to accept packages[] and items[] - Auto-calculate volumetric weight from dimensions - 5-step order form with conditional Invoice step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 3.5 — core complete" git push origin main --- .../assets/js/ifnex-order-form.js | 266 +++++++++++++++++- .../ifnex-bridge/includes/shortcodes.php | 48 +++- 2 files changed, 306 insertions(+), 8 deletions(-) diff --git a/03_WordPress/wp-content/plugins/ifnex-bridge/assets/js/ifnex-order-form.js b/03_WordPress/wp-content/plugins/ifnex-bridge/assets/js/ifnex-order-form.js index 347b7ee..774b70f 100644 --- a/03_WordPress/wp-content/plugins/ifnex-bridge/assets/js/ifnex-order-form.js +++ b/03_WordPress/wp-content/plugins/ifnex-bridge/assets/js/ifnex-order-form.js @@ -5,6 +5,8 @@ jQuery(document).ready(function($) { var countries = []; var priceData = null; var packages = []; // آرایه بسته‌ها + var invoiceItems = []; // آرایه اقلام گمرکی + var MAX_ITEMS = 9; // حداکثر تعداد اقلام // ─── Load Countries ─── function loadCountries() { @@ -276,6 +278,225 @@ jQuery(document).ready(function($) { removePackage(pkgId); }); + // ══════════════════════════════════════════════════════════════ + // ─── Invoice Items Management (برای PARCEL) ─── + // ══════════════════════════════════════════════════════════════ + + // افزودن یه قلم جدید + function addInvoiceItem() { + if (invoiceItems.length >= MAX_ITEMS) { + alert('حداکثر ' + MAX_ITEMS + ' قلم می‌توانید اضافه کنید.'); + return; + } + var itemNumber = invoiceItems.length + 1; + var item = { + id: 'item_' + Date.now() + '_' + itemNumber, + number: itemNumber, + description: '', + hsCode: '', + quantity: '', + unitPrice: '' + }; + invoiceItems.push(item); + renderInvoiceItem(item); + updateItemsSummary(); + } + + // حذف یه قلم + function removeInvoiceItem(itemId) { + if (invoiceItems.length <= 1) { + alert('حداقل باید یک قلم وجود داشته باشد.'); + return; + } + invoiceItems = invoiceItems.filter(function(i) { return i.id !== itemId; }); + invoiceItems.forEach(function(item, i) { + item.number = i + 1; + }); + renderAllInvoiceItems(); + updateItemsSummary(); + } + + // رندر یه قلم + function renderInvoiceItem(item) { + var html = '
'; + html += '
'; + html += '📋 قلم #' + item.number + ''; + html += ''; + html += '
'; + html += '
'; + + // توضیحات + html += '
'; + html += ''; + html += ''; + html += '
'; + + // HS Code + html += '
'; + html += ''; + html += ''; + html += '
'; + + // تعداد + html += '
'; + html += ''; + html += ''; + html += '
'; + + // قیمت واحد + html += '
'; + html += ''; + html += ''; + html += '
'; + + // مجموع (محاسبه خودکار) + html += '
'; + html += ''; + html += ''; + html += '
'; + + html += '
'; + html += '
'; + + $('#ifnex-items-container').append(html); + } + + // رندر همه اقلام + function renderAllInvoiceItems() { + $('#ifnex-items-container').empty(); + invoiceItems.forEach(function(item) { + renderInvoiceItem(item); + }); + } + + // محاسبه مجموع یه قلم + function calculateItemTotal(itemId) { + var item = invoiceItems.find(function(i) { return i.id === itemId; }); + if (!item) return 0; + var qty = parseFloat(item.quantity) || 0; + var price = parseFloat(item.unitPrice) || 0; + return qty * price; + } + + // بروزرسانی خلاصه اقلام + function updateItemsSummary() { + var total = 0; + invoiceItems.forEach(function(item) { + total += calculateItemTotal(item.id); + }); + + $('#ifnex-item-count').text(invoiceItems.length); + $('#ifnex-invoice-total').text(total.toFixed(2)); + + if (invoiceItems.length > 0) { + $('#ifnex-items-summary').show(); + } else { + $('#ifnex-items-summary').hide(); + } + } + + // Event: افزودن قلم + $(document).on('click', '#ifnex-add-item', function() { + addInvoiceItem(); + }); + + // Event: تغییر توضیحات + $(document).on('input', '.ifnex-item-description', function() { + var itemId = $(this).data('item-id'); + var item = invoiceItems.find(function(i) { return i.id === itemId; }); + if (item) item.description = $(this).val(); + }); + + // Event: تغییر HS Code + $(document).on('input', '.ifnex-item-hs-code', function() { + var itemId = $(this).data('item-id'); + var item = invoiceItems.find(function(i) { return i.id === itemId; }); + if (item) item.hsCode = $(this).val(); + }); + + // Event: تغییر تعداد (محاسبه مجموع) + $(document).on('input', '.ifnex-item-quantity', function() { + var itemId = $(this).data('item-id'); + var item = invoiceItems.find(function(i) { return i.id === itemId; }); + if (item) { + item.quantity = $(this).val(); + var total = calculateItemTotal(itemId); + $('.ifnex-item-total-display[data-item-id="' + itemId + '"]').val(total.toFixed(2)); + updateItemsSummary(); + } + }); + + // Event: تغییر قیمت واحد (محاسبه مجموع) + $(document).on('input', '.ifnex-item-unit-price', function() { + var itemId = $(this).data('item-id'); + var item = invoiceItems.find(function(i) { return i.id === itemId; }); + if (item) { + item.unitPrice = $(this).val(); + var total = calculateItemTotal(itemId); + $('.ifnex-item-total-display[data-item-id="' + itemId + '"]').val(total.toFixed(2)); + updateItemsSummary(); + } + }); + + // Event: حذف قلم + $(document).on('click', '.ifnex-remove-item', function() { + var itemId = $(this).data('item-id'); + removeInvoiceItem(itemId); + }); + + // ─── بررسی نوع محموله و نمایش/مخفی‌کردن Step Invoice ─── + function updateInvoiceStepVisibility() { + var type = $('#ifnex-type').val(); + if (type === 'PARCEL') { + $('.ifnex-step-invoice').show(); + $('.ifnex-step-invoice-content').show(); + // اگه اقلام خالی هست، یه قلم اولیه اضافه کن + if (invoiceItems.length === 0) { + addInvoiceItem(); + } + } else { + $('.ifnex-step-invoice').hide(); + $('.ifnex-step-invoice-content').hide(); + // اگه کاربر توی Step 3 بود و نوع رو تغییر داد + if (currentStep === 3) { + goToStep(2); + } + } + } + + $('#ifnex-type').on('change', function() { + updateInvoiceStepVisibility(); + }); + + // اعتبارسنجی اقلام گمرکی + function validateStep3() { + if ($('#ifnex-type').val() !== 'PARCEL') { + return true; // اگه PARCEL نیست، این مرحله نیست + } + + if (invoiceItems.length === 0) { + showFormError('حداقل باید یک قلم اضافه کنید.'); + return false; + } + + var allValid = true; + invoiceItems.forEach(function(item) { + if (!item.description || !item.hsCode || !item.quantity || !item.unitPrice) { + allValid = false; + if (!item.description) $('.ifnex-item-description[data-item-id="' + item.id + '"]').css('border-color', '#ef4444'); + if (!item.hsCode) $('.ifnex-item-hs-code[data-item-id="' + item.id + '"]').css('border-color', '#ef4444'); + if (!item.quantity) $('.ifnex-item-quantity[data-item-id="' + item.id + '"]').css('border-color', '#ef4444'); + if (!item.unitPrice) $('.ifnex-item-unit-price[data-item-id="' + item.id + '"]').css('border-color', '#ef4444'); + } + }); + + if (!allValid) { + showFormError('تمامی فیلدهای اقلام گمرکی را تکمیل کنید.'); + return false; + } + return true; + } + // ─── Step Navigation ─── function goToStep(step) { currentStep = step; @@ -293,12 +514,24 @@ jQuery(document).ready(function($) { var next = currentStep + 1; if (currentStep === 1 && !validateStep1()) return; if (currentStep === 2 && !validateStep2()) return; - if (currentStep === 3) { calculatePrice(); return; } + if (currentStep === 3 && !validateStep3()) return; + if (currentStep === 4) { calculatePrice(); return; } + // اگه PARCEL نیست، از Step 2 مستقیم به Step 4 بپر + if (currentStep === 2 && $('#ifnex-type').val() !== 'PARCEL') { + goToStep(4); + return; + } goToStep(next); }); $('.ifnex-prev-step').on('click', function() { - goToStep(currentStep - 1); + var prev = currentStep - 1; + // اگه PARCEL نیست، از Step 4 مستقیم به Step 2 برگرد + if (currentStep === 4 && $('#ifnex-type').val() !== 'PARCEL') { + goToStep(2); + return; + } + goToStep(prev); }); function validateStep1() { @@ -402,6 +635,19 @@ jQuery(document).ready(function($) { }; }); + // ساخت آرایه اقلام گمرکی برای ارسال به API (فقط اگه PARCEL هست) + var itemsArray = []; + if ($('#ifnex-type').val() === 'PARCEL') { + itemsArray = invoiceItems.map(function(item) { + return { + description: item.description || '', + hs_code: item.hsCode || '', + quantity: parseInt(item.quantity) || 0, + unit_price: parseFloat(item.unitPrice) || 0 + }; + }); + } + return { direction: $('#ifnex-direction').val(), type: $('#ifnex-type').val(), @@ -414,6 +660,7 @@ jQuery(document).ready(function($) { volumetric_weight: totalVolumetric, chargeable_weight: chargeableWeight, packages: packagesArray, + items: itemsArray, discount_code: $('#ifnex-discount-code').val() || '', sender_name: $('#ifnex-sender-name').val(), sender_phone: $('#ifnex-sender-phone').val(), @@ -432,6 +679,18 @@ jQuery(document).ready(function($) { html += '
مجموع وزن واقعی:' + numberFormat(data.weight || 0) + ' kg
'; html += '
مجموع وزن حجمی:' + numberFormat(data.volumetric_weight || 0) + ' kg
'; html += '
وزن قابل محاسبه:' + numberFormat(data.chargeable_weight || 0) + ' kg
'; + + // نمایش اقلام گمرکی (اگه PARCEL هست) + if ($('#ifnex-type').val() === 'PARCEL' && invoiceItems.length > 0) { + html += '
'; + html += '
📋 تعداد اقلام:' + invoiceItems.length + '
'; + var invoiceTotal = 0; + invoiceItems.forEach(function(item) { + invoiceTotal += calculateItemTotal(item.id); + }); + html += '
💰 مجموع فاکتور:$' + numberFormat(invoiceTotal) + ' USD
'; + } + html += '
'; html += '
قیمت پایه:' + (data.base_price || '0') + ' درهم
'; html += '
ناخالص:' + (data.net_dirham || '0') + ' درهم
'; @@ -489,5 +748,8 @@ jQuery(document).ready(function($) { loadCountries(); // افزودن بسته اول به‌صورت پیش‌فرض addPackage(); + // بررسی نوع محموله برای نمایش/مخفی‌کردن Step Invoice + // این تابع خودش اگه PARCEL باشه و اقلام خالی باشه، یه قلم اضافه می‌کنه + updateInvoiceStepVisibility(); } }); 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 21e7915..bb1239b 100644 --- a/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php +++ b/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php @@ -497,8 +497,9 @@ function ifnex_order_form_shortcode($atts) {
۱
مسیر و بسته
۲
اطلاعات تماس
-
۳
بررسی قیمت
-
۴
تأیید نهایی
+ +
۴
بررسی قیمت
+
۵
تأیید نهایی
@@ -593,8 +594,43 @@ function ifnex_order_form_shortcode($atts) { - -
+ + + + +

🏷️ کد تخفیف (اختیاری)

@@ -611,8 +647,8 @@ function ifnex_order_form_shortcode($atts) {
- -
+ +

✅ تأیید نهایی سفارش