diff --git a/app/Exports/ProductStockDealers.php b/app/Exports/ProductStockDealers.php new file mode 100644 index 0000000..1d87ba4 --- /dev/null +++ b/app/Exports/ProductStockDealers.php @@ -0,0 +1,201 @@ +get(); + + /** @var Dealer $dealer */ + foreach ($dealers as $dealer) { + $dealerSheet = new DealerStockSheet($dealer); + $sheetTitle = $dealerSheet->title(); + + // Handle duplicate sheet names + $originalTitle = $sheetTitle; + $counter = 1; + while (in_array($sheetTitle, $usedNames)) { + $sheetTitle = substr($originalTitle, 0, 28) . '_' . $counter; + $counter++; + } + $usedNames[] = $sheetTitle; + + // Set the unique title + $dealerSheet->setUniqueTitle($sheetTitle); + $sheets[] = $dealerSheet; + } + + return $sheets; + } +} + +class DealerStockSheet implements FromCollection, WithTitle, WithHeadings, WithStyles, WithColumnWidths +{ + protected $dealer; + protected $uniqueTitle; + + public function __construct(Dealer $dealer) + { + $this->dealer = $dealer; + } + + public function collection() + { + // Get all products with stock for this dealer + $stocks = $this->dealer->stocks() + ->with(['product.category']) + ->whereHas('product', function($query) { + $query->where('active', true); + }) + ->get(); + + $data = collect(); + $no = 1; + + foreach ($stocks as $stock) { + $product = $stock->product; + $data->push([ + 'no' => $no++, + 'kode_produk' => $product->code, + 'nama_produk' => $product->name, + 'kategori' => $product->category ? $product->category->name : '-', + 'satuan' => $product->unit ?? '-', + 'stok' => number_format($stock->quantity, 2) + ]); + } + + // If no stock, add empty row + if ($data->isEmpty()) { + $data->push([ + 'no' => '-', + 'kode_produk' => '-', + 'nama_produk' => 'Tidak ada stok produk', + 'kategori' => '-', + 'satuan' => '-', + 'stok' => '0' + ]); + } + + return $data; + } + + public function setUniqueTitle(string $title): void + { + $this->uniqueTitle = $title; + } + + public function title(): string + { + if (isset($this->uniqueTitle)) { + return $this->uniqueTitle; + } + + // Clean dealer name for sheet title (remove invalid characters and handle edge cases) + $cleanName = $this->dealer->name; + + // Remove parentheses and their contents + $cleanName = preg_replace('/\([^)]*\)/', '', $cleanName); + + // Remove dots, commas, and other special characters + $cleanName = preg_replace('/[^A-Za-z0-9\-_ ]/', '', $cleanName); + + // Clean up multiple spaces and trim + $cleanName = preg_replace('/\s+/', ' ', trim($cleanName)); + + // If name is empty after cleaning, use dealer ID + if (empty($cleanName)) { + $cleanName = 'Dealer_' . $this->dealer->id; + } + + // Limit to 31 characters and ensure no leading/trailing spaces + $cleanName = trim(substr($cleanName, 0, 31)); + + // Ensure it doesn't end with a space (which can cause Excel issues) + return rtrim($cleanName); + } + + public function headings(): array + { + return [ + 'No', + 'Kode Produk', + 'Nama Produk', + 'Kategori', + 'Satuan', + 'Stok' + ]; + } + + public function styles(Worksheet $sheet) + { + // Add dealer info at the top first + $sheet->insertNewRowBefore(1, 2); + $sheet->setCellValue('A1', 'STOK PRODUK DEALER: ' . strtoupper($this->dealer->name)); + $sheet->setCellValue('A2', 'Tanggal Export: ' . now()->format('d/m/Y H:i:s')); + + // Merge cells for dealer info + $sheet->mergeCells('A1:F1'); + $sheet->mergeCells('A2:F2'); + + $lastRow = $sheet->getHighestRow(); + + // Style dealer info + $sheet->getStyle('A1:A2')->applyFromArray([ + 'font' => ['bold' => true, 'size' => 12], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER] + ]); + + // Style headers (row 3 after inserting 2 rows) + $sheet->getStyle('A3:F3')->applyFromArray([ + 'font' => ['bold' => true, 'color' => ['rgb' => 'FFFFFF']], + 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => '4472C4']], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER], + 'borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN]] + ]); + + // Style data rows if they exist + if ($lastRow > 3) { + $sheet->getStyle('A4:F' . $lastRow)->applyFromArray([ + 'borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN, 'color' => ['rgb' => 'CCCCCC']]], + 'alignment' => ['vertical' => Alignment::VERTICAL_CENTER] + ]); + + // Center align specific columns + $sheet->getStyle('A4:A' . $lastRow)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); + $sheet->getStyle('E4:F' . $lastRow)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); + } + + return $sheet; + } + + public function columnWidths(): array + { + return [ + 'A' => 8, // No + 'B' => 15, // Kode Produk + 'C' => 30, // Nama Produk + 'D' => 20, // Kategori + 'E' => 12, // Satuan + 'F' => 12 // Stok + ]; + } +} diff --git a/app/Http/Controllers/WarehouseManagement/ProductsController.php b/app/Http/Controllers/WarehouseManagement/ProductsController.php index 9e649f8..92387f3 100755 --- a/app/Http/Controllers/WarehouseManagement/ProductsController.php +++ b/app/Http/Controllers/WarehouseManagement/ProductsController.php @@ -7,6 +7,7 @@ use App\Models\Dealer; use App\Models\Menu; use App\Models\Product; use App\Models\ProductCategory; +use App\Exports\ProductStockDealers; use Carbon\Carbon; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; @@ -15,6 +16,7 @@ use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\DB; use Yajra\DataTables\Facades\DataTables; use Illuminate\Validation\Rule; +use Maatwebsite\Excel\Facades\Excel; class ProductsController extends Controller { @@ -270,4 +272,16 @@ class ProductsController extends Controller return DataTables::of($data)->make(true); } + + public function exportDealersStock() + { + try { + $fileName = 'stok_produk_dealers_' . date('Y-m-d_H-i-s') . '.xlsx'; + + return Excel::download(new ProductStockDealers(), $fileName); + } catch (\Exception $e) { + Log::error('Export dealers stock error: ' . $e->getMessage()); + return back()->with('error', 'Gagal mengexport data. Silakan coba lagi.'); + } + } } diff --git a/resources/views/warehouse_management/products/index.blade.php b/resources/views/warehouse_management/products/index.blade.php index 055e2cd..582dd9c 100755 --- a/resources/views/warehouse_management/products/index.blade.php +++ b/resources/views/warehouse_management/products/index.blade.php @@ -81,15 +81,18 @@ table.dataTable thead th.sorting:hover:before { Tabel Produk - @can('create', $menus['products.index'])
- @endcan