ExportSparePartsService.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <?php
  2. namespace App\Services\Export;
  3. use App\Models\File;
  4. use App\Models\PricingCode;
  5. use App\Models\SparePart;
  6. use Illuminate\Support\Facades\Storage;
  7. use PhpOffice\PhpSpreadsheet\IOFactory;
  8. use PhpOffice\PhpSpreadsheet\Style\Border;
  9. use PhpOffice\PhpSpreadsheet\Style\Color;
  10. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  11. class ExportSparePartsService
  12. {
  13. public function handle(int $userId): string
  14. {
  15. $inputFileType = 'Xlsx';
  16. $inputFileName = './templates/SpareParts.xlsx';
  17. $reader = IOFactory::createReader($inputFileType);
  18. $spreadsheet = $reader->load($inputFileName);
  19. $sheet = $spreadsheet->getActiveSheet();
  20. // Получаем данные из модели (НЕ view!)
  21. // ВАЖНО: Вычисляемые поля учитывают текущий год из сессии
  22. $spareParts = SparePart::with('pricingCodes')->orderBy('article')->get();
  23. $i = 2;
  24. foreach ($spareParts as $sp) {
  25. $sheet->setCellValue('A' . $i, $sp->id);
  26. $sheet->setCellValue('B' . $i, $sp->article);
  27. $sheet->setCellValue('C' . $i, $sp->used_in_maf);
  28. $sheet->setCellValue('D' . $i, $sp->quantity_without_docs);
  29. $sheet->setCellValue('E' . $i, $sp->quantity_with_docs);
  30. $sheet->setCellValue('F' . $i, $sp->total_quantity);
  31. $sheet->setCellValue('G' . $i, $sp->note);
  32. $sheet->setCellValue('H' . $i, $sp->purchase_price);
  33. $sheet->setCellValue('I' . $i, $sp->customer_price);
  34. $sheet->setCellValue('J' . $i, $sp->expertise_price);
  35. $sheet->setCellValue('K' . $i, $sp->tsn_number);
  36. // Экспортируем множественные шифры расценки через запятую
  37. $sheet->setCellValue('L' . $i, $sp->pricingCodes->pluck('code')->implode(', '));
  38. $sheet->setCellValue('M' . $i, $sp->min_stock);
  39. $i++;
  40. }
  41. $sheet->getStyle('A1:M' . ($i - 1))
  42. ->getBorders()
  43. ->getAllBorders()
  44. ->setBorderStyle(Border::BORDER_THIN)
  45. ->setColor(new Color('777777'));
  46. // Создаём вторую вкладку для справочника расшифровок
  47. $pricingCodesSheet = $spreadsheet->createSheet(1);
  48. $pricingCodesSheet->setTitle('Справочник расшифровок');
  49. // Заголовки
  50. $pricingCodesSheet->setCellValue('A1', 'ID');
  51. $pricingCodesSheet->setCellValue('B1', 'Тип');
  52. $pricingCodesSheet->setCellValue('C1', 'Код');
  53. $pricingCodesSheet->setCellValue('D1', 'Расшифровка');
  54. // Стиль заголовков
  55. $pricingCodesSheet->getStyle('A1:D1')->getFont()->setBold(true);
  56. $pricingCodesSheet->getStyle('A1:D1')->getFill()
  57. ->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
  58. ->getStartColor()->setARGB('DDDDDD');
  59. // Данные справочника
  60. $pricingCodes = PricingCode::orderBy('type')->orderBy('code')->get();
  61. $j = 2;
  62. foreach ($pricingCodes as $pc) {
  63. $pricingCodesSheet->setCellValue('A' . $j, $pc->id);
  64. $pricingCodesSheet->setCellValue('B' . $j, $pc->type === PricingCode::TYPE_TSN_NUMBER ? '№ по ТСН' : 'Шифр расценки');
  65. $pricingCodesSheet->setCellValue('C' . $j, $pc->code);
  66. $pricingCodesSheet->setCellValue('D' . $j, $pc->description);
  67. $j++;
  68. }
  69. // Границы для справочника
  70. if ($j > 2) {
  71. $pricingCodesSheet->getStyle('A1:D' . ($j - 1))
  72. ->getBorders()
  73. ->getAllBorders()
  74. ->setBorderStyle(Border::BORDER_THIN)
  75. ->setColor(new Color('777777'));
  76. }
  77. // Автоширина колонок
  78. foreach (range('A', 'D') as $col) {
  79. $pricingCodesSheet->getColumnDimension($col)->setAutoSize(true);
  80. }
  81. // Возвращаемся на первую вкладку
  82. $spreadsheet->setActiveSheetIndex(0);
  83. $fileName = 'export_spare_parts_' . date('Y-m-d_H-i-s') . '.xlsx';
  84. $writer = new Xlsx($spreadsheet);
  85. $fd = 'export/spare_parts';
  86. Storage::disk('public')->makeDirectory($fd);
  87. $fp = storage_path('app/public/' . $fd . '/') . $fileName;
  88. Storage::disk('public')->delete($fd . '/' . $fileName);
  89. $writer->save($fp);
  90. $link = url('/storage/' . $fd . '/' . $fileName);
  91. // Создаём запись в таблице files
  92. File::query()->create([
  93. 'link' => $link,
  94. 'path' => $fp,
  95. 'user_id' => $userId,
  96. 'original_name' => $fileName,
  97. 'mime_type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  98. ]);
  99. return $link;
  100. }
  101. }