|
|
@@ -18,6 +18,7 @@ use Illuminate\Support\Collection;
|
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
use Illuminate\Support\Str;
|
|
|
use PhpOffice\PhpSpreadsheet\IOFactory;
|
|
|
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
|
|
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
|
|
|
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
|
|
|
|
|
@@ -48,42 +49,47 @@ class GenerateDocumentsService
|
|
|
->where('year', $order->year)
|
|
|
->get();
|
|
|
$order->setRelation('products_sku', $products_sku);
|
|
|
- $articles = [];
|
|
|
- Storage::disk('public')->makeDirectory('orders/' . $order->id . '/tmp/Схемы сборки/');
|
|
|
-
|
|
|
- foreach ($products_sku as $sku) {
|
|
|
- if (!in_array($sku->product->article, $articles)) {
|
|
|
- $articles[] = $sku->product->article;
|
|
|
- // find and copy scheme files to installation directory
|
|
|
- if (file_exists($techDocsPath . $sku->product->article . '/')) {
|
|
|
- foreach (Storage::disk('base')->allFiles('public/images/tech-docs/' . $sku->product->article) as $p) {
|
|
|
- $content = Storage::disk('base')->get($p);
|
|
|
- Storage::disk('public')->put('orders/' . $order->id . '/tmp/Схемы сборки/' . basename($p), $content);
|
|
|
+ $tmpRoot = 'orders/' . $order->id . '/tmp';
|
|
|
+
|
|
|
+ try {
|
|
|
+ $articles = [];
|
|
|
+ Storage::disk('public')->makeDirectory($tmpRoot . '/Схемы сборки/');
|
|
|
+
|
|
|
+ foreach ($products_sku as $sku) {
|
|
|
+ if (!in_array($sku->product->article, $articles)) {
|
|
|
+ $articles[] = $sku->product->article;
|
|
|
+ // find and copy scheme files to installation directory
|
|
|
+ if (file_exists($techDocsPath . $sku->product->article . '/')) {
|
|
|
+ foreach (Storage::disk('base')->allFiles('public/images/tech-docs/' . $sku->product->article) as $p) {
|
|
|
+ $content = Storage::disk('base')->get($p);
|
|
|
+ Storage::disk('public')->put($tmpRoot . '/Схемы сборки/' . basename($p), $content);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- $orderDocumentsDir = 'orders/' . $order->id . '/tmp/Документы площадки';
|
|
|
- foreach ($order->documents as $document) {
|
|
|
- if ($this->shouldSkipArchiveDocument($document)) {
|
|
|
- continue;
|
|
|
+ $orderDocumentsDir = $tmpRoot . '/Документы площадки';
|
|
|
+ foreach ($order->documents as $document) {
|
|
|
+ if ($this->shouldSkipArchiveDocument($document)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $this->copyFileToDir($document->path, $orderDocumentsDir, $document->original_name);
|
|
|
}
|
|
|
- $this->copyFileToDir($document->path, $orderDocumentsDir, $document->original_name);
|
|
|
- }
|
|
|
|
|
|
- // generate xlsx order file
|
|
|
- $this->generateOrderForMount($order);
|
|
|
+ // generate xlsx order file
|
|
|
+ $this->generateOrderForMount($order);
|
|
|
|
|
|
- // create zip archive
|
|
|
- $fileModel = (new FileService())->createZipArchive('orders/' . $order->id . '/tmp', self::INSTALL_FILENAME . fileName($order->common_name) . '.zip', $userId);
|
|
|
+ // create zip archive
|
|
|
+ $fileModel = (new FileService())->createZipArchive($tmpRoot, self::INSTALL_FILENAME . fileName($order->common_name) . '.zip', $userId);
|
|
|
|
|
|
- // remove temp files
|
|
|
- Storage::disk('public')->deleteDirectory('orders/' . $order->id . '/tmp');
|
|
|
- $order->documents()->syncWithoutDetaching($fileModel);
|
|
|
+ $order->documents()->syncWithoutDetaching($fileModel);
|
|
|
|
|
|
- // return link
|
|
|
- return $fileModel?->link ?? '';
|
|
|
+ // return link
|
|
|
+ return $fileModel?->link ?? '';
|
|
|
+ } finally {
|
|
|
+ // remove temp files
|
|
|
+ Storage::disk('public')->deleteDirectory($tmpRoot);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private function generateOrderForMount(Order $order): void
|
|
|
@@ -142,61 +148,65 @@ class GenerateDocumentsService
|
|
|
->get();
|
|
|
$order->setRelation('products_sku', $productsSku);
|
|
|
|
|
|
- $articles = [];
|
|
|
- Storage::disk('public')->makeDirectory('orders/' . $order->id . '/tmp/ПАСПОРТ/');
|
|
|
- Storage::disk('public')->makeDirectory('orders/' . $order->id . '/tmp/СЕРТИФИКАТ/');
|
|
|
- Storage::disk('public')->makeDirectory('orders/' . $order->id . '/tmp/ФОТО ПСТ/');
|
|
|
- Storage::disk('public')->makeDirectory('orders/' . $order->id . '/tmp/ФОТО ТН/');
|
|
|
-
|
|
|
- // copy app photos
|
|
|
- foreach ($order->photos as $photo) {
|
|
|
- $from = $photo->path;
|
|
|
- $to = 'orders/' . $order->id . '/tmp/ФОТО ПСТ/' . $photo->original_name;
|
|
|
- if (!Storage::disk('public')->exists($to)) {
|
|
|
- Storage::disk('public')->copy($from, $to);
|
|
|
- }
|
|
|
- }
|
|
|
+ $tmpRoot = 'orders/' . $order->id . '/tmp';
|
|
|
+
|
|
|
+ try {
|
|
|
+ Storage::disk('public')->makeDirectory($tmpRoot . '/ПАСПОРТ/');
|
|
|
+ Storage::disk('public')->makeDirectory($tmpRoot . '/СЕРТИФИКАТ/');
|
|
|
+ Storage::disk('public')->makeDirectory($tmpRoot . '/ФОТО ПСТ/');
|
|
|
+ Storage::disk('public')->makeDirectory($tmpRoot . '/ФОТО ТН/');
|
|
|
|
|
|
- foreach ($productsSku as $sku) {
|
|
|
- // copy certificates
|
|
|
- if ($sku->product->certificate_id) {
|
|
|
- $from = $sku->product->certificate->path;
|
|
|
- $to = 'orders/' . $order->id . '/tmp/СЕРТИФИКАТ/' . $sku->product->certificate->original_name;
|
|
|
+ // copy app photos
|
|
|
+ foreach ($order->photos as $photo) {
|
|
|
+ $from = $photo->path;
|
|
|
+ $to = $tmpRoot . '/ФОТО ПСТ/' . $photo->original_name;
|
|
|
if (!Storage::disk('public')->exists($to)) {
|
|
|
Storage::disk('public')->copy($from, $to);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // copy passport
|
|
|
- if ($sku->passport_id) {
|
|
|
- $from = $sku->passport->path;
|
|
|
- $to = 'orders/' . $order->id . '/tmp/ПАСПОРТ/';
|
|
|
- if (!Storage::disk('public')->exists($to . $sku->passport->original_name)) {
|
|
|
- $f = Storage::disk('public')->get($from);
|
|
|
- $ext = \File::extension($sku->passport->original_name);
|
|
|
- $targetName = $to . 'Паспорт ' . $sku->factory_number . ' арт. ' . $sku->product->article . '.' . $ext;
|
|
|
- Storage::disk('public')->put($targetName, $f);
|
|
|
+ foreach ($productsSku as $sku) {
|
|
|
+ // copy certificates
|
|
|
+ if ($sku->product->certificate_id) {
|
|
|
+ $from = $sku->product->certificate->path;
|
|
|
+ $to = $tmpRoot . '/СЕРТИФИКАТ/' . $sku->product->certificate->original_name;
|
|
|
+ if (!Storage::disk('public')->exists($to)) {
|
|
|
+ Storage::disk('public')->copy($from, $to);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- }
|
|
|
+ // copy passport
|
|
|
+ if ($sku->passport_id) {
|
|
|
+ $from = $sku->passport->path;
|
|
|
+ $to = $tmpRoot . '/ПАСПОРТ/';
|
|
|
+ if (!Storage::disk('public')->exists($to . $sku->passport->original_name)) {
|
|
|
+ $f = Storage::disk('public')->get($from);
|
|
|
+ $ext = \File::extension($sku->passport->original_name);
|
|
|
+ $targetName = $to . 'Паспорт ' . $sku->factory_number . ' арт. ' . $sku->product->article . '.' . $ext;
|
|
|
+ Storage::disk('public')->put($targetName, $f);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // generate xlsx order files
|
|
|
- $this->generateStatement($order);
|
|
|
- $this->generateQualityDeclaration($order);
|
|
|
- $this->generateInventory($order);
|
|
|
- $this->generatePassport($order);
|
|
|
+ }
|
|
|
+
|
|
|
+ // generate xlsx order files
|
|
|
+ $this->generateStatement($order);
|
|
|
+ $this->generateQualityDeclaration($order);
|
|
|
+ $this->generateInventory($order);
|
|
|
+ $this->generatePassport($order);
|
|
|
|
|
|
|
|
|
- // create zip archive
|
|
|
- $fileModel = (new FileService())->createZipArchive('orders/' . $order->id . '/tmp', self::HANDOVER_FILENAME . fileName($order->common_name) . '.zip', $userId);
|
|
|
+ // create zip archive
|
|
|
+ $fileModel = (new FileService())->createZipArchive($tmpRoot, self::HANDOVER_FILENAME . fileName($order->common_name) . '.zip', $userId);
|
|
|
|
|
|
- // remove temp files
|
|
|
- Storage::disk('public')->deleteDirectory('orders/' . $order->id . '/tmp');
|
|
|
- $order->documents()->syncWithoutDetaching($fileModel);
|
|
|
+ $order->documents()->syncWithoutDetaching($fileModel);
|
|
|
|
|
|
- // return link
|
|
|
- return $fileModel?->link ?? '';
|
|
|
+ // return link
|
|
|
+ return $fileModel?->link ?? '';
|
|
|
+ } finally {
|
|
|
+ // remove temp files
|
|
|
+ Storage::disk('public')->deleteDirectory($tmpRoot);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private function generateStatement(Order $order): void
|
|
|
@@ -248,21 +258,25 @@ class GenerateDocumentsService
|
|
|
|
|
|
private function generateQualityDeclaration(Order $order): void
|
|
|
{
|
|
|
+ $rowsPerDeclaration = 57;
|
|
|
$inputFileType = 'Xlsx';
|
|
|
$inputFileName = './templates/QualityDeclaration.xlsx';
|
|
|
|
|
|
$reader = IOFactory::createReader($inputFileType);
|
|
|
$spreadsheet = $reader->load($inputFileName);
|
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
|
+ $sheet->getPageSetup()->setFitToWidth(1);
|
|
|
+ $sheet->getPageSetup()->setFitToHeight(0);
|
|
|
|
|
|
$address = 'г. Москва, ' . $order->district->shortname . ', район ' . $order->area->name . ', по адресу: ' . (filled(trim((string) $order->name)) ? $order->name : $order->object_address);
|
|
|
$i = 1; // start of table
|
|
|
$n = 1;
|
|
|
foreach ($order->products_sku as $sku) {
|
|
|
if ($n++ > 1) {
|
|
|
- $range = 'A' . $i . ':I' . $i + 56;
|
|
|
- $i = $i + 57;
|
|
|
+ $range = 'A' . $i . ':I' . ($i + $rowsPerDeclaration - 1);
|
|
|
+ $i += $rowsPerDeclaration;
|
|
|
ExcelHelper::copyRows($sheet, $range, 'A' . $i);
|
|
|
+ $sheet->setBreak('A' . ($i - 1), Worksheet::BREAK_ROW);
|
|
|
|
|
|
// add header img
|
|
|
$drawing = new Drawing();
|
|
|
@@ -279,16 +293,15 @@ class GenerateDocumentsService
|
|
|
}
|
|
|
|
|
|
// document date?
|
|
|
- $sheet->setCellValue('A' . $i + 7, DateHelper::getHumanDate(date('Y-m-d'), true));
|
|
|
+ $sheet->setCellValue('A' . ($i + 7), DateHelper::getHumanDate(date('Y-m-d'), true));
|
|
|
|
|
|
- $sheet->setCellValue('B' . $i + 16, $sku->product->passport_name);
|
|
|
- $sheet->setCellValue('C' . $i + 18, $sku->rfid);
|
|
|
- $sheet->setCellValue('C' . $i + 20, $address);
|
|
|
-
|
|
|
- // add page break and copy prev page
|
|
|
+ $sheet->setCellValue('B' . ($i + 16), $sku->product->passport_name);
|
|
|
+ $sheet->setCellValue('C' . ($i + 18), $sku->rfid);
|
|
|
+ $sheet->setCellValue('C' . ($i + 20), $address);
|
|
|
|
|
|
|
|
|
}
|
|
|
+ $sheet->getPageSetup()->setPrintArea('A1:I' . ($i + $rowsPerDeclaration - 1));
|
|
|
|
|
|
// save file
|
|
|
$fileName = '2.Декларация качества.xlsx';
|
|
|
@@ -390,39 +403,44 @@ class GenerateDocumentsService
|
|
|
$baseDir = 'reclamations/' . $reclamation->id . '/tmp/' . fileName($reclamation->order->object_address);
|
|
|
$photosDir = $baseDir . '/ФОТО НАРУШЕНИЯ';
|
|
|
|
|
|
- Storage::disk('public')->makeDirectory($photosDir);
|
|
|
+ $tmpRoot = 'reclamations/' . $reclamation->id . '/tmp';
|
|
|
|
|
|
- // copy photos
|
|
|
- foreach ($reclamation->photos_before as $photo) {
|
|
|
- $from = $photo->path;
|
|
|
- $to = $photosDir . '/' . $photo->original_name;
|
|
|
- if (!Storage::disk('public')->exists($to)) {
|
|
|
- Storage::disk('public')->copy($from, $to);
|
|
|
- }
|
|
|
- }
|
|
|
+ try {
|
|
|
+ Storage::disk('public')->makeDirectory($photosDir);
|
|
|
|
|
|
- foreach ($reclamation->documents as $document) {
|
|
|
- if ($this->shouldSkipArchiveDocument($document)) {
|
|
|
- continue;
|
|
|
+ // copy photos
|
|
|
+ foreach ($reclamation->photos_before as $photo) {
|
|
|
+ $from = $photo->path;
|
|
|
+ $to = $photosDir . '/' . $photo->original_name;
|
|
|
+ if (!Storage::disk('public')->exists($to)) {
|
|
|
+ Storage::disk('public')->copy($from, $to);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- $this->copyFileToDir($document->path, $baseDir, $document->original_name);
|
|
|
- }
|
|
|
+ foreach ($reclamation->documents as $document) {
|
|
|
+ if ($this->shouldSkipArchiveDocument($document)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->copyFileToDir($document->path, $baseDir, $document->original_name);
|
|
|
+ }
|
|
|
|
|
|
- // create xls and pdf
|
|
|
- $this->generateReclamationOrder($reclamation);
|
|
|
- $this->generateReclamationAct($reclamation);
|
|
|
- $this->generateReclamationGuarantee($reclamation);
|
|
|
+ // create xls and pdf
|
|
|
+ $this->generateReclamationOrder($reclamation);
|
|
|
+ $this->generateReclamationAct($reclamation);
|
|
|
+ $this->generateReclamationGuarantee($reclamation);
|
|
|
|
|
|
- // create zip archive
|
|
|
- $fileModel = (new FileService())->createZipArchive('reclamations/' . $reclamation->id . '/tmp', self::RECLAMATION_FILENAME . fileName($reclamation->order->object_address) . '.zip', $userId);
|
|
|
+ // create zip archive
|
|
|
+ $fileModel = (new FileService())->createZipArchive($tmpRoot, self::RECLAMATION_FILENAME . fileName($reclamation->order->object_address) . '.zip', $userId);
|
|
|
|
|
|
- // remove temp files
|
|
|
- Storage::disk('public')->deleteDirectory('reclamations/' . $reclamation->id . '/tmp');
|
|
|
- $reclamation->documents()->syncWithoutDetaching($fileModel);
|
|
|
+ $reclamation->documents()->syncWithoutDetaching($fileModel);
|
|
|
|
|
|
- // return link
|
|
|
- return $fileModel?->link ?? '';
|
|
|
+ // return link
|
|
|
+ return $fileModel?->link ?? '';
|
|
|
+ } finally {
|
|
|
+ // remove temp files
|
|
|
+ Storage::disk('public')->deleteDirectory($tmpRoot);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -443,34 +461,37 @@ class GenerateDocumentsService
|
|
|
$beforeDir = $baseDir . '/Фотографии проблемы';
|
|
|
$afterDir = $baseDir . '/Фотографии после устранения';
|
|
|
|
|
|
- Storage::disk('public')->makeDirectory($beforeDir);
|
|
|
- Storage::disk('public')->makeDirectory($afterDir);
|
|
|
+ try {
|
|
|
+ Storage::disk('public')->makeDirectory($beforeDir);
|
|
|
+ Storage::disk('public')->makeDirectory($afterDir);
|
|
|
|
|
|
- $this->copyPhotosWithEmptyFallback($reclamation->photos_before, $beforeDir);
|
|
|
- $this->copyPhotosWithEmptyFallback($reclamation->photos_after, $afterDir);
|
|
|
+ $this->copyPhotosWithEmptyFallback($reclamation->photos_before, $beforeDir);
|
|
|
+ $this->copyPhotosWithEmptyFallback($reclamation->photos_after, $afterDir);
|
|
|
|
|
|
- foreach ($reclamation->documents as $document) {
|
|
|
- if ($this->shouldSkipDocumentForPaymentPack($document)) {
|
|
|
- continue;
|
|
|
+ foreach ($reclamation->documents as $document) {
|
|
|
+ if ($this->shouldSkipDocumentForPaymentPack($document)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $this->copyFileToDir($document->path, $baseDir, $document->original_name);
|
|
|
}
|
|
|
- $this->copyFileToDir($document->path, $baseDir, $document->original_name);
|
|
|
- }
|
|
|
|
|
|
- foreach ($reclamation->acts as $act) {
|
|
|
- $this->copyFileToDir($act->path, $baseDir, $act->original_name);
|
|
|
- }
|
|
|
+ foreach ($reclamation->acts as $act) {
|
|
|
+ $this->copyFileToDir($act->path, $baseDir, $act->original_name);
|
|
|
+ }
|
|
|
|
|
|
- foreach ($reclamation->order?->statements ?? [] as $statement) {
|
|
|
- $this->copyFileToDir($statement->path, $baseDir, $statement->original_name);
|
|
|
- }
|
|
|
+ foreach ($reclamation->order?->statements ?? [] as $statement) {
|
|
|
+ $this->copyFileToDir($statement->path, $baseDir, $statement->original_name);
|
|
|
+ }
|
|
|
|
|
|
- $archiveName = 'Пакет документов на оплату - ' . fileName($reclamation->order->object_address) . '.zip';
|
|
|
- $fileModel = (new FileService())->createZipArchive($tmpRoot, $archiveName, $userId);
|
|
|
+ $archiveName = 'Пакет документов на оплату - ' . fileName($reclamation->order->object_address) . '.zip';
|
|
|
+ $fileModel = (new FileService())->createZipArchive($tmpRoot, $archiveName, $userId);
|
|
|
|
|
|
- Storage::disk('public')->deleteDirectory($tmpRoot);
|
|
|
- $reclamation->documents()->syncWithoutDetaching($fileModel);
|
|
|
+ $reclamation->documents()->syncWithoutDetaching($fileModel);
|
|
|
|
|
|
- return $fileModel?->link ?? '';
|
|
|
+ return $fileModel?->link ?? '';
|
|
|
+ } finally {
|
|
|
+ Storage::disk('public')->deleteDirectory($tmpRoot);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -610,25 +631,30 @@ class GenerateDocumentsService
|
|
|
public function generateFilePack(Collection $files, int $userId, string $name = 'files'): \App\Models\File
|
|
|
{
|
|
|
$dir = Str::random(2);
|
|
|
- Storage::disk('public')->makeDirectory('files/' . $dir . '/tmp/');
|
|
|
-
|
|
|
- // copy files
|
|
|
- foreach ($files as $file) {
|
|
|
- $from = $file->path;
|
|
|
- $to = 'files/' . $dir . '/tmp/' . $file->original_name;
|
|
|
- if (!Storage::disk('public')->exists($to)) {
|
|
|
- Storage::disk('public')->copy($from, $to);
|
|
|
+ $tmpRoot = 'files/' . $dir . '/tmp';
|
|
|
+
|
|
|
+ try {
|
|
|
+ Storage::disk('public')->makeDirectory($tmpRoot . '/');
|
|
|
+
|
|
|
+ // copy files
|
|
|
+ foreach ($files as $file) {
|
|
|
+ $from = $file->path;
|
|
|
+ $to = $tmpRoot . '/' . $file->original_name;
|
|
|
+ if (!Storage::disk('public')->exists($to)) {
|
|
|
+ Storage::disk('public')->copy($from, $to);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- // create zip archive
|
|
|
- $fileModel = (new FileService())->createZipArchive('files/' . $dir . '/tmp', $name .'_' . date('Y-m-d_h-i-s') . '.zip', $userId);
|
|
|
+ // create zip archive
|
|
|
+ $fileModel = (new FileService())->createZipArchive($tmpRoot, $name .'_' . date('Y-m-d_h-i-s') . '.zip', $userId);
|
|
|
|
|
|
- // remove temp files
|
|
|
- Storage::disk('public')->deleteDirectory('files/' . $dir . '/tmp');
|
|
|
+ // return link
|
|
|
+ return $fileModel;
|
|
|
+ } finally {
|
|
|
+ // remove temp files
|
|
|
+ Storage::disk('public')->deleteDirectory($tmpRoot);
|
|
|
+ }
|
|
|
|
|
|
- // return link
|
|
|
- return $fileModel;
|
|
|
}
|
|
|
|
|
|
private function copyPhotosWithEmptyFallback(Collection $photos, string $targetDir): void
|