Explorar el Código

added Schedule export to excel and pdf

Alexander Musikhin hace 2 meses
padre
commit
8c1d2de109

+ 6 - 0
Dockerfile

@@ -60,6 +60,12 @@ RUN apt-get clean \
     && rm -fr /tmp/* \
     && rm -fr /var/tmp/*
 
+# Set the locale
+RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
+ENV LANG en_US.UTF-8
+ENV LANGUAGE en_US:en
+ENV LC_ALL en_US.UTF-8
+
 #
 RUN usermod -u ${UID} www-data
 

+ 21 - 0
app/Http/Controllers/ScheduleController.php

@@ -2,10 +2,13 @@
 
 namespace App\Http\Controllers;
 
+use App\Events\SendWebSocketMessageEvent;
 use App\Helpers\DateHelper;
 use App\Http\Requests\CreateScheduleFromOrderRequest;
 use App\Http\Requests\CreateScheduleFromReclamationRequest;
+use App\Http\Requests\ExportScheduleRequest;
 use App\Http\Requests\UpdateScheduleRequest;
+use App\Jobs\ExportScheduleJob;
 use App\Models\Dictionary\Area;
 use App\Models\Dictionary\District;
 use App\Models\Order;
@@ -214,4 +217,22 @@ class ScheduleController extends Controller
         $schedule->delete();
         return redirect()->back();
     }
+
+    public function export(ExportScheduleRequest $request)
+    {
+        $startDate = $request->validated()['start_date'];
+        $endDate   = $request->validated()['end_date'];
+
+        $schedules = Schedule::query()
+            ->where('installation_date', '>=', $startDate)
+            ->where('installation_date', '<=', $endDate)
+            ->orderBy('installation_date')
+            ->orderBy('brigadier_id')
+            ->get();
+
+        ExportScheduleJob::dispatch($schedules, $request->user()->id);
+        return redirect()->route('schedule.index', ['week' => $request->validated()['week']])
+            ->with(['success' => 'Задача генерации графика создана!']);
+
+    }
 }

+ 30 - 0
app/Http/Requests/ExportScheduleRequest.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class ExportScheduleRequest extends FormRequest
+{
+    /**
+     * Determine if the user is authorized to make this request.
+     */
+    public function authorize(): bool
+    {
+        return hasRole('admin');
+    }
+
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
+     */
+    public function rules(): array
+    {
+        return [
+            'start_date'    => 'required|date_format:Y-m-d',
+            'end_date'      => 'required|date_format:Y-m-d',
+            'week'          => 'required|integer',
+        ];
+    }
+}

+ 40 - 0
app/Jobs/ExportScheduleJob.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace App\Jobs;
+
+use App\Events\SendWebSocketMessageEvent;
+use App\Services\ExportScheduleService;
+use Exception;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Queue\Queueable;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\Log;
+
+class ExportScheduleJob implements ShouldQueue
+{
+    use Queueable;
+
+    /**
+     * Create a new job instance.
+     */
+    public function __construct(
+        private readonly Collection $schedules,
+        private readonly int $userId,
+    )
+    {}
+
+    /**
+     * Execute the job.
+     */
+    public function handle(): void
+    {
+        try {
+            $link = (new ExportScheduleService())->handle($this->schedules, $this->userId);
+            Log::info('Export schedule finished!');
+            event(new SendWebSocketMessageEvent('Экспорт графика готов!', $this->userId, ['success' => true, 'link' => $link]));
+        } catch (Exception $e) {
+            Log::error('Export schedule failed! ' . $e->getMessage());
+            event(new SendWebSocketMessageEvent('Ошибка экспорта графика! ', $this->userId, ['error' => $e->getMessage()]));
+        }
+    }
+}

+ 114 - 0
app/Services/ExportScheduleService.php

@@ -0,0 +1,114 @@
+<?php
+
+namespace App\Services;
+
+use App\Helpers\DateHelper;
+use App\Models\Product;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\Storage;
+use Illuminate\Support\Str;
+use PhpOffice\PhpSpreadsheet\IOFactory;
+use PhpOffice\PhpSpreadsheet\Style\Alignment;
+use PhpOffice\PhpSpreadsheet\Style\Border;
+use PhpOffice\PhpSpreadsheet\Style\Color;
+use PhpOffice\PhpSpreadsheet\Style\Fill;
+use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
+use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
+
+class ExportScheduleService
+{
+
+
+    /**
+     * @throws \Exception
+     */
+    public function handle(Collection $schedules, int $userId): string
+    {
+
+        $inputFileType = 'Xlsx'; // Xlsx - Xml - Ods - Slk - Gnumeric - Csv
+        $inputFileName = './templates/Schedule.xlsx';
+
+        $reader = IOFactory::createReader($inputFileType);
+        $spreadsheet = $reader->load($inputFileName);
+        $sheet = $spreadsheet->getActiveSheet();
+        $sheet->getPageSetup()->setOrientation(PageSetup::ORIENTATION_LANDSCAPE);
+
+        $i = 3;
+        $first = true;
+        $from = '-';
+        $prevInstDate = '';
+        $j = 1;
+        foreach ($schedules as $schedule) {
+            if($first) {
+                $first = false;
+                $from = $schedule->installation_date;
+                $prevInstDate = $schedule->installation_date;
+
+            } elseif($prevInstDate === $schedule->installation_date) {
+                $j++;
+            } else {
+                if($j > 1) {
+                    $sheet->mergeCells('A' . $i - $j . ':A' . $i - 1);
+                    $sheet->mergeCells('B' . $i - $j . ':B' . $i - 1);
+                }
+                $j = 1;
+                $prevInstDate = $schedule->installation_date;
+            }
+
+            $sheet->setCellValue('A' . $i, DateHelper::getHumanDayOfWeek($schedule->installation_date));
+            $sheet->setCellValue('B' . $i, DateHelper::getHumanDate($schedule->installation_date, true));
+
+
+            $sheet->setCellValue('C' . $i, $schedule->address_code);
+            $sheet->setCellValue('D' . $i, $schedule->district->shortname);
+            $sheet->setCellValue('E' . $i, $schedule->area->name);
+            $sheet->setCellValue('F' . $i, $schedule->object_address);
+            $sheet->setCellValue('G' . $i, $schedule->object_type);
+            $sheet->setCellValue('H' . $i, Str::trim($schedule->mafs));
+            $sheet->setCellValue('I' . $i, $schedule->mafs_count);
+            $sheet->setCellValue('J' . $i, $schedule->brigadier->name);
+            $sheet->setCellValue('K' . $i, $schedule->comment);
+
+            $sheet->getStyle('C' . $i . ':K' . $i)->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setRGB(Str::replace('#', '', $schedule->brigadier->color));
+            $i++;
+        }
+        // merge last cells if $j > 1
+        if($j > 1) {
+            $sheet->mergeCells('A' . $i - $j . ':A' . $i - 1);
+            $sheet->mergeCells('B' . $i - $j . ':B' . $i - 1);
+        }
+
+        $sheet->getStyle('A2:B' . $i -1)->getAlignment()->setTextRotation(90);
+
+        $sheet->getStyle('A2:K' . $i - 1)->getBorders()->getAllBorders()->setBorderStyle(Border::BORDER_THIN)->setColor(new Color('777777'));
+        $sheet->getStyle('A2:K' . $i - 1)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
+        $sheet->getStyle('C2:K' . $i - 1)->getAlignment()->setWrapText(true);
+
+        $fromText = (DateHelper::isDate($from)) ? DateHelper::getHumanDate($from) : '-';
+        $toText = (isset($schedule) && $schedule->installation_date) ? DateHelper::getHumanDate($schedule->installation_date) : '-';
+        $header = 'График монтажей с ' . $fromText . ' по ' . $toText;
+
+        $sheet->setCellValue('A1', $header);
+        $sheet->getStyle('A1')->getFont()->setBold(true);
+        $fileName = $header . '.xlsx';
+
+        $writer = new Xlsx($spreadsheet);
+        $fd = 'export/schedule/tmp';
+        Storage::disk('public')->makeDirectory($fd);
+        $fp = storage_path('app/public/export/schedule/') . '/tmp/' . $fileName;
+        Storage::disk('public')->delete($fd . '/' . $fileName);
+        $writer->save($fp);
+        PdfConverterClient::convert($fp);
+
+        // create zip archive
+        $fileModel = (new FileService())->createZipArchive($fd, Str::replace('.xlsx', '.zip', $fileName), $userId);
+
+        //   remove temp files
+        Storage::disk('public')->deleteDirectory($fd);
+
+        // return link
+        return $fileModel?->link ?? '';
+
+    }
+}

+ 11 - 0
resources/views/schedule/index.blade.php

@@ -40,6 +40,17 @@
                             <i class="bi bi-arrow-right"></i>
                         </button>
                     </div>
+                    @if(hasRole('admin'))
+                    <div class="p-2 ms-3">
+                        <form action="{{ route('schedule.export') }}" method="post">
+                            @csrf
+                            <input type="hidden" name="start_date" value="{{ $weekDates['mon'] }}">
+                            <input type="hidden" name="end_date" value="{{ $weekDates['sun'] }}">
+                            <input type="hidden" name="week" value="{{ $weekNumber }}">
+                            <button type="submit" class="btn btn-sm btn-primary" id="exportScheduleButton">Экспорт</button>
+                        </form>
+                    </div>
+                    @endif
                 </div>
             </div>
         </div>

+ 1 - 0
routes/web.php

@@ -136,6 +136,7 @@ Route::middleware('auth:web')->group(function () {
         Route::post('schedule/create_from_order', [ScheduleController::class, 'createFromOrder'])->name('schedule.create-from-order');
         Route::post('schedule/create_from_reclamation', [ScheduleController::class, 'createFromReclamation'])->name('schedule.create-from-reclamation');
         Route::post('schedule/update', [ScheduleController::class, 'update'])->name('schedule.update');
+        Route::post('schedule/export', [ScheduleController::class, 'export'])->name('schedule.export');
         Route::delete('schedule/delete/{schedule}', [ScheduleController::class, 'delete'])->name('schedule.delete');
 
         Route::get('order/create', [OrderController::class, 'create'])->name('order.create');

BIN
templates/Schedule.xlsx