ExportProductionOrdersService.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Services\Export;
  4. use App\Models\File;
  5. use App\Models\ProductionOrder;
  6. use Illuminate\Support\Facades\Storage;
  7. use Illuminate\Support\Str;
  8. use PhpOffice\PhpSpreadsheet\Cell\DataType;
  9. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  10. use PhpOffice\PhpSpreadsheet\Style\Alignment;
  11. use PhpOffice\PhpSpreadsheet\Style\Border;
  12. use PhpOffice\PhpSpreadsheet\Style\Fill;
  13. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  14. class ExportProductionOrdersService
  15. {
  16. public const ORDERS_SHEET = 'График заказов';
  17. public const ITEMS_SHEET = 'МАФ';
  18. public const HEADERS = [
  19. 'ID',
  20. 'Номер заказа',
  21. 'Год',
  22. 'Заказчик',
  23. 'Адрес объекта',
  24. 'Номер счёта',
  25. 'Дата счёта',
  26. 'Номер договора',
  27. 'Дата договора',
  28. 'Дата оплаты',
  29. 'Срок поставки, раб. дней',
  30. 'Дата отгрузки по договору',
  31. 'Дата отгрузки по заявке',
  32. 'Статус',
  33. 'Тип исполнения',
  34. 'Менеджер',
  35. 'Оборудование',
  36. 'Примечание',
  37. ];
  38. public const ITEM_HEADERS = [
  39. 'Строка заказа',
  40. 'ID МАФ',
  41. 'ID позиции каталога',
  42. 'Артикул',
  43. 'Наименование',
  44. 'Номер заказа МАФ',
  45. 'Заводской номер',
  46. 'Дата производства',
  47. ];
  48. /** @param list<int> $orderIds */
  49. public function handle(array $orderIds, int $userId): File
  50. {
  51. $spreadsheet = new Spreadsheet;
  52. $sheet = $spreadsheet->getActiveSheet();
  53. $sheet->setTitle(self::ORDERS_SHEET);
  54. $sheet->fromArray(self::HEADERS, null, 'A1');
  55. $sheet->getStyle('A1:R1')->getFont()->setBold(true);
  56. $sheet->getStyle('A1:R1')->getFill()
  57. ->setFillType(Fill::FILL_SOLID)
  58. ->getStartColor()->setARGB('FFD9EAF7');
  59. $itemsSheet = $spreadsheet->createSheet();
  60. $itemsSheet->setTitle(self::ITEMS_SHEET);
  61. $itemsSheet->fromArray(self::ITEM_HEADERS, null, 'A1');
  62. $itemsSheet->getStyle('A1:H1')->getFont()->setBold(true);
  63. $itemsSheet->getStyle('A1:H1')->getFill()
  64. ->setFillType(Fill::FILL_SOLID)
  65. ->getStartColor()->setARGB('FFE2F0D9');
  66. $row = 2;
  67. $itemRow = 2;
  68. ProductionOrder::query()
  69. ->with(['manager', 'items.catalogItem'])
  70. ->whereKey($orderIds)
  71. ->orderByDesc('created_at')
  72. ->orderByDesc('id')
  73. ->chunk(200, function ($orders) use ($sheet, $itemsSheet, &$row, &$itemRow): void {
  74. foreach ($orders as $order) {
  75. $orderRow = $row;
  76. $sheet->setCellValue("A{$row}", $order->id);
  77. $sheet->setCellValueExplicit("B{$row}", $order->order_number, DataType::TYPE_STRING);
  78. $sheet->setCellValue("C{$row}", $order->order_year);
  79. $sheet->setCellValue("D{$row}", $order->customer_name);
  80. $sheet->setCellValue("E{$row}", $order->object_address);
  81. $sheet->setCellValueExplicit("F{$row}", $order->invoice_number, DataType::TYPE_STRING);
  82. $sheet->setCellValue("G{$row}", $order->invoice_date?->format('d.m.Y'));
  83. $sheet->setCellValueExplicit("H{$row}", (string) $order->contract_number, DataType::TYPE_STRING);
  84. $sheet->setCellValue("I{$row}", $order->contract_date?->format('d.m.Y'));
  85. $sheet->setCellValue("J{$row}", $order->payment_date?->format('d.m.Y'));
  86. $sheet->setCellValue("K{$row}", $order->supply_working_days);
  87. $sheet->setCellValue("L{$row}", $order->contract_shipment_date?->format('d.m.Y'));
  88. $sheet->setCellValue("M{$row}", $order->application_shipment_date?->format('d.m.Y'));
  89. $sheet->setCellValue("N{$row}", $order->statusLabel());
  90. $sheet->setCellValue("O{$row}", $order->executionTypeLabel());
  91. $sheet->setCellValue("P{$row}", $order->manager?->name);
  92. $sheet->setCellValue("Q{$row}", $this->equipmentSummary($order));
  93. $sheet->setCellValue("R{$row}", $order->note);
  94. foreach ($order->items as $item) {
  95. $itemsSheet->setCellValue("A{$itemRow}", $orderRow);
  96. $itemsSheet->setCellValue("B{$itemRow}", $item->id);
  97. $itemsSheet->setCellValue("C{$itemRow}", $item->common_catalog_item_id);
  98. $itemsSheet->setCellValueExplicit(
  99. "D{$itemRow}",
  100. (string) $item->catalogItem?->article,
  101. DataType::TYPE_STRING,
  102. );
  103. $itemsSheet->setCellValue(
  104. "E{$itemRow}",
  105. $item->catalogItem?->calculator_name ?: $item->catalogItem?->print_name,
  106. );
  107. $itemsSheet->setCellValueExplicit(
  108. "F{$itemRow}",
  109. $item->order_item_number,
  110. DataType::TYPE_STRING,
  111. );
  112. $itemsSheet->setCellValueExplicit(
  113. "G{$itemRow}",
  114. (string) $item->factory_number,
  115. DataType::TYPE_STRING,
  116. );
  117. $itemsSheet->setCellValue(
  118. "H{$itemRow}",
  119. $item->manufacture_date?->format('d.m.Y'),
  120. );
  121. $itemRow++;
  122. }
  123. $row++;
  124. }
  125. });
  126. $lastRow = max(1, $row - 1);
  127. $sheet->getStyle("A1:R{$lastRow}")->getBorders()->getAllBorders()->setBorderStyle(Border::BORDER_THIN);
  128. $sheet->getStyle("A1:R{$lastRow}")->getAlignment()->setWrapText(true)->setVertical(Alignment::VERTICAL_TOP);
  129. $sheet->freezePane('A2');
  130. $sheet->setAutoFilter("A1:R{$lastRow}");
  131. foreach (range('A', 'R') as $column) {
  132. $sheet->getColumnDimension($column)->setWidth(in_array($column, ['D', 'E', 'Q', 'R'], true) ? 36 : 18);
  133. }
  134. $lastItemRow = max(1, $itemRow - 1);
  135. $itemsSheet->getStyle("A1:H{$lastItemRow}")->getBorders()->getAllBorders()->setBorderStyle(Border::BORDER_THIN);
  136. $itemsSheet->getStyle("A1:H{$lastItemRow}")->getAlignment()->setWrapText(true)->setVertical(Alignment::VERTICAL_TOP);
  137. $itemsSheet->freezePane('A2');
  138. $itemsSheet->setAutoFilter("A1:H{$lastItemRow}");
  139. foreach (range('A', 'H') as $column) {
  140. $itemsSheet->getColumnDimension($column)->setWidth(in_array($column, ['D', 'E', 'F'], true) ? 30 : 18);
  141. }
  142. $spreadsheet->setActiveSheetIndex(0);
  143. $filename = 'График_заказов_'.now()->format('Y-m-d_H-i-s').'.xlsx';
  144. $path = 'generated/production-orders/'.$userId.'/'.Str::uuid().'/'.$filename;
  145. Storage::disk('local')->makeDirectory(dirname($path));
  146. (new Xlsx($spreadsheet))->save(Storage::disk('local')->path($path));
  147. $spreadsheet->disconnectWorksheets();
  148. $file = File::query()->create([
  149. 'user_id' => $userId,
  150. 'original_name' => $filename,
  151. 'mime_type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  152. 'path' => $path,
  153. 'link' => '',
  154. 'is_generated' => true,
  155. ]);
  156. $file->update(['link' => route('schedule.orders.files.download', $file)]);
  157. return $file;
  158. }
  159. private function equipmentSummary(ProductionOrder $order): string
  160. {
  161. return $order->items
  162. ->groupBy(static fn ($item): string => implode('|', [
  163. $item->catalogItem?->article,
  164. $item->catalogItem?->calculator_name ?: $item->catalogItem?->print_name,
  165. ]))
  166. ->map(static function ($items): string {
  167. $item = $items->first();
  168. $name = $item->catalogItem?->calculator_name ?: $item->catalogItem?->print_name;
  169. $label = collect([$item->catalogItem?->article, $name])
  170. ->filter(static fn ($value): bool => filled($value))
  171. ->implode(' — ');
  172. return ($label !== '' ? $label.' — ' : '').$items->count().' шт.';
  173. })
  174. ->implode("\n");
  175. }
  176. }