feat(core): enhance order processing and bridge integration
Refactor the order and shipment lifecycle across WordPress and Laravel,
improving multi-package handling, payment automation, and frontend
reliability.
- Laravel:
- Rename `package_number` to `package_no` and `description` to
`content_description` in `ShipmentPackage` model and controller.
- Update `PaymentController` to automatically transition approved
shipments to `Processed` status upon successful payment.
- Adjust `OrderPaymentService` to validate against `Approved` status
instead of `PendingPayment`.
- Expose `/countries` endpoint as a public route (unauthenticated).
- Remove obsolete `read_excel.php` utility.
- WordPress (Bridge Plugin & Theme):
- Implement AJAX handler for wallet-based order payments.
- Update `ifnex-order-form.js` to support multi-package input names
and auto-select Iran based on shipment direction.
- Improve error handling and feedback in the order form and country
loading logic.
- Add automatic tracking submission when an `awb` parameter is
present in the URL.
- Update CSS with `!important` flags to ensure correct visibility
of form steps and dashboard elements.
- Implement cache-busting for plugin assets and prevent OPcache
stale files via header controls.
- Optimize theme logo loading with eager loading and explicit
dimensions.
This commit is contained in:
parent
eda3110ac1
commit
b25bfda597
@ -153,8 +153,8 @@
|
|||||||
}
|
}
|
||||||
.ifnex-step.active { color: var(--ifnex-primary-dark); font-weight: 700; }
|
.ifnex-step.active { color: var(--ifnex-primary-dark); font-weight: 700; }
|
||||||
|
|
||||||
.ifnex-form-step { display: none; }
|
.ifnex-form-step { display: none !important; }
|
||||||
.ifnex-form-step.active { display: block; animation: ifnexFadeIn 0.3s; }
|
.ifnex-form-step.active { display: block !important; }
|
||||||
@keyframes ifnexFadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; } }
|
@keyframes ifnexFadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; } }
|
||||||
|
|
||||||
.ifnex-form-card {
|
.ifnex-form-card {
|
||||||
@ -374,14 +374,14 @@
|
|||||||
|
|
||||||
/* ═══ Modern Customer Dashboard (ifnx) ═══ */
|
/* ═══ Modern Customer Dashboard (ifnx) ═══ */
|
||||||
.ifnx-dashboard {
|
.ifnx-dashboard {
|
||||||
display: flex; gap: 24px; max-width: 1240px; margin: 0 auto; padding: 24px 0;
|
display: flex !important; gap: 24px; max-width: 1240px; margin: 0 auto; padding: 24px 0;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Sidebar ─ */
|
/* ── Sidebar ─ */
|
||||||
.ifnx-sidebar {
|
.ifnx-sidebar {
|
||||||
width: 260px; flex-shrink: 0; align-self: flex-start;
|
width: 260px !important; flex-shrink: 0 !important; align-self: flex-start !important;
|
||||||
background: linear-gradient(180deg, #0f172a 0%, #1e293b 100%);
|
background: linear-gradient(180deg, #0f172a 0%, #1e293b 100%) !important;
|
||||||
border-radius: 20px; overflow: hidden;
|
border-radius: 20px; overflow: hidden;
|
||||||
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.25);
|
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.25);
|
||||||
}
|
}
|
||||||
@ -395,7 +395,7 @@
|
|||||||
.ifnx-user-name { color: #fff; font-weight: 700; font-size: 16px; }
|
.ifnx-user-name { color: #fff; font-weight: 700; font-size: 16px; }
|
||||||
.ifnx-user-email { color: rgba(255,255,255,0.55); font-size: 12px; margin-top: 4px; direction: ltr; }
|
.ifnx-user-email { color: rgba(255,255,255,0.55); font-size: 12px; margin-top: 4px; direction: ltr; }
|
||||||
|
|
||||||
.ifnx-menu { padding: 12px 0; display: flex; flex-direction: column; }
|
.ifnx-menu { padding: 12px 0; display: flex !important; flex-direction: column !important; }
|
||||||
.ifnx-menu-item {
|
.ifnx-menu-item {
|
||||||
display: flex; align-items: center; gap: 12px;
|
display: flex; align-items: center; gap: 12px;
|
||||||
padding: 13px 22px; color: rgba(255,255,255,0.72);
|
padding: 13px 22px; color: rgba(255,255,255,0.72);
|
||||||
|
|||||||
@ -10,20 +10,38 @@ jQuery(document).ready(function($) {
|
|||||||
|
|
||||||
// ─── Load Countries ───
|
// ─── Load Countries ───
|
||||||
function loadCountries() {
|
function loadCountries() {
|
||||||
|
if (!ifnex_ajax || !ifnex_ajax.ajax_url) {
|
||||||
|
console.error('IFNEX: ifnex_ajax is not defined');
|
||||||
|
showFormError('خطا در تنظیمات پلاگین. لطفاً صفحه را دوباره بارگذاری کنید.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: ifnex_ajax.ajax_url,
|
url: ifnex_ajax.ajax_url,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: { action: 'ifnex_get_countries', nonce: ifnex_ajax.nonce },
|
data: { action: 'ifnex_get_countries', nonce: ifnex_ajax.nonce },
|
||||||
success: function(res) {
|
success: function(res) {
|
||||||
if (res.success) {
|
if (res.success && res.data && res.data.length > 0) {
|
||||||
countries = res.data;
|
countries = res.data;
|
||||||
populateCountrySelects();
|
populateCountrySelects();
|
||||||
|
// Auto-select Iran based on default direction
|
||||||
|
var iran = countries.find(function(c) { return c.iso_code === 'IR'; });
|
||||||
|
if (iran) {
|
||||||
|
var dir = $('#ifnex-direction').val();
|
||||||
|
if (dir === 'export') {
|
||||||
|
$('#ifnex-from-country').val(iran.id).trigger('change');
|
||||||
|
} else if (dir === 'import') {
|
||||||
|
$('#ifnex-to-country').val(iran.id).trigger('change');
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error('IFNEX: Failed to load countries', res);
|
console.error('IFNEX: Failed to load countries', res);
|
||||||
|
showFormError('خطا در دریافت لیست کشورها. لطفاً صفحه را دوباره بارگذاری کنید.');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function(xhr) {
|
error: function(xhr) {
|
||||||
console.error('IFNEX: AJAX error loading countries', xhr.status);
|
console.error('IFNEX: AJAX error loading countries', xhr.status);
|
||||||
|
showFormError('خطا در ارتباط با سرور. لطفاً اینترنت خود را بررسی کنید.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -166,26 +184,26 @@ jQuery(document).ready(function($) {
|
|||||||
|
|
||||||
// وزن واقعی
|
// وزن واقعی
|
||||||
html += '<div class="ifnex-field">';
|
html += '<div class="ifnex-field">';
|
||||||
html += '<label>وزن واقعی (kg) *</label>';
|
html += '<label for="ifnex-pkg-weight-' + pkg.id + '">وزن واقعی (kg) *</label>';
|
||||||
html += '<input type="number" class="ifnex-pkg-weight" step="0.1" min="0.1" data-pkg-id="' + pkg.id + '" placeholder="مثلاً 2.5" value="' + (pkg.weight || '') + '" required>';
|
html += '<input type="number" id="ifnex-pkg-weight-' + pkg.id + '" class="ifnex-pkg-weight" name="packages[' + pkg.number + '][weight]" step="0.1" min="0.1" data-pkg-id="' + pkg.id + '" placeholder="مثلاً 2.5" value="' + (pkg.weight || '') + '" required>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
// ابعاد
|
// ابعاد
|
||||||
html += '<div class="ifnex-field">';
|
html += '<div class="ifnex-field">';
|
||||||
html += '<label>ابعاد (طول×عرض×ارتفاع cm) *</label>';
|
html += '<label for="ifnex-pkg-dimensions-' + pkg.id + '">ابعاد (طول×عرض×ارتفاع cm) *</label>';
|
||||||
html += '<input type="text" class="ifnex-pkg-dimensions" data-pkg-id="' + pkg.id + '" placeholder="مثلاً 5*6*9" value="' + (pkg.dimensions || '') + '" style="direction: ltr;" required>';
|
html += '<input type="text" id="ifnex-pkg-dimensions-' + pkg.id + '" class="ifnex-pkg-dimensions" name="packages[' + pkg.number + '][dimensions]" data-pkg-id="' + pkg.id + '" placeholder="مثلاً 5*6*9" value="' + (pkg.dimensions || '') + '" style="direction: ltr;" required>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
// وزن حجمی (محاسبه خودکار - فقط نمایش)
|
// وزن حجمی (محاسبه خودکار - فقط نمایش)
|
||||||
html += '<div class="ifnex-field">';
|
html += '<div class="ifnex-field">';
|
||||||
html += '<label>وزن حجمی (kg)</label>';
|
html += '<label for="ifnex-pkg-volumetric-' + pkg.id + '">وزن حجمی (kg)</label>';
|
||||||
html += '<input type="text" class="ifnex-pkg-volumetric-display" data-pkg-id="' + pkg.id + '" value="0" readonly style="background: #f0f9ff; color: #0369a1; font-weight: bold;">';
|
html += '<input type="text" id="ifnex-pkg-volumetric-' + pkg.id + '" class="ifnex-pkg-volumetric-display" name="packages[' + pkg.number + '][volumetric_weight]" data-pkg-id="' + pkg.id + '" value="0" readonly style="background: #f0f9ff; color: #0369a1; font-weight: bold;">';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
// توضیحات
|
// توضیحات
|
||||||
html += '<div class="ifnex-field full">';
|
html += '<div class="ifnex-field full">';
|
||||||
html += '<label>توضیحات بسته (اختیاری)</label>';
|
html += '<label for="ifnex-pkg-desc-' + pkg.id + '">توضیحات بسته (اختیاری)</label>';
|
||||||
html += '<input type="text" class="ifnex-pkg-description" data-pkg-id="' + pkg.id + '" placeholder="مثلاً کتاب، لباس، اسباببازی..." value="' + (pkg.description || '') + '">';
|
html += '<input type="text" id="ifnex-pkg-desc-' + pkg.id + '" class="ifnex-pkg-description" name="packages[' + pkg.number + '][description]" data-pkg-id="' + pkg.id + '" placeholder="مثلاً کتاب، لباس، اسباببازی..." value="' + (pkg.description || '') + '">';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
@ -327,32 +345,32 @@ jQuery(document).ready(function($) {
|
|||||||
|
|
||||||
// توضیحات
|
// توضیحات
|
||||||
html += '<div class="ifnex-field full">';
|
html += '<div class="ifnex-field full">';
|
||||||
html += '<label>شرح کالا *</label>';
|
html += '<label for="ifnex-item-desc-' + item.id + '">شرح کالا *</label>';
|
||||||
html += '<input type="text" class="ifnex-item-description" data-item-id="' + item.id + '" placeholder="مثلاً Electronics PCB Board" value="' + (item.description || '') + '" required style="direction: ltr;">';
|
html += '<input type="text" id="ifnex-item-desc-' + item.id + '" class="ifnex-item-description" name="items[' + item.number + '][description]" data-item-id="' + item.id + '" placeholder="مثلاً Electronics PCB Board" value="' + (item.description || '') + '" required style="direction: ltr;">';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
// HS Code
|
// HS Code
|
||||||
html += '<div class="ifnex-field">';
|
html += '<div class="ifnex-field">';
|
||||||
html += '<label>کد گمرکی (HS Code) *</label>';
|
html += '<label for="ifnex-item-hs-' + item.id + '">کد گمرکی (HS Code) *</label>';
|
||||||
html += '<input type="text" class="ifnex-item-hs-code" data-item-id="' + item.id + '" placeholder="مثلاً 8542390001" value="' + (item.hsCode || '') + '" required style="direction: ltr;">';
|
html += '<input type="text" id="ifnex-item-hs-' + item.id + '" class="ifnex-item-hs-code" name="items[' + item.number + '][hs_code]" data-item-id="' + item.id + '" placeholder="مثلاً 8542390001" value="' + (item.hsCode || '') + '" required style="direction: ltr;">';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
// تعداد
|
// تعداد
|
||||||
html += '<div class="ifnex-field">';
|
html += '<div class="ifnex-field">';
|
||||||
html += '<label>تعداد *</label>';
|
html += '<label for="ifnex-item-qty-' + item.id + '">تعداد *</label>';
|
||||||
html += '<input type="number" class="ifnex-item-quantity" data-item-id="' + item.id + '" min="1" step="1" placeholder="مثلاً 100" value="' + (item.quantity || '') + '" required>';
|
html += '<input type="number" id="ifnex-item-qty-' + item.id + '" class="ifnex-item-quantity" name="items[' + item.number + '][quantity]" min="1" step="1" data-item-id="' + item.id + '" placeholder="مثلاً 100" value="' + (item.quantity || '') + '" required>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
// قیمت واحد
|
// قیمت واحد
|
||||||
html += '<div class="ifnex-field">';
|
html += '<div class="ifnex-field">';
|
||||||
html += '<label>قیمت واحد (USD) *</label>';
|
html += '<label for="ifnex-item-price-' + item.id + '">قیمت واحد (USD) *</label>';
|
||||||
html += '<input type="number" class="ifnex-item-unit-price" data-item-id="' + item.id + '" min="0" step="0.01" placeholder="مثلاً 1.10" value="' + (item.unitPrice || '') + '" required style="direction: ltr;">';
|
html += '<input type="number" id="ifnex-item-price-' + item.id + '" class="ifnex-item-unit-price" name="items[' + item.number + '][unit_price]" min="0" step="0.01" data-item-id="' + item.id + '" placeholder="مثلاً 1.10" value="' + (item.unitPrice || '') + '" required style="direction: ltr;">';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
// مجموع (محاسبه خودکار)
|
// مجموع (محاسبه خودکار)
|
||||||
html += '<div class="ifnex-field">';
|
html += '<div class="ifnex-field">';
|
||||||
html += '<label>مجموع (USD)</label>';
|
html += '<label>مجموع (USD)</label>';
|
||||||
html += '<input type="text" class="ifnex-item-total-display" data-item-id="' + item.id + '" value="0.00" readonly style="background: #f0f9ff; color: #0369a1; font-weight: bold;">';
|
html += '<input type="text" id="ifnex-item-total-' + item.id + '" class="ifnex-item-total-display" name="items[' + item.number + '][total]" data-item-id="' + item.id + '" value="0.00" readonly style="background: #f0f9ff; color: #0369a1; font-weight: bold;">';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
@ -448,15 +466,15 @@ jQuery(document).ready(function($) {
|
|||||||
function updateInvoiceStepVisibility() {
|
function updateInvoiceStepVisibility() {
|
||||||
var type = $('#ifnex-type').val();
|
var type = $('#ifnex-type').val();
|
||||||
if (type === 'PARCEL') {
|
if (type === 'PARCEL') {
|
||||||
$('.ifnex-step-invoice').show();
|
$('.ifnex-step-invoice').css('display', '');
|
||||||
$('.ifnex-step-invoice-content').show();
|
$('.ifnex-step-invoice-content').each(function() { this.style.setProperty('display', '', 'important'); });
|
||||||
// اگه اقلام خالی هست، یه قلم اولیه اضافه کن
|
// اگه اقلام خالی هست، یه قلم اولیه اضافه کن
|
||||||
if (invoiceItems.length === 0) {
|
if (invoiceItems.length === 0) {
|
||||||
addInvoiceItem();
|
addInvoiceItem();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$('.ifnex-step-invoice').hide();
|
$('.ifnex-step-invoice').css('display', 'none');
|
||||||
$('.ifnex-step-invoice-content').hide();
|
$('.ifnex-step-invoice-content').each(function() { this.style.setProperty('display', 'none', 'important'); });
|
||||||
// اگه کاربر توی Step 3 بود و نوع رو تغییر داد
|
// اگه کاربر توی Step 3 بود و نوع رو تغییر داد
|
||||||
if (currentStep === 3) {
|
if (currentStep === 3) {
|
||||||
goToStep(2);
|
goToStep(2);
|
||||||
@ -498,16 +516,24 @@ jQuery(document).ready(function($) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ─── Step Navigation ───
|
// ─── Step Navigation ───
|
||||||
|
// مراحل فرم خواهر هستند و فقط با کلاس active نمایش داده میشوند (CSS داخل ifnex-orders.css)
|
||||||
function goToStep(step) {
|
function goToStep(step) {
|
||||||
currentStep = step;
|
currentStep = step;
|
||||||
$('.ifnex-form-step').removeClass('active');
|
var $steps = $('#ifnex-order-form .ifnex-form-step');
|
||||||
$('.ifnex-form-step[data-step="' + step + '"]').addClass('active');
|
$steps.removeClass('active');
|
||||||
$('.ifnex-step').each(function() {
|
$steps.filter('[data-step="' + step + '"]').addClass('active');
|
||||||
var s = parseInt($(this).data('step'));
|
|
||||||
$(this).toggleClass('active', s === step);
|
// بهروزرسانی نشانگرهای پیشرفت بالای فرم
|
||||||
$(this).toggleClass('done', s < step);
|
$('.ifnex-steps .ifnex-step').each(function() {
|
||||||
|
var s = parseInt($(this).attr('data-step'), 10);
|
||||||
|
$(this).removeClass('active done');
|
||||||
|
if (s === step) $(this).addClass('active');
|
||||||
|
else if (s < step) $(this).addClass('done');
|
||||||
});
|
});
|
||||||
$('.ifnex-order-form-container')[0].scrollIntoView({ behavior: 'smooth' });
|
|
||||||
|
try {
|
||||||
|
document.querySelector('.ifnex-order-form-container').scrollIntoView({ behavior: 'smooth' });
|
||||||
|
} catch(e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.ifnex-next-step').on('click', function() {
|
$('.ifnex-next-step').on('click', function() {
|
||||||
@ -574,12 +600,15 @@ jQuery(document).ready(function($) {
|
|||||||
|
|
||||||
function validateStep2() {
|
function validateStep2() {
|
||||||
var ok = true;
|
var ok = true;
|
||||||
|
var persianRegex = /[\u0600-\u06FF]/;
|
||||||
['#ifnex-sender-name', '#ifnex-sender-phone', '#ifnex-sender-city', '#ifnex-sender-address',
|
['#ifnex-sender-name', '#ifnex-sender-phone', '#ifnex-sender-city', '#ifnex-sender-address',
|
||||||
'#ifnex-receiver-name', '#ifnex-receiver-phone', '#ifnex-receiver-city', '#ifnex-receiver-address'].forEach(function(sel) {
|
'#ifnex-receiver-name', '#ifnex-receiver-phone', '#ifnex-receiver-city', '#ifnex-receiver-address'].forEach(function(sel) {
|
||||||
if (!$(sel).val()) { $(sel).css('border-color', '#ef4444'); ok = false; }
|
var val = $(sel).val();
|
||||||
|
if (!val) { $(sel).css('border-color', '#ef4444'); ok = false; }
|
||||||
|
else if (persianRegex.test(val)) { $(sel).css('border-color', '#ef4444'); ok = false; }
|
||||||
else { $(sel).css('border-color', ''); }
|
else { $(sel).css('border-color', ''); }
|
||||||
});
|
});
|
||||||
if (!ok) showFormError('لطفاً اطلاعات فرستنده و گیرنده را کامل کنید.');
|
if (!ok) showFormError('لطفاً اطلاعات را به انگلیسی وارد کنید. آدرس و مشخصات باید به انگلیسی باشد.');
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -599,7 +628,7 @@ jQuery(document).ready(function($) {
|
|||||||
if (res.success) {
|
if (res.success) {
|
||||||
priceData = res.data;
|
priceData = res.data;
|
||||||
renderPriceSummary(res.data);
|
renderPriceSummary(res.data);
|
||||||
goToStep(4);
|
goToStep(5);
|
||||||
} else {
|
} else {
|
||||||
showCalcError(res.data || 'خطا در محاسبه قیمت');
|
showCalcError(res.data || 'خطا در محاسبه قیمت');
|
||||||
}
|
}
|
||||||
@ -733,7 +762,7 @@ jQuery(document).ready(function($) {
|
|||||||
var orderId = res.data.data.id || res.data.id;
|
var orderId = res.data.data.id || res.data.id;
|
||||||
// با فلوی جدید، کاربر به صفحه جزئیات سفارش هدایت میشود
|
// با فلوی جدید، کاربر به صفحه جزئیات سفارش هدایت میشود
|
||||||
// (چون پرداخت فقط بعد از تأیید کارمند امکانپذیر است)
|
// (چون پرداخت فقط بعد از تأیید کارمند امکانپذیر است)
|
||||||
window.location.href = ifnex_ajax.orders_url + 'order-detail/?order_id=' + orderId;
|
window.location.href = ifnex_ajax.orders_url + '?tab=orders';
|
||||||
} else {
|
} else {
|
||||||
$('#ifnex-submit-error').text(res.data || 'خطا در ثبت سفارش').show();
|
$('#ifnex-submit-error').text(res.data || 'خطا در ثبت سفارش').show();
|
||||||
}
|
}
|
||||||
@ -745,13 +774,26 @@ jQuery(document).ready(function($) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Auto-select Iran based on direction ───
|
||||||
|
$('#ifnex-direction').on('change', function() {
|
||||||
|
var direction = $(this).val();
|
||||||
|
if (!countries.length) return;
|
||||||
|
var iran = countries.find(function(c) { return c.iso_code === 'IR'; });
|
||||||
|
if (!iran) return;
|
||||||
|
if (direction === 'export') {
|
||||||
|
$('#ifnex-from-country').val(iran.id).trigger('change');
|
||||||
|
} else if (direction === 'import') {
|
||||||
|
$('#ifnex-to-country').val(iran.id).trigger('change');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// ─── Init ───
|
// ─── Init ───
|
||||||
if ($('#ifnex-order-form').length) {
|
if ($('#ifnex-order-form').length) {
|
||||||
loadCountries();
|
// افزودن بسته اول بهصورت پیشفرض (قبل از loadCountries تا اگه خطا داد، بسته باشه)
|
||||||
// افزودن بسته اول بهصورت پیشفرض
|
|
||||||
addPackage();
|
addPackage();
|
||||||
// بررسی نوع محموله برای نمایش/مخفیکردن Step Invoice
|
// بررسی نوع محموله برای نمایش/مخفیکردن Step Invoice
|
||||||
// این تابع خودش اگه PARCEL باشه و اقلام خالی باشه، یه قلم اضافه میکنه
|
|
||||||
updateInvoiceStepVisibility();
|
updateInvoiceStepVisibility();
|
||||||
|
// لود کشورها (اگه خطا داد اشکالی نداره)
|
||||||
|
try { loadCountries(); } catch(e) { console.error('IFNEX: loadCountries error', e); }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
if (function_exists('opcache_reset')) { @opcache_reset(); }
|
||||||
|
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
||||||
|
header('Pragma: no-cache');
|
||||||
/**
|
/**
|
||||||
* Plugin Name: IFNEX Logistics Bridge
|
* Plugin Name: IFNEX Logistics Bridge
|
||||||
* Description: اتصال فرانتاند سایت ایفنکس به API لاراول
|
* Description: اتصال فرانتاند سایت ایفنکس به API لاراول
|
||||||
@ -16,7 +19,7 @@ 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/shortcodes.php';
|
||||||
require_once plugin_dir_path( __FILE__ ) . 'includes/tracking-form.php';
|
require_once plugin_dir_path( __FILE__ ) . 'includes/tracking-form.php';
|
||||||
|
|
||||||
// لود کردن استایلهای پلاگین
|
// لود کردن استایلهای و اسکریپتهای پلاگین
|
||||||
add_action('wp_enqueue_scripts', 'ifnex_enqueue_scripts');
|
add_action('wp_enqueue_scripts', 'ifnex_enqueue_scripts');
|
||||||
function ifnex_enqueue_scripts() {
|
function ifnex_enqueue_scripts() {
|
||||||
global $post;
|
global $post;
|
||||||
@ -24,8 +27,15 @@ function ifnex_enqueue_scripts() {
|
|||||||
(has_shortcode($post->post_content, 'ifnex_tracking_form') ||
|
(has_shortcode($post->post_content, 'ifnex_tracking_form') ||
|
||||||
has_shortcode($post->post_content, 'ifnex_wallet_balance') ||
|
has_shortcode($post->post_content, 'ifnex_wallet_balance') ||
|
||||||
has_shortcode($post->post_content, 'ifnex_transactions') ||
|
has_shortcode($post->post_content, 'ifnex_transactions') ||
|
||||||
has_shortcode($post->post_content, 'ifnex_tracking_status'))) {
|
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');
|
has_shortcode($post->post_content, 'ifnex_order_form') ||
|
||||||
|
has_shortcode($post->post_content, 'ifnex_user_profile') ||
|
||||||
|
has_shortcode($post->post_content, 'ifnex_orders_list') ||
|
||||||
|
has_shortcode($post->post_content, 'ifnex_order_detail') ||
|
||||||
|
has_shortcode($post->post_content, 'ifnex_order_payment') ||
|
||||||
|
has_shortcode($post->post_content, 'ifnex_customer_dashboard'))) {
|
||||||
|
wp_enqueue_style('ifnex-bridge-css', plugin_dir_url(__FILE__) . 'assets/css/ifnex-bridge.css', array('ifnex-main'), '2.0.0-' . time());
|
||||||
|
wp_enqueue_script('ifnex-order-form-js', plugin_dir_url(__FILE__) . 'assets/js/ifnex-order-form.js', array('jquery'), '2.0.0-' . time(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
if (function_exists('opcache_reset')) { @opcache_reset(); }
|
||||||
|
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
||||||
|
header('Pragma: no-cache');
|
||||||
/**
|
/**
|
||||||
* IFNEX API Client
|
* IFNEX API Client
|
||||||
* اتصال به API لاراول برای استعلام ترکینگ
|
* اتصال به API لاراول برای استعلام ترکینگ
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
if (function_exists('opcache_reset')) { @opcache_reset(); }
|
||||||
|
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
||||||
|
header('Pragma: no-cache');
|
||||||
/**
|
/**
|
||||||
* IFNEX Shortcodes
|
* IFNEX Shortcodes
|
||||||
* شورتکدهای پلاگین IFNEX Bridge
|
* شورتکدهای پلاگین IFNEX Bridge
|
||||||
@ -18,13 +21,16 @@ function ifnex_tracking_form_shortcode($atts) {
|
|||||||
'button_text' => 'رهگیری',
|
'button_text' => 'رهگیری',
|
||||||
), $atts);
|
), $atts);
|
||||||
|
|
||||||
|
// خواندن پارامتر awb از URL
|
||||||
|
$awb_from_url = isset($_GET['awb']) ? sanitize_text_field($_GET['awb']) : '';
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
||||||
?>
|
?>
|
||||||
<div class="ifnex-tracking-container">
|
<div class="ifnex-tracking-container">
|
||||||
<h2><?php echo esc_html($atts['title']); ?></h2>
|
<h2><?php echo esc_html($atts['title']); ?></h2>
|
||||||
<form id="ifnex-tracking-form" class="ifnex-tracking-form">
|
<form id="ifnex-tracking-form" class="ifnex-tracking-form">
|
||||||
<div class="ifnex-form-group">
|
<div class="ifnex-form-group">
|
||||||
<input type="text" id="ifnex-awb-input" placeholder="<?php echo esc_attr($atts['placeholder']); ?>" required>
|
<input type="text" id="ifnex-awb-input" placeholder="<?php echo esc_attr($atts['placeholder']); ?>" value="<?php echo esc_attr($awb_from_url); ?>" required>
|
||||||
<button type="submit" id="ifnex-track-btn"><?php echo esc_html($atts['button_text']); ?></button>
|
<button type="submit" id="ifnex-track-btn"><?php echo esc_html($atts['button_text']); ?></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -537,28 +543,29 @@ function ifnex_order_form_shortcode($atts) {
|
|||||||
<h3>📦 مشخصات مرسوله</h3>
|
<h3>📦 مشخصات مرسوله</h3>
|
||||||
<div class="ifnex-form-grid">
|
<div class="ifnex-form-grid">
|
||||||
<div class="ifnex-field">
|
<div class="ifnex-field">
|
||||||
<label>جهت ارسال *</label>
|
<label for="ifnex-direction">جهت ارسال *</label>
|
||||||
<select id="ifnex-direction">
|
<select id="ifnex-direction" name="ifnex_direction">
|
||||||
<option value="export">صادرات (از ایران به خارج)</option>
|
<option value="export">صادرات (از ایران به خارج)</option>
|
||||||
<option value="import">واردات (از خارج به ایران)</option>
|
<option value="import">واردات (از خارج به ایران)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="ifnex-field">
|
<div class="ifnex-field">
|
||||||
<label>نوع سرویس *</label>
|
<label for="ifnex-type">نوع سرویس *</label>
|
||||||
<select id="ifnex-type">
|
<select id="ifnex-type" name="ifnex_type">
|
||||||
<option value="PARCEL">بسته (Parcel)</option>
|
<option value="PARCEL">بسته (Parcel)</option>
|
||||||
<option value="DOC_NORMAL">مدارک عادی</option>
|
<option value="DOC_NORMAL">مدارک عادی</option>
|
||||||
<option value="DOC_ECONOMY">مدارک اقتصادی</option>
|
<option value="DOC_ECONOMY">مدارک اقتصادی</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="ifnex-field">
|
<div class="ifnex-field">
|
||||||
<label>کشور مبدأ *</label>
|
<label for="ifnex-from-country">کشور مبدأ *</label>
|
||||||
<select id="ifnex-from-country"></select>
|
<select id="ifnex-from-country" name="ifnex_from_country"></select>
|
||||||
</div>
|
</div>
|
||||||
<div class="ifnex-field">
|
<div class="ifnex-field">
|
||||||
<label>کشور مقصد *</label>
|
<label for="ifnex-to-country">کشور مقصد *</label>
|
||||||
<select id="ifnex-to-country"></select>
|
<select id="ifnex-to-country" name="ifnex_to_country"></select>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<!-- ─── بخش بستهها (Multi-Package) ─── -->
|
<!-- ─── بخش بستهها (Multi-Package) ─── -->
|
||||||
<h3 style="margin-top: 24px;">📦 بستههای مرسوله</h3>
|
<h3 style="margin-top: 24px;">📦 بستههای مرسوله</h3>
|
||||||
<p style="font-size: 12px; color: #666; margin-bottom: 12px;">
|
<p style="font-size: 12px; color: #666; margin-bottom: 12px;">
|
||||||
@ -602,17 +609,17 @@ function ifnex_order_form_shortcode($atts) {
|
|||||||
<div class="ifnex-form-card">
|
<div class="ifnex-form-card">
|
||||||
<h3>👤 اطلاعات فرستنده</h3>
|
<h3>👤 اطلاعات فرستنده</h3>
|
||||||
<div class="ifnex-form-grid">
|
<div class="ifnex-form-grid">
|
||||||
<div class="ifnex-field"><label>نام و نام خانوادگی *</label><input type="text" id="ifnex-sender-name"></div>
|
<div class="ifnex-field"><label for="ifnex-sender-name">نام و نام خانوادگی *</label><input type="text" id="ifnex-sender-name" name="ifnex_sender_name"></div>
|
||||||
<div class="ifnex-field"><label>شماره تماس *</label><input type="tel" id="ifnex-sender-phone"></div>
|
<div class="ifnex-field"><label for="ifnex-sender-phone">شماره تماس *</label><input type="tel" id="ifnex-sender-phone" name="ifnex_sender_phone"></div>
|
||||||
<div class="ifnex-field"><label>شهر</label><input type="text" id="ifnex-sender-city"></div>
|
<div class="ifnex-field"><label for="ifnex-sender-city">شهر</label><input type="text" id="ifnex-sender-city" name="ifnex_sender_city"></div>
|
||||||
<div class="ifnex-field full"><label>آدرس کامل *</label><textarea id="ifnex-sender-address" rows="2"></textarea></div>
|
<div class="ifnex-field full"><label for="ifnex-sender-address">آدرس کامل *</label><textarea id="ifnex-sender-address" name="ifnex_sender_address" rows="2"></textarea></div>
|
||||||
</div>
|
</div>
|
||||||
<h3 style="margin-top:24px;">📮 اطلاعات گیرنده</h3>
|
<h3 style="margin-top:24px;">📮 اطلاعات گیرنده</h3>
|
||||||
<div class="ifnex-form-grid">
|
<div class="ifnex-form-grid">
|
||||||
<div class="ifnex-field"><label>نام و نام خانوادگی *</label><input type="text" id="ifnex-receiver-name"></div>
|
<div class="ifnex-field"><label for="ifnex-receiver-name">نام و نام خانوادگی *</label><input type="text" id="ifnex-receiver-name" name="ifnex_receiver_name"></div>
|
||||||
<div class="ifnex-field"><label>شماره تماس *</label><input type="tel" id="ifnex-receiver-phone"></div>
|
<div class="ifnex-field"><label for="ifnex-receiver-phone">شماره تماس *</label><input type="tel" id="ifnex-receiver-phone" name="ifnex_receiver_phone"></div>
|
||||||
<div class="ifnex-field"><label>شهر</label><input type="text" id="ifnex-receiver-city"></div>
|
<div class="ifnex-field"><label for="ifnex-receiver-city">شهر</label><input type="text" id="ifnex-receiver-city" name="ifnex_receiver_city"></div>
|
||||||
<div class="ifnex-field full"><label>آدرس کامل *</label><textarea id="ifnex-receiver-address" rows="2"></textarea></div>
|
<div class="ifnex-field full"><label for="ifnex-receiver-address">آدرس کامل *</label><textarea id="ifnex-receiver-address" name="ifnex_receiver_address" rows="2"></textarea></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ifnex-form-nav">
|
<div class="ifnex-form-nav">
|
||||||
<button class="ifnex-btn ifnex-prev-step">→ قبلی</button>
|
<button class="ifnex-btn ifnex-prev-step">→ قبلی</button>
|
||||||
@ -661,7 +668,7 @@ function ifnex_order_form_shortcode($atts) {
|
|||||||
<div class="ifnex-form-card">
|
<div class="ifnex-form-card">
|
||||||
<h3>🏷️ کد تخفیف (اختیاری)</h3>
|
<h3>🏷️ کد تخفیف (اختیاری)</h3>
|
||||||
<div class="ifnex-form-grid">
|
<div class="ifnex-form-grid">
|
||||||
<div class="ifnex-field full"><label>کد تخفیف</label><input type="text" id="ifnex-discount-code" placeholder="مثلاً WELCOME10"></div>
|
<div class="ifnex-field full"><label for="ifnex-discount-code">کد تخفیف</label><input type="text" id="ifnex-discount-code" name="ifnex_discount_code" placeholder="مثلاً WELCOME10"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="ifnex-calc-error" class="ifnex-error-box" style="display:none;"></div>
|
<div id="ifnex-calc-error" class="ifnex-error-box" style="display:none;"></div>
|
||||||
<div id="ifnex-calc-loading" style="display:none; text-align:center; padding:20px;">
|
<div id="ifnex-calc-loading" style="display:none; text-align:center; padding:20px;">
|
||||||
@ -742,12 +749,37 @@ function ifnex_order_payment_shortcode($atts) {
|
|||||||
$wallet_balance = is_wp_error($balance) ? 0 : ($balance['balance'] ?? 0);
|
$wallet_balance = is_wp_error($balance) ? 0 : ($balance['balance'] ?? 0);
|
||||||
$can_pay_wallet = $wallet_balance >= $data['total_fee'];
|
$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();
|
ob_start();
|
||||||
?>
|
?>
|
||||||
<div class="ifnex-payment-page">
|
<div class="ifnex-payment-page">
|
||||||
<div class="ifnex-payment-card">
|
<div class="ifnex-payment-card">
|
||||||
<h2>💳 پرداخت سفارش</h2>
|
<h2>💳 پرداخت سفارش</h2>
|
||||||
|
|
||||||
|
<?php if ($payment_status === 'success'): ?>
|
||||||
|
<div class="ifnex-success-box">
|
||||||
|
<h3>✅ پرداخت با موفقیت انجام شد!</h3>
|
||||||
|
<p>کد پیگیری تراکنش: <strong><?php echo esc_html($payment_ref_id); ?></strong></p>
|
||||||
|
<p>مبلغ: <strong><?php echo number_format($data['total_fee']); ?> ریال</strong></p>
|
||||||
|
<p>سفارش شما در حال پردازش است.</p>
|
||||||
|
<a href="<?php echo esc_url(home_url('/my-orders/')); ?>" class="ifnex-btn ifnex-btn-primary">مشاهده سفارشات</a>
|
||||||
|
</div>
|
||||||
|
<?php elseif ($payment_status === 'failed'): ?>
|
||||||
|
<div class="ifnex-error-box">
|
||||||
|
<h3>❌ پرداخت ناموفق بود</h3>
|
||||||
|
<p><?php echo esc_html($payment_message ?: 'پرداخت با خطا مواجه شد. لطفاً دوباره تلاش کنید.'); ?></p>
|
||||||
|
</div>
|
||||||
|
<?php elseif ($payment_status === 'error'): ?>
|
||||||
|
<div class="ifnex-error-box">
|
||||||
|
<h3>⚠️ خطا در پرداخت</h3>
|
||||||
|
<p><?php echo esc_html($payment_message ?: 'خطای سیستمی رخ داده است.'); ?></p>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
|
||||||
<div class="ifnex-order-summary">
|
<div class="ifnex-order-summary">
|
||||||
<div class="ifnex-summary-row">
|
<div class="ifnex-summary-row">
|
||||||
<span>شماره پیگیری:</span>
|
<span>شماره پیگیری:</span>
|
||||||
@ -797,7 +829,7 @@ function ifnex_order_payment_shortcode($atts) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
<script>
|
<script>
|
||||||
jQuery(document).ready(function($) {
|
jQuery(document).ready(function($) {
|
||||||
// پرداخت از کیف پول
|
// پرداخت از کیف پول
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
if (function_exists('opcache_reset')) { @opcache_reset(); }
|
||||||
|
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
||||||
|
header('Pragma: no-cache');
|
||||||
/**
|
/**
|
||||||
* IFNEX Tracking Form Handler
|
* IFNEX Tracking Form Handler
|
||||||
* JavaScript و منطق فرم رهگیری
|
* JavaScript و منطق فرم رهگیری
|
||||||
@ -67,6 +70,12 @@ function ifnex_tracking_form_scripts() {
|
|||||||
};
|
};
|
||||||
xhr.send('action=ifnex_track_shipment&awb=' + encodeURIComponent(awb));
|
xhr.send('action=ifnex_track_shipment&awb=' + encodeURIComponent(awb));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ارسال خودکار اگر AWB از URL اومده باشد
|
||||||
|
var input = document.getElementById('ifnex-awb-input');
|
||||||
|
if (input && input.value.trim()) {
|
||||||
|
form.dispatchEvent(new Event('submit'));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
if (function_exists('opcache_reset')) { @opcache_reset(); }
|
||||||
|
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
||||||
|
header('Pragma: no-cache');
|
||||||
/**
|
/**
|
||||||
* IFNEX User Bridge
|
* IFNEX User Bridge
|
||||||
* مدیریت ارتباط کاربران وردپرس با لاراول
|
* مدیریت ارتباط کاربران وردپرس با لاراول
|
||||||
@ -254,13 +257,24 @@ class IFNEX_User_Bridge {
|
|||||||
* دریافت لیست کشورها
|
* دریافت لیست کشورها
|
||||||
*/
|
*/
|
||||||
public function get_countries($user_id) {
|
public function get_countries($user_id) {
|
||||||
$result = $this->authenticated_request($user_id, '/customer/countries');
|
$api_url = rtrim(get_option('ifnex_api_url', 'http://localhost:8000/api/v1'), '/');
|
||||||
|
$response = wp_remote_get($api_url . '/countries', array(
|
||||||
if (is_wp_error($result)) {
|
'headers' => array('Accept' => 'application/json'),
|
||||||
return $result;
|
'timeout' => 15,
|
||||||
|
));
|
||||||
|
|
||||||
|
if (is_wp_error($response)) {
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result['data'] ?? [];
|
$body = json_decode(wp_remote_retrieve_body($response), true);
|
||||||
|
$code = wp_remote_retrieve_response_code($response);
|
||||||
|
|
||||||
|
if ($code !== 200 || empty($body['data'])) {
|
||||||
|
return new WP_Error('countries_error', 'خطا در دریافت لیست کشورها');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $body['data'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -462,14 +476,14 @@ function ifnex_enqueue_order_assets() {
|
|||||||
global $post;
|
global $post;
|
||||||
if (!is_a($post, 'WP_Post')) return;
|
if (!is_a($post, 'WP_Post')) return;
|
||||||
|
|
||||||
$plugin_url = plugin_dir_url(dirname(__FILE__));
|
$plugin_url = trailingslashit(plugins_url('', dirname(__FILE__)));
|
||||||
|
|
||||||
// لود CSS
|
// لود CSS — وابسته به CSS قالب
|
||||||
wp_enqueue_style(
|
wp_enqueue_style(
|
||||||
'ifnex-orders-css',
|
'ifnex-orders-css',
|
||||||
$plugin_url . 'assets/css/ifnex-orders.css',
|
$plugin_url . 'assets/css/ifnex-orders.css',
|
||||||
array(),
|
array('ifnex-main'),
|
||||||
'1.7.0'
|
'2.0.0-' . time()
|
||||||
);
|
);
|
||||||
|
|
||||||
// لود jQuery & JS
|
// لود jQuery & JS
|
||||||
@ -478,7 +492,7 @@ function ifnex_enqueue_order_assets() {
|
|||||||
'ifnex-order-form-js',
|
'ifnex-order-form-js',
|
||||||
$plugin_url . 'assets/js/ifnex-order-form.js',
|
$plugin_url . 'assets/js/ifnex-order-form.js',
|
||||||
array('jquery'),
|
array('jquery'),
|
||||||
'1.7.0',
|
'2.0.0-' . time(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -486,7 +500,7 @@ function ifnex_enqueue_order_assets() {
|
|||||||
wp_localize_script('ifnex-order-form-js', 'ifnex_ajax', array(
|
wp_localize_script('ifnex-order-form-js', 'ifnex_ajax', array(
|
||||||
'ajax_url' => admin_url('admin-ajax.php'),
|
'ajax_url' => admin_url('admin-ajax.php'),
|
||||||
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
|
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
|
||||||
'orders_url' => home_url('/my-orders/'),
|
'orders_url' => home_url('/my-account/?tab=orders'),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,6 +546,41 @@ function ifnex_wallet_charge_ajax() {
|
|||||||
wp_send_json_success($result);
|
wp_send_json_success($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
// AJAX Handler برای پرداخت سفارش از کیف پول
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
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');
|
add_action('wp_ajax_ifnex_pay_order_gateway', 'ifnex_pay_order_gateway_ajax');
|
||||||
function ifnex_pay_order_gateway_ajax() {
|
function ifnex_pay_order_gateway_ajax() {
|
||||||
check_ajax_referer('ifnex_ajax_nonce', 'nonce');
|
check_ajax_referer('ifnex_ajax_nonce', 'nonce');
|
||||||
@ -566,14 +615,19 @@ function ifnex_enqueue_payment_assets() {
|
|||||||
if (!is_a($post, 'WP_Post')) return;
|
if (!is_a($post, 'WP_Post')) return;
|
||||||
|
|
||||||
if (has_shortcode($post->post_content, 'ifnex_order_payment')) {
|
if (has_shortcode($post->post_content, 'ifnex_order_payment')) {
|
||||||
$plugin_url = plugin_dir_url(dirname(__FILE__));
|
$plugin_url = trailingslashit(plugins_url('', dirname(__FILE__)));
|
||||||
wp_enqueue_style('ifnex-orders-css', $plugin_url . 'assets/css/ifnex-orders.css', array(), '1.4.0');
|
wp_enqueue_style(
|
||||||
|
'ifnex-orders-css',
|
||||||
|
$plugin_url . 'assets/css/ifnex-orders.css',
|
||||||
|
array('ifnex-main'),
|
||||||
|
'2.0.0-' . time()
|
||||||
|
);
|
||||||
wp_enqueue_script('jquery');
|
wp_enqueue_script('jquery');
|
||||||
wp_localize_script('jquery', 'ifnex_ajax', array(
|
wp_add_inline_script('jquery', 'var ifnex_ajax = ' . wp_json_encode(array(
|
||||||
'ajax_url' => admin_url('admin-ajax.php'),
|
'ajax_url' => admin_url('admin-ajax.php'),
|
||||||
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
|
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
|
||||||
'orders_url' => home_url('/my-orders/'),
|
'orders_url' => home_url('/my-account/?tab=orders'),
|
||||||
));
|
)) . ';', 'before');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,24 +639,24 @@ function ifnex_enqueue_payment_assets() {
|
|||||||
add_action('wp_enqueue_scripts', 'ifnex_enqueue_global_assets', 20);
|
add_action('wp_enqueue_scripts', 'ifnex_enqueue_global_assets', 20);
|
||||||
|
|
||||||
function ifnex_enqueue_global_assets() {
|
function ifnex_enqueue_global_assets() {
|
||||||
$plugin_url = plugin_dir_url(dirname(__FILE__));
|
$plugin_url = trailingslashit(plugins_url('', dirname(__FILE__)));
|
||||||
|
|
||||||
// لود CSS اصلی (نسخه را بالا بردیم تا cache مرورگر بشکند)
|
// لود CSS اصلی — وابسته به CSS قالب تا بعد از آن لود شود
|
||||||
wp_enqueue_style(
|
wp_enqueue_style(
|
||||||
'ifnex-orders-css',
|
'ifnex-orders-css',
|
||||||
$plugin_url . 'assets/css/ifnex-orders.css',
|
$plugin_url . 'assets/css/ifnex-orders.css',
|
||||||
array(),
|
array('ifnex-main'),
|
||||||
'1.6.0'
|
'2.0.0-' . time()
|
||||||
);
|
);
|
||||||
|
|
||||||
// لود jQuery
|
// لود jQuery
|
||||||
wp_enqueue_script('jquery');
|
wp_enqueue_script('jquery');
|
||||||
|
|
||||||
// متغیرهای AJAX برای همه صفحات
|
// متغیرهای AJAX برای همه صفحات
|
||||||
wp_localize_script('jquery', 'ifnex_ajax', array(
|
wp_add_inline_script('jquery', 'var ifnex_ajax = ' . wp_json_encode(array(
|
||||||
'ajax_url' => admin_url('admin-ajax.php'),
|
'ajax_url' => admin_url('admin-ajax.php'),
|
||||||
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
|
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
|
||||||
'orders_url' => home_url('/my-account/?tab=orders'),
|
'orders_url' => home_url('/my-account/?tab=orders'),
|
||||||
'home_url' => home_url('/'),
|
'home_url' => home_url('/'),
|
||||||
));
|
)) . ';', 'before');
|
||||||
}
|
}
|
||||||
@ -97,4 +97,32 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Hero Tracking Form ───
|
||||||
|
const trackingForm = document.querySelector('.tracking-form');
|
||||||
|
if (trackingForm) {
|
||||||
|
const trackingInput = trackingForm.querySelector('.tracking-input');
|
||||||
|
const trackingBtn = trackingForm.querySelector('.tracking-btn');
|
||||||
|
|
||||||
|
function submitTracking() {
|
||||||
|
var awb = trackingInput.value.trim();
|
||||||
|
if (!awb) {
|
||||||
|
trackingInput.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var baseUrl = (typeof ifnexConfig !== 'undefined' && ifnexConfig.homeUrl) ? ifnexConfig.homeUrl : '/';
|
||||||
|
window.location.href = baseUrl.replace(/\/$/, '') + '/tracking/?awb=' + encodeURIComponent(awb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trackingBtn) {
|
||||||
|
trackingBtn.addEventListener('click', submitTracking);
|
||||||
|
}
|
||||||
|
|
||||||
|
trackingInput.addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
submitTracking();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
@ -176,6 +176,9 @@ function ifnex_get_logo_html($context = 'header') {
|
|||||||
$custom_logo = wp_get_attachment_image($logo_id, 'full', false, [
|
$custom_logo = wp_get_attachment_image($logo_id, 'full', false, [
|
||||||
'class' => 'logo-image',
|
'class' => 'logo-image',
|
||||||
'alt' => get_bloginfo('name'),
|
'alt' => get_bloginfo('name'),
|
||||||
|
'loading' => 'eager',
|
||||||
|
'width' => 200,
|
||||||
|
'height' => 50,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($custom_logo) {
|
if ($custom_logo) {
|
||||||
|
|||||||
@ -266,24 +266,24 @@ class CustomerOrderController extends Controller
|
|||||||
|
|
||||||
ShipmentPackage::create([
|
ShipmentPackage::create([
|
||||||
'shipment_id' => $shipment->id,
|
'shipment_id' => $shipment->id,
|
||||||
'package_number' => $index + 1,
|
'package_no' => $index + 1,
|
||||||
'weight' => $pkg['weight'],
|
'weight' => $pkg['weight'],
|
||||||
'volumetric_weight' => $volWeight,
|
'volumetric_weight' => $volWeight,
|
||||||
'chargeable_weight' => $chargeable,
|
'chargeable_weight' => $chargeable,
|
||||||
'dimensions' => $pkg['dimensions'] ?? null,
|
'dimensions' => $pkg['dimensions'] ?? null,
|
||||||
'description' => $pkg['description'] ?? null,
|
'content_description' => $pkg['description'] ?? null,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// حالت قدیمی: یه بسته با وزن کلی سفارش
|
// حالت قدیمی: یه بسته با وزن کلی سفارش
|
||||||
ShipmentPackage::create([
|
ShipmentPackage::create([
|
||||||
'shipment_id' => $shipment->id,
|
'shipment_id' => $shipment->id,
|
||||||
'package_number' => 1,
|
'package_no' => 1,
|
||||||
'weight' => $validated['weight'],
|
'weight' => $validated['weight'],
|
||||||
'volumetric_weight' => $validated['volumetric_weight'] ?? 0,
|
'volumetric_weight' => $validated['volumetric_weight'] ?? 0,
|
||||||
'chargeable_weight' => $validated['chargeable_weight'],
|
'chargeable_weight' => $validated['chargeable_weight'],
|
||||||
'dimensions' => $validated['dimensions'] ?? null,
|
'dimensions' => $validated['dimensions'] ?? null,
|
||||||
'description' => null,
|
'content_description' => null,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -213,7 +213,14 @@ class PaymentController extends Controller
|
|||||||
gatewayReferenceId: $verification['ref_id'] ?? $authority
|
gatewayReferenceId: $verification['ref_id'] ?? $authority
|
||||||
);
|
);
|
||||||
|
|
||||||
// ─── NEW: اگر تراکنش مربوط به سفارش است، status سفارش را تغییر بده ─
|
// اگر تراکنش مربوط به سفارش است، status سفارش را تغییر بده
|
||||||
|
$metadata = $transaction->metadata ?? [];
|
||||||
|
if (!empty($metadata['is_order_payment']) && !empty($metadata['shipment_id'])) {
|
||||||
|
$shipment = \App\Models\Shipment::find($metadata['shipment_id']);
|
||||||
|
if ($shipment && $shipment->status === \App\Enums\ShipmentStatus::Approved) {
|
||||||
|
$shipment->update(['status' => \App\Enums\ShipmentStatus::Processed]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log::info('Payment completed successfully', [
|
Log::info('Payment completed successfully', [
|
||||||
'transaction_id' => $transaction->id,
|
'transaction_id' => $transaction->id,
|
||||||
|
|||||||
@ -9,12 +9,12 @@ class ShipmentPackage extends Model
|
|||||||
{
|
{
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'shipment_id',
|
'shipment_id',
|
||||||
'package_number',
|
'package_no',
|
||||||
'weight',
|
'weight',
|
||||||
'volumetric_weight',
|
'volumetric_weight',
|
||||||
'chargeable_weight',
|
'chargeable_weight',
|
||||||
'dimensions',
|
'dimensions',
|
||||||
'description',
|
'content_description',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
|
|||||||
@ -163,7 +163,7 @@ class OrderPaymentService
|
|||||||
return DB::transaction(function () use ($transaction) {
|
return DB::transaction(function () use ($transaction) {
|
||||||
$shipment = Shipment::find($transaction->transactionable_id);
|
$shipment = Shipment::find($transaction->transactionable_id);
|
||||||
|
|
||||||
if (!$shipment || $shipment->status !== ShipmentStatus::PendingPayment) {
|
if (!$shipment || $shipment->status !== ShipmentStatus::Approved) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
require 'vendor/autoload.php';
|
|
||||||
|
|
||||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
|
||||||
|
|
||||||
$reader = IOFactory::createReader('Xlsx');
|
|
||||||
$spreadsheet = $reader->load(__DIR__ . '/../01_Documents/Sheet ENG invoice.xlsx');
|
|
||||||
$sheet = $spreadsheet->getActiveSheet();
|
|
||||||
|
|
||||||
echo 'Sheet: ' . $sheet->getTitle() . PHP_EOL;
|
|
||||||
echo 'Rows: ' . $sheet->getHighestRow() . PHP_EOL;
|
|
||||||
|
|
||||||
// Use toArray for cleaner output
|
|
||||||
$data = $sheet->toArray(null, true, true, true);
|
|
||||||
|
|
||||||
echo PHP_EOL . '=== CONTENT ===' . PHP_EOL;
|
|
||||||
|
|
||||||
foreach ($data as $rowIndex => $row) {
|
|
||||||
$line = '';
|
|
||||||
foreach ($row as $colIndex => $value) {
|
|
||||||
if ($value !== null && trim((string)$value) !== '') {
|
|
||||||
$line .= $colIndex . '=' . trim((string)$value) . ' | ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($line) echo 'Row' . $rowIndex . ': ' . $line . PHP_EOL;
|
|
||||||
}
|
|
||||||
@ -29,6 +29,13 @@ Route::middleware([ApiKeyMiddleware::class])->prefix('v1')->group(function () {
|
|||||||
Route::get('/track/{awb_no}', [TrackController::class, 'show']);
|
Route::get('/track/{awb_no}', [TrackController::class, 'show']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
// API عمومی (بدون نیاز به احراز هویت)
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
Route::prefix('v1')->group(function () {
|
||||||
|
Route::get('/countries', [CustomerOrderController::class, 'countries']);
|
||||||
|
});
|
||||||
|
|
||||||
// ══════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════
|
||||||
// Auth API (عمومی - برای دریافت توکن)
|
// Auth API (عمومی - برای دریافت توکن)
|
||||||
// ══════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════
|
||||||
@ -60,8 +67,8 @@ Route::middleware(['auth:sanctum'])->prefix('v1')->group(function () {
|
|||||||
// پروفایل و آمار
|
// پروفایل و آمار
|
||||||
Route::get('/profile', [CustomerOrderController::class, 'profile']);
|
Route::get('/profile', [CustomerOrderController::class, 'profile']);
|
||||||
|
|
||||||
// لیست کشورها
|
// لیست کشورها (عمومی - بدون نیاز به احراز هویت)
|
||||||
Route::get('/countries', [CustomerOrderController::class, 'countries']);
|
// این endpoint در گروه auth:sanctum نیست
|
||||||
|
|
||||||
// سفارشات
|
// سفارشات
|
||||||
Route::get('/orders', [CustomerOrderController::class, 'index']);
|
Route::get('/orders', [CustomerOrderController::class, 'index']);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user