fix(rate-import): fix file path resolution + redirect old import page to new 4-quadrant page

- Fix 'File not found' error in ImportRates page by using Storage facade
  to resolve the actual path on the 'local' disk (which points to
  storage/app/private, not storage/app).
- Deprecate the old ImportRatesPage (2-zone format) — hide from navigation
  and redirect anyone hitting its URL to /admin/rate-import.
- Update the template download route to serve the new 4-quadrant
  IFNEX_Rate_Template.xlsx from public/templates/ instead of the old
  ShippingRatesTemplateExport (2-zone format).
- Update rate-import.blade.php to use the named route for the download link.
- Add public/templates/IFNEX_Rate_Template.xlsx for direct web access.
This commit is contained in:
Kazem Alghasi 2026-10-29 15:56:30 +03:30
parent 563f89495c
commit c43b6b0bec
5 changed files with 59 additions and 18 deletions

View File

@ -12,20 +12,35 @@ use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Maatwebsite\Excel\Facades\Excel;
/**
* ⚠️ DEPRECATED — این صفحه قدیمی برای فرمت ۲-زونی است.
*
* با معماری ۴-رُبعی جدید، ایمپورت نرخ‌ها از طریق Resource جدید انجام می‌شود:
* App\Filament\Resources\RateImportResource → URL: /admin/rate-import
*
* این صفحه فقط برای backward-compatibility باقی مانده و در منوی ناوبری
* نمایش داده نمی‌شود. اگر کاربر مستقیم URL قدیمی را باز کرد، به صفحه جدید
* ریدایرکت می‌شود.
*/
class ImportRatesPage extends Page implements HasForms
{
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-arrow-up-on-square';
protected static ?string $navigationLabel = 'ایمپورت زون ها';
protected static ?string $navigationLabel = 'ایمپورت زون ها (قدیمی)';
protected static ?int $navigationSort = 8;
protected static string $view = 'filament.pages.import-rates';
/** ❌ این صفحه از منوی ناوبری پنهان است — از /admin/rate-import استفاده کنید. */
protected static bool $shouldRegisterNavigation = false;
public ?array $formData = [];
public function mount(): void
{
$this->form->fill();
// ریدایرکت به صفحه جدید ایمپورت نرخ‌ها (۴-رُبعی)
redirect()->to('/admin/rate-import')->send();
exit;
}
public function form(Form $form): Form

View File

@ -13,6 +13,7 @@ use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Form;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\Page;
use Illuminate\Support\Facades\Storage;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
/**
@ -85,17 +86,23 @@ class ImportRates extends Page implements HasForms
$uploadedPath = $state['uploaded_file'];
// FileUpload on 'local' disk returns a relative path inside storage/app/
$filePath = is_string($uploadedPath)
? storage_path('app/' . $uploadedPath)
: ($uploadedPath instanceof TemporaryUploadedFile
? $uploadedPath->getRealPath()
: (string) $uploadedPath);
// FileUpload روی دیسک 'local' ذخیره می‌شود که در config/filesystems.php
// به storage_path('app/private') اشاره دارد. مسیر واقعی را از خود دیسک
// می‌پرسیم تا با تغییر کانفیگ هم درست کار کند.
$filePath = null;
if (is_string($uploadedPath)) {
// مسیر نسبی روی دیسک 'local' — Storage مسیر کامل را برمی‌گرداند
$filePath = Storage::disk('local')->path($uploadedPath);
} elseif ($uploadedPath instanceof TemporaryUploadedFile) {
$filePath = $uploadedPath->getRealPath();
} else {
$filePath = (string) $uploadedPath;
}
if (! file_exists($filePath)) {
if (! $filePath || ! file_exists($filePath)) {
Notification::make()
->title('File not found after upload')
->body('Path: ' . $filePath)
->body('Path checked: ' . $filePath)
->danger()
->send();
return;
@ -111,8 +118,8 @@ class ImportRates extends Page implements HasForms
"✓ Imported: %d | Updated: %d | Skipped: %d | Zone rows: %d",
$summary['imported'] ?? 0,
$summary['updated'] ?? 0,
$summary['skipped'] ?? 0,
$summary['zones_updated'] ?? 0,
$summary['skipped'] ?? 0,
$summary['zones_updated'] ?? 0,
);
if (! empty($summary['errors'])) {
@ -139,4 +146,4 @@ class ImportRates extends Page implements HasForms
->send();
}
}
}
}

View File

@ -32,10 +32,15 @@
</div>
<div class="filament-card p-4">
<h3 class="text-sm font-semibold mb-2">Download template</h3>
<h3 class="text-sm font-semibold mb-2">دانلود قالب خالی</h3>
<p class="text-xs text-gray-600 mb-2">
Need the blank template? <a href="/admin/rate-import/template" class="text-blue-600 underline">Download IFNEX_Rate_Template.xlsx</a>
اگر قالب خالی را می‌خواهید،
<a href="{{ route('download.rate-template') }}" class="text-blue-600 underline">دانلود IFNEX_Rate_Template.xlsx</a>
(فرمت ۴-رُبعی: Import Rate، Export Rate، Zone).
</p>
<p class="text-xs text-amber-600 mt-2">
⚠️ توجه: فایل اصلی مشتری (با داده‌های نرخ واقعی) را مستقیم آپلود کنید — این قالب فقط فرمت خالی است.
</p>
</div>
</div>
</x-filament-panels::page>
</x-filament-panels::page>

Binary file not shown.

View File

@ -48,6 +48,20 @@ Route::get('/payment-result', function (Illuminate\Http\Request $request) {
'message' => $message,
]);
})->name('payment.result');
// دانلود قالب خالی نرخ‌ها (IFNEX_Rate_Template.xlsx — فرمت ۴-رُبعی جدید)
// فایل واقعی در public/templates قرار دارد تا مستقیم از طریق وب هم قابل دسترس باشد.
Route::get('/download-rate-template', function () {
return (new \App\Exports\ShippingRatesTemplateExport)->download('IFNEX_Rate_Template.xlsx');
})->middleware(['auth', 'panel:admin'])->name('download.rate-template');
$file = public_path('templates/IFNEX_Rate_Template.xlsx');
if (! file_exists($file)) {
abort(404, 'Template file not found. Please add public/templates/IFNEX_Rate_Template.xlsx');
}
return response()->download($file, 'IFNEX_Rate_Template.xlsx', [
'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
]);
})->name('download.rate-template');
// alias کوتاه‌تر که از صفحه /admin/rate-import لینک شده
Route::get('/admin/rate-import/template', function () {
return redirect()->route('download.rate-template');
})->name('admin.rate-import.template');