İlk temizlik tamamlandı bir önceki projeden
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
<?php function active_projects() {
|
||||
return db("weld_logs")->whereNotNull("project")->groupBy("project")->get()->pluck("project")->toArray();
|
||||
} ?>
|
||||
@@ -0,0 +1,448 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Register Creator için Excel tablosuna yeni satır ekleme fonksiyonu.
|
||||
*
|
||||
* Bu fonksiyon belge bilgilerini alarak Excel tablosuna formatlı bir şekilde yeni satır ekler,
|
||||
* ilgili PDF dosyasını kopyalar ve log kaydı oluşturur.
|
||||
*
|
||||
* @param array $search Aranılan dosya yolları
|
||||
* @param array $selectDocument Seçilen doküman bilgileri (title, path vs.)
|
||||
* @param string $fullFolder Hedef klasör yolu
|
||||
* @param string $lineNumber Hat numarası veya benzeri tanımlayıcı
|
||||
* @param string $documentDate Doküman tarihi
|
||||
* @param int $rowNo Satır numarası (sıra)
|
||||
* @param object $sheet PhpSpreadsheet nesnesi
|
||||
* @param int $currentRow Mevcut satır pozisyonu
|
||||
* @param bool $override Mevcut dosyaların üzerine yazılıp yazılmayacağı
|
||||
*
|
||||
* @return int Yeni eklenen satırın sonraki pozisyonu veya satır eklenemediyse mevcut pozisyon
|
||||
*/
|
||||
function addRowInTable($search, $selectDocument, $fullFolder, $lineNumber, $documentDate, $rowNo, &$sheet, $currentRow, $override = false)
|
||||
{
|
||||
try {
|
||||
// Log başlangıcı
|
||||
$logPrefix = "[ROW-$rowNo]";
|
||||
Log::debug("$logPrefix Processing document: " . $selectDocument['title2'] . ', Line: ' . $lineNumber);
|
||||
|
||||
// Aynı rapor numarası için zaten satır eklenmiş mi kontrol et
|
||||
static $addedReports = [];
|
||||
$reportKey = $selectDocument['title2'] . '_' . $lineNumber;
|
||||
|
||||
if (in_array($reportKey, $addedReports)) {
|
||||
Log::debug("$logPrefix Duplicate report detected, skipping: " . $selectDocument['title2'] . ' - ' . $lineNumber);
|
||||
|
||||
// Tekrarlı rapor için basit log
|
||||
try {
|
||||
$fullFolder = str_replace("storage/documents/", "", $fullFolder);
|
||||
$duplicateLog = "🔄 DUPLICATE: " . $selectDocument['title2'] . ' - ' . $lineNumber . "\n";
|
||||
Storage::append($fullFolder . 'log.txt', $duplicateLog);
|
||||
} catch (\Throwable $logError) {
|
||||
echo("⚠️ Log write error\n");
|
||||
}
|
||||
|
||||
return $currentRow;
|
||||
}
|
||||
|
||||
// Bu raporu eklenmiş olarak işaretle
|
||||
$addedReports[] = $reportKey;
|
||||
|
||||
$constructor = Cache::get("rc_contractor");
|
||||
$firstPage = Cache::get("rc_firstPage");
|
||||
$lastPage = Cache::get("rc_lastPage");
|
||||
|
||||
$rowTitle = $selectDocument['title2'];
|
||||
|
||||
if(isset($selectDocument['title3'])) {
|
||||
$rowTitle = $selectDocument['title3'];
|
||||
$selectDocument['title2'] = $selectDocument['title3'];
|
||||
}
|
||||
|
||||
if(isset($selectDocument['title4'])) {
|
||||
$rowTitle = $selectDocument['title4'];
|
||||
}
|
||||
|
||||
$convertTerm = $selectDocument['path'];
|
||||
|
||||
if(strpos($convertTerm, "Naks_Consumables") !== false) {
|
||||
$convertTerm = $selectDocument['path'] . '_' . $selectDocument['type'];
|
||||
}
|
||||
|
||||
if(strpos($convertTerm, "Procedure") !== false) {
|
||||
$convertTerm = $lineNumber;
|
||||
}
|
||||
|
||||
|
||||
if(isset($selectDocument['incoming_control_description'])) {
|
||||
$convertTerm = $selectDocument['incoming_control_description'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Get row title safely - convertRu might return array
|
||||
$rowTitleRaw = convertRu($convertTerm);
|
||||
$rowTitle = is_array($rowTitleRaw) ? json_encode($rowTitleRaw) : (string)$rowTitleRaw;
|
||||
|
||||
// Log if conversion returned unexpected type
|
||||
if (is_array($rowTitleRaw)) {
|
||||
Log::warning('convertRu returned array', [
|
||||
'term' => $convertTerm,
|
||||
'result' => $rowTitleRaw
|
||||
]);
|
||||
}
|
||||
|
||||
// Basit dosya kontrolü ve log hazırlığı
|
||||
$foundFiles = [];
|
||||
$notFoundFiles = [];
|
||||
|
||||
foreach ($search as $searchPath) {
|
||||
if (file_exists($searchPath) || Storage::exists(str_replace("storage/documents/", "", $searchPath))) {
|
||||
$foundFiles[] = $searchPath;
|
||||
} else {
|
||||
$notFoundFiles[] = $searchPath;
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($foundFiles)) {
|
||||
// İlk bulunan dosyayı kullan
|
||||
$firstFoundFile = $foundFiles[0];
|
||||
|
||||
// Dosya türü istatistiği
|
||||
$fileExtension = strtolower(pathinfo($firstFoundFile, PATHINFO_EXTENSION));
|
||||
if (!isset($GLOBALS['file_type_stats'])) {
|
||||
$GLOBALS['file_type_stats'] = [];
|
||||
}
|
||||
if (!isset($GLOBALS['file_type_stats'][$fileExtension])) {
|
||||
$GLOBALS['file_type_stats'][$fileExtension] = 0;
|
||||
}
|
||||
$GLOBALS['file_type_stats'][$fileExtension]++;
|
||||
|
||||
$order = $selectDocument['order'] + 1;
|
||||
$addInLineNumber = ['по сварке трубопроводов(ЖСР)'];
|
||||
if(in_array($selectDocument['title2'], $addInLineNumber)) {
|
||||
$fileName = "$order - {$selectDocument['title2']} - $lineNumber.pdf";
|
||||
$fullPath = "$fullFolder"."$fileName";
|
||||
} else {
|
||||
if(isset($selectDocument['file_name'])) {
|
||||
$fileName = "$order - {$selectDocument['file_name']}.pdf";
|
||||
} else {
|
||||
if(isset($selectDocument['title2'])) {
|
||||
$fileName = "$order - {$selectDocument['title2']}.pdf";
|
||||
} else {
|
||||
$fileName = "$order - {$selectDocument['title2']}.pdf";
|
||||
}
|
||||
}
|
||||
$fullPath = "$fullFolder"."$fileName";
|
||||
}
|
||||
Log::debug("File name: " . $fileName);
|
||||
$documentDate = df($documentDate);
|
||||
|
||||
// Sayfa sayısını al
|
||||
$allPath = "{$firstFoundFile}";
|
||||
$command = "pdftk '$allPath' dump_data | grep NumberOfPages";
|
||||
putenv('LANG=ru_RU.UTF-8');
|
||||
$output = shell_exec($command);
|
||||
|
||||
try {
|
||||
$pageCount = (int) trim(explode(" ", $output)[1]);
|
||||
} catch (\Throwable $th) {
|
||||
$pageCount = 1;
|
||||
}
|
||||
|
||||
if($firstPage == 0) {
|
||||
$firstPage = 1;
|
||||
} else {
|
||||
$firstPage = $lastPage + 1;
|
||||
}
|
||||
|
||||
$lastPage = $firstPage + $pageCount - 1;
|
||||
Cache::put("rc_lastPage", $lastPage);
|
||||
Cache::put("rc_firstPage", $firstPage);
|
||||
|
||||
// Basit log formatı oluştur
|
||||
$simpleLog = "";
|
||||
$simpleLog .= "📋 " . ($rowNo) . ". " . $rowTitle . " - " . $lineNumber . " | " . count($foundFiles) . " file(s)\n";
|
||||
|
||||
foreach ($foundFiles as $index => $file) {
|
||||
$simpleLog .= " -- " . basename($file) . "\n";
|
||||
}
|
||||
|
||||
if (!empty($notFoundFiles)) {
|
||||
$simpleLog .= " ❓ Not found: " . count($notFoundFiles) . " file(s)\n";
|
||||
foreach ($notFoundFiles as $index => $file) {
|
||||
$simpleLog .= " -- " . basename($file) . " (missing)\n";
|
||||
}
|
||||
}
|
||||
$simpleLog .= "\n";
|
||||
|
||||
// Sayfa aralığını oluştur
|
||||
if ($pageCount == 1) {
|
||||
if($firstPage == 1) {
|
||||
$pageIndex = $firstPage;
|
||||
} else {
|
||||
$prevPage = $firstPage - 1;
|
||||
$pageIndex = "$prevPage - $firstPage";
|
||||
}
|
||||
} else {
|
||||
$pageIndex = "$firstPage - $lastPage";
|
||||
}
|
||||
|
||||
// Excel'e veri ekle
|
||||
try {
|
||||
$templateRowCells = [];
|
||||
$templateFormulas = [];
|
||||
$templateRow = Cache::get("rc_template_row", $currentRow);
|
||||
|
||||
foreach ($sheet->getRowIterator($templateRow, $templateRow)->current()->getCellIterator() as $cell) {
|
||||
$colIndex = $cell->getColumn();
|
||||
$templateRowCells[$colIndex] = $cell->getValue();
|
||||
|
||||
if ($cell->isFormula()) {
|
||||
$templateFormulas[$colIndex] = $cell->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
$mergedCells = [];
|
||||
foreach ($sheet->getMergeCells() as $mergeRange) {
|
||||
if (preg_match('/^\D*'.$templateRow.'$/', explode(':', $mergeRange)[0])) {
|
||||
$mergedCells[] = $mergeRange;
|
||||
}
|
||||
}
|
||||
|
||||
$sheet->insertNewRowBefore($currentRow + 1, 1);
|
||||
|
||||
$replacements = [];
|
||||
$replacements['{rowNo}'] = $rowNo;
|
||||
$replacements['{rowTitle}'] = $rowTitle;
|
||||
$replacements['{documentReportNumber}'] = $lineNumber;
|
||||
$replacements['{documentDate}'] = $documentDate;
|
||||
$replacements['{constructor}'] = $constructor;
|
||||
$replacements['{pageCount}'] = $pageCount;
|
||||
$replacements['{pageIndex}'] = $pageIndex;
|
||||
|
||||
// Safe get with type checking for all title fields
|
||||
$replacements['{title1}'] = isset($selectDocument['title1'])
|
||||
? (is_array($selectDocument['title1']) ? json_encode($selectDocument['title1']) : (string)$selectDocument['title1'])
|
||||
: '';
|
||||
|
||||
$replacements['{ndt_report_no}'] = isset($selectDocument['title2'])
|
||||
? (is_array($selectDocument['title2']) ? json_encode($selectDocument['title2']) : (string)$selectDocument['title2'])
|
||||
: '';
|
||||
|
||||
$replacements['{pdf_document_title}'] = isset($selectDocument['title3'])
|
||||
? (is_array($selectDocument['title3']) ? json_encode($selectDocument['title3']) : (string)$selectDocument['title3'])
|
||||
: '';
|
||||
|
||||
$replacements['{ndt_register_title}'] = isset($selectDocument['title4'])
|
||||
? (is_array($selectDocument['title4']) ? json_encode($selectDocument['title4']) : (string)$selectDocument['title4'])
|
||||
: '';
|
||||
|
||||
foreach ($templateRowCells as $colIndex => $cellValue) {
|
||||
if (isset($templateFormulas[$colIndex])) {
|
||||
$formula = $templateFormulas[$colIndex];
|
||||
$rowOffset = ($currentRow + 1) - $templateRow;
|
||||
$updatedFormula = preg_replace_callback(
|
||||
'/([A-Z]+)(\d+)/',
|
||||
function($matches) use ($rowOffset) {
|
||||
$col = $matches[1];
|
||||
$row = intval($matches[2]);
|
||||
$row += $rowOffset;
|
||||
return $col . $row;
|
||||
},
|
||||
$formula
|
||||
);
|
||||
$sheet->setCellValue($colIndex . ($currentRow + 1), $updatedFormula);
|
||||
} else {
|
||||
if (is_string($cellValue)) {
|
||||
foreach ($replacements as $placeholder => $replacement) {
|
||||
if (strpos($cellValue, $placeholder) !== false) {
|
||||
$cellValue = str_replace($placeholder, $replacement, $cellValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
$sheet->setCellValue($colIndex . ($currentRow + 1), $cellValue);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($mergedCells as $mergeRange) {
|
||||
$adjustedMergeRange = preg_replace_callback('/\d+/', function($matches) use ($currentRow, $templateRow) {
|
||||
return $matches[0] == $templateRow ? $currentRow + 1 : $matches[0];
|
||||
}, $mergeRange);
|
||||
|
||||
try {
|
||||
$sheet->mergeCells($adjustedMergeRange);
|
||||
} catch (\Throwable $th) {
|
||||
// Hata önemsiz
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($sheet->getRowIterator($templateRow, $templateRow)->current()->getCellIterator() as $cell) {
|
||||
$colIndex = $cell->getColumn();
|
||||
try {
|
||||
$style = $sheet->getStyle($colIndex . $templateRow);
|
||||
$sheet->duplicateStyle($style, $colIndex . ($currentRow + 1));
|
||||
} catch (\Throwable $th) {
|
||||
// Hata önemsiz
|
||||
}
|
||||
}
|
||||
|
||||
$templateRowHeight = $sheet->getRowDimension($templateRow)->getRowHeight();
|
||||
$sheet->getRowDimension($currentRow + 1)->setRowHeight($templateRowHeight);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
$simpleLog .= " ❌ Excel error: " . $th->getMessage() . "\n\n";
|
||||
throw $th;
|
||||
}
|
||||
|
||||
// Dosya kopyalama
|
||||
$originalSearchPath = $firstFoundFile;
|
||||
$search[0] = str_replace("storage/documents/", "", $firstFoundFile);
|
||||
$fullFolder = str_replace("storage/documents/", "", $fullFolder);
|
||||
$fullPath = $fullFolder . basename($fileName);
|
||||
|
||||
try {
|
||||
$targetDir = dirname($fullPath);
|
||||
if (!Storage::exists($targetDir)) {
|
||||
Storage::makeDirectory($targetDir);
|
||||
}
|
||||
|
||||
$copyStatus = "";
|
||||
|
||||
if(Storage::exists($fullPath)) {
|
||||
if ($override) {
|
||||
Storage::delete($fullPath);
|
||||
$copyStatus = "overwritten";
|
||||
} else {
|
||||
$currentContent = md5(Storage::get($fullPath));
|
||||
$newContent = '';
|
||||
if (Storage::exists($search[0])) {
|
||||
$newContent = md5(Storage::get($search[0]));
|
||||
} else if (file_exists($originalSearchPath)) {
|
||||
$newContent = md5(file_get_contents($originalSearchPath));
|
||||
}
|
||||
|
||||
if ($currentContent !== $newContent) {
|
||||
Storage::delete($fullPath);
|
||||
$copyStatus = "updated";
|
||||
} else {
|
||||
$copyStatus = "same content, skipped";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$copyStatus = "copied";
|
||||
}
|
||||
|
||||
if ($copyStatus !== "same content, skipped") {
|
||||
if (Storage::exists($search[0])) {
|
||||
Storage::copy($search[0], $fullPath);
|
||||
} else if (file_exists($originalSearchPath)) {
|
||||
$fileContent = file_get_contents($originalSearchPath);
|
||||
Storage::put($fullPath, $fileContent);
|
||||
}
|
||||
}
|
||||
|
||||
$simpleLog .= " 📁 File: " . $copyStatus . "\n";
|
||||
|
||||
// Template dosyası kontrolü (xlsx)
|
||||
if(isset($selectDocument['type']) && $selectDocument['type'] === 'template') {
|
||||
$xlsxSourcePath = str_replace('.pdf', '.xlsx', $search[0]);
|
||||
$xlsxOriginalSourcePath = str_replace('.pdf', '.xlsx', $originalSearchPath);
|
||||
$xlsxTargetPath = str_replace('.pdf', '.xlsx', $fullPath);
|
||||
|
||||
if(Storage::exists($xlsxSourcePath) || file_exists($xlsxOriginalSourcePath)) {
|
||||
$xlsxCopyStatus = "";
|
||||
|
||||
if(Storage::exists($xlsxTargetPath)) {
|
||||
if ($override) {
|
||||
Storage::delete($xlsxTargetPath);
|
||||
$xlsxCopyStatus = "overwritten";
|
||||
} else {
|
||||
$currentXlsxContent = md5(Storage::get($xlsxTargetPath));
|
||||
$newXlsxContent = '';
|
||||
if (Storage::exists($xlsxSourcePath)) {
|
||||
$newXlsxContent = md5(Storage::get($xlsxSourcePath));
|
||||
} else if (file_exists($xlsxOriginalSourcePath)) {
|
||||
$newXlsxContent = md5(file_get_contents($xlsxOriginalSourcePath));
|
||||
}
|
||||
|
||||
if ($currentXlsxContent !== $newXlsxContent) {
|
||||
Storage::delete($xlsxTargetPath);
|
||||
$xlsxCopyStatus = "updated";
|
||||
} else {
|
||||
$xlsxCopyStatus = "same content, skipped";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$xlsxCopyStatus = "copied";
|
||||
}
|
||||
|
||||
if ($xlsxCopyStatus !== "same content, skipped") {
|
||||
if (Storage::exists($xlsxSourcePath)) {
|
||||
Storage::copy($xlsxSourcePath, $xlsxTargetPath);
|
||||
} else if (file_exists($xlsxOriginalSourcePath)) {
|
||||
$xlsxContent = file_get_contents($xlsxOriginalSourcePath);
|
||||
Storage::put($xlsxTargetPath, $xlsxContent);
|
||||
}
|
||||
}
|
||||
|
||||
$simpleLog .= " 📊 XLSX: " . $xlsxCopyStatus . "\n";
|
||||
} else {
|
||||
$simpleLog .= " ❓ XLSX: not found\n";
|
||||
}
|
||||
}
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
$simpleLog .= " ❌ Copy error: " . $th->getMessage() . "\n";
|
||||
}
|
||||
|
||||
$simpleLog .= "\n";
|
||||
|
||||
// Basit log'u dosyaya ve ekrana yaz
|
||||
echo($simpleLog);
|
||||
Storage::append($fullFolder . 'log.txt', $simpleLog);
|
||||
|
||||
// Başarılı işlem sayacı
|
||||
if (!isset($GLOBALS['successful_operations'])) {
|
||||
$GLOBALS['successful_operations'] = 0;
|
||||
}
|
||||
$GLOBALS['successful_operations']++;
|
||||
|
||||
return $currentRow + 1;
|
||||
|
||||
} else {
|
||||
// Dosya bulunamadı - basit log
|
||||
$notFoundLog = "❌ " . ($rowNo) . ". " . $rowTitle . " - " . $lineNumber . " | NO FILES FOUND\n";
|
||||
$notFoundLog .= " Search paths:\n";
|
||||
foreach ($search as $index => $searchPath) {
|
||||
$notFoundLog .= " -- " . basename($searchPath) . "\n";
|
||||
}
|
||||
$notFoundLog .= "\n";
|
||||
|
||||
echo($notFoundLog);
|
||||
|
||||
try {
|
||||
$fullFolder = str_replace("storage/documents/", "", $fullFolder);
|
||||
Storage::append($fullFolder . 'log.txt', $notFoundLog);
|
||||
} catch (\Throwable $logError) {
|
||||
echo("❌ Log write error\n");
|
||||
}
|
||||
|
||||
return $currentRow;
|
||||
}
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
Log::error("Unexpected error in addRowInTable: " . $th->getMessage());
|
||||
|
||||
try {
|
||||
$errorLog = "❌ " . ($rowNo ?? 'UNKNOWN') . ". ERROR: " . $th->getMessage() . "\n\n";
|
||||
$fullFolder = str_replace("storage/documents/", "", $fullFolder ?? '');
|
||||
Storage::append($fullFolder . 'log.txt', $errorLog);
|
||||
echo($errorLog);
|
||||
} catch (\Throwable $logError) {
|
||||
echo("❌ Fatal error occurred\n");
|
||||
}
|
||||
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php function addRowInTableTpCreator($search, $selectDocument, $fullFolder, $lineNumber, $documentDate, $rowNo)
|
||||
{
|
||||
Log::debug("➡️ addRowInTableTpCreator called with parameters:");
|
||||
Log::debug("📄 Has search results: " . (isset($search[0]) ? "Yes" : "No"));
|
||||
Log::debug("📑 Document title: " . $selectDocument['title2']);
|
||||
Log::debug("📁 Folder: " . $fullFolder);
|
||||
Log::debug("🔢 Line number: " . $lineNumber);
|
||||
Log::debug("📅 Document date: " . $documentDate);
|
||||
Log::debug("🔢 Row number: " . $rowNo);
|
||||
|
||||
$constructor = Cache::get("rc_contractor");
|
||||
$firstPage = Cache::get("rc_firstPage");
|
||||
$lastPage = Cache::get("rc_lastPage");
|
||||
/*
|
||||
Log::info("firstPage $firstPage");
|
||||
Log::info("lastPage $lastPage");
|
||||
*/
|
||||
|
||||
$rowTitle = $selectDocument['title2'];
|
||||
|
||||
if(isset($selectDocument['title3'])) {
|
||||
$rowTitle = $selectDocument['title3'];
|
||||
$selectDocument['title2'] = $selectDocument['title3'];
|
||||
}
|
||||
|
||||
if(isset($selectDocument['title4'])) {
|
||||
$rowTitle = $selectDocument['title4'];
|
||||
}
|
||||
|
||||
|
||||
if(isset($search[0])) {
|
||||
|
||||
$order = $selectDocument['order'] + 1;
|
||||
@mkdir($fullFolder, 0777, true);
|
||||
Log::info("creating folder $fullFolder");
|
||||
|
||||
$addInLineNumber = ['по сварке трубопроводов(ЖСР)'];
|
||||
if(in_array($selectDocument['title2'], $addInLineNumber)) {
|
||||
$fileName = "$order - {$selectDocument['title2']} - $lineNumber.pdf";
|
||||
$fullPath = "$fullFolder"."$fileName";
|
||||
Log::debug("🔖 Special case file name with line number: " . $fileName);
|
||||
} else {
|
||||
$fileName = "$order - {$selectDocument['title2']}.pdf";
|
||||
$fullPath = "$fullFolder"."$fileName";
|
||||
Log::debug("🔖 Standard file name: " . $fileName);
|
||||
}
|
||||
|
||||
$documentDate = df($documentDate);
|
||||
$output = null;
|
||||
$returnValue = null;
|
||||
$allPath = "{$search[0]}";
|
||||
/*
|
||||
$command = "pdftk '$allPath' dump_data | grep NumberOfPages";
|
||||
// dump($command);
|
||||
// dump($allPath);
|
||||
putenv('LANG=ru_RU.UTF-8');
|
||||
|
||||
$output = shell_exec($command);
|
||||
|
||||
|
||||
try {
|
||||
$pageCount = (int) trim(explode(" ", $output)[1]);
|
||||
} catch (\Throwable $th) {
|
||||
$pageCount = 1;
|
||||
}
|
||||
|
||||
if($firstPage == 0) {
|
||||
$firstPage = 1;
|
||||
} else {
|
||||
$firstPage = $lastPage + 1;
|
||||
}
|
||||
|
||||
// Son sayfa numarasını hesapla
|
||||
$lastPage = $firstPage + $pageCount - 1;
|
||||
|
||||
Cache::put("rc_lastPage", $lastPage);
|
||||
Cache::put("rc_firstPage", $firstPage);
|
||||
|
||||
// Sayfa aralığını oluştur
|
||||
$pageIndex = ($firstPage == $lastPage) ? $firstPage : "$firstPage - $lastPage";
|
||||
|
||||
|
||||
|
||||
|
||||
$tableRow = "
|
||||
<tr class='bordered'>
|
||||
<td >$rowNo</td>
|
||||
<td width='50%' colspan='2'>$rowTitle</td>
|
||||
<td>$lineNumber</td>
|
||||
<td>$documentDate</td>
|
||||
<td>$constructor</td>
|
||||
<td>$pageCount</td>
|
||||
<td>$pageIndex</td>
|
||||
</tr>
|
||||
|
||||
";
|
||||
*/
|
||||
|
||||
$search[0] = str_replace("storage/documents/", "", $search[0]);
|
||||
$fullFolder = str_replace("storage/documents/", "", $fullFolder);
|
||||
$fullPath = $fullFolder . basename($fileName);
|
||||
Log::debug("🛠️ File path processing:");
|
||||
Log::debug("📄 Original source path: storage/documents/" . $search[0]);
|
||||
Log::debug("📁 Original folder path: storage/documents/" . $fullFolder);
|
||||
Log::debug("📄 Target filename: " . basename($fileName));
|
||||
Log::debug("📄 Final target path: " . $fullPath);
|
||||
/*
|
||||
Log::info("fullPath: " . $fullPath);
|
||||
Log::info("search: " . $search[0]);
|
||||
Log::info("fullFolder: " . $fullFolder);
|
||||
*/
|
||||
|
||||
try {
|
||||
if(Storage::exists($fullPath)) {
|
||||
$currentContent = md5(Storage::get($fullPath));
|
||||
$newContent = md5(Storage::get($search[0]));
|
||||
|
||||
Log::debug("📁 Checking file: " . $fullPath);
|
||||
Log::debug("🔑 Current content MD5: " . $currentContent);
|
||||
Log::debug("🔑 New content MD5: " . $newContent);
|
||||
|
||||
if ($currentContent !== $newContent) {
|
||||
$log = "🔃✅".$search[0] . " old file deleted and new file copied" . "\n";
|
||||
Log::debug("📝 " . $log);
|
||||
Storage::delete($fullPath);
|
||||
Storage::copy($search[0], $fullPath);
|
||||
|
||||
} else {
|
||||
$log = "🟰" . $search[0] . " already same file, not copied" . "\n";
|
||||
Log::debug("📝 " . $log);
|
||||
}
|
||||
} else {
|
||||
$log = "✅".$search[0] . " file copied" . "\n";
|
||||
Log::debug("📝 " . $log);
|
||||
Storage::copy($search[0], $fullPath);
|
||||
}
|
||||
|
||||
echo($log);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
$log = "❌" . $search[0] . " error ---> \n " . $th->getMessage() . "\n";
|
||||
echo($log);
|
||||
Log::debug("❌ Error copying file: " . $search[0]);
|
||||
Log::debug("❌ Error message: " . $th->getMessage());
|
||||
Log::debug("❌ Error trace: " . $th->getTraceAsString());
|
||||
}
|
||||
|
||||
|
||||
Storage::append($fullFolder . 'log.txt', $log);
|
||||
Log::debug("📜 Appended to log file: " . $fullFolder . 'log.txt');
|
||||
Log::debug("📜 Log entry: " . $log);
|
||||
|
||||
$return = null; //= $tableRow;
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
$log = "❓$rowTitle - $lineNumber not found " . "\n";
|
||||
echo($log);
|
||||
Log::debug("❓ Document not found: " . $rowTitle . " - " . $lineNumber);
|
||||
Log::debug("❓ Search path likely was: storage/documents/{$selectDocument['path']}/*{$lineNumber}*.pdf");
|
||||
$fullFolder = str_replace("storage/documents/", "", $fullFolder);
|
||||
Storage::append($fullFolder . 'log.txt', $log);
|
||||
Log::debug("📜 Appended to log file: " . $fullFolder . 'log.txt');
|
||||
$return = null;
|
||||
}
|
||||
|
||||
return $return;
|
||||
} ?>
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
/**
|
||||
* Excel dosyasını analiz eder ve bellek kullanımı, sorunlu formüller hakkında bilgi verir
|
||||
*
|
||||
* @param string $filePath Excel dosyasının geçici yolu
|
||||
* @return array Analiz sonuçları
|
||||
*/
|
||||
function analyzeExcelFile($filePath) {
|
||||
// Varsayılan sonuç
|
||||
$result = [
|
||||
'file_size' => filesize($filePath),
|
||||
'file_size_formatted' => formatBytes(filesize($filePath)),
|
||||
'memory_warning' => false,
|
||||
'problematic_formulas' => []
|
||||
];
|
||||
|
||||
// 5MB üzerindeki dosyalar için bellek uyarısı
|
||||
if ($result['file_size'] > 5 * 1024 * 1024) {
|
||||
$result['memory_warning'] = true;
|
||||
}
|
||||
|
||||
// PhpSpreadsheet kütüphanesini kullanarak Excel'i analiz et
|
||||
try {
|
||||
require_once base_path('vendor/autoload.php');
|
||||
|
||||
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile($filePath);
|
||||
$reader->setReadDataOnly(false);
|
||||
$spreadsheet = $reader->load($filePath);
|
||||
|
||||
// Tüm çalışma sayfalarını kontrol et
|
||||
foreach ($spreadsheet->getWorksheetIterator() as $worksheet) {
|
||||
$sheetTitle = $worksheet->getTitle();
|
||||
|
||||
// Formül içeren hücreleri bul
|
||||
foreach ($worksheet->getCoordinates() as $coordinate) {
|
||||
$cell = $worksheet->getCell($coordinate);
|
||||
|
||||
if ($cell->isFormula()) {
|
||||
$formula = $cell->getValue();
|
||||
|
||||
// Sorunlu formülleri kontrol et
|
||||
// 1. Çok geniş aralıkları kontrol et (örn. A1:Z1000000)
|
||||
if (preg_match('/[A-Z]+\d+:[A-Z]+\d+/', $formula, $matches)) {
|
||||
foreach ($matches as $range) {
|
||||
list($start, $end) = explode(':', $range);
|
||||
|
||||
// Sayısal kısmı al
|
||||
preg_match('/\d+/', $end, $endRow);
|
||||
$endRowNum = intval($endRow[0]);
|
||||
|
||||
// Çok büyük aralıklar için uyarı (örneğin 10000 satırdan fazla)
|
||||
if ($endRowNum > 10000) {
|
||||
$result['problematic_formulas'][] = [
|
||||
'sheet' => $sheetTitle,
|
||||
'cell' => $coordinate,
|
||||
'formula' => $formula,
|
||||
'issue' => "Çok geniş aralık kullanımı: $range ($endRowNum satır)"
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. MAX, MIN, SUM gibi fonksiyonlarda büyük aralıklar
|
||||
if (preg_match('/(SUM|MIN|MAX|AVERAGE|COUNT)\s*\([A-Z]+\d+:[A-Z]+\d+\)/i', $formula, $matches)) {
|
||||
foreach ($matches as $func) {
|
||||
if (preg_match('/\(([A-Z]+\d+:[A-Z]+\d+)\)/', $func, $rangeMatches)) {
|
||||
$range = $rangeMatches[1];
|
||||
list($start, $end) = explode(':', $range);
|
||||
|
||||
preg_match('/\d+/', $end, $endRow);
|
||||
$endRowNum = intval($endRow[0]);
|
||||
|
||||
if ($endRowNum > 10000) {
|
||||
$result['problematic_formulas'][] = [
|
||||
'sheet' => $sheetTitle,
|
||||
'cell' => $coordinate,
|
||||
'formula' => $formula,
|
||||
'issue' => "Fonksiyonda büyük aralık: $func ($endRowNum satır)"
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. OFFSET fonksiyonunun kontrolü
|
||||
if (stripos($formula, 'OFFSET') !== false) {
|
||||
$result['problematic_formulas'][] = [
|
||||
'sheet' => $sheetTitle,
|
||||
'cell' => $coordinate,
|
||||
'formula' => $formula,
|
||||
'issue' => "OFFSET fonksiyonu kullanımı bellek problemlerine neden olabilir"
|
||||
];
|
||||
}
|
||||
|
||||
// 4. Çok karmaşık iç içe formüller
|
||||
$openParenCount = substr_count($formula, '(');
|
||||
if ($openParenCount > 10) {
|
||||
$result['problematic_formulas'][] = [
|
||||
'sheet' => $sheetTitle,
|
||||
'cell' => $coordinate,
|
||||
'formula' => $formula,
|
||||
'issue' => "Çok karmaşık iç içe formül ($openParenCount seviyesinde iç içe geçmiş)"
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Hata durumunda
|
||||
$result['error'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bayt cinsinden boyutu okunabilir formata çevirir
|
||||
*/
|
||||
function formatBytes($bytes, $precision = 2) {
|
||||
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
|
||||
$bytes /= pow(1024, $pow);
|
||||
|
||||
return round($bytes, $precision) . ' ' . $units[$pow];
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
function autocomplete_url($tableName, $column) {
|
||||
return url("admin/autocomplete/$tableName/$column?with-column");
|
||||
}
|
||||
function autocomplete_url2($tableName, $column) {
|
||||
return url("admin/autocomplete/$tableName/$column");
|
||||
}
|
||||
function autocomplete_type($type) {
|
||||
return url("admin/autocomplete_type/$type");
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
function cacheBladeLoad($cacheName) {
|
||||
|
||||
try {
|
||||
// Fetch the cached content
|
||||
$cachedContent = Storage::get('cache/'. $cacheName .'.blade.php');
|
||||
|
||||
// Display the cached content
|
||||
echo $cachedContent;
|
||||
} catch (\Throwable $th) {
|
||||
//throw $th;
|
||||
Log::error('Cache blade load error: ' . $th->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
use App\Jobs\CacheBladeViewJob;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Dispatch cache blade view jobs
|
||||
*
|
||||
* This helper function dispatches CacheBladeViewJob for specified views.
|
||||
* It can be used to refresh cached blade views after data updates.
|
||||
*
|
||||
* @param array $cacheViews Optional array of cache views to dispatch.
|
||||
* If provided, only these views will be dispatched (default views will be ignored).
|
||||
* If empty, default cache views will be dispatched.
|
||||
* Format: [['view' => 'view.path', 'cache' => 'cache-name'], ...]
|
||||
* @return void
|
||||
*/
|
||||
function dispatchCacheBladeViews(array $cacheViews = [])
|
||||
{
|
||||
|
||||
// Default cache views that should be refreshed after spool-related operations
|
||||
$defaultCacheViews = [
|
||||
|
||||
[
|
||||
'view' => 'admin-ajax.spool-area-release-no-cache',
|
||||
'cache' => 'spool-area-release'
|
||||
],
|
||||
[
|
||||
'view' => 'admin-ajax.spool-list-no-cache',
|
||||
'cache' => 'spool-list'
|
||||
],
|
||||
[
|
||||
'view' => 'admin.type.spool-release.spool-list-chart-no-cache',
|
||||
'cache' => 'spool-list-chart'
|
||||
],
|
||||
];
|
||||
|
||||
// If cacheViews is empty, use defaultCacheViews; otherwise use only cacheViews
|
||||
if (empty($cacheViews)) {
|
||||
$uniqueCacheViews = $defaultCacheViews;
|
||||
} else {
|
||||
// Remove duplicates based on cache name (keep the last one)
|
||||
$seen = [];
|
||||
$uniqueCacheViews = [];
|
||||
|
||||
// Reverse to process from end, so we keep the last occurrence
|
||||
foreach (array_reverse($cacheViews) as $cacheView) {
|
||||
// Validate array structure
|
||||
if (!is_array($cacheView) || !isset($cacheView['cache']) || !isset($cacheView['view'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$cacheName = $cacheView['cache'];
|
||||
if (!in_array($cacheName, $seen)) {
|
||||
$seen[] = $cacheName;
|
||||
$uniqueCacheViews[] = $cacheView;
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse back to original order
|
||||
$uniqueCacheViews = array_reverse($uniqueCacheViews);
|
||||
}
|
||||
|
||||
// Dispatch job for each cache view
|
||||
foreach ($uniqueCacheViews as $cacheView) {
|
||||
if (isset($cacheView['view']) && isset($cacheView['cache'])) {
|
||||
try {
|
||||
// Rate Limiting (Debounce): Aynı cache view için 60 saniyede bir kez job oluştur.
|
||||
// Batch excel gibi aynı anda binlerce satırın import edildiği senaryolarda kuyruğun dolmasını engeller.
|
||||
$rateLimitKey = "rate_limit_dispatch_{$cacheView['cache']}";
|
||||
|
||||
if (!\Illuminate\Support\Facades\Cache::has($rateLimitKey)) {
|
||||
// 60 saniyeliğine kilitle
|
||||
\Illuminate\Support\Facades\Cache::put($rateLimitKey, true, 60);
|
||||
|
||||
// Job'u 15 saniye gecikmeli gönder (arka plandaki güncellemelerin bitmesi için zaman tanı)
|
||||
CacheBladeViewJob::dispatch($cacheView['view'], $cacheView['cache'])->delay(now()->addSeconds(15));
|
||||
|
||||
Log::info('CacheBladeViewJob dispatched to queue with 15s delay (Rate limit started)', [
|
||||
'view' => $cacheView['view'],
|
||||
'cache' => $cacheView['cache']
|
||||
]);
|
||||
} else {
|
||||
// Log::debug('CacheBladeViewJob skipped due to rate limit (debounce)', ['cache' => $cacheView['cache']]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Silently fail to prevent breaking the main operation
|
||||
Log::error('Failed to dispatch CacheBladeViewJob', [
|
||||
'view' => $cacheView['view'],
|
||||
'cache' => $cacheView['cache'],
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
use App\Models\CalibrationLog;
|
||||
use App\Models\WeldingEquipment;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
if (!function_exists('syncCalibrationFromWeldingEquipment')) {
|
||||
/**
|
||||
* Sync a single WeldingEquipment record into CalibrationLog table.
|
||||
*
|
||||
* This allows NAKS Welding Equipments to automatically appear in the
|
||||
* QA -> Calibration Log module while still allowing manual entries.
|
||||
*
|
||||
* @param \App\Models\WeldingEquipment|array $equipment
|
||||
* @return \App\Models\CalibrationLog
|
||||
*/
|
||||
function syncCalibrationFromWeldingEquipment($equipment): CalibrationLog
|
||||
{
|
||||
if (is_array($equipment)) {
|
||||
$data = $equipment;
|
||||
} else {
|
||||
$data = $equipment->toArray();
|
||||
}
|
||||
|
||||
$sourceId = $data['id'] ?? null;
|
||||
|
||||
\Log::debug("Sync attempt for equipment ID: " . $sourceId);
|
||||
|
||||
$log = CalibrationLog::firstOrNew([
|
||||
'source_module' => 'naks_welding_equipment',
|
||||
'source_id' => $sourceId,
|
||||
]);
|
||||
|
||||
\Log::debug("CalibrationLog exists: " . ($log->exists ? "yes (id: {$log->id})" : "no, will create new"));
|
||||
|
||||
$log->instrument = 'Welding Equipment';
|
||||
$log->description = $data['type_of_welding_machine'] ?? null;
|
||||
$log->item_no = $log->item_no ?? null;
|
||||
$log->equipment_name = $data['brand'] ?? null; // brand -> equipment_name
|
||||
$log->manufacturer = $data['producer'] ?? null; // producer -> manufacturer
|
||||
$log->serial_no = $data['manufacturer_code'] ?? null; // manufacturer_code -> serial_no
|
||||
$log->passport_certificate_no = $data['attestation'] ?? null;
|
||||
$log->quantity = 1; // Always set quantity to 1
|
||||
|
||||
// Use date_of_issue as calibration_date and valid_until as calibration_due_date
|
||||
if (!empty($data['date_of_issue'])) {
|
||||
$log->calibration_date = $data['date_of_issue'];
|
||||
}
|
||||
|
||||
if (!empty($data['valid_until'])) {
|
||||
$log->calibration_due_date = $data['valid_until'];
|
||||
}
|
||||
|
||||
// Status calculation based on due date
|
||||
if (!empty($log->calibration_due_date)) {
|
||||
$today = Carbon::today();
|
||||
$dueDate = Carbon::parse($log->calibration_due_date)->startOfDay();
|
||||
|
||||
if ($dueDate->lt($today)) {
|
||||
$log->status = 'Out Of service'; // Expired -> Out Of service
|
||||
} elseif ($dueDate->lte($today->copy()->addDays(20))) {
|
||||
$log->status = 'Calibration-Verification'; // Due Soon -> needs calibration
|
||||
} else {
|
||||
$log->status = 'In use'; // Valid -> In use
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $log->save();
|
||||
\Log::debug("Save result: " . ($result ? "success, new id: {$log->id}" : "failed"));
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("Save exception: " . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $log;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
function col($size, $title="", $color="0", $options=[], $topButtons=[], $columns=[]) {
|
||||
$id = str_slug($title);
|
||||
$colors = colors();
|
||||
$u = u();
|
||||
?>
|
||||
|
||||
|
||||
|
||||
<div class="<?php echo $size ?>">
|
||||
<div class="block block-themed block-rounded <?php echo isset($options['border']) ? "border" : "" ?>" id="<?php echo $id; ?>">
|
||||
<?php if($title!="") {
|
||||
?>
|
||||
<div class="block-header
|
||||
<?php if($color!=-1) {
|
||||
?>
|
||||
bg-<?php echo $colors[$color]; ?>
|
||||
<?php
|
||||
} ?>
|
||||
">
|
||||
<div class="block-title"><?php echo e2($title) ?></div>
|
||||
<?php if(!isset($options['no-options'])) {
|
||||
?>
|
||||
<div class="block-options">
|
||||
<div type="button" class="btn-block-option select-columns d-none" data-toggle="modal" data-target="#select-columns" >
|
||||
<i class="fa fa-table-columns"></i>
|
||||
</div>
|
||||
<?php foreach($options AS $icon => $href) {
|
||||
?>
|
||||
<a href="<?php echo $href ?>" class="btn-block-option"><i class="fa fa-<?php echo $icon ?>"></i></a>
|
||||
<?php
|
||||
} ?>
|
||||
<?php if(isAuth($id, "write")) { ?>
|
||||
<div class="btn btn-outline-success add-btn d-none" onclick="$('#new-modal').modal()"><i class="fa fa-plus"></i></div>
|
||||
<?php } ?>
|
||||
|
||||
<!-- To toggle fullscreen a block, just add the following properties to your button: data-toggle="block-option" data-action="fullscreen_toggle" -->
|
||||
<button type="button" class="btn-block-option d-none" data-toggle="block-option"
|
||||
<?php if(oturumesit("full-screen-block", $id)) {
|
||||
?>
|
||||
onclick="$.get('?ajax=full-screen-block-remove')"
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
onclick="$.get('?ajax=full-screen-block&id=<?php echo($id) ?>')"
|
||||
<?php } ?>
|
||||
data-action="fullscreen_toggle"><i class="si si-size-fullscreen"></i></button>
|
||||
<?php if(isset($options['export'])) { ?>
|
||||
<?php if($u->level == "Admin") { ?>
|
||||
|
||||
<a href="<?php echo url("admin/truncate/". $options['export']) ?>" <?php echo delete_teyit() ?> class="btn-block-option " title="<?php echo e2("Delete All") ?>" ><i class="fa fa-trash"></i></a>
|
||||
|
||||
<?php } ?>
|
||||
<?php //if(is_stellar()) {
|
||||
?>
|
||||
<a target="_blank" href="<?php echo url("admin-ajax/export-query?table_name=". $options['export']) ?>&module=<?php echo $id ?>&columns=<?php echo base64_encode(implode(",", $columns)) ?>" class="btn-block-option" title="<?php echo e2("Export to CSV") ?>" ><i class="fa fa-download"></i> CSV</a>
|
||||
<a target="_blank" href="<?php echo url("admin-ajax/export-query?file_type=xlsx&table_name=". $options['export']) ?>&module=<?php echo $id ?>&columns=<?php echo base64_encode(implode(",", $columns)) ?>" class="btn-block-option" title="<?php echo e2("Export to XLSX") ?>" ><i class="fa fa-download"></i> XLSX</a>
|
||||
|
||||
<a href="<?php echo url("admin/export/". $options['export']) ?>?&module=<?php echo $id ?>&columns=<?php echo base64_encode(implode(",", $columns)) ?>" class="btn-block-option d-none" title="<?php echo e2("Export to Excel") ?>" ><i class="fa fa-download"></i></a>
|
||||
<?php // } ?>
|
||||
<?php if(isAuth($id, "write")) {
|
||||
?>
|
||||
<label
|
||||
for="excel-file"
|
||||
class="btn-block-option d-none" click="" title="<?php echo e2("Import to Excel") ?>" ><i class="fa fa-upload"></i></label>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
<?php if(isset($topButtons)) {
|
||||
foreach($topButtons AS $topButton) {
|
||||
?>
|
||||
<a href="<?php echo $topButton['href'] ?>" class="<?php echo @$topButton['class'] ?>"><?php echo $topButton['html'] ?></a>
|
||||
<?php
|
||||
}
|
||||
} ?>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
} ?>
|
||||
|
||||
<div class="block-content <?php echo isset($options['content-class']) ? $options['content-class'] : "" ?>">
|
||||
|
||||
|
||||
<?php
|
||||
}
|
||||
function _col() {
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
function col2($size, $title="", $color="0", $options=[], $topButtons=[], $columns=[]) {
|
||||
$id = str_slug($title);
|
||||
$colors = colors();
|
||||
$u = u();
|
||||
?>
|
||||
|
||||
<div class="<?php echo $size ?>">
|
||||
<div class="block block-themed block-rounded <?php echo isset($options['border']) ? "border" : "" ?>" id="<?php echo $id; ?>">
|
||||
<?php if(!isset($options['no-options']) && $title!="") { ?>
|
||||
<!-- Fixed toolbar for buttons, positioned at the top-right -->
|
||||
<div class="fixed-toolbar" style="position: fixed; top: 70px; right: 0px; width: auto; z-index: 1000; background-color: rgba(255,255,255,0.8); padding: 5px; border-radius: 4px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
|
||||
<div type="button" class="btn-block-option select-columns d-none" data-toggle="modal" data-target="#select-columns" >
|
||||
<i class="fa fa-table-columns"></i>
|
||||
</div>
|
||||
<?php foreach($options AS $icon => $href) { ?>
|
||||
<a href="<?php echo $href ?>" class="btn-block-option"><i class="fa fa-<?php echo $icon ?>"></i></a>
|
||||
<?php } ?>
|
||||
<?php if(isAuth($id, "write")) { ?>
|
||||
<div class="btn btn-outline-success add-btn d-none" onclick="$('#new-modal').modal()"><i class="fa fa-plus"></i></div>
|
||||
<?php } ?>
|
||||
|
||||
<!-- To toggle fullscreen a block, just add the following properties to your button: data-toggle="block-option" data-action="fullscreen_toggle" -->
|
||||
<button type="button" class="btn-block-option d-none" data-toggle="block-option"
|
||||
<?php if(oturumesit("full-screen-block", $id)) { ?>
|
||||
onclick="$.get('?ajax=full-screen-block-remove')"
|
||||
<?php } else { ?>
|
||||
onclick="$.get('?ajax=full-screen-block&id=<?php echo($id) ?>')"
|
||||
<?php } ?>
|
||||
data-action="fullscreen_toggle"><i class="si si-size-fullscreen"></i></button>
|
||||
|
||||
<?php if(isset($options['export'])) { ?>
|
||||
<?php if($u->level == "Admin") { ?>
|
||||
<a href="<?php echo url("admin/truncate/". $options['export']) ?>" <?php echo delete_teyit() ?> class="btn-block-option " title="<?php echo e2("Delete All") ?>" ><i class="fa fa-trash"></i></a>
|
||||
<?php } ?>
|
||||
<a target="_blank" href="<?php echo url("admin-ajax/export-query?table_name=". $options['export']) ?>&module=<?php echo $id ?>&columns=<?php echo base64_encode(implode(",", $columns)) ?>" class="btn-block-option" title="<?php echo e2("Export to CSV") ?>" ><i class="fa fa-download"></i> CSV (Semicolon ;;;)</a>
|
||||
<a target="_blank" href="<?php echo url("admin-ajax/export-query?table_name=". $options['export']) ?>&module=<?php echo $id ?>&delimiter=,&columns=<?php echo base64_encode(implode(",", $columns)) ?>" class="btn-block-option" title="<?php echo e2("Export to CSV") ?>" ><i class="fa fa-download"></i> CSV (Comma ,,,)</a>
|
||||
<a target="_blank" href="<?php echo url("admin-ajax/export-query?file_type=xlsx&table_name=". $options['export']) ?>&module=<?php echo $id ?>&columns=<?php echo base64_encode(implode(",", $columns)) ?>" class="btn-block-option" title="<?php echo e2("Export to XLSX") ?>" ><i class="fa fa-download"></i> XLSX</a>
|
||||
|
||||
<a href="<?php echo url("admin/export/". $options['export']) ?>?&module=<?php echo $id ?>&columns=<?php echo base64_encode(implode(",", $columns)) ?>" class="btn-block-option d-none" title="<?php echo e2("Export to Excel") ?>" ><i class="fa fa-download"></i></a>
|
||||
<?php if(isAuth($id, "write")) { ?>
|
||||
<label for="excel-file" class="btn-block-option d-none" click="" title="<?php echo e2("Import to Excel") ?>" ><i class="fa fa-upload"></i></label>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
<?php if(isset($topButtons)) {
|
||||
foreach($topButtons AS $topButton) { ?>
|
||||
<a href="<?php echo $topButton['href'] ?>" class="<?php echo @$topButton['class'] ?>"><?php echo $topButton['html'] ?></a>
|
||||
<?php }
|
||||
} ?>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="block-content <?php echo isset($options['content-class']) ? $options['content-class'] : "" ?>">
|
||||
|
||||
|
||||
<?php
|
||||
}
|
||||
function _col2() {
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
function convertMapCache() {
|
||||
// Converter-map verilerini al
|
||||
$converterMap = j(setting("converter-map"));
|
||||
|
||||
// Mapping arrays oluştur ve cache'le
|
||||
$cacheKey = "converter_map_data";
|
||||
$mappings = Cache::remember($cacheKey, 3600, function() use ($converterMap) {
|
||||
$termToRu = $termToEn = $enToRu = $ruToEn = $enToTerm = $ruToTerm = [];
|
||||
|
||||
if (is_array($converterMap)) {
|
||||
foreach ($converterMap as $row) {
|
||||
if (!empty($row['term']) && !empty($row['term_ru'])) {
|
||||
$termToRu[$row['term']] = $row['term_ru'];
|
||||
}
|
||||
if (!empty($row['term']) && !empty($row['term_eng'])) {
|
||||
$termToEn[$row['term']] = $row['term_eng'];
|
||||
}
|
||||
if (!empty($row['term_eng']) && !empty($row['term_ru'])) {
|
||||
$enToRu[$row['term_eng']] = $row['term_ru'];
|
||||
}
|
||||
if (!empty($row['term_ru']) && !empty($row['term_eng'])) {
|
||||
$ruToEn[$row['term_ru']] = $row['term_eng'];
|
||||
}
|
||||
if (!empty($row['term_eng']) && !empty($row['term'])) {
|
||||
$enToTerm[$row['term_eng']] = $row['term'];
|
||||
}
|
||||
if (!empty($row['term_ru']) && !empty($row['term'])) {
|
||||
$ruToTerm[$row['term_ru']] = $row['term'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'termToRu' => $termToRu,
|
||||
'termToEn' => $termToEn,
|
||||
'enToRu' => $enToRu,
|
||||
'ruToEn' => $ruToEn,
|
||||
'enToTerm' => $enToTerm,
|
||||
'ruToTerm' => $ruToTerm
|
||||
];
|
||||
});
|
||||
|
||||
// Her bir mapping'i ayrı cache key'e kaydet
|
||||
Cache::put('termToRu', $mappings['termToRu'], 3600);
|
||||
Cache::put('termToEn', $mappings['termToEn'], 3600);
|
||||
Cache::put('enToRu', $mappings['enToRu'], 3600);
|
||||
Cache::put('ruToEn', $mappings['ruToEn'], 3600);
|
||||
Cache::put('enToTerm', $mappings['enToTerm'], 3600);
|
||||
Cache::put('ruToTerm', $mappings['ruToTerm'], 3600);
|
||||
|
||||
return $mappings;
|
||||
}
|
||||
function convertMap() {
|
||||
$cacheKey = "converter_map_data";
|
||||
|
||||
// Önce cache'den okumayı dene
|
||||
if (Cache::has($cacheKey)) {
|
||||
$mappings = Cache::get($cacheKey);
|
||||
// Cache'den okunan veri geçerli mi kontrol et
|
||||
if (!empty($mappings) && is_array($mappings)) {
|
||||
return $mappings;
|
||||
}
|
||||
}
|
||||
|
||||
// Cache yoksa veya geçersizse yeniden oluştur
|
||||
$mappings = j(setting("converter-map"));
|
||||
|
||||
// Yeni veriyi cache'e kaydet
|
||||
if (!empty($mappings) && is_array($mappings)) {
|
||||
Cache::put($cacheKey, $mappings, 60);
|
||||
}
|
||||
|
||||
return $mappings;
|
||||
}
|
||||
|
||||
function convertRu($term) {
|
||||
// Önce cache'de mapping var mı kontrol et
|
||||
$converterMap = Cache::get('termToRu');
|
||||
|
||||
// Eğer cache'de yoksa, convertMapCache'i çağır
|
||||
if (empty($converterMap)) {
|
||||
convertMapCache();
|
||||
$converterMap = Cache::get('termToRu');
|
||||
}
|
||||
|
||||
if(isset($converterMap[$term])) {
|
||||
return $converterMap[$term];
|
||||
} else {
|
||||
Log::info("convertRu not found", ['term' => $term]);
|
||||
}
|
||||
return $term;
|
||||
|
||||
}
|
||||
|
||||
function convertEn($term) {
|
||||
// Önce cache'de mapping var mı kontrol et
|
||||
$converterMap = Cache::get('termToEn');
|
||||
|
||||
// Eğer cache'de yoksa, convertMapCache'i çağır
|
||||
if (empty($converterMap)) {
|
||||
convertMapCache();
|
||||
$converterMap = Cache::get('termToEn');
|
||||
}
|
||||
|
||||
if(isset($converterMap[$term])) {
|
||||
return $converterMap[$term];
|
||||
}
|
||||
return $term;
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
function converterMapReplacer(?Spreadsheet $spreadsheet, $type="replacer") {
|
||||
// Converter-map verilerini al
|
||||
$converterMap = j(setting("converter-map"));
|
||||
|
||||
// Mapping arrays oluştur ve cache'le
|
||||
$cacheKey = "converter_map_data";
|
||||
$mappings = Cache::remember($cacheKey, 3600, function() use ($converterMap) {
|
||||
$termToRu = $termToEn = $enToRu = $ruToEn = $enToTerm = $ruToTerm = [];
|
||||
|
||||
if (is_array($converterMap)) {
|
||||
foreach ($converterMap as $row) {
|
||||
if (!empty($row['term']) && !empty($row['term_ru'])) {
|
||||
$termToRu[$row['term']] = $row['term_ru'];
|
||||
}
|
||||
if (!empty($row['term']) && !empty($row['term_eng'])) {
|
||||
$termToEn[$row['term']] = $row['term_eng'];
|
||||
}
|
||||
if (!empty($row['term_eng']) && !empty($row['term_ru'])) {
|
||||
$enToRu[$row['term_eng']] = $row['term_ru'];
|
||||
}
|
||||
if (!empty($row['term_ru']) && !empty($row['term_eng'])) {
|
||||
$ruToEn[$row['term_ru']] = $row['term_eng'];
|
||||
}
|
||||
if (!empty($row['term_eng']) && !empty($row['term'])) {
|
||||
$enToTerm[$row['term_eng']] = $row['term'];
|
||||
}
|
||||
if (!empty($row['term_ru']) && !empty($row['term'])) {
|
||||
$ruToTerm[$row['term_ru']] = $row['term'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'termToRu' => $termToRu,
|
||||
'termToEn' => $termToEn,
|
||||
'enToRu' => $enToRu,
|
||||
'ruToEn' => $ruToEn,
|
||||
'enToTerm' => $enToTerm,
|
||||
'ruToTerm' => $ruToTerm
|
||||
];
|
||||
});
|
||||
|
||||
if ($type == "replacer") {
|
||||
// Sadece spreadsheet null değilse işle
|
||||
if ($spreadsheet !== null) {
|
||||
try {
|
||||
// Spreadsheet'teki her sheet'i dolaş
|
||||
foreach ($spreadsheet->getAllSheets() as $sheet) {
|
||||
// Her satır ve hücreyi dolaş
|
||||
foreach ($sheet->getRowIterator() as $row) {
|
||||
foreach ($row->getCellIterator() as $cell) {
|
||||
$cellValue = $cell->getValue();
|
||||
if (is_string($cellValue)) {
|
||||
$originalValue = $cellValue;
|
||||
|
||||
// _en pattern'lerini bul ve değiştir (TERM_en -> İngilizce karşılığı)
|
||||
$cellValue = preg_replace_callback('/(\w+)_en\b/', function($matches) use ($mappings) {
|
||||
$term = $matches[1];
|
||||
if (isset($mappings['termToEn'][$term])) {
|
||||
return $mappings['termToEn'][$term];
|
||||
}
|
||||
return $matches[0]; // Bulunamazsa orijinal değeri döndür
|
||||
}, $cellValue);
|
||||
|
||||
// _ru pattern'lerini bul ve değiştir (TERM_ru -> Rusça karşılığı)
|
||||
$cellValue = preg_replace_callback('/(\w+)_ru\b/', function($matches) use ($mappings) {
|
||||
$term = $matches[1];
|
||||
if (isset($mappings['termToRu'][$term])) {
|
||||
return $mappings['termToRu'][$term];
|
||||
}
|
||||
return $matches[0]; // Bulunamazsa orijinal değeri döndür
|
||||
}, $cellValue);
|
||||
|
||||
// _tr pattern'lerini bul ve değiştir (TERM_tr -> Türkçe karşılığı)
|
||||
$cellValue = preg_replace_callback('/(\w+)_tr\b/', function($matches) use ($mappings) {
|
||||
$term = $matches[1];
|
||||
// Türkçe için term alanını kullan (orijinal)
|
||||
return $term; // Terim kendisi zaten Türkçe
|
||||
}, $cellValue);
|
||||
|
||||
// Placeholder formatında da çeviri yap: {TERM_en}, {TERM_ru}
|
||||
$cellValue = preg_replace_callback('/\{(\w+)_en\}/', function($matches) use ($mappings) {
|
||||
$term = $matches[1];
|
||||
if (isset($mappings['termToEn'][$term])) {
|
||||
return $mappings['termToEn'][$term];
|
||||
}
|
||||
return $matches[0]; // Bulunamazsa orijinal değeri döndür
|
||||
}, $cellValue);
|
||||
|
||||
$cellValue = preg_replace_callback('/\{(\w+)_ru\}/', function($matches) use ($mappings) {
|
||||
$term = $matches[1];
|
||||
if (isset($mappings['termToRu'][$term])) {
|
||||
return $mappings['termToRu'][$term];
|
||||
}
|
||||
return $matches[0]; // Bulunamazsa orijinal değeri döndür
|
||||
}, $cellValue);
|
||||
|
||||
$cellValue = preg_replace_callback('/\{(\w+)_tr\}/', function($matches) use ($mappings) {
|
||||
$term = $matches[1];
|
||||
// Türkçe için term alanını kullan (orijinal)
|
||||
return $term; // Terim kendisi zaten Türkçe
|
||||
}, $cellValue);
|
||||
|
||||
// Eğer değişiklik olduysa hücreyi güncelle
|
||||
if ($cellValue !== $originalValue) {
|
||||
$cell->setValue($cellValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Değiştirilmiş spreadsheet'i döndür
|
||||
return $spreadsheet;
|
||||
} catch (\Throwable $th) {
|
||||
// Hata durumunda log ama devam et
|
||||
logProcessInfo('Error in converterMapReplacer', [
|
||||
'error' => $th->getMessage(),
|
||||
'trace' => $th->getTraceAsString()
|
||||
], 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Spreadsheet null ise veya hata oluştuysa boş array döndür
|
||||
return [];
|
||||
} else {
|
||||
// "data" tipi için mevcut terimleri placeholder listesi olarak döndür
|
||||
$placeholders = [];
|
||||
|
||||
if (is_array($converterMap)) {
|
||||
foreach ($converterMap as $row) {
|
||||
if (!empty($row['term'])) {
|
||||
$term = $row['term'];
|
||||
// Farklı dil pattern'leri ekle
|
||||
$placeholders[] = $term . "_en";
|
||||
$placeholders[] = $term . "_ru";
|
||||
$placeholders[] = $term . "_tr";
|
||||
$placeholders[] = "{" . $term . "_en}";
|
||||
$placeholders[] = "{" . $term . "_ru}";
|
||||
$placeholders[] = "{" . $term . "_tr}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($placeholders);
|
||||
}
|
||||
}
|
||||
|
||||
// String replacement için yardımcı fonksiyon
|
||||
function converterMapStringReplacer($string) {
|
||||
// Cache kullanarak converter-map verilerini al (1 saat süreyle)
|
||||
$mappings = Cache::remember('converter_map_string_data', 3600, function() {
|
||||
$converterMap = j(setting("converter-map"));
|
||||
$termToRu = $termToEn = [];
|
||||
|
||||
if (is_array($converterMap)) {
|
||||
foreach ($converterMap as $row) {
|
||||
if (!empty($row['term']) && !empty($row['term_ru'])) {
|
||||
$termToRu[$row['term']] = $row['term_ru'];
|
||||
}
|
||||
if (!empty($row['term']) && !empty($row['term_eng'])) {
|
||||
$termToEn[$row['term']] = $row['term_eng'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'termToRu' => $termToRu,
|
||||
'termToEn' => $termToEn
|
||||
];
|
||||
});
|
||||
|
||||
$termToRu = $mappings['termToRu'];
|
||||
$termToEn = $mappings['termToEn'];
|
||||
|
||||
|
||||
// _en pattern'lerini değiştir
|
||||
$string = preg_replace_callback('/(\w+)_en\b/', function($matches) use ($termToEn) {
|
||||
$term = $matches[1];
|
||||
if (isset($termToEn[$term])) {
|
||||
return $termToEn[$term];
|
||||
}
|
||||
return $matches[0];
|
||||
}, $string);
|
||||
|
||||
// _ru pattern'lerini değiştir
|
||||
$string = preg_replace_callback('/(\w+)_ru\b/', function($matches) use ($termToRu) {
|
||||
$term = $matches[1];
|
||||
if (isset($termToRu[$term])) {
|
||||
return $termToRu[$term];
|
||||
}
|
||||
return $matches[0];
|
||||
}, $string);
|
||||
|
||||
// _tr pattern'lerini değiştir (Türkçe - orijinal terim)
|
||||
$string = preg_replace_callback('/(\w+)_tr\b/', function($matches) {
|
||||
$term = $matches[1];
|
||||
return $term; // Terim kendisi zaten Türkçe
|
||||
}, $string);
|
||||
|
||||
// Placeholder formatında da çeviri yap
|
||||
$string = preg_replace_callback('/\{(\w+)_en\}/', function($matches) use ($termToEn) {
|
||||
$term = $matches[1];
|
||||
if (isset($termToEn[$term])) {
|
||||
return $termToEn[$term];
|
||||
}
|
||||
return $matches[0];
|
||||
}, $string);
|
||||
|
||||
$string = preg_replace_callback('/\{(\w+)_ru\}/', function($matches) use ($termToRu) {
|
||||
$term = $matches[1];
|
||||
if (isset($termToRu[$term])) {
|
||||
return $termToRu[$term];
|
||||
}
|
||||
return $matches[0];
|
||||
}, $string);
|
||||
|
||||
$string = preg_replace_callback('/\{(\w+)_tr\}/', function($matches) {
|
||||
$term = $matches[1];
|
||||
return $term; // Terim kendisi zaten Türkçe
|
||||
}, $string);
|
||||
|
||||
return $string;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
use App\Models\Counter;
|
||||
use Carbon\Carbon;
|
||||
|
||||
function get_counter($prefix, $type="1") {
|
||||
//eğer type boşsa o gün üretilen başka bir counter varsa onu al
|
||||
$run = true;
|
||||
if($type == "") {
|
||||
$todayCounter = Counter::whereDate("updated_at", Carbon::today())->where("prefix", $prefix)->first();
|
||||
if($todayCounter) {
|
||||
$get = $todayCounter->value;
|
||||
$run = false;
|
||||
} else {
|
||||
$run = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($run) {
|
||||
$set = Counter::updateOrCreate(
|
||||
[
|
||||
'prefix' => $prefix
|
||||
])
|
||||
->increment('value');
|
||||
|
||||
$get = Counter::where("prefix", $prefix)->first()->value;
|
||||
}
|
||||
|
||||
$totalZero = 6;
|
||||
$totalGet = strlen($get);
|
||||
$resultZero = $totalZero - $totalGet;
|
||||
$result = "";
|
||||
for($k=1;$k<=$resultZero; $k++) {
|
||||
$result .= "0";
|
||||
}
|
||||
$result .= $get;
|
||||
|
||||
return $result;
|
||||
} ?>
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
function csv_to_xlsx($csvFilePath, $outputFilePath, $delimiter= "\t")
|
||||
{
|
||||
try {
|
||||
// Create a new Spreadsheet object
|
||||
$spreadsheet = new Spreadsheet();
|
||||
|
||||
// Get the active sheet
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
// Open the CSV file
|
||||
$file = fopen($csvFilePath, 'r');
|
||||
if (!$file) {
|
||||
throw new \Exception("Cannot open CSV file.");
|
||||
}
|
||||
|
||||
$rowIndex = 1;
|
||||
|
||||
// Read each row and add it to the spreadsheet
|
||||
while (($row = fgetcsv($file, 0, $delimiter)) !== false) {
|
||||
$colIndex = 'A';
|
||||
|
||||
foreach ($row as $cell) {
|
||||
// Veriyi hücreye yaz
|
||||
// if($cell == "NULL") $cell = "";
|
||||
$sheet->setCellValue($colIndex . $rowIndex, $cell);
|
||||
$colIndex++;
|
||||
}
|
||||
|
||||
$rowIndex++;
|
||||
}
|
||||
fclose($file);
|
||||
|
||||
// Write to XLSX file
|
||||
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
|
||||
$writer->save($outputFilePath);
|
||||
|
||||
return $outputFilePath;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$result = [];
|
||||
$result['error'] = "Error: " . $e->getMessage();
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,278 @@
|
||||
<?php function datagrid_scripts() {
|
||||
?>
|
||||
<!-- DevExtreme CSS -->
|
||||
<link rel="stylesheet" href="https://cdn3.devexpress.com/jslib/23.1.5/css/dx-diagram.css" />
|
||||
|
||||
<!-- DevExtreme Diagram JavaScript -->
|
||||
<script src="https://cdn3.devexpress.com/jslib/23.1.5/js/dx-diagram.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.4.0/polyfill.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.1.1/exceljs.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.2/FileSaver.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.0.0/jspdf.umd.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/devextreme-dist/23.1.5/css/<?php echo setting("DevExpress_Theme", false,"dx.light.compact") ?>">
|
||||
<!-- Quill CSS -->
|
||||
<link rel="stylesheet" href="https://cdn.quilljs.com/1.3.7/quill.snow.css">
|
||||
|
||||
<!-- Quill JS -->
|
||||
<script src="https://cdn.quilljs.com/1.3.7/quill.min.js"></script>
|
||||
|
||||
|
||||
<script type="text/javascript" src="https://cdn3.devexpress.com/jslib/23.1.5/js/dx.all.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.0.0/jspdf.umd.min.js"></script>
|
||||
|
||||
|
||||
|
||||
<style>
|
||||
.dx-datagrid tr:nth-child(odd) {
|
||||
background-color:#e8e8e8;
|
||||
}
|
||||
#dataGrid {
|
||||
height: calc(100vh - 220px);
|
||||
}
|
||||
|
||||
.dx-datagrid .dx-row > td, .dx-datagrid .dx-row > tr > td {
|
||||
padding: 5px !important;
|
||||
}
|
||||
.dx-editor-cell .dx-texteditor .dx-texteditor-input {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.dx-datagrid .dx-row-lines > td {
|
||||
border-bottom: 1px solid #d2d2d2;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
} ?>
|
||||
|
||||
<?php function datagrid_configurations() {
|
||||
?>
|
||||
toolbar: {
|
||||
items: [
|
||||
"addRowButton",
|
||||
"applyFilterButton",
|
||||
"columnChooserButton",
|
||||
"revertButton",
|
||||
"saveButton",
|
||||
"searchPanel",
|
||||
"exportButton",
|
||||
"groupPanel",
|
||||
{
|
||||
location: 'before',
|
||||
widget: 'dxButton',
|
||||
options: {
|
||||
icon: 'filter',
|
||||
text: '{{e2("Clear Filter")}}',
|
||||
onClick: function(e) {
|
||||
dataGrid.clearFilter();
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
paging: {
|
||||
pageSize: <?php echo setting('row_count') ?>,
|
||||
},
|
||||
allowColumnResizing: true,
|
||||
columnAutoWidth: true,
|
||||
allowColumnReordering: true,
|
||||
columnMinWidth: 150,
|
||||
columnMaxWidth: 250,
|
||||
columnResizingMode: "widget",
|
||||
showColumnLines: true,
|
||||
filterRow: { visible: true },
|
||||
searchPanel: { visible: true },
|
||||
columnFixing: {
|
||||
enabled: true
|
||||
},
|
||||
headerFilter: {
|
||||
visible: true,
|
||||
allowSearch: true,
|
||||
},
|
||||
|
||||
loadPanel: {
|
||||
enabled: true,
|
||||
},
|
||||
|
||||
scrolling: {
|
||||
mode: 'standart',
|
||||
rowRenderingMode: 'infinite',
|
||||
columnRenderingMode: 'infinite',
|
||||
},
|
||||
hoverStateEnabled: true,
|
||||
showBorders: true,
|
||||
|
||||
remoteOperations: {
|
||||
filtering: true,
|
||||
paging: true,
|
||||
sorting: true,
|
||||
groupPaging: true,
|
||||
grouping: true,
|
||||
summary: true
|
||||
},
|
||||
|
||||
|
||||
|
||||
onContextMenuPreparing: function(e) {
|
||||
console.log("onContextMenuPreparing");
|
||||
console.log(e);
|
||||
if (e.target == "content") {
|
||||
if (!e.items) e.items = [];
|
||||
|
||||
@if(isAuth($id, "modify"))
|
||||
|
||||
e.items.push({
|
||||
text: "<?php echo e2("Clear Value") ?>",
|
||||
onItemClick: function(args) {
|
||||
e.component.cellValue(e.rowIndex, e.columnIndex, null);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@endif
|
||||
|
||||
@if(isAuth($id, "write"))
|
||||
|
||||
e.items.push({
|
||||
text: "<?php echo e2("Clone Row") ?>",
|
||||
onItemClick: function(args) {
|
||||
$(".dx-icon-edit-button-addrow").trigger("click");
|
||||
selectedData = e.row.data;
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@endif
|
||||
|
||||
@if(isAuth($id, "modify"))
|
||||
|
||||
e.items.push({
|
||||
text: "<?php echo e2("Copy Start") ?>",
|
||||
onItemClick: function(args) {
|
||||
copyData = e.component.cellValue(e.rowIndex, e.columnIndex);
|
||||
selectedColIndex = e.columnIndex;
|
||||
selectedRowIndex = e.rowIndex;
|
||||
console.log(e);
|
||||
console.log(selectedColIndex);
|
||||
console.log(selectedRowIndex);
|
||||
Swal.fire(copyData, "<?php echo e2("Data copied start") ?>", "success");
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
e.items.push({
|
||||
text: "<?php echo e2("Until Paste") ?>",
|
||||
onItemClick: function(args) {
|
||||
|
||||
if(e.columnIndex != selectedColIndex) {
|
||||
Swal.fire("<?php echo e2("Wrong") ?>", "<?php echo e2("Please copy using the same columns.") ?>", "error");
|
||||
} else {
|
||||
for(var rowIndex = selectedRowIndex + 1; rowIndex<=e.rowIndex; rowIndex++) {
|
||||
e.component.cellValue(rowIndex, e.columnIndex, copyData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@endif
|
||||
}
|
||||
},
|
||||
|
||||
onEditingStart(e) {
|
||||
var focusedSelector = $("td.dx-focused");
|
||||
var rowIndex = dataGrid.option("focusedRowIndex");
|
||||
var colIndex = dataGrid.option("focusedColumnIndex");
|
||||
try {
|
||||
var dataField = e.column.dataField;
|
||||
var allEntries = JSON.parse(localStorage.getItem("originalData" + rowIndex + colIndex)) || [];
|
||||
allEntries.push(e.data[dataField]);
|
||||
localStorage.setItem("originalData" + rowIndex + colIndex, JSON.stringify(allEntries));
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
||||
onInitNewRow(e) {
|
||||
|
||||
if(selectedData) {
|
||||
e.data = selectedData;
|
||||
selectedData = null;
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
onRowInserting(e) {
|
||||
logEvent('RowInserting');
|
||||
console.log(e);
|
||||
},
|
||||
|
||||
onRowInserted() {
|
||||
// logEvent('RowInserted');
|
||||
},
|
||||
onRowUpdating() {
|
||||
},
|
||||
onRowUpdated() {
|
||||
// logEvent('RowUpdated');
|
||||
},
|
||||
onRowRemoving() {
|
||||
// logEvent('RowRemoving');
|
||||
},
|
||||
onRowRemoved() {
|
||||
// logEvent('RowRemoved');
|
||||
},
|
||||
onSaving() {
|
||||
|
||||
},
|
||||
onInitialized() {
|
||||
|
||||
$("#dataGrid td").on("click", function() {
|
||||
logEvent("#dataGrid td");
|
||||
});
|
||||
},
|
||||
onRowClick: function(e) {
|
||||
|
||||
/*
|
||||
console.log("onRowClick");
|
||||
console.log(e);
|
||||
selectedData = e.data;
|
||||
selectedData.id = null;
|
||||
if(e.rowType === "data") {
|
||||
e.component.editRow(e.rowIndex);
|
||||
}
|
||||
|
||||
*/
|
||||
},
|
||||
onSaved() {
|
||||
|
||||
logEvent('Saving Success');
|
||||
},
|
||||
onEditCanceling() {
|
||||
// logEvent('EditCanceling');
|
||||
},
|
||||
onEditCanceled() {
|
||||
// logEvent('EditCanceled');
|
||||
},
|
||||
onFocusedRowChanging(e) {
|
||||
// console.log(e);
|
||||
},
|
||||
|
||||
|
||||
sorting: {
|
||||
mode: "multiple" // or "multiple" | "none"
|
||||
},
|
||||
|
||||
|
||||
<?php
|
||||
} ?>
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
function defect_names() {
|
||||
return array_map("trim", explode("\n", "Single Porosity
|
||||
Chain Porosity
|
||||
Cluster Porosity
|
||||
Single Slag
|
||||
Chain Slag
|
||||
Cluster Slag
|
||||
Single Tungsten
|
||||
Chain Tungsten
|
||||
Cluster Tungsten
|
||||
Incomplete Root Penetration
|
||||
Incomplete Inter-pass Fusion
|
||||
Incomplet Side Wall Fusion
|
||||
Longitudinal Crack
|
||||
Transverse Crack
|
||||
Branched Crack
|
||||
Root Concavity / Suck Back
|
||||
Root Convexity / Extensive Root
|
||||
Undercut
|
||||
High-Low
|
||||
Other"));
|
||||
}
|
||||
function defects() {
|
||||
|
||||
return [
|
||||
'aa',
|
||||
'ab',
|
||||
'ac',
|
||||
'ba',
|
||||
'bb',
|
||||
'bc',
|
||||
'ca',
|
||||
'cb',
|
||||
'cc',
|
||||
'da',
|
||||
'db',
|
||||
'dc',
|
||||
'ea',
|
||||
'eb',
|
||||
'ec',
|
||||
'fa',
|
||||
'fb',
|
||||
'fc',
|
||||
'fd',
|
||||
'other',
|
||||
];
|
||||
} ?>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
function deleteAfterR($input) {
|
||||
$pos = strpos($input, 'R'); // R karakterinin pozisyonunu bul
|
||||
if ($pos !== false) {
|
||||
// Eğer R karakteri bulunduysa, R karakterinden sonrasını sil
|
||||
$output = substr($input, 0, $pos);
|
||||
} else {
|
||||
// Eğer R karakteri bulunamazsa, input'u olduğu gibi döndür
|
||||
$output = $input;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Helper function to detect changed fields
|
||||
*
|
||||
* Compares current data with previous data to identify which fields changed
|
||||
*
|
||||
* @param mixed $data Current data
|
||||
* @param mixed $beforeData Previous data (null for new records)
|
||||
* @return array Array of changed field names
|
||||
*/
|
||||
function detectChangedFields($data, $beforeData): array
|
||||
{
|
||||
if (is_null($beforeData)) {
|
||||
// New record - all fields are "changed"
|
||||
return array_keys((array) $data);
|
||||
}
|
||||
|
||||
$changedFields = [];
|
||||
$dataArray = (array) $data;
|
||||
$beforeDataArray = (array) $beforeData;
|
||||
|
||||
foreach ($dataArray as $key => $value) {
|
||||
$oldValue = $beforeDataArray[$key] ?? null;
|
||||
|
||||
// Compare values - consider both strict and loose equality for type changes
|
||||
if ($oldValue !== $value) {
|
||||
$changedFields[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
return $changedFields;
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
function onPreparingVariables() {
|
||||
?>
|
||||
var options = e.editorOptions;
|
||||
var rowIndex = e.row.rowIndex;
|
||||
var rowData = e.row.data;
|
||||
var dataGrid = $("#dataGrid").dxDataGrid("instance");
|
||||
var exceptValue = ['undefined', 'null'];
|
||||
var column = e.dataField;
|
||||
var urlRowData = encodeURIComponent(JSON.stringify(rowData));
|
||||
<?php
|
||||
}
|
||||
|
||||
function dxAutocomplete($columnName, $tableName, $targetColumn, $filter = "", $affected = "") {
|
||||
if ($filter != "") {
|
||||
$filter2 = [];
|
||||
foreach ($filter as $filterColumn => $filterValue) {
|
||||
if (is_array($filterValue)) {
|
||||
$filter2[$filterColumn] = implode(",", $filterValue);
|
||||
} elseif (strpos($filterValue, '"') !== false) {
|
||||
$filterValue = str_replace('"', "", $filterValue);
|
||||
$filter2[$filterColumn] = "{$filterValue}";
|
||||
} else {
|
||||
$filter2[$filterColumn] = "'+ dataRow.{$filterValue} +'";
|
||||
}
|
||||
}
|
||||
$filter = "&filter=" . json_encode_tr($filter2);
|
||||
}
|
||||
?>
|
||||
<?php if ($affected == "") { ?>
|
||||
if (e.dataField == "<?php echo $columnName ?>") {
|
||||
e.editorName = "dxAutocomplete";
|
||||
e.editorOptions.searchEnabled = true;
|
||||
e.editorOptions.acceptCustomValue = true;
|
||||
e.editorOptions.dataSource = new DevExpress.data.ODataStore({
|
||||
url: '<?php echo autocomplete_url($tableName, $targetColumn) ?><?php echo $filter ?>',
|
||||
key: 'id',
|
||||
});
|
||||
e.editorOptions.valueExpr = '<?php echo $targetColumn ?>';
|
||||
e.editorOptions.displayExpr = '<?php echo $targetColumn ?>';
|
||||
}
|
||||
<?php } else { ?>
|
||||
var options = e.editorOptions;
|
||||
var rowIndex = e.row.rowIndex;
|
||||
var dataGrid = $("#dataGrid").dxDataGrid("instance");
|
||||
var exceptValue = ['undefined', 'null'];
|
||||
|
||||
if (e.dataField == "<?php echo $columnName ?>") {
|
||||
e.editorName = "dxAutocomplete";
|
||||
e.editorOptions.searchEnabled = true;
|
||||
e.editorOptions.acceptCustomValue = true;
|
||||
e.editorOptions.showClearButton = true;
|
||||
e.editorOptions.dataSource = new DevExpress.data.ODataStore({
|
||||
url: '<?php echo autocomplete_url($tableName, $targetColumn) ?><?php echo $filter ?>',
|
||||
key: 'id',
|
||||
});
|
||||
e.editorOptions.valueExpr = '<?php echo $targetColumn ?>';
|
||||
e.editorOptions.displayExpr = '<?php echo $targetColumn ?>';
|
||||
|
||||
var fetchRelatedData = function(typedValue) {
|
||||
if (typedValue === null || typedValue === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$.getJSON("<?php echo row_detail_url($tableName, $targetColumn) ?>?value=" + typedValue, function(responseJSON) {
|
||||
console.log(responseJSON);
|
||||
if (responseJSON && typeof responseJSON.<?php echo $targetColumn ?> !== 'undefined') {
|
||||
<?php
|
||||
$affectedCols = $affected;
|
||||
foreach ($affectedCols as $affectedCol => $valueCol) {
|
||||
$valueCol = str_replace('{', '${responseJSON.', $valueCol); ?>
|
||||
if (!exceptValue.includes(`<?php echo $valueCol ?>`)) {
|
||||
dataGrid.cellValue(rowIndex, "<?php echo $affectedCol ?>", `<?php echo $valueCol ?>`);
|
||||
} else {
|
||||
console.log("except value <?php echo $valueCol ?>");
|
||||
}
|
||||
<?php } ?>
|
||||
} else {
|
||||
console.log("undefined <?php echo $targetColumn ?>");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
options.onValueChanged = function(selectData) {
|
||||
console.log("on value changed");
|
||||
e.setValue(selectData.value);
|
||||
|
||||
if (options.__stellarExactMatchTimer) {
|
||||
clearTimeout(options.__stellarExactMatchTimer);
|
||||
}
|
||||
|
||||
options.__stellarExactMatchTimer = setTimeout(function() {
|
||||
var typedValue = (selectData && typeof selectData.value !== 'undefined') ? selectData.value : null;
|
||||
fetchRelatedData(typedValue);
|
||||
}, 250);
|
||||
}
|
||||
|
||||
options.onSelectionChanged = function(eSelection) {
|
||||
if (eSelection.selectedItem) {
|
||||
if (options.__stellarExactMatchTimer) {
|
||||
clearTimeout(options.__stellarExactMatchTimer);
|
||||
}
|
||||
// Use the value directly from the selected item
|
||||
var selectedValue = eSelection.selectedItem['<?php echo $targetColumn ?>'];
|
||||
fetchRelatedData(selectedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
<?php } ?>
|
||||
<?php
|
||||
}
|
||||
|
||||
function dxSelectBox($columnName, $tableName, $targetColumn, $filter = "", $affected = "", $order = "") {
|
||||
if ($filter != "") {
|
||||
$filter2 = [];
|
||||
foreach ($filter as $filterColumn => $filterValue) {
|
||||
if (is_array($filterValue)) {
|
||||
$filter2[$filterColumn] = implode(",", $filterValue);
|
||||
} elseif (strpos($filterValue, '"') !== false) {
|
||||
$filterValue = str_replace('"', "", $filterValue);
|
||||
$filter2[$filterColumn] = "{$filterValue}";
|
||||
} else {
|
||||
$filter2[$filterColumn] = "'+ dataRow.{$filterValue} +'";
|
||||
}
|
||||
}
|
||||
$filter = "&filter=" . json_encode_tr($filter2);
|
||||
}
|
||||
?>
|
||||
<?php if ($affected == "") { ?>
|
||||
if (e.dataField == "<?php echo $columnName ?>") {
|
||||
e.editorName = "dxSelectBox";
|
||||
e.editorOptions.searchEnabled = true;
|
||||
e.editorOptions.acceptCustomValue = true;
|
||||
e.editorOptions.allowCustomValues = true;
|
||||
e.editorOptions.dataSource = new DevExpress.data.ODataStore({
|
||||
url: '<?php echo autocomplete_url($tableName, $targetColumn) ?><?php echo $filter ?>',
|
||||
key: 'id',
|
||||
});
|
||||
e.editorOptions.valueExpr = '<?php echo $targetColumn ?>';
|
||||
e.editorOptions.displayExpr = '<?php echo $targetColumn ?>';
|
||||
}
|
||||
<?php } else { ?>
|
||||
var options = e.editorOptions;
|
||||
var rowIndex = e.row.rowIndex;
|
||||
var dataGrid = $("#dataGrid").dxDataGrid("instance");
|
||||
var exceptValue = ['undefined', 'null'];
|
||||
|
||||
if (e.dataField == "<?php echo $columnName ?>") {
|
||||
e.editorName = "dxSelectBox";
|
||||
e.editorOptions.searchEnabled = true;
|
||||
e.editorOptions.acceptCustomValue = true;
|
||||
e.editorOptions.allowCustomValues = true;
|
||||
e.editorOptions.showClearButton = true;
|
||||
e.editorOptions.dataSource = new DevExpress.data.ODataStore({
|
||||
url: '<?php echo autocomplete_url($tableName, $targetColumn) ?><?php echo $filter ?>',
|
||||
key: 'id',
|
||||
});
|
||||
e.editorOptions.valueExpr = '<?php echo $targetColumn ?>';
|
||||
e.editorOptions.displayExpr = '<?php echo $targetColumn ?>';
|
||||
|
||||
options.onValueChanged = function(selectData) {
|
||||
e.setValue(selectData.value);
|
||||
|
||||
if (options.__stellarExactMatchTimer) {
|
||||
clearTimeout(options.__stellarExactMatchTimer);
|
||||
}
|
||||
|
||||
options.__stellarExactMatchTimer = setTimeout(function() {
|
||||
var typedValue = (selectData && typeof selectData.value !== 'undefined') ? selectData.value : null;
|
||||
if (typedValue === null || typedValue === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$.getJSON("<?php echo row_detail_url($tableName, $targetColumn) ?>?order=<?php echo $order ?>&nolike=1&value=" + encodeURIComponent(typedValue), function(responseJSON) {
|
||||
console.log(responseJSON);
|
||||
if (responseJSON && typeof responseJSON.<?php echo $targetColumn ?> !== 'undefined') {
|
||||
<?php
|
||||
$affectedCols = $affected;
|
||||
foreach ($affectedCols as $affectedCol => $valueCol) {
|
||||
$valueCol = str_replace('{', '${responseJSON.', $valueCol); ?>
|
||||
if (!exceptValue.includes(`<?php echo $valueCol ?>`)) {
|
||||
dataGrid.cellValue(rowIndex, "<?php echo $affectedCol ?>", `<?php echo $valueCol ?>`);
|
||||
} else {
|
||||
console.log("except value <?php echo $valueCol ?>");
|
||||
}
|
||||
<?php } ?>
|
||||
} else {
|
||||
console.log("undefined <?php echo $targetColumn ?>");
|
||||
}
|
||||
});
|
||||
}, 250);
|
||||
}
|
||||
}
|
||||
<?php } ?>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php function dxDataStore($tableName, $columnName, $filter = "") {
|
||||
?>
|
||||
new DevExpress.data.ODataStore({
|
||||
url: '<?php echo autocomplete_url2($tableName, $columnName) ?><?php echo $filter ?>,
|
||||
key: 'id',
|
||||
});
|
||||
<?php
|
||||
} ?>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php function document_template($id) {
|
||||
$document = db("document_templates")->orWhere("slug", $id)->orWhere("id", $id)->first();
|
||||
return $document;
|
||||
} ?>
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
use PhpOffice\PhpWord\TemplateProcessor;
|
||||
|
||||
function replacePlaceholdersInDocx($templateFilePath, $outputFilePath, $replacements) {
|
||||
// Load the DOCX template
|
||||
//$storagePath = "storage/documents/$outputFilePath";
|
||||
$storagePath = $outputFilePath;
|
||||
$directoryPath = dirname($storagePath);
|
||||
|
||||
if (!is_dir($directoryPath)) {
|
||||
mkdir($directoryPath, 0777, true);
|
||||
}
|
||||
|
||||
$templateProcessor = new TemplateProcessor($templateFilePath);
|
||||
|
||||
$templateProcessor->setValue("text.ncr_no", "test");
|
||||
|
||||
// $templateProcessor->setValue("corrective_action_ru", "teasdasdast");
|
||||
/*
|
||||
$reflectionClass = new \ReflectionClass($templateProcessor);
|
||||
|
||||
// Accessing the protected/private property
|
||||
$property = $reflectionClass->getProperty('tempDocumentMainPart');
|
||||
$property->setAccessible(true);
|
||||
|
||||
// Get the value of the property
|
||||
$xmlContent = $property->getValue($templateProcessor);
|
||||
|
||||
$xmlContent = str_replace("corrective_action_ru", "test", $xmlContent);
|
||||
|
||||
$property->setValue($templateProcessor, $xmlContent);
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
$formTypes = ['date', 'time', 'text', 'textarea', 'radio', 'checkbox', 'select'];
|
||||
|
||||
// Replace placeholders
|
||||
|
||||
foreach ($replacements as $search => $replace) {
|
||||
|
||||
foreach($formTypes AS $formType)
|
||||
{
|
||||
|
||||
$isValidDate = false;
|
||||
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $replace)) {
|
||||
// YYYY-MM-DD formatında tarih
|
||||
$isValidDate = true;
|
||||
} elseif (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $replace)) {
|
||||
// YYYY-MM-DD HH:MM:SS formatında tarih ve saat
|
||||
$isValidDate = true;
|
||||
} elseif (preg_match('/^\d{2}.\d{2}.\d{4}$/', $replace)) {
|
||||
// DD.MM.YYYY formatında tarih
|
||||
$isValidDate = true;
|
||||
} elseif (preg_match('/^\d{2}.\d{2}.\d{4} \d{2}:\d{2}:\d{2}$/', $replace)) {
|
||||
// DD.MM.YYYY HH:MM:SS formatında tarih ve saat
|
||||
$isValidDate = true;
|
||||
}
|
||||
|
||||
if($isValidDate)
|
||||
{
|
||||
if (strtotime($replace)) {
|
||||
$dateTime = new DateTime($replace);
|
||||
|
||||
// Eğer $replace saati de içeriyorsa
|
||||
if ($dateTime->format('H:i:s') !== '00:00:00') {
|
||||
$replace = $dateTime->format('H:i');
|
||||
} else {
|
||||
$replace = $dateTime->format('d.m.Y');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($formType, ['radio', 'checkbox'])) {
|
||||
$replacePlaceHolder = $formType . '.' . $search . '.' . $replace;
|
||||
$okValue = '✓';
|
||||
$cellValue = $okValue;
|
||||
|
||||
$otherPattern = "/<w:t>\{$formType\.$search\.[^}]*\}<\/w:t>/";
|
||||
|
||||
//$xmlContent = preg_replace($otherPattern, "", /$xmlContent);
|
||||
} else {
|
||||
$replacePlaceHolder = $formType . '.' . $search; // Note the curly braces
|
||||
$cellValue = $replace;
|
||||
|
||||
$pattern = '/\{' . preg_quote($formType, '/') . '\.<\/w:t><\/w:r><w:r[^>]*><w:rPr>.*?<\/w:rPr><w:t>' . preg_quote($search, '/') . '<\/w:t>/';
|
||||
dump($pattern);
|
||||
// $xmlContent = preg_replace($pattern, $cellValue, $xmlContent);
|
||||
$property->setValue($templateProcessor, $xmlContent);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// dump($pattern);
|
||||
// dump($cellValue);
|
||||
|
||||
// preg_replace ile değişim
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
$templateProcessor->saveAs($storagePath);
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
function docx_to_html($docx, $html_dir) {
|
||||
// Ensure the LANG environment variable is set
|
||||
putenv('LANG=ru_RU.UTF-8');
|
||||
|
||||
// Ensure the output directory exists
|
||||
if (!is_dir($html_dir)) {
|
||||
mkdir($html_dir, 0777, true);
|
||||
}
|
||||
|
||||
// Construct the command
|
||||
$command = "libreoffice --headless --convert-to html --outdir " . escapeshellarg($html_dir) . " " . escapeshellarg($docx);
|
||||
// Execute the command
|
||||
$output = shell_exec($command);
|
||||
$output = extract_between_markers_docx($output);
|
||||
|
||||
update_src_paths($output, $html_dir);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
function extract_between_markers_docx($input_str) {
|
||||
// Define the regular expression pattern to match the content between the markers
|
||||
$pattern = '/->\s*(.*?)\s*using filter : HTML \(StarWriter\)/';
|
||||
|
||||
// Perform the regex match
|
||||
if (preg_match($pattern, $input_str, $matches)) {
|
||||
// Return the matched content
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
// Return null if no match is found
|
||||
return null;
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
function export_excel($dizi, $dosya_adi) {
|
||||
$dizi = $dizi->toArray();
|
||||
|
||||
$excepts = ['created_at', 'updated_at'];
|
||||
|
||||
$filtered = [];
|
||||
foreach($dizi AS $key => $value) {
|
||||
foreach($excepts AS $except) {
|
||||
$value = (Array) $value;
|
||||
unset($value[$except]);
|
||||
}
|
||||
$filtered[] = $value;
|
||||
}
|
||||
|
||||
|
||||
$dizi = $filtered;
|
||||
|
||||
$dosya_adi = (String) $dosya_adi;
|
||||
$icerik = "";
|
||||
foreach($dizi[0] AS $column => $value) {
|
||||
$icerik .= "$column\t";
|
||||
}
|
||||
$icerik .= "\r\n";
|
||||
foreach($dizi AS $column) {
|
||||
foreach($column AS $col => $value) {
|
||||
$icerik .= "$value\t";
|
||||
}
|
||||
$icerik .= "\r\n";
|
||||
}
|
||||
$icerik = trim($icerik);
|
||||
|
||||
return response($icerik)
|
||||
->header('Content-type','application/ms-excel')
|
||||
->header('Content-Disposition','attachment; filename="'.$dosya_adi.'.xls"')
|
||||
->send();
|
||||
} ?>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
|
||||
function file_force_contents( $fullPath, $contents, $flags = 0 ){
|
||||
$parts = explode( '/', $fullPath );
|
||||
array_pop( $parts );
|
||||
$dir = implode( '/', $parts );
|
||||
|
||||
if( !is_dir( $dir ) )
|
||||
mkdir( $dir, 0777, true );
|
||||
|
||||
file_put_contents( $fullPath, $contents, $flags );
|
||||
}
|
||||
function pdf_create($path, $html)
|
||||
{
|
||||
$pdf = App::make('dompdf.wrapper');
|
||||
$pdf->setPaper('A4',$j['paper']);
|
||||
$pdf->setOption(['dpi' => $j['dpi'], ]);
|
||||
$pdf->loadHTML($html);
|
||||
|
||||
$path = "$path.pdf";
|
||||
|
||||
Storage::delete($path);
|
||||
Storage::put($path, $pdf->output());
|
||||
}
|
||||
|
||||
function html_create($path, $html, $paper="portrait")
|
||||
{
|
||||
$path = "$path.html";
|
||||
Storage::delete($path);
|
||||
Storage::put($path, $html);
|
||||
|
||||
|
||||
$htmlPath = "storage/documents/" . $path;
|
||||
$pdfPath = str_replace(".html", ".pdf", $htmlPath);
|
||||
html_to_pdf($htmlPath, $pdfPath, $paper);
|
||||
unlink($htmlPath);
|
||||
} ?>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php function findItemObject($text, $column, $object) {
|
||||
$array = @json_decode(json_encode($object));
|
||||
$find = array_search($text, array_column($array, $column));
|
||||
if(!$find) {
|
||||
return false;
|
||||
} else {
|
||||
return $object[$find];
|
||||
}
|
||||
|
||||
} ?>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* Try catch kullanarak index değerine göre yoksa ekler
|
||||
*/
|
||||
function firstOrCreate($data, $table, $debug=false) {
|
||||
|
||||
try {
|
||||
$data['created_at'] = simdi();
|
||||
$id = db($table)->insertGetId($data);
|
||||
return $id;
|
||||
} catch (\Throwable $th) {
|
||||
if($debug) {
|
||||
dump($th);
|
||||
}
|
||||
}
|
||||
|
||||
} ?>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Try catch kullanarak ekler veya günceller
|
||||
* Transaction management added to prevent lock issues
|
||||
*/
|
||||
function firstOrUpdate($data, $table, $where, $debug = false) {
|
||||
|
||||
if(isset($data['id'])) {
|
||||
if($data['id'] == "") {
|
||||
unset($data['id']);
|
||||
}
|
||||
}
|
||||
|
||||
return \DB::transaction(function() use ($data, $table, $where, $debug) {
|
||||
try {
|
||||
$data['created_at'] = simdi();
|
||||
$id = db($table)->insertGetId($data);
|
||||
return $id;
|
||||
} catch (\Throwable $th) {
|
||||
|
||||
if($debug) {
|
||||
dump($th);
|
||||
}
|
||||
|
||||
// Use lockForUpdate to prevent race conditions
|
||||
$affectedRows = db($table)
|
||||
->where($where)
|
||||
->lockForUpdate()
|
||||
->get();
|
||||
|
||||
$affectedRows = db($table)->where($where)->update($data);
|
||||
return "update $affectedRows";
|
||||
}
|
||||
}, 3); // 3 retry attempts
|
||||
|
||||
} ?>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* Generate a unique report number with prefix and identifier
|
||||
*
|
||||
* @param string $prefix The prefix for the report number
|
||||
* @param string $identifier The identifier (line+spool) for the report
|
||||
* @return string The formatted report number
|
||||
*/
|
||||
if (!function_exists('generateReportNumber')) {
|
||||
function generateReportNumber($prefix, $identifier) {
|
||||
$date = date('Ymd');
|
||||
$randomNumber = mt_rand(100, 999);
|
||||
return $prefix . '-' . $identifier . '-' . $date . '-' . $randomNumber;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php function generate_hash_link($type, $title="") {
|
||||
$hash = Hash::make($type);
|
||||
$showLink = url("mail-link?title=$title&type=$type&hash=$hash");
|
||||
return $showLink;
|
||||
} ?>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
function getBeforeSlash($input) {
|
||||
$input = str_replace("/141", "", $input);
|
||||
$input = str_replace("/111", "", $input);
|
||||
return $input;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
function getKeyColumns($table) {
|
||||
$keyColumnsMap = [
|
||||
"line_lists" => ["line", "fluid_code"],
|
||||
"supports" => ["id"],
|
||||
"paint_matrices" => ["line", "fluid_code"],
|
||||
"nde_matrices" => ["line", "fluid", "type_of_joint"],
|
||||
"document_revisions" => ["drawing_no", "zone"],
|
||||
"m_t_o_s" => ["line", "component_code_id"],
|
||||
"test_packages" => ["test_package_number"],
|
||||
"test_pack_base_statuses" => ["test_package_no"],
|
||||
"punch_lists" => ["test_package", "punch_list_no"],
|
||||
"weld_logs" => ["iso", "joint"]
|
||||
];
|
||||
|
||||
// log_test_types() tabloları için özel kontrol
|
||||
if (in_array($table, log_test_types())) {
|
||||
return ["iso", "joint", "welding_date"];
|
||||
}
|
||||
|
||||
// Tablo için tanımlı sütunları döndür
|
||||
return $keyColumnsMap[$table] ?? [];
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php function get_revision_from_string($string) {
|
||||
|
||||
preg_match('/(?i)(?<=rev)\w+/', $string, $matches);
|
||||
$number = $matches[0] ?? "";
|
||||
return $number;
|
||||
} ?>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php function get_variables_from_pattern($patternString) {
|
||||
preg_match_all('/{(.*?)}/',$patternString, $matches);
|
||||
return $matches[1];
|
||||
} ?>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
function getLatestSpoolStatus($spoolStatuses) {
|
||||
// Eğer tüm spool_status değerleri "Waiting" ise
|
||||
if (count(array_filter($spoolStatuses, fn($status) => $status !== 'Waiting')) === 0) {
|
||||
return 'Waiting';
|
||||
}
|
||||
|
||||
// Spool durumlarını sayısal değerlere göre sıralayıp en yüksek olanı döndür
|
||||
$statusValues = [
|
||||
'Waiting',
|
||||
'On Going',
|
||||
'Spool Release',
|
||||
'NDT Release',
|
||||
'Paint',
|
||||
'Completed'
|
||||
];
|
||||
|
||||
// Geçerli spool durumlarını kontrol et ve en yüksek durumu bul
|
||||
$latestStatus = null; // Başlangıçta en yüksek durum yok
|
||||
foreach ($statusValues as $status) {
|
||||
if (in_array($status, $spoolStatuses)) {
|
||||
if ($latestStatus === null || array_search($status, $statusValues) > array_search($latestStatus, $statusValues)) {
|
||||
$latestStatus = $status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $latestStatus;
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
function getLowestSpoolStatus($spoolStatuses) {
|
||||
// Eğer tüm spool_status değerleri "Completed" ise
|
||||
if (count(array_filter($spoolStatuses, fn($status) => $status !== 'Completed')) === 0) {
|
||||
return 'Completed';
|
||||
}
|
||||
|
||||
// Spool durumlarını sayısal değerlere göre sıralayıp en düşük olanı döndür
|
||||
$statusValues = [
|
||||
'Waiting',
|
||||
'On Going',
|
||||
'Spool Release',
|
||||
'NDT Release',
|
||||
'Paint',
|
||||
'Completed'
|
||||
];
|
||||
|
||||
// Geçerli spool durumlarını kontrol et ve en düşük durumu bul
|
||||
$lowestStatus = null; // Başlangıçta en düşük durum yok
|
||||
foreach ($statusValues as $status) {
|
||||
if (in_array($status, $spoolStatuses)) {
|
||||
if ($lowestStatus === null || array_search($status, $statusValues) < array_search($lowestStatus, $statusValues)) {
|
||||
$lowestStatus = $status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $lowestStatus;
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php function get_number() {
|
||||
return date("ynjg") . rand(111,999);
|
||||
} ?>
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php function get_url_json($tableName, $columnName, $value="") {
|
||||
return url("admin/get/$tableName/$columnName/$value") . "/";
|
||||
} ?>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php function get_welder_id($metin) {
|
||||
$pattern = "/\[([A-Z0-9]+)\]/"; // "[BZ7X]" gibi örüntüyü yakalar
|
||||
|
||||
if (preg_match($pattern, $metin, $matches)) {
|
||||
$deger = $matches[1];
|
||||
$deger = trim($deger);
|
||||
return $deger;
|
||||
} else {
|
||||
return $metin;
|
||||
}
|
||||
} ?>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
function get_welder_name($welder_id, $type = "en") {
|
||||
$welderName = db("naks_welders")->where("welder_id", $welder_id)->first();
|
||||
if($welderName) {
|
||||
if($type == "en") {
|
||||
return $welderName->welder_name_en;
|
||||
} else {
|
||||
return $welderName->welder_name_ru;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function get_welder_info($welder_id) {
|
||||
return db("naks_welders")->where("welder_id", $welder_id)->first();
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php function html_to_pdf($html, $pdf, $paper="portrait")
|
||||
{
|
||||
$params = "";
|
||||
if($paper == "landscape") {
|
||||
$params = "-O landscape";
|
||||
}
|
||||
putenv('LANG=ru_RU.UTF-8');
|
||||
$wk_path = env("wk_path");
|
||||
$command = "$wk_path $params '$html' '$pdf'";
|
||||
return shell_exec($command);
|
||||
} ?>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php function icon($type) {
|
||||
echo "<span class=\"material-symbols-outlined\">
|
||||
$type
|
||||
</span>";
|
||||
} ?>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php function get_cache_id($prefix) {
|
||||
$lastId = 0;
|
||||
|
||||
if(Cache::has($prefix)) {
|
||||
$lastId = Cache::get($prefix);
|
||||
}
|
||||
|
||||
return $lastId;
|
||||
}
|
||||
|
||||
function set_cache_id($prefix, $lastId) {
|
||||
Cache::put($prefix, $lastId);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Get inspection history configuration for a module from settings
|
||||
*
|
||||
* @param string $moduleSlug Module slug to get configuration for
|
||||
* @param string|null $moduleTitle Optional module title for path generation
|
||||
* @return array|null Returns array with 'path', 'pattern', and 'active' keys, or null if not found
|
||||
*/
|
||||
function getInspectionHistoryConfig($moduleSlug, $moduleTitle = null)
|
||||
{
|
||||
if (empty($moduleSlug)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the module settings value
|
||||
$settingsJson = setting('inspection_history_management', false, '{}');
|
||||
$settings = json_decode($settingsJson, true);
|
||||
|
||||
$moduleConfig = null;
|
||||
|
||||
if (isset($settings[$moduleSlug])) {
|
||||
$moduleConfig = $settings[$moduleSlug];
|
||||
} else {
|
||||
// Try kebab-case version if underscore version not found
|
||||
$kebabSlug = str_replace('_', '-', $moduleSlug);
|
||||
if (isset($settings[$kebabSlug])) {
|
||||
$moduleConfig = $settings[$kebabSlug];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$moduleConfig) {
|
||||
if ($moduleSlug === 'Other') {
|
||||
$moduleConfig = [
|
||||
'active' => true,
|
||||
'path_pattern' => '',
|
||||
'file_pattern' => '{timestamp}_{file_name}'
|
||||
];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the main path setting
|
||||
$mainPath = setting('inspection_history_main_path', false, '');
|
||||
|
||||
// If no main path is set, return null (feature not configured)
|
||||
if (empty($mainPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get module title if not provided
|
||||
if (empty($moduleTitle)) {
|
||||
$module = \App\Types::where('slug', $moduleSlug)->first(['title']);
|
||||
$moduleTitle = $module ? $module->title : $moduleSlug;
|
||||
}
|
||||
|
||||
// Clean module title for use as directory name
|
||||
$cleanTitle = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $moduleTitle);
|
||||
$cleanTitle = preg_replace('/_+/', '_', $cleanTitle);
|
||||
$cleanTitle = trim($cleanTitle, '_');
|
||||
|
||||
// Build the full path: main_path/module_title
|
||||
$fullPath = $mainPath . '/' . $cleanTitle;
|
||||
|
||||
return [
|
||||
'path' => $fullPath,
|
||||
'path' => $fullPath,
|
||||
'path_pattern' => $moduleConfig['path_pattern'] ?? null,
|
||||
'file_pattern' => $moduleConfig['file_pattern'] ?? $moduleConfig['pattern'] ?? null,
|
||||
'pattern' => $moduleConfig['pattern'] ?? null, // Keep for backward compatibility elsewhere if needed
|
||||
'active' => $moduleConfig['active'] ?? false
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php function isAdmin($u = null) {
|
||||
if(is_null($u)) {
|
||||
$u = u();
|
||||
}
|
||||
if($u->level=="Admin") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} ?>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php function is_stellar() {
|
||||
$stellar = db("subcontractors")->where("company_name_en", "like", "%stellar%")->first()->company_name_en;
|
||||
$u = u();
|
||||
if($u->subcontructer == $stellar) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} ?>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
function isoToLine()
|
||||
{
|
||||
// ISO numaralarına karşılık gelen line_number'ları almak
|
||||
$isoToLine = db("weld_logs")
|
||||
->select('line_number', 'iso_number')
|
||||
->pluck('line_number', 'iso_number')
|
||||
->toArray();
|
||||
|
||||
return $isoToLine;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php function job_descriptions() {
|
||||
$jobDesc = db("job_descriptions")->get()->pluck("title")->toArray();
|
||||
$jobDesc[] = null;
|
||||
$jobDesc[] = "";
|
||||
return $jobDesc;
|
||||
} ?>
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
use App\Services\JointTypeService;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
if (!function_exists('joint_type_service')) {
|
||||
function joint_type_service(): JointTypeService
|
||||
{
|
||||
return app(JointTypeService::class);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('is_welded_joint')) {
|
||||
/**
|
||||
* Check if a joint type is a welded joint
|
||||
*
|
||||
* @param string $jointType - Joint type short_name_en or naks_name
|
||||
* @return bool
|
||||
*/
|
||||
function is_welded_joint($jointType) {
|
||||
return joint_type_service()->isWelded($jointType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('requires_ndt')) {
|
||||
/**
|
||||
* Check if a joint type requires NDT
|
||||
*
|
||||
* @param string $jointType - Joint type short_name_en or naks_name
|
||||
* @return bool
|
||||
*/
|
||||
function requires_ndt($jointType) {
|
||||
return joint_type_service()->requiresNdt($jointType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('is_mechanical_joint')) {
|
||||
/**
|
||||
* Check if a joint type is mechanical
|
||||
*
|
||||
* @param string $jointType - Joint type short_name_en or naks_name
|
||||
* @return bool
|
||||
*/
|
||||
function is_mechanical_joint($jointType) {
|
||||
return joint_type_service()->isMechanical($jointType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_welded_joint_types')) {
|
||||
/**
|
||||
* Get array of welded joint types for query filtering
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_welded_joint_types() {
|
||||
return joint_type_service()->weldedTypes();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_mechanical_joint_types')) {
|
||||
/**
|
||||
* Get array of mechanical joint types for query filtering
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_mechanical_joint_types() {
|
||||
return joint_type_service()->mechanicalTypes();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('clear_joint_types_cache')) {
|
||||
/**
|
||||
* Clear joint types cache
|
||||
* Call this after updating joint_types table
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function clear_joint_types_cache() {
|
||||
joint_type_service()->clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('apply_welded_filter')) {
|
||||
/**
|
||||
* Apply welded joint filtering to a query builder or table name
|
||||
*
|
||||
* @param Builder|EloquentBuilder|string $queryOrTable
|
||||
* @param string $column
|
||||
* @return Builder|EloquentBuilder
|
||||
*/
|
||||
function apply_welded_filter($queryOrTable, string $column = 'type_of_welds') {
|
||||
$builder = resolve_builder_from_argument($queryOrTable);
|
||||
return joint_type_service()->filterWelded($builder, $column);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('apply_mechanical_filter')) {
|
||||
/**
|
||||
* Apply mechanical joint filtering to a query builder or table name
|
||||
*
|
||||
* @param Builder|EloquentBuilder|string $queryOrTable
|
||||
* @param string $column
|
||||
* @return Builder|EloquentBuilder
|
||||
*/
|
||||
function apply_mechanical_filter($queryOrTable, string $column = 'type_of_welds') {
|
||||
$builder = resolve_builder_from_argument($queryOrTable);
|
||||
return joint_type_service()->filterMechanical($builder, $column);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('resolve_builder_from_argument')) {
|
||||
/**
|
||||
* @param Builder|EloquentBuilder|string $queryOrTable
|
||||
* @return Builder|EloquentBuilder
|
||||
*/
|
||||
function resolve_builder_from_argument($queryOrTable) {
|
||||
if ($queryOrTable instanceof Builder || $queryOrTable instanceof EloquentBuilder) {
|
||||
return $queryOrTable;
|
||||
}
|
||||
|
||||
return DB::table($queryOrTable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
function languages() {
|
||||
$diller = explode(",","en,tr,ru");
|
||||
return $diller;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
if (!function_exists('levelColor')) {
|
||||
function levelColor($level) {
|
||||
$colors = [
|
||||
1 => 'success',
|
||||
2 => 'primary',
|
||||
3 => 'warning',
|
||||
4 => 'info'
|
||||
];
|
||||
return $colors[$level] ?? 'secondary';
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
function permission_type_index($type) {
|
||||
$permissionTypeToIndex = [
|
||||
'full_control' => 1,
|
||||
'write' => 2,
|
||||
'read' => 3,
|
||||
'modify' => 4,
|
||||
];
|
||||
return $permissionTypeToIndex[$type];
|
||||
}
|
||||
function levels_old() {
|
||||
// user no, full control, write, read, modify
|
||||
return [
|
||||
'Admin' => [1,1,1,1,1],
|
||||
'Manager (Center Office)' => [2,0,1,1,1],
|
||||
'Manager (QC)' => [2,0,1,1,0],
|
||||
'Manager (PTO)' => [2,0,1,1,0],
|
||||
'Manager (Lead)' => [3,0,1,1,0],
|
||||
'Welder (Subcontractor)' => [4,0,1,1,0],
|
||||
'Painter (Subcontractor)' => [5,0,1,1,0],
|
||||
'Insulator (Subcontractor)' => [6,0,1,1,0],
|
||||
'Welder, Painter, Insulator (Subcontractor / Payrollless)' => [7,0,1,1,0],
|
||||
'Quality Staff' => [8,0,1,1,1],
|
||||
'Document Staff' => [9,0,1,1,1],
|
||||
'Field Staff' => [10,0,0,1,0],
|
||||
];
|
||||
}
|
||||
|
||||
function levels() {
|
||||
// user no, full control, write, read, modify
|
||||
$userLevels = db("user_levels")->get();
|
||||
$levels = [];
|
||||
|
||||
foreach($userLevels AS $userLevel) {
|
||||
$levels[$userLevel->title] = [
|
||||
$userLevel->level_index,
|
||||
$userLevel->full_control,
|
||||
$userLevel->write,
|
||||
$userLevel->read,
|
||||
$userLevel->modify,
|
||||
];
|
||||
}
|
||||
|
||||
return $levels;
|
||||
}
|
||||
|
||||
function getLevelIndex($level) {
|
||||
$levels = levels();
|
||||
$k = 1;
|
||||
$index = null;
|
||||
|
||||
foreach($levels AS $thisLevel => $permissions) {
|
||||
if($thisLevel == $level) {
|
||||
$index = $permissions[0];
|
||||
}
|
||||
$k++;
|
||||
}
|
||||
return $index;
|
||||
}
|
||||
function levels2() {
|
||||
return [
|
||||
'Welder',
|
||||
'Engineer',
|
||||
];
|
||||
}
|
||||
|
||||
function level_keys() {
|
||||
return array_keys(levels());
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
function lineToIso()
|
||||
{
|
||||
// ISO numaralarına karşılık gelen line_number'ları almak
|
||||
$isoToLine = db("weld_logs")
|
||||
->select('line_number', 'iso_number')
|
||||
->pluck('iso_number', 'line_number')
|
||||
->toArray();
|
||||
|
||||
return $isoToLine;
|
||||
}
|
||||
|
||||
function lineTypeWelderToIso()
|
||||
{
|
||||
// (line_number, type_of_welds, welder) kombinasyonuna karşılık gelen iso_number'ları almak
|
||||
$rows = db("weld_logs")
|
||||
->select('line_number', 'type_of_welds', 'welder_1', 'welder_2', 'iso_number')
|
||||
->get();
|
||||
|
||||
$map = [];
|
||||
foreach ($rows as $row) {
|
||||
// welder_1 için map oluştur
|
||||
if (!empty($row->welder_1)) {
|
||||
$key = $row->line_number . '|' . $row->type_of_welds . '|' . $row->welder_1;
|
||||
$map[$key] = $row->iso_number;
|
||||
}
|
||||
|
||||
// welder_2 için de map oluştur (eğer welder_1'den farklıysa)
|
||||
if (!empty($row->welder_2) && $row->welder_2 !== $row->welder_1) {
|
||||
$key = $row->line_number . '|' . $row->type_of_welds . '|' . $row->welder_2;
|
||||
$map[$key] = $row->iso_number;
|
||||
}
|
||||
}
|
||||
return $map;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php function locations() {
|
||||
return json_encode_tr(db("locations")->get()->pluck("title")->toArray());
|
||||
} ?>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php function log_test_types() {
|
||||
return [
|
||||
'ht' => 'hardness_tests',
|
||||
'rt' => 'radiographic_tests',
|
||||
'ut' => 'ultrasonic_tests',
|
||||
'mt' => 'magnetic_tests',
|
||||
'pmi' => 'p_m_i_tests',
|
||||
'vt' => 'v_t_logs',
|
||||
'pt' => 'p_t_logs',
|
||||
'ferrite' => 'ferrits',
|
||||
'pwht' => 'p_w_h_t_s',
|
||||
];
|
||||
}
|
||||
|
||||
function get_key_by_value($value) {
|
||||
$array = log_test_types();
|
||||
$key = array_search($value, $array);
|
||||
return $key !== false ? $key : null; // Eğer değer bulunamazsa null döner
|
||||
}
|
||||
|
||||
function log_paths() {
|
||||
$mainPath = "004_QA/";
|
||||
return [
|
||||
'ht' => $mainPath . '0008_HT',
|
||||
'rt' => $mainPath . '0001_RT',
|
||||
'ut' => $mainPath . '0002_UT',
|
||||
'mt' => $mainPath . '0003_MT',
|
||||
'pmi' => $mainPath . '0005_PMI',
|
||||
'vt' => $mainPath . '0000_VT',
|
||||
'pt' => $mainPath . '0004_PT',
|
||||
'ferrite' => $mainPath . '0006_Ferrite',
|
||||
'pwht' => $mainPath . '0007_PWHT',
|
||||
];
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
function mailtemp($mail,$name,$data="") {
|
||||
$temp = db("mail_templates")->where("title",$name)->first();
|
||||
$html = $temp->html;
|
||||
$subject = $temp->title2;
|
||||
if(is_array($data)) {
|
||||
foreach($data AS $a => $d) {
|
||||
$html = str_replace("{".$a."}",$d,$html);
|
||||
$subject = str_replace("{".$a."}",$d,$subject);
|
||||
}
|
||||
}
|
||||
|
||||
@mailsend($mail,$subject,$html);
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
use App\Models\MaterialGroupMap;
|
||||
|
||||
|
||||
function materialGroupMap($ru1, $ru2)
|
||||
{
|
||||
|
||||
// Step 1: Get qualified materials
|
||||
$qualifiedMaterials = MaterialGroupMap::orWhere("material_name", $ru1)
|
||||
->orWhere("material_name", $ru2)
|
||||
->select("qualified_materials")
|
||||
->first()?->qualified_materials;
|
||||
|
||||
if ($qualifiedMaterials === null) {
|
||||
$response = [];
|
||||
} else {
|
||||
$groupArray = explode(",", $qualifiedMaterials);
|
||||
$response = $groupArray;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
if (!function_exists('whatMaterialGroup')) {
|
||||
|
||||
function whatMaterialGroup($thisSteelGrade, $materialMap) {
|
||||
foreach($materialMap as $steelGrade => $group) {
|
||||
$similar = similar_text($steelGrade, $thisSteelGrade, $percentage);
|
||||
|
||||
if($percentage > 95) {
|
||||
Log::debug("Benzerlik eşiği aşıldı, grup döndürülüyor", [
|
||||
'aranan_steel_grade' => $thisSteelGrade,
|
||||
'eslesen_steel_grade' => $steelGrade,
|
||||
'benzerlik_orani' => $percentage,
|
||||
'dondurulen_group' => $group
|
||||
]);
|
||||
return $group;
|
||||
}
|
||||
}
|
||||
Log::debug("Uygun material group bulunamadı", [
|
||||
'aranan_steel_grade' => $thisSteelGrade
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
function materialGroupUpdater($id) {
|
||||
// Material Group Finder
|
||||
//if ($shouldRunMaterialGroupUpdate) {
|
||||
// Material verilerini çek ve logla
|
||||
$materials = db("materials")->where("steel_grade", "<>", "*")->whereNotNull("steel_grade")->get();
|
||||
Log::debug("Material verileri çekildi", [
|
||||
'material_count' => $materials->count(),
|
||||
'material_examples' => $materials->take(3)->toArray()
|
||||
]);
|
||||
|
||||
$materialMap = [];
|
||||
foreach($materials as $material) {
|
||||
$material->steel_grade = trim($material->steel_grade);
|
||||
$materialMap[$material->steel_grade] = $material->ru_group;
|
||||
}
|
||||
Log::debug("MaterialMap oluşturuldu", [
|
||||
'materialMap_count' => count($materialMap),
|
||||
'materialMap_examples' => array_slice($materialMap, 0, 3, true)
|
||||
]);
|
||||
|
||||
$weldmaps = db("weld_logs")
|
||||
->where('id', $id)
|
||||
->get();
|
||||
|
||||
$materialGroupUpdateCount = 0;
|
||||
|
||||
foreach($weldmaps AS $weldmap) {
|
||||
$weldmap->material_no_1 = trim($weldmap->material_no_1);
|
||||
$group1 = whatMaterialGroup($weldmap->material_no_1, $materialMap); //isset($materialMap[$weldmap->material_no_1]) ? $materialMap[$weldmap->material_no_1] : "";
|
||||
$group2 = whatMaterialGroup($weldmap->material_no_2, $materialMap); //isset($materialMap[$weldmap->material_no_2]) ? $materialMap[$weldmap->material_no_2] : "";
|
||||
|
||||
|
||||
db("weld_logs")
|
||||
->where("id", $weldmap->id)
|
||||
->update([
|
||||
"ru_material_group_1" => $group1,
|
||||
"ru_material_group_2" => $group2
|
||||
]);
|
||||
|
||||
//dump($group1);
|
||||
//dump($group2);
|
||||
|
||||
$materialGroupUpdateCount++;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
return [
|
||||
'materialGroupUpdateCount' => $materialGroupUpdateCount,
|
||||
'ru_material_group_1' => $group1,
|
||||
'ru_material_group_2' => $group2,
|
||||
'material_no_1' => $weldmap->material_no_1,
|
||||
'material_no_2' => $weldmap->material_no_2,
|
||||
'id' => $weldmap->id,
|
||||
];
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,575 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Notification;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Send notification to users based on notification code and role mapping
|
||||
*
|
||||
* Performance optimizations:
|
||||
* - Single query to get target roles from settings
|
||||
* - Bulk insert for notifications (one query for all users)
|
||||
* - Uses whereIn for efficient user filtering
|
||||
* - Chunked inserts (500 per chunk) to avoid max packet size issues
|
||||
*
|
||||
* Note: Direct execution is fast enough (1-2 seconds for typical 10-50 users)
|
||||
* Queue integration was removed to avoid unnecessary complexity and worker dependency.
|
||||
*
|
||||
* @param string $notificationCode Notification code from catalog
|
||||
* @param string $message Notification message
|
||||
* @param string|null $link Optional link for notification
|
||||
* @param string|null $title Optional custom title (if null, uses default from code)
|
||||
* @param array|null $filterParams Optional filter parameters for filtered list view
|
||||
* @param int $itemCount Item count for batch notifications (default: 1)
|
||||
* @return int Number of notifications created
|
||||
*/
|
||||
function sendNotification($notificationCode, $message, $link = null, $title = null, $filterParams = null, $itemCount = 1) {
|
||||
try {
|
||||
// Get target roles from settings
|
||||
$targetRoles = j(setting($notificationCode));
|
||||
|
||||
// If no roles defined or empty, log warning and return early
|
||||
if (!is_array($targetRoles) || empty($targetRoles)) {
|
||||
Log::warning("Notification not sent: No roles defined in settings", [
|
||||
'notification_code' => $notificationCode,
|
||||
'message' => $message,
|
||||
'title' => $title,
|
||||
]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get active users with target roles in single query
|
||||
// Performance: Uses whereIn for efficient filtering
|
||||
$users = DB::table('users')
|
||||
->select('id', 'level', 'name', 'email')
|
||||
->whereIn('level', $targetRoles)
|
||||
->whereNotNull('level') // Ensure level is not null
|
||||
->get();
|
||||
|
||||
// Remove level, name, email from selection after logging (we only need id for insert)
|
||||
$userIds = $users->pluck('id');
|
||||
|
||||
// Debug: Log all users found
|
||||
Log::info("Notification target users found", [
|
||||
'notification_code' => $notificationCode,
|
||||
'target_roles' => $targetRoles,
|
||||
'users_count' => $users->count(),
|
||||
'user_ids' => $users->pluck('id')->toArray(),
|
||||
'user_levels' => $users->pluck('level')->toArray(),
|
||||
]);
|
||||
|
||||
// If no users found, log warning and return early
|
||||
if ($users->isEmpty()) {
|
||||
// Debug: Check what users exist with these levels
|
||||
$allUsersWithLevels = DB::table('users')
|
||||
->select('id', 'level', 'name', 'email')
|
||||
->whereNotNull('level')
|
||||
->get()
|
||||
->groupBy('level');
|
||||
|
||||
Log::warning("Notification not sent: No users found with target roles", [
|
||||
'notification_code' => $notificationCode,
|
||||
'target_roles' => $targetRoles,
|
||||
'message' => $message,
|
||||
'available_levels' => $allUsersWithLevels->keys()->toArray(),
|
||||
'users_by_level' => $allUsersWithLevels->map(function($group) {
|
||||
return $group->pluck('id')->toArray();
|
||||
})->toArray(),
|
||||
]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate title if not provided
|
||||
if ($title === null) {
|
||||
$title = ucwords(str_replace('_', ' ', $notificationCode));
|
||||
}
|
||||
|
||||
// If filterParams provided, generate link to filtered list page
|
||||
// We'll update link after insert with notification ID
|
||||
$useFilteredList = !empty($filterParams);
|
||||
if ($useFilteredList && $link === null) {
|
||||
$link = '/admin/notifications/filtered-list'; // Will be updated with notification ID after insert
|
||||
}
|
||||
|
||||
// Prepare bulk insert data
|
||||
// Performance: Single insert query for all notifications
|
||||
$now = now();
|
||||
$notificationsData = [];
|
||||
|
||||
foreach ($userIds as $userId) {
|
||||
$notificationsData[] = [
|
||||
'user_id' => $userId,
|
||||
'notification_code' => $notificationCode,
|
||||
'title' => $title,
|
||||
'message' => $message,
|
||||
'link' => $link,
|
||||
'is_read' => false,
|
||||
'filter_params' => $filterParams ? json_encode($filterParams) : null,
|
||||
'item_count' => $itemCount,
|
||||
'notification_type' => $filterParams ? 'batch' : 'single',
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
}
|
||||
|
||||
// Bulk insert notifications
|
||||
// Performance: One query instead of N queries
|
||||
if (!empty($notificationsData)) {
|
||||
// Split into chunks to avoid max packet size issues
|
||||
$chunks = array_chunk($notificationsData, 500);
|
||||
$totalInserted = 0;
|
||||
|
||||
foreach ($chunks as $chunk) {
|
||||
// If using filtered list, we need to update links with notification IDs after insert
|
||||
if ($useFilteredList) {
|
||||
$ids = [];
|
||||
foreach ($chunk as $data) {
|
||||
$id = DB::table('notifications')->insertGetId($data);
|
||||
$ids[] = $id;
|
||||
}
|
||||
// Update links with notification IDs
|
||||
foreach ($ids as $id) {
|
||||
DB::table('notifications')
|
||||
->where('id', $id)
|
||||
->update(['link' => '/admin/notifications/filtered-list?id=' . $id]);
|
||||
}
|
||||
$totalInserted += count($chunk);
|
||||
} else {
|
||||
DB::table('notifications')->insert($chunk);
|
||||
$totalInserted += count($chunk);
|
||||
}
|
||||
}
|
||||
|
||||
return $totalInserted;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// Log error but don't break the main flow
|
||||
Log::error('Notification send error: ' . $e->getMessage(), [
|
||||
'code' => $notificationCode,
|
||||
'message' => $message,
|
||||
]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Send batch notification with filter params and count-based message
|
||||
*
|
||||
* @param string $notificationCode
|
||||
* @param string $title
|
||||
* @param string $messageTemplate String with %d placeholder for count
|
||||
* @param array $filterParams
|
||||
* @param int $count
|
||||
* @return int
|
||||
*/
|
||||
function sendBatchNotificationWithFilter($notificationCode, $title, $messageTemplate, array $filterParams, int $count)
|
||||
{
|
||||
$count = (int) $count;
|
||||
if ($count <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$message = $messageTemplate ? sprintf($messageTemplate, $count) : sprintf('%d record(s) require attention.', $count);
|
||||
return sendNotification($notificationCode, $message, null, $title, $filterParams, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notification to specific users (by user IDs)
|
||||
* Performance: Bulk insert for multiple users
|
||||
*
|
||||
* @param array $userIds Array of user IDs
|
||||
* @param string $notificationCode Notification code
|
||||
* @param string $message Notification message
|
||||
* @param string|null $link Optional link
|
||||
* @param string|null $title Optional title
|
||||
* @return int Number of notifications created
|
||||
*/
|
||||
function sendNotificationToUsers($userIds, $notificationCode, $message, $link = null, $title = null) {
|
||||
try {
|
||||
if (empty($userIds)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate title if not provided
|
||||
if ($title === null) {
|
||||
$title = ucwords(str_replace('_', ' ', $notificationCode));
|
||||
}
|
||||
|
||||
// Prepare bulk insert data
|
||||
$now = now();
|
||||
$notificationsData = [];
|
||||
|
||||
foreach ($userIds as $userId) {
|
||||
$notificationsData[] = [
|
||||
'user_id' => $userId,
|
||||
'notification_code' => $notificationCode,
|
||||
'title' => $title,
|
||||
'message' => $message,
|
||||
'link' => $link,
|
||||
'is_read' => false,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
}
|
||||
|
||||
// Bulk insert
|
||||
if (!empty($notificationsData)) {
|
||||
$chunks = array_chunk($notificationsData, 500);
|
||||
$totalInserted = 0;
|
||||
|
||||
foreach ($chunks as $chunk) {
|
||||
DB::table('notifications')->insert($chunk);
|
||||
$totalInserted += count($chunk);
|
||||
}
|
||||
|
||||
return $totalInserted;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Notification send error (specific users): ' . $e->getMessage());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notification to single user
|
||||
* Performance: Single insert query
|
||||
*
|
||||
* @param int $userId User ID
|
||||
* @param string $notificationCode Notification code
|
||||
* @param string $message Notification message
|
||||
* @param string|null $link Optional link
|
||||
* @param string|null $title Optional title
|
||||
* @return bool Success status
|
||||
*/
|
||||
function sendNotificationToUser($userId, $notificationCode, $message, $link = null, $title = null) {
|
||||
try {
|
||||
if ($title === null) {
|
||||
$title = ucwords(str_replace('_', ' ', $notificationCode));
|
||||
}
|
||||
|
||||
Notification::create([
|
||||
'user_id' => $userId,
|
||||
'notification_code' => $notificationCode,
|
||||
'title' => $title,
|
||||
'message' => $message,
|
||||
'link' => $link,
|
||||
'is_read' => false,
|
||||
]);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Notification send error (single user): ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up old notifications
|
||||
* Performance: Bulk delete query with date filter
|
||||
*
|
||||
* @param int $days Number of days to keep (default: 90)
|
||||
* @return int Number of deleted notifications
|
||||
*/
|
||||
function cleanupOldNotifications($days = 90) {
|
||||
try {
|
||||
return Notification::deleteOldNotifications($days);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Notification cleanup error: ' . $e->getMessage());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy existing notifications to new users based on their level
|
||||
* DISABLED: This function was causing duplicate notifications and system issues
|
||||
*
|
||||
* @param string $notificationCode Notification code to copy
|
||||
* @return int Always returns 0 (disabled)
|
||||
*/
|
||||
function copyNotificationsToNewUsers($notificationCode) {
|
||||
// DISABLED: This function was causing excessive duplicate notifications
|
||||
// All calls to this function should be removed from notification check commands
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize filter_params for comparison
|
||||
*
|
||||
* @param mixed $filterParams
|
||||
* @return string
|
||||
*/
|
||||
function normalizeFilterParams($filterParams): string
|
||||
{
|
||||
if (empty($filterParams)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$decoded = is_string($filterParams)
|
||||
? json_decode($filterParams, true)
|
||||
: $filterParams;
|
||||
|
||||
if ($decoded === null || !is_array($decoded)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
ksort($decoded);
|
||||
return json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up duplicate notifications by notification_code + user_id + filter_params
|
||||
* This is more aggressive and handles cases where same notification_code is sent multiple times
|
||||
* Uses direct SQL queries with minimal memory usage
|
||||
*
|
||||
* @return array{total_deleted: int, notifications_before: int, notifications_after: int, error?: string}
|
||||
*/
|
||||
function cleanupDuplicateNotificationsByCode(): array
|
||||
{
|
||||
try {
|
||||
$stats = [
|
||||
'total_deleted' => 0,
|
||||
'notifications_before' => 0,
|
||||
'notifications_after' => 0,
|
||||
];
|
||||
|
||||
$stats['notifications_before'] = DB::table('notifications')->count();
|
||||
|
||||
// Process in very small batches to avoid memory issues
|
||||
$batchSize = 10; // Process 10 users at a time
|
||||
$totalDeleted = 0;
|
||||
$usersAffected = [];
|
||||
|
||||
// Get all notification codes one by one
|
||||
$notificationCodes = DB::table('notifications')
|
||||
->select('notification_code')
|
||||
->distinct()
|
||||
->pluck('notification_code');
|
||||
|
||||
foreach ($notificationCodes as $notificationCode) {
|
||||
// Get user IDs for this code in batches
|
||||
$offset = 0;
|
||||
while (true) {
|
||||
$userIds = DB::table('notifications')
|
||||
->where('notification_code', $notificationCode)
|
||||
->select('user_id')
|
||||
->distinct()
|
||||
->offset($offset)
|
||||
->limit($batchSize)
|
||||
->pluck('user_id');
|
||||
|
||||
if ($userIds->isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($userIds as $userId) {
|
||||
// Get notification IDs for this code + user, ordered by created_at desc
|
||||
// Process in small chunks
|
||||
$notificationOffset = 0;
|
||||
$notificationLimit = 100;
|
||||
$seenFilterParams = [];
|
||||
$idsToDelete = [];
|
||||
|
||||
while (true) {
|
||||
$notifications = DB::table('notifications')
|
||||
->where('notification_code', $notificationCode)
|
||||
->where('user_id', $userId)
|
||||
->select('id', 'filter_params', 'created_at')
|
||||
->orderBy('created_at', 'desc')
|
||||
->offset($notificationOffset)
|
||||
->limit($notificationLimit)
|
||||
->get();
|
||||
|
||||
if ($notifications->isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($notifications as $notification) {
|
||||
// Normalize filter_params
|
||||
$filterParams = normalizeFilterParams($notification->filter_params);
|
||||
|
||||
// If we've seen this filter_params before, it's a duplicate
|
||||
if (isset($seenFilterParams[$filterParams])) {
|
||||
$idsToDelete[] = $notification->id;
|
||||
} else {
|
||||
// First occurrence - keep it
|
||||
$seenFilterParams[$filterParams] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$notificationOffset += $notificationLimit;
|
||||
|
||||
// If we got less than limit, we're done
|
||||
if ($notifications->count() < $notificationLimit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete duplicates for this user
|
||||
if (!empty($idsToDelete)) {
|
||||
$deleteChunks = array_chunk($idsToDelete, 500);
|
||||
foreach ($deleteChunks as $chunk) {
|
||||
$deleted = DB::table('notifications')->whereIn('id', $chunk)->delete();
|
||||
$totalDeleted += $deleted;
|
||||
}
|
||||
|
||||
if (!in_array($userId, $usersAffected)) {
|
||||
$usersAffected[] = $userId;
|
||||
}
|
||||
}
|
||||
|
||||
// Free memory
|
||||
unset($notifications, $idsToDelete, $seenFilterParams);
|
||||
}
|
||||
|
||||
$offset += $batchSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear cache for affected users
|
||||
foreach ($usersAffected as $userId) {
|
||||
Cache::forget("user_notifications_{$userId}");
|
||||
Cache::forget("user_unread_type_count_{$userId}");
|
||||
}
|
||||
|
||||
$stats['total_deleted'] = $totalDeleted;
|
||||
$stats['notifications_after'] = DB::table('notifications')->count();
|
||||
|
||||
Log::info('Duplicate notifications cleanup by code completed', $stats);
|
||||
|
||||
return $stats;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error cleaning up duplicate notifications by code: ' . $e->getMessage());
|
||||
return [
|
||||
'error' => $e->getMessage(),
|
||||
'total_deleted' => 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up duplicate notifications
|
||||
* Removes duplicate notifications keeping only the most recent one for each user
|
||||
* Duplicates are identified by: user_id + message + link + normalized filter_params
|
||||
*
|
||||
* Performance: Uses SQL-based approach with chunking to avoid memory issues
|
||||
*
|
||||
* @return array{total_deleted: int, users_affected: int, notifications_before: int, notifications_after: int, error?: string}
|
||||
*/
|
||||
function cleanupDuplicateNotifications(): array
|
||||
{
|
||||
try {
|
||||
$stats = [
|
||||
'total_deleted' => 0,
|
||||
'users_affected' => 0,
|
||||
'notifications_before' => 0,
|
||||
'notifications_after' => 0,
|
||||
];
|
||||
|
||||
// Get total count before cleanup
|
||||
$stats['notifications_before'] = DB::table('notifications')->count();
|
||||
|
||||
// Process one user at a time to minimize memory usage
|
||||
$userIds = DB::table('notifications')
|
||||
->select('user_id')
|
||||
->distinct()
|
||||
->pluck('user_id');
|
||||
|
||||
$usersAffected = [];
|
||||
$totalDeleted = 0;
|
||||
|
||||
foreach ($userIds as $userId) {
|
||||
// Get notifications for this user, ordered by created_at desc (newest first)
|
||||
// Process in smaller chunks to avoid memory issues
|
||||
$offset = 0;
|
||||
$limit = 500;
|
||||
$userHasDuplicates = false;
|
||||
$seen = [];
|
||||
$idsToDelete = [];
|
||||
|
||||
while (true) {
|
||||
$notifications = DB::table('notifications')
|
||||
->where('user_id', $userId)
|
||||
->select('id', 'message', 'link', 'filter_params', 'created_at')
|
||||
->orderBy('created_at', 'desc')
|
||||
->offset($offset)
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
if ($notifications->isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($notifications as $notification) {
|
||||
// Normalize filter_params
|
||||
$filterParams = normalizeFilterParams($notification->filter_params);
|
||||
|
||||
$key = $notification->message . '|' . ($notification->link ?? '') . '|' . $filterParams;
|
||||
|
||||
// If we've seen this key before, it's a duplicate
|
||||
if (isset($seen[$key])) {
|
||||
$idsToDelete[] = $notification->id;
|
||||
$userHasDuplicates = true;
|
||||
} else {
|
||||
// First occurrence - keep it
|
||||
$seen[$key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$offset += $limit;
|
||||
|
||||
// If we got less than limit, we're done with this user
|
||||
if ($notifications->count() < $limit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete duplicates for this user
|
||||
if (!empty($idsToDelete)) {
|
||||
$deleteChunks = array_chunk($idsToDelete, 500);
|
||||
foreach ($deleteChunks as $chunk) {
|
||||
$deleted = DB::table('notifications')->whereIn('id', $chunk)->delete();
|
||||
$totalDeleted += $deleted;
|
||||
}
|
||||
|
||||
if ($userHasDuplicates) {
|
||||
$usersAffected[] = $userId;
|
||||
// Clear cache for this user
|
||||
Cache::forget("user_notifications_{$userId}");
|
||||
Cache::forget("user_unread_type_count_{$userId}");
|
||||
}
|
||||
}
|
||||
|
||||
// Free memory
|
||||
unset($notifications, $idsToDelete, $seen);
|
||||
}
|
||||
|
||||
$stats['total_deleted'] = $totalDeleted;
|
||||
$stats['users_affected'] = count($usersAffected);
|
||||
|
||||
// Get total count after cleanup
|
||||
$stats['notifications_after'] = DB::table('notifications')->count();
|
||||
|
||||
Log::info('Duplicate notifications cleanup completed', $stats);
|
||||
|
||||
return $stats;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error cleaning up duplicate notifications: ' . $e->getMessage());
|
||||
return [
|
||||
'error' => $e->getMessage(),
|
||||
'total_deleted' => 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Log scheduler execution
|
||||
*
|
||||
* @param string $action Action: 'schedule_run_started', 'schedule_run_completed', 'command_scheduled'
|
||||
* @param array $data Additional data
|
||||
* @return void
|
||||
*/
|
||||
function logSchedulerExecution(string $action, array $data = [])
|
||||
{
|
||||
try {
|
||||
$timestamp = now()->toDateTimeString();
|
||||
$logData = [
|
||||
'timestamp' => $timestamp,
|
||||
'action' => $action,
|
||||
'data' => $data,
|
||||
];
|
||||
|
||||
$message = "[Scheduler] {$action}";
|
||||
if (!empty($data)) {
|
||||
$message .= " | " . json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
Log::info($message, $logData);
|
||||
|
||||
// Write to dedicated notification log file
|
||||
// Use storage_path() to write directly to storage/logs/ directory
|
||||
$logDir = storage_path('logs');
|
||||
$logFile = $logDir . '/notifications-' . date('Y-m-d') . '.log';
|
||||
|
||||
// Determine status for log file
|
||||
$status = 'scheduled';
|
||||
if ($action === 'command_finished') {
|
||||
$status = 'finished';
|
||||
} elseif ($action === 'schedule_run_started') {
|
||||
$status = 'started';
|
||||
} elseif ($action === 'schedule_run_completed') {
|
||||
$status = 'completed';
|
||||
}
|
||||
|
||||
$logLine = sprintf(
|
||||
"[%s] %s | SCHEDULER | %s\n",
|
||||
$timestamp,
|
||||
str_pad($status, 10),
|
||||
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
|
||||
);
|
||||
|
||||
// Use file_put_contents with FILE_APPEND flag
|
||||
file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Failed to write scheduler log', [
|
||||
'error' => $e->getMessage(),
|
||||
'action' => $action
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log notification command execution
|
||||
*
|
||||
* @param string $commandName Command name (e.g., 'notifications:check-deleted-joints')
|
||||
* @param string $status Status: 'started', 'completed', 'skipped', 'error'
|
||||
* @param array $data Additional data to log
|
||||
* @return void
|
||||
*/
|
||||
function logNotificationCommand(string $commandName, string $status, array $data = [])
|
||||
{
|
||||
try {
|
||||
$timestamp = now()->toDateTimeString();
|
||||
$logData = [
|
||||
'timestamp' => $timestamp,
|
||||
'command' => $commandName,
|
||||
'status' => $status,
|
||||
'data' => $data,
|
||||
];
|
||||
|
||||
// Log to Laravel's default log
|
||||
$message = "[Notification Command] {$commandName} - {$status}";
|
||||
if (!empty($data)) {
|
||||
$message .= " | " . json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
switch ($status) {
|
||||
case 'started':
|
||||
Log::info($message, $logData);
|
||||
break;
|
||||
case 'completed':
|
||||
Log::info($message, $logData);
|
||||
break;
|
||||
case 'skipped':
|
||||
Log::info($message, $logData);
|
||||
break;
|
||||
case 'error':
|
||||
Log::error($message, $logData);
|
||||
break;
|
||||
default:
|
||||
Log::info($message, $logData);
|
||||
}
|
||||
|
||||
// Also write to dedicated notification log file
|
||||
// Use storage_path() to write directly to storage/logs/ directory
|
||||
$logDir = storage_path('logs');
|
||||
$logFile = $logDir . '/notifications-' . date('Y-m-d') . '.log';
|
||||
$logLine = sprintf(
|
||||
"[%s] %s | %s | %s\n",
|
||||
$timestamp,
|
||||
str_pad($status, 10),
|
||||
str_pad($commandName, 50),
|
||||
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
|
||||
);
|
||||
|
||||
// Use file_put_contents with FILE_APPEND flag
|
||||
file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// Fallback to Laravel log if file write fails
|
||||
Log::error('Failed to write notification log', [
|
||||
'error' => $e->getMessage(),
|
||||
'command' => $commandName,
|
||||
'status' => $status
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log notification command start
|
||||
*
|
||||
* @param string $commandName
|
||||
* @return void
|
||||
*/
|
||||
function logNotificationStart(string $commandName)
|
||||
{
|
||||
logNotificationCommand($commandName, 'started', [
|
||||
'time' => now()->toTimeString(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log notification command completion
|
||||
*
|
||||
* @param string $commandName
|
||||
* @param int $sentCount Number of notifications sent
|
||||
* @param int $recordCount Number of records found
|
||||
* @param int $newCount Number of new records (if applicable)
|
||||
* @param float|null $duration Execution duration in seconds
|
||||
* @return void
|
||||
*/
|
||||
function logNotificationComplete(string $commandName, int $sentCount = 0, int $recordCount = 0, int $newCount = 0, ?float $duration = null)
|
||||
{
|
||||
logNotificationCommand($commandName, 'completed', [
|
||||
'sent_count' => $sentCount,
|
||||
'record_count' => $recordCount,
|
||||
'new_count' => $newCount,
|
||||
'duration_seconds' => $duration ? round($duration, 2) : null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log notification command skip
|
||||
*
|
||||
* @param string $commandName
|
||||
* @param string $reason Reason for skipping
|
||||
* @return void
|
||||
*/
|
||||
function logNotificationSkip(string $commandName, string $reason)
|
||||
{
|
||||
logNotificationCommand($commandName, 'skipped', [
|
||||
'reason' => $reason,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log notification command error
|
||||
*
|
||||
* @param string $commandName
|
||||
* @param string $errorMessage
|
||||
* @param array $context Additional context
|
||||
* @return void
|
||||
*/
|
||||
function logNotificationError(string $commandName, string $errorMessage, array $context = [])
|
||||
{
|
||||
logNotificationCommand($commandName, 'error', array_merge([
|
||||
'error' => $errorMessage,
|
||||
], $context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notification log summary for a specific date
|
||||
*
|
||||
* @param string|null $date Date in Y-m-d format (default: today)
|
||||
* @return array
|
||||
*/
|
||||
function getNotificationLogSummary(?string $date = null): array
|
||||
{
|
||||
$date = $date ?: date('Y-m-d');
|
||||
$logFile = storage_path('logs/notifications-' . $date . '.log');
|
||||
|
||||
if (!file_exists($logFile)) {
|
||||
return [
|
||||
'date' => $date,
|
||||
'total_executions' => 0,
|
||||
'completed' => 0,
|
||||
'skipped' => 0,
|
||||
'errors' => 0,
|
||||
'total_notifications_sent' => 0,
|
||||
'commands' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$content = file_get_contents($logFile);
|
||||
$lines = explode("\n", trim($content));
|
||||
|
||||
$summary = [
|
||||
'date' => $date,
|
||||
'total_executions' => 0,
|
||||
'completed' => 0,
|
||||
'skipped' => 0,
|
||||
'errors' => 0,
|
||||
'total_notifications_sent' => 0,
|
||||
'commands' => [],
|
||||
];
|
||||
|
||||
foreach ($lines as $line) {
|
||||
if (empty(trim($line))) continue;
|
||||
|
||||
// Parse log line: [timestamp] status | command | data
|
||||
// Handle both command logs and scheduler logs
|
||||
if (preg_match('/\[([^\]]+)\]\s+(\w+)\s+\|\s+([^\|]+)\s+\|\s+(.+)/', $line, $matches)) {
|
||||
$timestamp = $matches[1];
|
||||
$status = trim($matches[2]);
|
||||
$command = trim($matches[3]);
|
||||
$dataJson = trim($matches[4]);
|
||||
|
||||
// Check if it's a scheduler log
|
||||
if ($command === 'SCHEDULER') {
|
||||
$data = json_decode($dataJson, true);
|
||||
if (isset($data['command'])) {
|
||||
// Scheduler log for a specific command
|
||||
$scheduledCommand = $data['command'];
|
||||
|
||||
if ($status === 'scheduled') {
|
||||
// Command was scheduled to run
|
||||
if (!isset($summary['commands'][$scheduledCommand])) {
|
||||
$summary['commands'][$scheduledCommand] = [
|
||||
'executions' => 0,
|
||||
'completed' => 0,
|
||||
'skipped' => 0,
|
||||
'errors' => 0,
|
||||
'total_sent' => 0,
|
||||
'scheduled_count' => 0,
|
||||
];
|
||||
}
|
||||
$summary['commands'][$scheduledCommand]['scheduled_count']++;
|
||||
}
|
||||
// Note: 'finished' status is just informational, actual completion is logged by command itself
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$summary['total_executions']++;
|
||||
|
||||
if ($status === 'completed') {
|
||||
$summary['completed']++;
|
||||
$data = json_decode($dataJson, true);
|
||||
if (isset($data['sent_count'])) {
|
||||
$summary['total_notifications_sent'] += $data['sent_count'];
|
||||
}
|
||||
|
||||
if (!isset($summary['commands'][$command])) {
|
||||
$summary['commands'][$command] = [
|
||||
'executions' => 0,
|
||||
'completed' => 0,
|
||||
'skipped' => 0,
|
||||
'errors' => 0,
|
||||
'total_sent' => 0,
|
||||
'scheduled_count' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
$summary['commands'][$command]['executions']++;
|
||||
$summary['commands'][$command]['completed']++;
|
||||
if (isset($data['sent_count'])) {
|
||||
$summary['commands'][$command]['total_sent'] += $data['sent_count'];
|
||||
}
|
||||
} elseif ($status === 'skipped') {
|
||||
$summary['skipped']++;
|
||||
|
||||
if (!isset($summary['commands'][$command])) {
|
||||
$summary['commands'][$command] = [
|
||||
'executions' => 0,
|
||||
'completed' => 0,
|
||||
'skipped' => 0,
|
||||
'errors' => 0,
|
||||
'total_sent' => 0,
|
||||
'scheduled_count' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
$summary['commands'][$command]['executions']++;
|
||||
$summary['commands'][$command]['skipped']++;
|
||||
} elseif ($status === 'error') {
|
||||
$summary['errors']++;
|
||||
|
||||
if (!isset($summary['commands'][$command])) {
|
||||
$summary['commands'][$command] = [
|
||||
'executions' => 0,
|
||||
'completed' => 0,
|
||||
'skipped' => 0,
|
||||
'errors' => 0,
|
||||
'total_sent' => 0,
|
||||
'scheduled_count' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
$summary['commands'][$command]['executions']++;
|
||||
$summary['commands'][$command]['errors']++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $summary;
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Notification;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Get last notification time for a notification code
|
||||
* Returns null if never sent (first time)
|
||||
*/
|
||||
function getLastNotificationTime(string $notificationCode): ?Carbon
|
||||
{
|
||||
$lastNotification = Notification::where('notification_code', $notificationCode)
|
||||
->orderBy('created_at', 'DESC')
|
||||
->first();
|
||||
|
||||
return $lastNotification ? $lastNotification->created_at : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we should run the check
|
||||
* Returns true if last notification was more than 5 minutes ago (or never sent)
|
||||
*/
|
||||
function shouldCheckNotification(string $notificationCode, int $minMinutes = 5): bool
|
||||
{
|
||||
$lastNotification = getLastNotificationTime($notificationCode);
|
||||
|
||||
// If never sent, should check
|
||||
if (!$lastNotification) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If last notification was more than 5 minutes ago, should check
|
||||
return $lastNotification->diffInMinutes(now()) >= $minMinutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get records created/updated after last notification
|
||||
* Returns null if first run (should check all records)
|
||||
*/
|
||||
function getLastCheckTimestamp(string $notificationCode): ?Carbon
|
||||
{
|
||||
$lastNotification = getLastNotificationTime($notificationCode);
|
||||
|
||||
// If never sent, return null (will check all records on first run)
|
||||
if (!$lastNotification) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check records after last notification
|
||||
return $lastNotification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if notification already sent for same issue (duplicate prevention)
|
||||
* Compares filter_params to detect same issue
|
||||
*
|
||||
* @param string $notificationCode
|
||||
* @param array|null $filterParams
|
||||
* @return bool True if duplicate exists
|
||||
*/
|
||||
function isNotificationDuplicate(string $notificationCode, ?array $filterParams = null): bool
|
||||
{
|
||||
// If no filter params, can't check for duplicates
|
||||
if (empty($filterParams)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get last notification with same code and filter params
|
||||
$lastNotification = Notification::where('notification_code', $notificationCode)
|
||||
->whereNotNull('filter_params')
|
||||
->orderBy('created_at', 'DESC')
|
||||
->first();
|
||||
|
||||
if (!$lastNotification || !$lastNotification->filter_params) {
|
||||
return false; // No previous notification
|
||||
}
|
||||
|
||||
// Compare filter_params (normalize arrays for comparison)
|
||||
$lastParams = is_array($lastNotification->filter_params)
|
||||
? $lastNotification->filter_params
|
||||
: json_decode($lastNotification->filter_params, true);
|
||||
|
||||
// Check if same table and same conditions
|
||||
if (isset($lastParams['table']) && isset($filterParams['table'])) {
|
||||
if ($lastParams['table'] !== $filterParams['table']) {
|
||||
return false; // Different tables, not duplicate
|
||||
}
|
||||
}
|
||||
|
||||
// Compare conditions (simplified - check if same IDs or same conditions)
|
||||
if (isset($lastParams['conditions']) && isset($filterParams['conditions'])) {
|
||||
// If both have 'id' conditions, check if they overlap
|
||||
if (isset($lastParams['conditions']['id']) && isset($filterParams['conditions']['id'])) {
|
||||
$lastIds = is_array($lastParams['conditions']['id'])
|
||||
? $lastParams['conditions']['id']
|
||||
: [$lastParams['conditions']['id']];
|
||||
$newIds = is_array($filterParams['conditions']['id'])
|
||||
? $filterParams['conditions']['id']
|
||||
: [$filterParams['conditions']['id']];
|
||||
|
||||
// If all new IDs are already in last notification, it's duplicate
|
||||
$newUniqueIds = array_diff($newIds, $lastIds);
|
||||
if (empty($newUniqueIds)) {
|
||||
return true; // All IDs already notified
|
||||
}
|
||||
}
|
||||
|
||||
// For other conditions, do simple comparison
|
||||
// If conditions are exactly same, it's duplicate
|
||||
$lastConditions = json_encode($lastParams['conditions'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
$newConditions = json_encode($filterParams['conditions'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
|
||||
if ($lastConditions === $newConditions) {
|
||||
return true; // Exact same conditions
|
||||
}
|
||||
}
|
||||
|
||||
return false; // Not duplicate
|
||||
}
|
||||
|
||||
/**
|
||||
* Get already notified IDs from last notification
|
||||
* Used to filter out already notified records
|
||||
*
|
||||
* @param string $notificationCode
|
||||
* @return array Array of already notified IDs
|
||||
*/
|
||||
function getAlreadyNotifiedIds(string $notificationCode): array
|
||||
{
|
||||
$lastNotification = Notification::where('notification_code', $notificationCode)
|
||||
->whereNotNull('filter_params')
|
||||
->orderBy('created_at', 'DESC')
|
||||
->first();
|
||||
|
||||
if (!$lastNotification || !$lastNotification->filter_params) {
|
||||
return []; // No previous notification
|
||||
}
|
||||
|
||||
$filterParams = is_array($lastNotification->filter_params)
|
||||
? $lastNotification->filter_params
|
||||
: json_decode($lastNotification->filter_params, true);
|
||||
|
||||
if (isset($filterParams['conditions']['id'])) {
|
||||
$ids = $filterParams['conditions']['id'];
|
||||
return is_array($ids) ? $ids : [$ids];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
function mask_replace($text) {
|
||||
$chars = ['0', '9', 'L', 'C', 'A', 'a', 'c', '#'];
|
||||
foreach($chars AS $char) {
|
||||
$text = str_replace($char, "\\\\$char", $text);
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
function number_mask($type, $typeNumber="09") {
|
||||
$projectNumber = mask_replace(setting("project_number"));
|
||||
$typeNumber = mask_replace($typeNumber);
|
||||
$type = mask_replace($type);
|
||||
// return $projectNumber . setting("company_code") . "-$type-$typeNumber-0000";
|
||||
$desiredLength = 35;
|
||||
return trim($projectNumber) . trim(setting("company_code")) . "-" . str_repeat('C', $desiredLength);
|
||||
//208STE-PQR-09-0006
|
||||
} ?>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
function numberToMonth($number) {
|
||||
$months = [
|
||||
1 => "January",
|
||||
2 => "February",
|
||||
3 => "March",
|
||||
4 => "April",
|
||||
5 => "May",
|
||||
6 => "June",
|
||||
7 => "July",
|
||||
8 => "August",
|
||||
9 => "September",
|
||||
10 => "October",
|
||||
11 => "November",
|
||||
12 => "December"
|
||||
];
|
||||
|
||||
if (array_key_exists($number, $months)) {
|
||||
return $months[$number];
|
||||
} else {
|
||||
return "Invalid month number";
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php function pattern_to_variables($patternString) {
|
||||
|
||||
|
||||
preg_match_all('/{(.*?)}/',$patternString, $matches);
|
||||
|
||||
return $matches;
|
||||
|
||||
} ?>
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
function bootstrap_css() {
|
||||
return file_get_contents("https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css");
|
||||
}
|
||||
function pdf_html_content($html) {
|
||||
$bootstrap = bootstrap_css();
|
||||
// $html = str_replace(" ", "", $html);
|
||||
$html = "<div class='pdf-container'>$html</html>";
|
||||
$start = '<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
th, td {
|
||||
border: 1px solid black;
|
||||
padding: 5px !important ;
|
||||
text-align: left;
|
||||
height:auto !important;
|
||||
max-width:100px !important;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
.header, .footer {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
.subheader {
|
||||
font-weight: bold;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
.signature {
|
||||
height: 60px;
|
||||
}
|
||||
.checkbox {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid black;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.pdf-container {
|
||||
width:100% !important;
|
||||
max-width:100% !important;
|
||||
}
|
||||
.pdf-container { margin: 0px;
|
||||
padding:0px;
|
||||
width:98% !important;
|
||||
}
|
||||
/*
|
||||
.pdf-container * {
|
||||
|
||||
font-family: DejaVu Sans !important;
|
||||
|
||||
}
|
||||
*/
|
||||
.pdf-container table {
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.pdf-container .bordered td {
|
||||
border:solid 1px #000 !important;
|
||||
|
||||
padding:3px;
|
||||
font-size:12px !important;
|
||||
}
|
||||
|
||||
/*
|
||||
table td, table th, p, span {
|
||||
|
||||
font-size:12px !important;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
.pagebreak {
|
||||
clear: both;
|
||||
page-break-after: always;
|
||||
}
|
||||
|
||||
td {
|
||||
|
||||
|
||||
}
|
||||
.pdf-container p, .pdf-container hr {
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
.pdf-container table {
|
||||
border-collapse: revert !important;
|
||||
/*
|
||||
border-spacing: -1px;
|
||||
border-left: 0.01em solid #ccc;
|
||||
border-right: 0;
|
||||
border-top: 0.01em solid #ccc;
|
||||
border-bottom: 0;
|
||||
border-collapse: collapse;
|
||||
*/
|
||||
}
|
||||
.pdf-container table td,
|
||||
.pdf-container table th {
|
||||
/*
|
||||
border-left: 0.01em solid black;
|
||||
border-right: 0.01em solid black;
|
||||
border-top: 0;
|
||||
border-bottom: 0.01em solid black;
|
||||
*/
|
||||
|
||||
}
|
||||
.text-center * {
|
||||
text-align:center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>';
|
||||
|
||||
$end = "</body>
|
||||
</html>";
|
||||
|
||||
return $start . $html . $end;
|
||||
} ?>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php function pdf_html_content2($html) {
|
||||
$start = '<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
|
||||
body{
|
||||
font-family: DejaVu Sans;
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>';
|
||||
|
||||
$end = "</body>
|
||||
</html>";
|
||||
|
||||
return $start . $html . $end;
|
||||
} ?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
<?php function percentage($number, $max, $fixed = 2) {
|
||||
|
||||
try {
|
||||
$percent = round($number * 100 / $max, $fixed);
|
||||
} catch (\Throwable $th) {
|
||||
$percent = 0;
|
||||
}
|
||||
|
||||
return $percent;
|
||||
} ?>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
function recorded_data($tableName, $cacheSeconds = 10) {
|
||||
|
||||
if(Cache::has('recordedData_' . $tableName)) {
|
||||
return Cache::get('recordedData_' . $tableName);
|
||||
} else {
|
||||
$recordedData = db($tableName)->get()->toArray();
|
||||
$refactoringRecordedData = [];
|
||||
foreach($recordedData AS $row => $data) {
|
||||
foreach($data AS $column => $value) {
|
||||
if(!isset($refactoringRecordedData[$column])) {
|
||||
$refactoringRecordedData[$column] = [];
|
||||
} else {
|
||||
if($value!="") {
|
||||
if(!in_array($value, $refactoringRecordedData[$column])) {
|
||||
$refactoringRecordedData[$column][] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Cache::put('recordedData_' . $tableName, $refactoringRecordedData, $seconds = $cacheSeconds);
|
||||
return $refactoringRecordedData;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php function rejected_date($date) {
|
||||
|
||||
$rejectedDate = [null, "0000-00-00", "", "1970-01-01", "0000-11-30"];
|
||||
$currentYear = date("Y");
|
||||
$dateYear = date("Y", strtotime($date));
|
||||
$differentYear = $currentYear - $dateYear;
|
||||
if(in_array($date, $rejectedDate)) {
|
||||
return true;
|
||||
} else {
|
||||
if($differentYear > -20 && $differentYear < 100) { //mevcut yıldan 2 yıl eksiğine ait kayda izin ver
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
} ?>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
function removeItemBySpoolNoJointNo(&$jointDatas, $spoolNoJointNoToRemove) {
|
||||
foreach ($jointDatas as &$fluidCodes) {
|
||||
foreach ($fluidCodes as &$items) {
|
||||
foreach ($items as $key => $item) {
|
||||
if (isset($item['spool_no_joint_no']) && $item['spool_no_joint_no'] == $spoolNoJointNoToRemove) {
|
||||
unset($items[$key]); // Belirli bir koşula göre değeri sil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
if (!function_exists('repair_results')) {
|
||||
function repair_results() {
|
||||
return ['Repair / Ремонт', 'Cut / Резать'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('ignore_results')) {
|
||||
function ignore_results() {
|
||||
return ['Cancel / Отмена', 'Reject / Reject'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
function replacePlaceholdersWithInputs($html, $relationDatas=[]) {
|
||||
// Placeholder deseni: {type.name}
|
||||
$pattern = '/\{(\w+)\.(\w+)(?:\.([^}]+))?\}/';
|
||||
|
||||
$html = str_replace("{page}", '<input type="number" name="page" >', $html);
|
||||
|
||||
$html = preg_replace_callback($pattern, function($matches) use($relationDatas) {
|
||||
$type = $matches[1];
|
||||
$name = $matches[2];
|
||||
$value = isset($matches[3]) ? $matches[3] : null;
|
||||
switch ($type) {
|
||||
case 'radio':
|
||||
case 'checkbox':
|
||||
return '<input type="' . htmlspecialchars($type) . '" placeholder="'. $name .'" value="' . $value . '" name="' . htmlspecialchars($name) . '" checked>';
|
||||
case 'text':
|
||||
case 'email':
|
||||
case 'number':
|
||||
case 'date':
|
||||
if($type == "date") {
|
||||
$value = date("Y-m-d");
|
||||
} else {
|
||||
$value = "";
|
||||
}
|
||||
return '<input type="' . htmlspecialchars($type) . '" placeholder="'. $name .'" class="form-control" value="'. $value .'" name="' . htmlspecialchars($name) . '">';
|
||||
case 'time':
|
||||
return '<input type="' . htmlspecialchars($type) . '" placeholder="'. $name .'" class="form-control" name="' . htmlspecialchars($name) . '">';
|
||||
case 'textarea':
|
||||
return '<textarea style="height: 400px;" name="' . htmlspecialchars($name) . '" placeholder="'. $name .'" class="form-control"></textarea>';
|
||||
case 'select':
|
||||
$options = "<option value=''>Select $name</option>";
|
||||
if(isset($relationDatas[$name]))
|
||||
{
|
||||
foreach($relationDatas[$name] AS $option)
|
||||
{
|
||||
$options .= "<option value='$option'>$option</option>";
|
||||
}
|
||||
}
|
||||
|
||||
return '<select class="form-control" name="' . htmlspecialchars($name) . '">'
|
||||
. $options
|
||||
. '</select>';
|
||||
default:
|
||||
return $matches[0]; // Değişiklik yapılmadan bırak
|
||||
}
|
||||
}, $html);
|
||||
|
||||
$mainContractor = db("subcontractors")->where("operation_type", "MAIN CONTRACTOR")->first();
|
||||
|
||||
if($mainContractor)
|
||||
{
|
||||
$html = str_replace("{project_address}", $mainContractor->address_ru . " / " . $mainContractor->address_en, $html);
|
||||
}
|
||||
|
||||
$html = str_replace("{project_name}", setting("project_name_ru") . " / " . setting("project_name"), $html);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
use Carbon\Carbon;
|
||||
|
||||
|
||||
function logProcessInfo($message, $data = [], $type = 'info') {
|
||||
$logData = [
|
||||
'timestamp' => now()->format('Y-m-d H:i:s'),
|
||||
'message' => $message,
|
||||
'memory_usage' => round(memory_get_usage() / 1024 / 1024, 2) . ' MB',
|
||||
'data' => $data
|
||||
];
|
||||
|
||||
switch ($type) {
|
||||
case 'error':
|
||||
Log::error($message, $logData);
|
||||
break;
|
||||
case 'warning':
|
||||
Log::warning($message, $logData);
|
||||
break;
|
||||
case 'info':
|
||||
Log::info($message, $logData);
|
||||
break;
|
||||
default:
|
||||
Log::debug($message, $logData);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sütun adında "date" geçen alanları Carbon ile formatlayan fonksiyon
|
||||
* @param array|object $data Formatlanacak veri
|
||||
* @param string $format Tarih formatı (default: d.m.Y)
|
||||
* @return array|object Formatlanmış veri
|
||||
*/
|
||||
function formatDateColumns($data, $format = 'd.m.Y') {
|
||||
// Veri tipini kontrol et
|
||||
if (!is_array($data) && !is_object($data)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Array'e çevir
|
||||
$dataArray = is_object($data) ? (array)$data : $data;
|
||||
$modified = false;
|
||||
|
||||
foreach ($dataArray as $field => $value) {
|
||||
// Eğer sütun adında "date" kelimesi varsa ve değer boş değilse
|
||||
if (stripos($field, 'date') !== false && !empty($value) && $value !== null) {
|
||||
// Zaten formatlanmış mı kontrol et (dd.mm.yyyy formatında)
|
||||
if (preg_match('/^\d{2}\.\d{2}\.\d{4}$/', $value)) {
|
||||
continue; // Zaten doğru formatta
|
||||
}
|
||||
|
||||
try {
|
||||
// Carbon ile tarihi parse et
|
||||
$carbonDate = Carbon::parse($value);
|
||||
|
||||
// Geçerli bir tarih mi kontrol et
|
||||
if ($carbonDate->isValid()) {
|
||||
$dataArray[$field] = $carbonDate->format($format);
|
||||
$modified = true;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Tarih parse edilemezse orijinal değeri koru
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sadece değişiklik varsa yeni obje/array oluştur
|
||||
if ($modified) {
|
||||
return is_object($data) ? (object)$dataArray : $dataArray;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
function mb_str_replace($search, $replace, $subject) {
|
||||
return implode($replace, explode($search, $subject, 2));
|
||||
}
|
||||
|
||||
function replacePlaceholdersFileName($template, $data) {
|
||||
return preg_replace_callback('/\{(\w+)\}/', function ($matches) use ($data) {
|
||||
$key = $matches[1]; // Süslü parantez içindeki anahtar
|
||||
return $data[$key] ?? $matches[0]; // Anahtar varsa değeri, yoksa orijinal metni döndür
|
||||
}, $template);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,269 @@
|
||||
<?php function required_fields() {
|
||||
return [
|
||||
/*
|
||||
'pqr_no',
|
||||
'valid_from',
|
||||
'valid_to',
|
||||
'welding_method',
|
||||
'mat_group_1',
|
||||
'mat_group_2',
|
||||
'welding_consumables',
|
||||
'technology_category',
|
||||
'work_type',
|
||||
'joint_type',
|
||||
'pwht',
|
||||
'connection_type',
|
||||
'joint_view',
|
||||
'angle_type',
|
||||
'position',
|
||||
'pre_heating',
|
||||
'naks_technology',
|
||||
'naks_certificate_no',
|
||||
'certificate_no',
|
||||
'wps_no',
|
||||
'details',
|
||||
'wpq_document_no',
|
||||
'design_area',
|
||||
'line',
|
||||
'iso_number',
|
||||
'line_specification',
|
||||
'welding_equipment',
|
||||
'performed_works_type',
|
||||
'naks_technology',
|
||||
'naks_technology',
|
||||
'technology_category',
|
||||
'pwps_no',
|
||||
'base_metal_used_for_pqr_coupon',
|
||||
'date',
|
||||
'welding_process',
|
||||
'welding_position',
|
||||
'type_grade_1',
|
||||
'type_grade_2',
|
||||
'russian_standart_group_no',
|
||||
'russian_standart_group_no_2',
|
||||
'p_no_to',
|
||||
'p_no_from',
|
||||
'outside_diameter',
|
||||
'thickness',
|
||||
'brend',
|
||||
'filter_metals_aws_sfa_no_class',
|
||||
'filter_metals_gost',
|
||||
'pre_heating_min',
|
||||
'inter_pass_max',
|
||||
'pwht_temp_range',
|
||||
'pwht_min_time',
|
||||
'backing_gas',
|
||||
'current_polarity',
|
||||
'joint_design',
|
||||
'base_metal',
|
||||
'type',
|
||||
'details',
|
||||
'pqr_no',
|
||||
'date',
|
||||
'naks_certificate_no',
|
||||
'technology_category',
|
||||
'welding_process',
|
||||
'joint_type',
|
||||
'joint_type_ru',
|
||||
'welding_position',
|
||||
'material_type_grade',
|
||||
'russian_standard_group_no_1',
|
||||
'russian_standard_group_no_2',
|
||||
'p_no_from',
|
||||
'p_no_to',
|
||||
'min_outside_diameter',
|
||||
'max_outside_diameter',
|
||||
'min_thick',
|
||||
'max_thick',
|
||||
'filler_metals_sfa_no',
|
||||
'filler_metals_gost',
|
||||
'pre_heating_min',
|
||||
'inter_pass_max',
|
||||
'pwht_temp_range',
|
||||
'pwht_min_time',
|
||||
'shielding_gas',
|
||||
'backing_gas',
|
||||
'current_polarity',
|
||||
'joint_type_definition',
|
||||
'work_type',
|
||||
'welder_name_ru',
|
||||
'welder_name_en',
|
||||
'year_of_birth',
|
||||
'qualitification_category',
|
||||
'work_experience',
|
||||
'welder_id',
|
||||
'process',
|
||||
'component',
|
||||
'weld_type',
|
||||
'naks_certificate_no',
|
||||
'period_of_validity',
|
||||
'group_of_technical_device',
|
||||
'material_1',
|
||||
'diameter_min_1',
|
||||
'diameter_max_1',
|
||||
'min_thick_1',
|
||||
'max_thick_1',
|
||||
'material_2',
|
||||
'diameter_min_2',
|
||||
'diameter_max_2',
|
||||
'welding_position',
|
||||
'company',
|
||||
'wpq_document_no',
|
||||
'naks_no',
|
||||
'name_surname',
|
||||
'naks_validity',
|
||||
'wps_no',
|
||||
'welding_date',
|
||||
'kss_number',
|
||||
'material_group_1',
|
||||
'material_group_2',
|
||||
'grade_1',
|
||||
'grade_2',
|
||||
'joint_type',
|
||||
'diameter',
|
||||
'thickness',
|
||||
'dia_min',
|
||||
'dia_max',
|
||||
'thk_min',
|
||||
'thk_max',
|
||||
'welding_method',
|
||||
'coupon_position',
|
||||
'wire',
|
||||
'electrode',
|
||||
'flux',
|
||||
'shield_gas',
|
||||
'naks_technology_group',
|
||||
'evaluated_norm',
|
||||
'vt_date',
|
||||
'type_of_consumable',
|
||||
'brand',
|
||||
'product_name',
|
||||
'aws_classification',
|
||||
'diameter',
|
||||
'group_of_base_material',
|
||||
'base_material',
|
||||
'batch_number',
|
||||
'naks_certificate_no',
|
||||
'naks_certificate_date',
|
||||
'naks_valid_date',
|
||||
'naks_tech_group',
|
||||
'inspection_test_report',
|
||||
'inspection_certificate_standart',
|
||||
'certification_date',
|
||||
'type_of_consumable',
|
||||
'brand',
|
||||
'product_name',
|
||||
'aws_classification',
|
||||
'diameter',
|
||||
'group_of_base_material',
|
||||
'base_material',
|
||||
'attestation',
|
||||
'producer',
|
||||
'type_of_welding_machine',
|
||||
'brand',
|
||||
'manufacturer_code',
|
||||
'type_of_weld',
|
||||
'groups_of_technical_devices',
|
||||
'date_of_issue',
|
||||
'valid_until',
|
||||
'working_status',
|
||||
'name_ru',
|
||||
'name_en',
|
||||
'date_of_birth',
|
||||
'certificate_no',
|
||||
'welding_specialist_level',
|
||||
'groups_of_technical_devices',
|
||||
'date_of_attestation',
|
||||
'expration_of_the_certificate',
|
||||
'general_contractor',
|
||||
'contractor',
|
||||
'ste_subcontractor',
|
||||
'project',
|
||||
'design_area',
|
||||
'line_specification',
|
||||
'line_number',
|
||||
'main_material',
|
||||
'main_nps',
|
||||
'fluid_code',
|
||||
'service_category',
|
||||
'fluid_group',
|
||||
'piping_class',
|
||||
'design_temperature_s',
|
||||
'design_pressure_mpa',
|
||||
'operating_temperature_s',
|
||||
'operating_pressure_mpa',
|
||||
'painting_cycle',
|
||||
'external_finish_type',
|
||||
'iso_number',
|
||||
'quantity_of_iso',
|
||||
'iso_rev',
|
||||
'spool_number',
|
||||
'spool_release_date',
|
||||
'type_of_joint',
|
||||
'no_of_the_joint_as_per_as_built_survey',
|
||||
'type_of_welds',
|
||||
'element_code_1',
|
||||
'member_no_1',
|
||||
'material_no_1',
|
||||
'ru_material_group_1',
|
||||
'element_code_2',
|
||||
'member_no_2',
|
||||
'material_no_2',
|
||||
'ru_material_group_2',
|
||||
'nps_1',
|
||||
'thickness_by_asme_1',
|
||||
'outside_diameter_1',
|
||||
'wall_thickness_1',
|
||||
'pose_no_1',
|
||||
'pose_no_2',
|
||||
'nps_2',
|
||||
'thickness_by_asme_2',
|
||||
'outside_diameter_2',
|
||||
'wall_thickness_2',
|
||||
'ndt_percent',
|
||||
'unit',
|
||||
'line_no',
|
||||
'line_specification',
|
||||
'fluid_code',
|
||||
'dn',
|
||||
'design_pressure_mpa',
|
||||
'working_pressure_mpa',
|
||||
'working_temperature',
|
||||
'design_temperature',
|
||||
'density',
|
||||
'ndt',
|
||||
'pwht',
|
||||
'asme_fluid_service',
|
||||
'category',
|
||||
'fluid_group',
|
||||
'test_media',
|
||||
'test_pressure_mpa',
|
||||
'project',
|
||||
'line',
|
||||
'rev',
|
||||
'component_code_id',
|
||||
'longdescription',
|
||||
'description_en',
|
||||
'description_ru',
|
||||
'material',
|
||||
'quantity',
|
||||
'dia_inch_1',
|
||||
'dn_1',
|
||||
'odmm_1',
|
||||
'schedule_1',
|
||||
'thicknessmm_1',
|
||||
'diainch_2',
|
||||
'design_area',
|
||||
'fluid',
|
||||
'line',
|
||||
'operation_temp',
|
||||
'operations_pressure_kg',
|
||||
'type_of_joint',
|
||||
'pwht',
|
||||
'ndt',
|
||||
'piping_class_according_to_gost',
|
||||
'piping_group',
|
||||
*/
|
||||
];
|
||||
|
||||
} ?>
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
if (!function_exists('resolveModuleFromTable')) {
|
||||
/**
|
||||
* Attempts to find the original module slug from a given table name.
|
||||
* Uses type configuration, naming conventions, and parses blade files as a fallback.
|
||||
*
|
||||
* @param string $tableName
|
||||
* @return string
|
||||
*/
|
||||
function resolveModuleFromTable($tableName)
|
||||
{
|
||||
if (empty($tableName)) {
|
||||
return $tableName;
|
||||
}
|
||||
|
||||
// Cache the result to avoid reading files repeatedly
|
||||
$cacheKey = "module_slug_for_table_" . md5($tableName);
|
||||
|
||||
return Cache::remember($cacheKey, 3600, function () use ($tableName) {
|
||||
|
||||
// Priority 1: Check types.slug explicitly
|
||||
$typeBySlug = DB::table('types')->where('slug', $tableName)->first();
|
||||
if ($typeBySlug) {
|
||||
return $typeBySlug->slug;
|
||||
}
|
||||
|
||||
// Priority 2: Check types.table_name explicitly (best match for API table params)
|
||||
if (Schema::hasColumn('types', 'table_name')) {
|
||||
$typeByTableName = DB::table('types')
|
||||
->where('table_name', $tableName)
|
||||
->first();
|
||||
if ($typeByTableName) {
|
||||
return $typeByTableName->slug;
|
||||
}
|
||||
}
|
||||
|
||||
// Priority 3: Read blade files to find $tableName definition (like in MobileTypeController)
|
||||
$types = DB::table('types')->get();
|
||||
foreach ($types as $type) {
|
||||
$bladePath = resource_path("views/admin/type/{$type->slug}.blade.php");
|
||||
if (File::exists($bladePath)) {
|
||||
$content = File::get($bladePath);
|
||||
if (preg_match('/\$tableName\s*=\s*["\']([^"\']+)["\']\s*;/', $content, $matches)) {
|
||||
$foundTable = $matches[1];
|
||||
if ($foundTable === $tableName) {
|
||||
return $type->slug;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Priority 4: Try some simple naming conventions
|
||||
if (\Illuminate\Support\Str::contains($tableName, '_')) {
|
||||
$guessedSlug = str_replace('_', '-', $tableName);
|
||||
$typeByGuessedSlug = DB::table('types')->where('slug', $guessedSlug)->first();
|
||||
if ($typeByGuessedSlug) {
|
||||
return $typeByGuessedSlug->slug;
|
||||
}
|
||||
|
||||
$guessedSlugSingular = \Illuminate\Support\Str::slug(\Illuminate\Support\Str::singular($tableName));
|
||||
$typeByGuessedSingular = DB::table('types')->where('slug', $guessedSlugSingular)->first();
|
||||
if ($typeByGuessedSingular) {
|
||||
return $typeByGuessedSingular->slug;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: return the original string
|
||||
return $tableName;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php function result_replace($result) {
|
||||
$result = str_replace("Repair / Ремонт", "🛠", $result);
|
||||
$result = str_replace("Accept / Годен", "✅", $result);
|
||||
$result = str_replace("Reject / Reject", "⛔️", $result);
|
||||
$result = str_replace("Cut / Резать", "✂️", $result);
|
||||
return $result;
|
||||
} ?>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
function row_detail_url($tableName, $column) {
|
||||
return url("admin/detail/$tableName/$column");
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php function setting($key, $strip_tags=false, $default="") {
|
||||
// Cache kaldırıldı, doğrudan veritabanından oku
|
||||
$setting = db("settings")->where("title", $key)->orderBy("id", "DESC")->first();
|
||||
|
||||
if ($setting) {
|
||||
if ($strip_tags) {
|
||||
$setting->html = strip_tags($setting->html);
|
||||
}
|
||||
return $setting->html;
|
||||
} else {
|
||||
// Eğer ayar yoksa, default ile oluştur
|
||||
ekle2([
|
||||
'title' => $key,
|
||||
'html' => $default
|
||||
], "settings");
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
function setting_put($key, $data)
|
||||
{
|
||||
// Use transaction with retry logic to prevent deadlocks
|
||||
$maxRetries = 3;
|
||||
$attempt = 0;
|
||||
|
||||
while ($attempt < $maxRetries) {
|
||||
try {
|
||||
DB::transaction(function() use ($key, $data) {
|
||||
db("settings")->updateOrInsert([
|
||||
'title' => $key
|
||||
],
|
||||
[
|
||||
'title' => $key,
|
||||
'html' => $data
|
||||
]);
|
||||
});
|
||||
|
||||
// Cache the value for faster reads
|
||||
Cache::put("setting_{$key}", $data, 3600); // 1 hour cache
|
||||
|
||||
return true;
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
// If deadlock detected, retry
|
||||
if ($e->getCode() == '40001' || strpos($e->getMessage(), 'Deadlock') !== false || strpos($e->getMessage(), 'Lock wait timeout') !== false) {
|
||||
$attempt++;
|
||||
if ($attempt >= $maxRetries) {
|
||||
throw $e; // Rethrow if max retries reached
|
||||
}
|
||||
usleep(100000 * $attempt); // Wait 100ms * attempt number before retry
|
||||
} else {
|
||||
throw $e; // Rethrow other exceptions immediately
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
function isSpecificPermission($permission, $user = null, $typeId = null) {
|
||||
|
||||
if($user == null) {
|
||||
$user = u();
|
||||
}
|
||||
|
||||
// Eğer kullanıcı admin ise her şeye yetkisi vardır
|
||||
if(isAdmin($user)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Kullanıcının level indexini bul
|
||||
$userLevelIndex = getLevelIndex($user->level);
|
||||
|
||||
// 1. Module Specific Permission Kontrolü
|
||||
if (!$typeId) {
|
||||
// Otomatik modül tespiti
|
||||
// URL: /admin/types/{slug}
|
||||
$slug = request()->segment(3);
|
||||
if ($slug) {
|
||||
$type = \App\Types::where('slug', $slug)->first();
|
||||
if($type) {
|
||||
$typeId = $type->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($typeId) {
|
||||
$key = "type_{$typeId}_specific_permissions";
|
||||
$moduleSettings = j(setting($key));
|
||||
|
||||
// Eğer permission bu modül için tanımlıysa
|
||||
if (isset($moduleSettings[$permission])) {
|
||||
$allowed = $moduleSettings[$permission];
|
||||
|
||||
if (!empty($allowed)) {
|
||||
$allowedLevels = explode(',', $allowed);
|
||||
// Trim whitespace from values
|
||||
$allowedLevels = array_map('trim', $allowedLevels);
|
||||
|
||||
// Modül ayarları level indexlerini (1, 2, 3) kullanıyor
|
||||
if (in_array($userLevelIndex, $allowedLevels)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Modülde ayar var ama boş veya kullanıcı uymuyorsa reddet (Global'e düşmez)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Global Specific Permission Kontrolü
|
||||
// Global ayarlar level isimlerini (Manager, User vb.) kullanıyor
|
||||
$globalSetting = setting($permission);
|
||||
|
||||
if($globalSetting) {
|
||||
$allowedGlobal = j($globalSetting);
|
||||
|
||||
if(!is_array($allowedGlobal)) {
|
||||
$allowedGlobal = explode(',', $globalSetting);
|
||||
}
|
||||
|
||||
if(!empty($allowedGlobal)) {
|
||||
if (in_array($user->level, $allowedGlobal)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Hiçbir ayar bulunamadıysa veya eşleşme olmadıysa varsayılan olarak reddet
|
||||
return false;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php function spool_status() {
|
||||
return [
|
||||
'Waiting',
|
||||
'Manufacturing',
|
||||
'QC',
|
||||
'Paint',
|
||||
'Completed'
|
||||
];
|
||||
}
|
||||
|
||||
function rollback_spool_status() {
|
||||
return [
|
||||
'QC',
|
||||
'Paint',
|
||||
'Completed'
|
||||
];
|
||||
}
|
||||
function spool_status_prev($status) {
|
||||
$spool_status = rollback_spool_status();
|
||||
$status_index = array_search($status, $spool_status);
|
||||
|
||||
if ($status_index > 0) {
|
||||
$previous_status = $spool_status[$status_index - 1];
|
||||
return $previous_status;
|
||||
} else {
|
||||
return $status;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
use Illuminate\Support\Facades\Log;
|
||||
function spoolStatusChanger($iso_number=null, $spool_number=null, $paintChanged=false) {
|
||||
if(!is_null($iso_number)) {
|
||||
if(is_null($spool_number)) {
|
||||
$params = [
|
||||
'iso_number' => $iso_number,
|
||||
];
|
||||
} else {
|
||||
$params = [
|
||||
'iso_number' => $iso_number,
|
||||
'spool_number' => $spool_number,
|
||||
];
|
||||
}
|
||||
|
||||
if($paintChanged) {
|
||||
$params['paintChanged'] = true;
|
||||
}
|
||||
|
||||
$result = view('cron.spool-status-changer',$params)->render();
|
||||
Log::info("Spool Status Changer result", ['result' => $result]);
|
||||
return $result;
|
||||
} else {
|
||||
Log::error("ISO number not found for spool status changer");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php function storage() {
|
||||
return "storage/app/files/";
|
||||
} ?>
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
function syncTrigger($tableName, $id)
|
||||
{
|
||||
$syncMap = [
|
||||
'line_lists' => [
|
||||
'cron.line_lists-sync-from-linelists-to-weldlog',
|
||||
'cron.line_lists-sync-from-linelists-paint-matrix',
|
||||
'cron.line_lists-sync-from-linelists-nde-matrix',
|
||||
],
|
||||
'nde_matrices' => [
|
||||
'cron.nde_matrices-sync-nde-to-weldlog',
|
||||
],
|
||||
'weld_logs' => [
|
||||
'cron.weld_logs-sync-from-weldlog-to-paint-follow-up',
|
||||
'cron.weld_logs-sync-from-weldlog-to-test-pack',
|
||||
'cron.weld_logs-sync-weldlog-nde-project',
|
||||
],
|
||||
'incoming_control_paints' => [
|
||||
'cron.incoming_control_paints-sync-from-incoming-control-paint-paint-follow-up',
|
||||
],
|
||||
'punch_lists' => [
|
||||
'cron.punch_lists-sync-punch-qty',
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
if(isset($syncMap[$tableName]))
|
||||
{
|
||||
foreach($syncMap[$tableName] AS $syncPath)
|
||||
{
|
||||
try {
|
||||
\App\Jobs\SyncTriggerJob::dispatch($syncPath, $id);
|
||||
\Log::info("SyncTriggerJob dispatched for $syncPath with ID $id");
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("Failed to dispatch SyncTriggerJob for $syncPath", [
|
||||
'id' => $id,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
function table_columns($tableName) {
|
||||
$prefix = 'table_columns_' . $tableName;
|
||||
if(Cache::has($prefix)) {
|
||||
$columnNames = Cache::get($prefix);
|
||||
} else {
|
||||
$exceptsColumns = ['created_at', 'updated_at'];
|
||||
$columnNames = array_diff(Schema::getColumnListing($tableName), $exceptsColumns);
|
||||
Cache::put($prefix, $columnNames);
|
||||
}
|
||||
|
||||
return $columnNames;
|
||||
}
|
||||
|
||||
function table_column_type($tableName, $columnName) {
|
||||
$prefix = 'table_column_type_' . $tableName . $columnName;
|
||||
|
||||
if(Cache::has($prefix)) {
|
||||
$columnType = Cache::get($prefix);
|
||||
} else {
|
||||
$columnType = Schema::getColumnType($tableName, $columnName);
|
||||
Cache::put($prefix, $columnType);
|
||||
}
|
||||
return $columnType;
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
function table_different_values($tableName) {
|
||||
$except = ['id', 'created_at', 'updated_at'];
|
||||
$key = 'table_different_values_' . $tableName;
|
||||
|
||||
if(Cache::has($key)) {
|
||||
$filterData = Cache::get($key);
|
||||
} else {
|
||||
$datas = db($tableName)->get()->toArray();
|
||||
$filterData = [];
|
||||
|
||||
foreach($datas AS $data) {
|
||||
|
||||
foreach($data AS $column => $value) {
|
||||
|
||||
if(!in_array($column, $except)) {
|
||||
|
||||
if(!isset($filterData[$column])) {
|
||||
$filterData[$column] = [];
|
||||
}
|
||||
|
||||
if(!in_array($value, $filterData[$column])) {
|
||||
$filterData[$column][] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Cache::put($key, $filterData);
|
||||
}
|
||||
|
||||
return $filterData;
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php function temperature($lat, $lng) {
|
||||
//55.581972
|
||||
//37.0559091
|
||||
$lat = "55.581972";
|
||||
$lng = "37.0559091";
|
||||
|
||||
$json = j(file_get_contents("https://api.openweathermap.org/data/2.5/weather?lat=$lat&lon=$lng&appid=5556bfdb8646e41911f33a956dba56ed&units=metric"));
|
||||
return $json['main']['temp'];
|
||||
} ?>
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
function updateTestPackageStatus($testPackage) {
|
||||
$status = "Waiting";
|
||||
$ndt_status = $testPackage->ndt_status;
|
||||
$updateData = [];
|
||||
|
||||
if (!rejected_date($testPackage->test_package_sent_date)) {
|
||||
$status = "Prepairing";
|
||||
}
|
||||
|
||||
if (!rejected_date($testPackage->test_package_approval_date)) {
|
||||
$status = "Walkdown";
|
||||
}
|
||||
|
||||
if (!rejected_date($testPackage->walkdown_date)) {
|
||||
$status = "Punch";
|
||||
}
|
||||
|
||||
if (in_array($testPackage->a_punch_point_open, [0, ''])) {
|
||||
if ($testPackage->welding_status != "Completed") {
|
||||
$ndt_status = $testPackage->welding_status;
|
||||
$status = "Welding Ongoing";
|
||||
} elseif (!in_array($testPackage->repair_remaining, [0, ''])) {
|
||||
$status = "Repair Waiting";
|
||||
} else {
|
||||
$status = "NDT";
|
||||
}
|
||||
|
||||
$updateData['punch_status'] = "Closed";
|
||||
if (!rejected_date($testPackage->walkdown_date)) {
|
||||
$updateData['punch_status'] = "Waiting Punch";
|
||||
}
|
||||
} else {
|
||||
$updateData['punch_status'] = "Open";
|
||||
}
|
||||
|
||||
if ($ndt_status == "Completed") {
|
||||
$status = "Ready for Test";
|
||||
}
|
||||
|
||||
if ($testPackage->test_status == "Accepted") {
|
||||
$status = "Ready Cleaning-Blowing";
|
||||
}
|
||||
|
||||
if ($testPackage->cleaning_blowing_drying_status == "Accepted") {
|
||||
if (!in_array($testPackage->b_punch_point_open, [0, ''])) {
|
||||
if (!in_array($testPackage->c_punch_point_open, [0, ''])) {
|
||||
$status = "Ready for Reinstatement";
|
||||
} else {
|
||||
$status = "C Waiting";
|
||||
}
|
||||
} else {
|
||||
$status = "B Waiting";
|
||||
}
|
||||
}
|
||||
|
||||
if ($testPackage->reinstatement_status == "Accepted") {
|
||||
$status = "Completed";
|
||||
}
|
||||
|
||||
$updateData['tp_general_status'] = $status;
|
||||
$updateData['ndt_status'] = $ndt_status;
|
||||
|
||||
return $updateData;
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php function userPermissions() {
|
||||
$user = u();
|
||||
if(!is_null($user)) {
|
||||
$userLevel = $user->level;
|
||||
$userLevelIndex = getLevelIndex($userLevel);
|
||||
$userLevelPermissions = db("types")
|
||||
->where(function($query) use($userLevelIndex){
|
||||
$query->where("read", $userLevelIndex)
|
||||
->orWhere("read", "like", "$userLevelIndex,%")
|
||||
->orWhere("read", "like", "%,$userLevelIndex")
|
||||
->orWhere("read", "like", "%,$userLevelIndex,%");
|
||||
})
|
||||
->get()
|
||||
->pluck("title")
|
||||
->join(",");
|
||||
|
||||
$allPermissions = $userLevelPermissions;
|
||||
return @explode(",",$allPermissions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isAuth($moduleType, $permissionType="read") {
|
||||
$user = u();
|
||||
// user no, full control, write, read, modify
|
||||
|
||||
if(!is_null($user)) {
|
||||
// Admin users have full access to everything
|
||||
if ($user->level == "Admin") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use session cache to avoid repeated DB queries
|
||||
$cacheKey = "isauth_{$user->id}_{$moduleType}_{$permissionType}";
|
||||
|
||||
// Check if result is already in session cache
|
||||
if (session()->has($cacheKey)) {
|
||||
return session($cacheKey);
|
||||
}
|
||||
|
||||
// Not in cache - query database
|
||||
$userLevel = $user->level;
|
||||
$userLevelIndex = getLevelIndex($userLevel);
|
||||
$singlePermission = db("types")->where("slug", $moduleType)
|
||||
->where(function($query) use($userLevelIndex, $permissionType){
|
||||
$query->orWhere($permissionType, "like", "%,$userLevelIndex,%");
|
||||
$query->orWhere($permissionType, "like", "%,$userLevelIndex");
|
||||
$query->orWhere($permissionType, "like", "$userLevelIndex,%");
|
||||
$query->orWhere($permissionType, $userLevelIndex);
|
||||
})
|
||||
->first();
|
||||
|
||||
$result = !is_null($singlePermission);
|
||||
|
||||
// Store result in session cache for future calls
|
||||
session([$cacheKey => $result]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
|
||||
function get_value_hints($tableName) {
|
||||
// Tables that use value hints
|
||||
$weldingRelatedTables = [
|
||||
'weld_logs', 'w_p_s', 'prosedure_qualification_records',
|
||||
'naks_certificates', 'naks_welders', 'welding_equipment',
|
||||
'fit_up_welding_follow_ups', 'deleted_joints', 'repair_logs',
|
||||
'radiographic_tests', 'ultrasonic_tests', 'magnetic_tests',
|
||||
'dye_penetrant_tests', 'hardness_tests', 'p_m_i_tests', 'p_w_h_t_s', 'ferrits',
|
||||
'v_t_logs', 'p_t_logs', 'nde_matrices'
|
||||
];
|
||||
|
||||
// Columns that show hints
|
||||
$hintColumns = [
|
||||
'joint_type', 'joint_type_ru', 'type_of_joint', 'type_of_welds',
|
||||
'welding_method', 'welding_process', 'process'
|
||||
];
|
||||
|
||||
if (!in_array($tableName, $weldingRelatedTables)) {
|
||||
return ['hints' => [], 'columns' => []];
|
||||
}
|
||||
|
||||
$hints = Cache::remember('value_hints_data', 3600, function() {
|
||||
$data = [];
|
||||
|
||||
// Joint types: short_name_en/ru -> definition_en + definition_ru + title
|
||||
$jointTypes = db("joint_types")->whereNotNull("short_name_en")->get();
|
||||
foreach($jointTypes as $jt) {
|
||||
$hint = [];
|
||||
if(!empty($jt->definition_en)) $hint[] = $jt->definition_en;
|
||||
if(!empty($jt->definition_ru)) $hint[] = $jt->definition_ru;
|
||||
if(!empty($jt->title)) $hint[] = $jt->title;
|
||||
|
||||
if(!empty($hint) && !empty($jt->short_name_en)) {
|
||||
$data[$jt->short_name_en] = implode(' / ', array_unique($hint));
|
||||
}
|
||||
if(!empty($jt->short_name_ru) && !empty($hint)) {
|
||||
$data[$jt->short_name_ru] = implode(' / ', array_unique($hint));
|
||||
}
|
||||
}
|
||||
|
||||
// Welding methods: iso_short_name/aws_short_name/ru_short_name -> definitions
|
||||
$weldingMethods = db("welding_methods")->get();
|
||||
foreach($weldingMethods as $wm) {
|
||||
$hint = [];
|
||||
if(!empty($wm->iso_4063_definition)) $hint[] = $wm->iso_4063_definition;
|
||||
if(!empty($wm->russian_definition)) $hint[] = $wm->russian_definition;
|
||||
|
||||
if(!empty($hint)) {
|
||||
if(!empty($wm->iso_short_name)) $data[$wm->iso_short_name] = implode(' / ', $hint);
|
||||
if(!empty($wm->aws_short_name)) $data[$wm->aws_short_name] = implode(' / ', $hint);
|
||||
if(!empty($wm->ru_short_name)) $data[$wm->ru_short_name] = implode(' / ', $hint);
|
||||
if(!empty($wm->en_welding_number)) $data[$wm->en_welding_number] = implode(' / ', $hint);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
});
|
||||
|
||||
return ['hints' => $hints, 'columns' => $hintColumns];
|
||||
}
|
||||
|
||||
function clear_value_hints_cache() {
|
||||
Cache::forget('value_hints_data');
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php function welder_locations() {
|
||||
$welderLocations = db("welder_tests")->get()->pluck("status", "naks_id")->toArray();
|
||||
return $welderLocations;
|
||||
} ?>
|
||||
@@ -0,0 +1,264 @@
|
||||
<?php function weldlog_accepted_columns() {
|
||||
return [
|
||||
'vt_result',
|
||||
'pwht',
|
||||
'ndt_percent',
|
||||
'vt_report',
|
||||
'vt_request_date',
|
||||
'vt_request_no',
|
||||
'vt_test_date',
|
||||
'test_laboratory_vt',
|
||||
'rt_request_no',
|
||||
'rt_request_date',
|
||||
'rt_report',
|
||||
'rt_test_date',
|
||||
'test_laboratory_rt',
|
||||
'rt_result',
|
||||
'ut_request_no',
|
||||
'ut_type',
|
||||
'ut_request_date',
|
||||
'ut_report',
|
||||
'ut_test_date',
|
||||
'test_laboratory_ut',
|
||||
'ut_result',
|
||||
'pt_request_no',
|
||||
'pt_request_date',
|
||||
'pt_report',
|
||||
'pt_test_date',
|
||||
'test_laboratory_pt',
|
||||
'pt_result',
|
||||
'mt_request_no',
|
||||
'mt_report',
|
||||
'mt_test_date',
|
||||
'test_laboratory_mt',
|
||||
'mt_result',
|
||||
'mt_request_date',
|
||||
'pmi_request_no',
|
||||
'pmi_request_date',
|
||||
'no_of_testing_report',
|
||||
'pmi_test_date',
|
||||
'test_laboratory_pmi',
|
||||
'pmi_result',
|
||||
'pwht_date',
|
||||
'pwht_request_no',
|
||||
'pwht_request_date',
|
||||
'no_of_pwht_report',
|
||||
'diagram_number_pwht',
|
||||
'test_laboratory_pwht',
|
||||
'ht_request_no',
|
||||
'no_of_ht_hardnes_test',
|
||||
'ht_request_date',
|
||||
'test_laboratory_ht',
|
||||
'diagram_number_pwht',
|
||||
'ht_test_date',
|
||||
'ht_result',
|
||||
'ht_request_date',
|
||||
'ferrite_request_no',
|
||||
'ferrite_request_date',
|
||||
'no_of_ferrite_check',
|
||||
'date_of_ferrite_check',
|
||||
'ferrite_test_date',
|
||||
'test_laboratory_ferrite',
|
||||
'ferrite_result',
|
||||
'ferrite_report',
|
||||
'pwht_result',
|
||||
'pwht_operator_id',
|
||||
'pwht_operator_name',
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
function logToWeldlogUpdate($data) {
|
||||
$data = (Array) $data;
|
||||
// dump($data);
|
||||
if(isset($data['iso_number'])) {
|
||||
$isoNumber = $data['iso_number'];
|
||||
$jointNumber = $data['no_of_the_joint_as_per_as_built_survey'];
|
||||
$weldingDate = $data['welding_date'];
|
||||
|
||||
// Generate unique key for tracking this update
|
||||
$logKey = 'WELDLOG_SYNC_' . time() . '_' . rand(1000, 9999);
|
||||
|
||||
\Log::info("[$logKey] === logToWeldlogUpdate START ===");
|
||||
\Log::info("[$logKey] ISO Number: $isoNumber, Joint: $jointNumber, Welding Date: $weldingDate");
|
||||
|
||||
$updateData = [];
|
||||
$weldlogAcceptedColumns = weldlog_accepted_columns();
|
||||
|
||||
// Check which test types are canceled
|
||||
$canceledTests = [];
|
||||
foreach($data AS $column => $value) {
|
||||
if($value === 'Cancel / отмена') {
|
||||
// Check for standard _result pattern (e.g., 'vt_result', 'ferrite_result')
|
||||
if(strpos($column, '_result') !== false) {
|
||||
$testType = str_replace('_result', '', $column);
|
||||
$canceledTests[] = $testType;
|
||||
\Log::info("[$logKey] CANCEL DETECTED: Test type '$testType' is canceled (column: $column)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($canceledTests)) {
|
||||
\Log::info("[$logKey] No canceled tests found");
|
||||
} else {
|
||||
\Log::info("[$logKey] Canceled test types: " . implode(', ', $canceledTests));
|
||||
}
|
||||
|
||||
// Handle PWHT operator fields
|
||||
if(isset($data['pwht_operator_id'])) {
|
||||
$updateData['pwht_operator_id'] = $data['pwht_operator_id'];
|
||||
\Log::info("[$logKey] PWHT Operator ID: " . $data['pwht_operator_id']);
|
||||
}
|
||||
|
||||
if(isset($data['pwht_operator'])) {
|
||||
$updateData['pwht_operator_name'] = $data['pwht_operator'];
|
||||
\Log::info("[$logKey] PWHT Operator Name: " . $data['pwht_operator']);
|
||||
}
|
||||
|
||||
// Process all fields
|
||||
$canceledColumnsCount = 0;
|
||||
$normalColumnsCount = 0;
|
||||
$canceledColumnsList = [];
|
||||
|
||||
foreach($data AS $column => $value) {
|
||||
if(in_array($column, $weldlogAcceptedColumns)) {
|
||||
// Check if this column belongs to a canceled test
|
||||
$isCanceledColumn = false;
|
||||
foreach($canceledTests as $testType) {
|
||||
// Check if column contains the test type (e.g., 'vt' in 'test_laboratory_vt' or 'vt_result')
|
||||
if(strpos($column, $testType) !== false) {
|
||||
$isCanceledColumn = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If canceled, set to null; otherwise process normally
|
||||
if($isCanceledColumn) {
|
||||
$canceledColumnsCount++;
|
||||
$canceledColumnsList[] = $column;
|
||||
$updateData[$column] = null;
|
||||
} else {
|
||||
$normalColumnsCount++;
|
||||
if($value == "") $value = null;
|
||||
$updateData[$column] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Log only canceled columns
|
||||
if(!empty($canceledColumnsList)) {
|
||||
\Log::info("[$logKey] Columns set to NULL: " . implode(', ', $canceledColumnsList));
|
||||
}
|
||||
|
||||
\Log::info("[$logKey] Summary: $canceledColumnsCount columns set to NULL (canceled), $normalColumnsCount columns processed normally");
|
||||
|
||||
$whereData = [
|
||||
'iso_number' => $isoNumber,
|
||||
'no_of_the_joint_as_per_as_built_survey' => $jointNumber,
|
||||
'welding_date' => $weldingDate,
|
||||
];
|
||||
|
||||
\Log::info("[$logKey] WHERE condition: " . json_encode($whereData));
|
||||
\Log::info("[$logKey] UPDATE data: " . json_encode($updateData));
|
||||
|
||||
$result = db("weld_logs")
|
||||
->where($whereData)
|
||||
->update($updateData);
|
||||
|
||||
\Log::info("[$logKey] weld_logs UPDATE result: $result affected rows");
|
||||
|
||||
// Sync to other tables and clear cache
|
||||
if ($result > 0) {
|
||||
$weldLogId = db("weld_logs")
|
||||
->where($whereData)
|
||||
->value('id');
|
||||
|
||||
if ($weldLogId) {
|
||||
if (function_exists('syncTrigger')) {
|
||||
\Log::info("[$logKey] Calling syncTrigger for weld_logs ID: $weldLogId");
|
||||
syncTrigger('weld_logs', $weldLogId);
|
||||
}
|
||||
|
||||
if (function_exists('dispatchCacheBladeViews')) {
|
||||
\Log::info("[$logKey] Dispatching cache invalidation for NDT calculation");
|
||||
dispatchCacheBladeViews([
|
||||
[
|
||||
'view' => 'admin-ajax.ndt-calculation-no-cache',
|
||||
'cache' => 'ndt-calculation'
|
||||
],
|
||||
[
|
||||
'view' => 'admin-ajax.ndt-order.order-list-no-cache',
|
||||
'cache' => 'ndt-order-list'
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repairLogUpdate($data);
|
||||
|
||||
\Log::info("[$logKey] === logToWeldlogUpdate END ===\n");
|
||||
|
||||
dump($whereData);
|
||||
dump($updateData);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function repairLogUpdate($data) {
|
||||
// Check if any test result contains "Repair / Ремонт" or "Cut / Резать"
|
||||
$testResultFields = [
|
||||
'vt_result',
|
||||
'rt_result',
|
||||
'ut_result',
|
||||
'pt_result',
|
||||
'mt_result',
|
||||
'pmi_result',
|
||||
'ht_result',
|
||||
'ferrite_result'
|
||||
];
|
||||
|
||||
|
||||
// Convert object properties to array access
|
||||
$hasRepairOrCut = false;
|
||||
$allFieldsEmpty = true;
|
||||
$rtAndUtEmpty = false;
|
||||
|
||||
// Check if RT or UT results are empty (array access)
|
||||
if (empty($data['rt_result']) && empty($data['ut_result'])) {
|
||||
$rtAndUtEmpty = true;
|
||||
}
|
||||
|
||||
foreach ($testResultFields as $field) {
|
||||
if (isset($data[$field]) && !empty($data[$field])) {
|
||||
$allFieldsEmpty = false;
|
||||
if (in_array($data[$field], ['Repair / Ремонт', 'Cut / Резать'])) {
|
||||
$hasRepairOrCut = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine repair status based on test results
|
||||
if ($allFieldsEmpty || $rtAndUtEmpty) {
|
||||
$repairStatus = "Not Done";
|
||||
} elseif (!$hasRepairOrCut) {
|
||||
$repairStatus = "Done";
|
||||
} else {
|
||||
$repairStatus = "Repair";
|
||||
}
|
||||
|
||||
$affected = db("repair_logs")
|
||||
->where([
|
||||
'iso_number' => $data['iso_number'],
|
||||
'new_joint_no' => $data['no_of_the_joint_as_per_as_built_survey'],
|
||||
])
|
||||
->update([
|
||||
'repair_date' => $data['welding_date'],
|
||||
'repair_status' => $repairStatus,
|
||||
]);
|
||||
dump("repairLogUpdate affected rows: " . $affected);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
|
||||
function workPermitReplacerExcel(Spreadsheet $spreadsheet, $weldLog, $documentInfo) {
|
||||
// Fetch the work permit users from the database
|
||||
$workPermitUsers = db("work_permit_documents")
|
||||
->join("subcontractors", "work_permit_documents.company", "subcontractors.company_name_ru")
|
||||
->where("zone", "like", "%{$weldLog?->project}%")
|
||||
->where("assigned_documents", "like", "%{$documentInfo->slug}%")
|
||||
->get();
|
||||
|
||||
// Iterate over each sheet in the spreadsheet
|
||||
foreach ($spreadsheet->getAllSheets() as $sheet) {
|
||||
// Loop through all the cells in the sheet and replace placeholders
|
||||
foreach ($sheet->getRowIterator() as $row) {
|
||||
foreach ($row->getCellIterator() as $cell) {
|
||||
$cellValue = $cell->getValue();
|
||||
if (is_string($cellValue)) {
|
||||
// Perform the replacement for each work permit user
|
||||
foreach ($workPermitUsers as $wpi) {
|
||||
$replacements = [
|
||||
"{".$wpi->company_code.$wpi->sign_order."_name_surname}" => $wpi->name_surname,
|
||||
"{".$wpi->company_code.$wpi->sign_order."_company_name}" => $wpi->company,
|
||||
"{".$wpi->company_code.$wpi->sign_order."_certificate_no}" => $wpi->certificates_number,
|
||||
"{".$wpi->company_code.$wpi->sign_order."_certificate_number}" => $wpi->certificates_number,
|
||||
"{".$wpi->company_code.$wpi->sign_order."_address_ru}" => $wpi->address_ru,
|
||||
"{".$wpi->company_code.$wpi->sign_order."_project_city_ru}" => $wpi->project_city_ru,
|
||||
"{".$wpi->company_code.$wpi->sign_order."_duty}" => $wpi->duty,
|
||||
"{".$wpi->company_code.$wpi->sign_order."_tax}" => $wpi->tax,
|
||||
"{".$wpi->company_code.$wpi->sign_order."_tax2}" => $wpi->tax2,
|
||||
"{".$wpi->company_code.$wpi->sign_order."_address_ru2}" => $wpi->address_ru2,
|
||||
"{".$wpi->company_code.$wpi->sign_order."_document_number}" => $wpi->document_number,
|
||||
"{".$wpi->company_code.$wpi->sign_order."_attorney}" => $wpi->attorney,
|
||||
"{".$wpi->company_code.$wpi->sign_order."_attorney_date}" => df($wpi->attorney_date),
|
||||
];
|
||||
|
||||
// Replace each placeholder in the cell value
|
||||
foreach ($replacements as $placeholder => $replacement) {
|
||||
if (strpos($cellValue, $placeholder) !== false) {
|
||||
$cellValue = str_replace($placeholder, $replacement, $cellValue);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the cell with the new value
|
||||
$cell->setValue($cellValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the modified spreadsheet
|
||||
return $spreadsheet;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
function workPermitReplacerExcel2(?Spreadsheet $spreadsheet, $weldLog, $documentInfo, $type="replacer") {
|
||||
// Handle project value from weldLog (may be array or object)
|
||||
$weldLog = (object)$weldLog;
|
||||
if(isset($weldLog->project)) {
|
||||
$project = $weldLog->project;
|
||||
}else{
|
||||
$project = '';
|
||||
}
|
||||
// Fetch the work permit users from the database
|
||||
$cacheKey = "work_permit_users_{$project}_{$documentInfo->slug}";
|
||||
$workPermitUsers = db("work_permit_documents")
|
||||
->select([
|
||||
'work_permit_documents.*',
|
||||
'subcontractors.*',
|
||||
'work_permit_documents.sign_order as personel_sign_order',
|
||||
'subcontractors.sign_order as firma_sign_order',
|
||||
])
|
||||
->leftJoin("subcontractors", "work_permit_documents.company", "subcontractors.company_name_ru")
|
||||
->where("zone", "like", "%{$project}%")
|
||||
->where("assigned_documents", "like", "%{$documentInfo->slug}%")
|
||||
->get();
|
||||
|
||||
// Initialize data array for placeholders
|
||||
$data = [];
|
||||
|
||||
if ($type == "replacer") {
|
||||
// Only process spreadsheet if it's not null
|
||||
if ($spreadsheet !== null) {
|
||||
try {
|
||||
// Iterate over each sheet in the spreadsheet
|
||||
foreach ($spreadsheet->getAllSheets() as $sheet) {
|
||||
// Loop through all the cells in the sheet and replace placeholders
|
||||
foreach ($sheet->getRowIterator() as $row) {
|
||||
foreach ($row->getCellIterator() as $cell) {
|
||||
$cellValue = $cell->getValue();
|
||||
if (is_string($cellValue)) {
|
||||
// Perform the replacement for each work permit user
|
||||
foreach ($workPermitUsers as $wpi) {
|
||||
// Get all properties for the current work permit user
|
||||
|
||||
// Support for old format (using only personel_sign_order)
|
||||
$jobDescPrefix = $wpi->job_description.$wpi->personel_sign_order;
|
||||
$companyCodePrefix = $wpi->company_code.$wpi->personel_sign_order;
|
||||
|
||||
// Support for new format (using both firma_sign_order and personel_sign_order)
|
||||
$jobDescPrefixNew = $wpi->job_description.$wpi->firma_sign_order."_".$wpi->personel_sign_order;
|
||||
$companyCodePrefixNew = $wpi->company_code.$wpi->firma_sign_order."_".$wpi->personel_sign_order;
|
||||
|
||||
// Dynamically replace all properties
|
||||
foreach ((array)$wpi as $key => $value) {
|
||||
// Skip internal properties and non-string/numeric values
|
||||
if (is_string($key) && !str_starts_with($key, "\0") && (is_string($value) || is_numeric($value))) {
|
||||
// Handle dates
|
||||
if (in_array($key, ['attorney_date', 'date_of_issue', 'certificate_date']) && !empty($value)) {
|
||||
$value = df($value);
|
||||
}
|
||||
|
||||
// Replace with old format (job_description + personel_sign_order)
|
||||
$cellValue = str_replace("{".$jobDescPrefix."_".$key."}", $value, $cellValue);
|
||||
$cellValue = str_replace("{".$companyCodePrefix."_".$key."}", $value, $cellValue);
|
||||
|
||||
// Replace with new format (job_description + firma_sign_order + "_" + personel_sign_order)
|
||||
$cellValue = str_replace("{".$jobDescPrefixNew."_".$key."}", $value, $cellValue);
|
||||
$cellValue = str_replace("{".$companyCodePrefixNew."_".$key."}", $value, $cellValue);
|
||||
}
|
||||
}
|
||||
|
||||
// For backward compatibility, add specific replacements for commonly used fields
|
||||
// Old format
|
||||
$cellValue = str_replace("{".$jobDescPrefix."_company_name}", $wpi->company, $cellValue);
|
||||
$cellValue = str_replace("{".$companyCodePrefix."_company_name}", $wpi->company, $cellValue);
|
||||
$cellValue = str_replace("{".$jobDescPrefix."_certificate_no}", $wpi->certificates_number, $cellValue);
|
||||
$cellValue = str_replace("{".$companyCodePrefix."_certificate_no}", $wpi->certificates_number, $cellValue);
|
||||
$cellValue = str_replace("{".$jobDescPrefix."_certificate_number}", $wpi->certificates_number, $cellValue);
|
||||
$cellValue = str_replace("{".$companyCodePrefix."_certificate_number}", $wpi->certificates_number, $cellValue);
|
||||
|
||||
// New format
|
||||
$cellValue = str_replace("{".$jobDescPrefixNew."_company_name}", $wpi->company, $cellValue);
|
||||
$cellValue = str_replace("{".$companyCodePrefixNew."_company_name}", $wpi->company, $cellValue);
|
||||
$cellValue = str_replace("{".$jobDescPrefixNew."_certificate_no}", $wpi->certificates_number, $cellValue);
|
||||
$cellValue = str_replace("{".$companyCodePrefixNew."_certificate_no}", $wpi->certificates_number, $cellValue);
|
||||
$cellValue = str_replace("{".$jobDescPrefixNew."_certificate_number}", $wpi->certificates_number, $cellValue);
|
||||
$cellValue = str_replace("{".$companyCodePrefixNew."_certificate_number}", $wpi->certificates_number, $cellValue);
|
||||
|
||||
// Update the cell with the new value
|
||||
$cell->setValue($cellValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the modified spreadsheet for replacer type
|
||||
return $spreadsheet;
|
||||
} catch (\Throwable $th) {
|
||||
// Log error but continue
|
||||
// error_log("Error processing spreadsheet: " . $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// If spreadsheet is null or an error occurred, return empty array
|
||||
return [];
|
||||
} else {
|
||||
// For other types (e.g. "data"), collect placeholders
|
||||
foreach ($workPermitUsers as $wpi) {
|
||||
// Get all properties for the current work permit user
|
||||
$wpiArray = (array)$wpi;
|
||||
|
||||
foreach ($wpiArray as $key => $value) {
|
||||
// Skip internal properties
|
||||
if (is_string($key) && !str_starts_with($key, "\0")) {
|
||||
// Old format placeholders (job_description + personel_sign_order)
|
||||
$jobDescPlaceholder = "{" . $wpi->job_description . $wpi->personel_sign_order . "_" . $key . "}";
|
||||
if (!in_array($jobDescPlaceholder, $data)) {
|
||||
$data[] = $jobDescPlaceholder;
|
||||
}
|
||||
|
||||
$companyCodePlaceholder = "{" . $wpi->company_code . $wpi->personel_sign_order . "_" . $key . "}";
|
||||
if (!in_array($companyCodePlaceholder, $data)) {
|
||||
$data[] = $companyCodePlaceholder;
|
||||
}
|
||||
|
||||
// New format placeholders (job_description + firma_sign_order + "_" + personel_sign_order)
|
||||
$jobDescPlaceholderNew = "{" . $wpi->job_description . $wpi->firma_sign_order . "_" . $wpi->personel_sign_order . "_" . $key . "}";
|
||||
if (!in_array($jobDescPlaceholderNew, $data)) {
|
||||
$data[] = $jobDescPlaceholderNew;
|
||||
}
|
||||
|
||||
$companyCodePlaceholderNew = "{" . $wpi->company_code . $wpi->firma_sign_order . "_" . $wpi->personel_sign_order . "_" . $key . "}";
|
||||
if (!in_array($companyCodePlaceholderNew, $data)) {
|
||||
$data[] = $companyCodePlaceholderNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For backward compatibility, add specific placeholders for commonly used fields
|
||||
$commonPlaceholders = [
|
||||
"company_name" => "company",
|
||||
"certificate_no" => "certificates_number",
|
||||
"certificate_number" => "certificates_number",
|
||||
"document_code" => "document_code",
|
||||
"document_number" => "document_number",
|
||||
"revision" => "revision",
|
||||
"date_of_issue" => "date_of_issue",
|
||||
"duty" => "duty",
|
||||
"attorney" => "attorney",
|
||||
"attorney_date" => "attorney_date",
|
||||
"name_surname" => "name_surname",
|
||||
"id_no" => "id_no",
|
||||
"level" => "level",
|
||||
"description" => "description",
|
||||
"status" => "status",
|
||||
"dept" => "dept",
|
||||
"zone" => "zone",
|
||||
"third_party" => "third_party",
|
||||
];
|
||||
|
||||
foreach ($commonPlaceholders as $placeholder => $field) {
|
||||
// Old format
|
||||
$jobDescPlaceholder = "{" . $wpi->job_description . $wpi->personel_sign_order . "_" . $placeholder . "}";
|
||||
$companyCodePlaceholder = "{" . $wpi->company_code . $wpi->personel_sign_order . "_" . $placeholder . "}";
|
||||
|
||||
if (!in_array($jobDescPlaceholder, $data)) {
|
||||
$data[] = $jobDescPlaceholder;
|
||||
}
|
||||
if (!in_array($companyCodePlaceholder, $data)) {
|
||||
$data[] = $companyCodePlaceholder;
|
||||
}
|
||||
|
||||
// New format
|
||||
$jobDescPlaceholderNew = "{" . $wpi->job_description . $wpi->firma_sign_order . "_" . $wpi->personel_sign_order . "_" . $placeholder . "}";
|
||||
$companyCodePlaceholderNew = "{" . $wpi->company_code . $wpi->firma_sign_order . "_" . $wpi->personel_sign_order . "_" . $placeholder . "}";
|
||||
|
||||
if (!in_array($jobDescPlaceholderNew, $data)) {
|
||||
$data[] = $jobDescPlaceholderNew;
|
||||
}
|
||||
if (!in_array($companyCodePlaceholderNew, $data)) {
|
||||
$data[] = $companyCodePlaceholderNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the placeholder list
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php function workPermitReplacer($string, $weldLog, $documentInfo) {
|
||||
|
||||
$workPermitUsers = db("work_permit_documents")
|
||||
->join("subcontractors", "work_permit_documents.company", "subcontractors.company_name_ru")
|
||||
->where("zone", "like", "%{$weldLog?->project}%")
|
||||
->where("assigned_documents", "like", "%{$documentInfo->slug}%")
|
||||
->get();
|
||||
|
||||
foreach($workPermitUsers AS $wpi) {
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_name_surname}", $wpi->name_surname, $string);
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_company_name}", $wpi->company, $string);
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_certificate_no}", $wpi->certificates_number, $string);
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_certificate_number}", $wpi->certificates_number, $string);
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_address_ru}", $wpi->address_ru, $string);
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_project_city_ru}", $wpi->project_city_ru, $string);
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_duty}", $wpi->duty, $string);
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_tax}", $wpi->tax, $string);
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_tax2}", $wpi->tax2, $string);
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_address_ru2}", $wpi->address_ru2, $string);
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_document_number}", $wpi->document_number, $string);
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_attorney}", $wpi->attorney, $string);
|
||||
$string = str_replace("{".$wpi->company_code.$wpi->sign_order."_attorney_date}", df($wpi->attorney_date), $string);
|
||||
}
|
||||
|
||||
return $string;
|
||||
} ?>
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php function workPermitReplacer2($string, $weldLog, $documentInfo, $type="replacer") {
|
||||
|
||||
$workPermitUsers = db("work_permit_documents")
|
||||
->select([
|
||||
'work_permit_documents.name_surname',
|
||||
'work_permit_documents.company',
|
||||
'work_permit_documents.certificates_number',
|
||||
'subcontractors.address_ru',
|
||||
'subcontractors.project_city_ru',
|
||||
'work_permit_documents.duty',
|
||||
'subcontractors.tax',
|
||||
'subcontractors.tax2',
|
||||
'subcontractors.address_ru2',
|
||||
'work_permit_documents.document_number',
|
||||
'work_permit_documents.attorney',
|
||||
'work_permit_documents.attorney_date',
|
||||
'subcontractors.job_description',
|
||||
'work_permit_documents.sign_order',
|
||||
'subcontractors.company_name_en',
|
||||
'subcontractors.company_name_ru',
|
||||
'subcontractors.company_code',
|
||||
'subcontractors.operation_type',
|
||||
'subcontractors.city',
|
||||
'subcontractors.address',
|
||||
'subcontractors.logo',
|
||||
'subcontractors.address_en',
|
||||
'subcontractors.project_city_en'
|
||||
])
|
||||
->join("subcontractors", "work_permit_documents.company", "subcontractors.company_name_ru")
|
||||
->where("zone", "like", "%{$weldLog?->project}%")
|
||||
->where("assigned_documents", "like", "%{$documentInfo->slug}%")
|
||||
->get();
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach($workPermitUsers AS $wpi) {
|
||||
if($type == "replacer") {
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_name_surname}", $wpi->name_surname, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_company_name}", $wpi->company, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_certificate_no}", $wpi->certificates_number, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_certificate_number}", $wpi->certificates_number, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_address_ru}", $wpi->address_ru, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_project_city_ru}", $wpi->project_city_ru, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_duty}", $wpi->duty, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_tax}", $wpi->tax, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_tax2}", $wpi->tax2, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_address_ru2}", $wpi->address_ru2, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_document_number}", $wpi->document_number, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_attorney}", $wpi->attorney, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_attorney_date}", df($wpi->attorney_date), $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_company_name_en}", $wpi->company_name_en, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_company_name_ru}", $wpi->company_name_ru, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_company_code}", $wpi->company_code, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_operation_type}", $wpi->operation_type, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_city}", $wpi->city, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_address}", $wpi->address, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_logo}", $wpi->logo, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_address_en}", $wpi->address_en, $string);
|
||||
$string = str_replace("{".$wpi->job_description.$wpi->sign_order."_project_city_en}", $wpi->project_city_en, $string);
|
||||
} else {
|
||||
|
||||
$placeholders = [
|
||||
"name_surname",
|
||||
"company_name",
|
||||
"certificate_no",
|
||||
"certificate_number",
|
||||
"address_ru",
|
||||
"project_city_ru",
|
||||
"duty",
|
||||
"tax",
|
||||
"tax2",
|
||||
"address_ru2",
|
||||
"document_number",
|
||||
"attorney",
|
||||
"attorney_date",
|
||||
"company_name_en",
|
||||
"company_name_ru",
|
||||
"company_code",
|
||||
"operation_type",
|
||||
"city",
|
||||
"address",
|
||||
"logo",
|
||||
"address_en",
|
||||
"project_city_en"
|
||||
];
|
||||
|
||||
foreach ($placeholders as $placeholder) {
|
||||
$thisPlaceHolder = "{" . $wpi->job_description . $wpi->sign_order . "_" . $placeholder . "}";
|
||||
if(!in_array($thisPlaceHolder, $data)) {
|
||||
$data[] = $thisPlaceHolder;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($type == "replacer") {
|
||||
return $string;
|
||||
} else {
|
||||
return $data;
|
||||
}
|
||||
} ?>
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php function wpqColumnsMap() {
|
||||
return [
|
||||
'vt_date' => 'vt_test_date',
|
||||
'vt_report_no' => 'vt_report',
|
||||
'vt_result' => 'vt_result',
|
||||
'ht_date' => 'ht_request_date',
|
||||
'ht_report_no' => 'no_of_ht_hardnes_test',
|
||||
'ht_result' => 'ht_result',
|
||||
'pt_date' => 'pt_test_date',
|
||||
'pt_report_no' => 'pt_report',
|
||||
'pt_result' => 'pt_result',
|
||||
'pmi_date' => 'pmi_test_date',
|
||||
'pmi_report_no' => 'no_of_testing_report',
|
||||
'pmi_result' => 'pmi_result',
|
||||
'rt_date' => 'rt_test_date',
|
||||
'rt_report_no' => 'rt_report',
|
||||
'rt_result' => 'rt_result',
|
||||
'ferrit_date' => 'date_of_ferrite_check',
|
||||
'ferrit_report_no' => 'no_of_ferrite_check',
|
||||
'ferrit_result' => 'ferrite_result',
|
||||
'pwht_diagram' => 'diagram_number_pwht',
|
||||
'pwht_date' => 'pwht_date',
|
||||
'pwht_report_no' => 'no_of_pwht_report',
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
function logColumnsMap() {
|
||||
return [
|
||||
'material_group_1' => 'ru_material_group_1',
|
||||
'material_group_2' => 'ru_material_group_2',
|
||||
'grade_1' => 'material_no_1',
|
||||
'grade_2' => 'material_no_2',
|
||||
'joint_type' => 'type_of_welds',
|
||||
'welding_method' => 'welding_method',
|
||||
'wire' => 'welding_materials_1',
|
||||
'electrode' => 'welding_materials_2',
|
||||
'thickness' => 'wall_thickness_1,wall_thickness_2',
|
||||
'diameter' => 'outside_diameter_1,outside_diameter_2',
|
||||
'welding_date' => 'welding_date',
|
||||
'name_surname' => 'welder_1',
|
||||
'naks_no' => 'certificate_no_1',
|
||||
'wps_no' => 'wps_no',
|
||||
];
|
||||
}
|
||||
|
||||
function logToWPQUpdate($data, $tableName) {
|
||||
$data = (Array) $data;
|
||||
|
||||
|
||||
if(strlen($data['iso_number']) == 4) {
|
||||
$updateData = [];
|
||||
$whereData = [
|
||||
'naks_id' => $data['iso_number'],
|
||||
'kss_number' => $data['no_of_the_joint_as_per_as_built_survey'],
|
||||
];
|
||||
|
||||
foreach(wpqColumnsMap() AS $wpqColumn => $testColumn) {
|
||||
if(isset($data[$testColumn])) {
|
||||
$updateData[$wpqColumn] = $data[$testColumn];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!empty($updateData)) {
|
||||
dump("ndt log -> wpq");
|
||||
dump($updateData);
|
||||
db("welder_tests")
|
||||
->where($whereData)
|
||||
->update($updateData);
|
||||
}
|
||||
|
||||
$wpqData = db("welder_tests")->where($whereData)->first();
|
||||
|
||||
$updateData = [];
|
||||
|
||||
foreach(logColumnsMap() AS $wpqColumn => $testColumn) {
|
||||
if(isset($wpqData->$wpqColumn)) {
|
||||
$testColumns = explode(",", $testColumn);
|
||||
foreach($testColumns AS $testColumn) {
|
||||
if(array_key_exists($testColumn, $data)) {
|
||||
$updateData[$testColumn] = $wpqData->$wpqColumn;
|
||||
} else {
|
||||
dump($wpqColumn);
|
||||
dump($testColumn);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
dump("wpq -> ndt log");
|
||||
dump($updateData);
|
||||
|
||||
if(!empty($updateData)) {
|
||||
db($tableName)
|
||||
->where("id", $data['id'])
|
||||
->update($updateData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
function xlsx_to_html($xlsx, $html_dir) {
|
||||
// Ensure the LANG environment variable is set
|
||||
putenv('LANG=ru_RU.UTF-8');
|
||||
|
||||
// Ensure the output directory exists
|
||||
if (!is_dir($html_dir)) {
|
||||
mkdir($html_dir, 0777, true);
|
||||
}
|
||||
|
||||
// Construct the command
|
||||
$command = "sudo -u root libreoffice --headless --convert-to html --outdir " . escapeshellarg($html_dir) . " " . escapeshellarg($xlsx);
|
||||
// Execute the command
|
||||
$output = shell_exec($command);
|
||||
$output = extract_between_markers($output);
|
||||
|
||||
update_src_paths($output, $html_dir);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
function extract_between_markers($input_str) {
|
||||
// Define the regular expression pattern to match the content between the markers
|
||||
$pattern = '/->\s*(.*?)\s*using filter : HTML \(StarCalc\)/';
|
||||
|
||||
// Perform the regex match
|
||||
if (preg_match($pattern, $input_str, $matches)) {
|
||||
// Return the matched content
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
// Return null if no match is found
|
||||
return null;
|
||||
}
|
||||
|
||||
function update_src_paths($htmlPath, $newBasePath) {
|
||||
// Load HTML content from the file
|
||||
if(is_null($htmlPath))
|
||||
{
|
||||
dd("htmlPath null dönüyor");
|
||||
}
|
||||
$htmlContent = file_get_contents($htmlPath);
|
||||
|
||||
// Create a new DOMDocument instance
|
||||
$dom = new DOMDocument();
|
||||
|
||||
// Suppress warnings due to malformed HTML
|
||||
libxml_use_internal_errors(true);
|
||||
|
||||
// Load HTML into the DOMDocument
|
||||
$dom->loadHTML($htmlContent, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
|
||||
|
||||
// Restore error handling
|
||||
libxml_clear_errors();
|
||||
|
||||
// Get all 'src' attributes
|
||||
$xpath = new DOMXPath($dom);
|
||||
$srcAttributes = $xpath->query('//img/@src | //script/@src | //link/@href');
|
||||
|
||||
foreach ($srcAttributes as $attribute) {
|
||||
$currentValue = $attribute->value;
|
||||
// Extract the current path and replace it with the new base path
|
||||
$updatedValue = url($newBasePath) . "/" . $currentValue;
|
||||
$attribute->value = $updatedValue;
|
||||
}
|
||||
|
||||
// Save the updated HTML back to the file
|
||||
$updatedHtmlContent = $dom->saveHTML();
|
||||
|
||||
chmod("storage/documents/", 0777);
|
||||
unlink($htmlPath);
|
||||
|
||||
if (!file_exists(dirname($htmlPath))) {
|
||||
mkdir(dirname($htmlPath), 0777, true);
|
||||
}
|
||||
|
||||
file_put_contents($htmlPath, $updatedHtmlContent);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Excel dosyasını PDF'e dönüştüren fonksiyon
|
||||
*
|
||||
* @param string $xlsx Excel dosyasının tam yolu
|
||||
* @param string $pdf_dir PDF çıktısının kaydedileceği dizin
|
||||
* @param array $options Ek seçenekler (timeout, log_level vb.)
|
||||
* @return array Dönüşüm sonucu bilgileri
|
||||
* @throws Exception Hata durumunda
|
||||
*/
|
||||
function xlsx_to_pdf($xlsx, $pdf_dir, $options = []) {
|
||||
|
||||
// PDF cache bypass: Dizin içerisinde mevcut aynı isimli PDF varsa siliyoruz ve tekrardan oluşturacak
|
||||
$pdf_output_path = rtrim($pdf_dir, '/\\') . DIRECTORY_SEPARATOR . basename(pathinfo($xlsx, PATHINFO_FILENAME)) . '.pdf';
|
||||
if (file_exists($pdf_output_path)) {
|
||||
@unlink($pdf_output_path);
|
||||
}
|
||||
|
||||
|
||||
// Varsayılan seçenekler
|
||||
$defaults = [
|
||||
'timeout' => 300, // 5 dakika timeout
|
||||
'log_level' => 'info',
|
||||
'create_backup' => true,
|
||||
'validate_input' => true,
|
||||
'cleanup_temp' => true
|
||||
];
|
||||
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
try {
|
||||
// Giriş parametrelerini doğrula
|
||||
if ($options['validate_input']) {
|
||||
validate_xlsx_to_pdf_inputs($xlsx, $pdf_dir);
|
||||
}
|
||||
|
||||
// Çıktı dizinini oluştur
|
||||
create_output_directory($pdf_dir);
|
||||
|
||||
// LibreOffice komutunu hazırla
|
||||
$command = build_libreoffice_command($xlsx, $pdf_dir);
|
||||
|
||||
// Komutu çalıştır
|
||||
$result = execute_conversion_command($command, $options['timeout']);
|
||||
|
||||
// Sonucu işle
|
||||
$output = process_conversion_output($result);
|
||||
|
||||
// Başarı logu
|
||||
log_conversion_success($xlsx, $pdf_dir, $output);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'output_file' => $output,
|
||||
'message' => 'Dönüşüm başarıyla tamamlandı',
|
||||
'timestamp' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
// Hata logu
|
||||
log_conversion_error($xlsx, $pdf_dir, $e->getMessage());
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => $e->getMessage(),
|
||||
'timestamp' => date('Y-m-d H:i:s')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Giriş parametrelerini doğrular
|
||||
*/
|
||||
function validate_xlsx_to_pdf_inputs($xlsx, $pdf_dir) {
|
||||
// Excel dosyasının varlığını kontrol et
|
||||
if (!file_exists($xlsx)) {
|
||||
throw new Exception("Excel dosyası bulunamadı: {$xlsx}");
|
||||
}
|
||||
|
||||
// Excel dosyasının okunabilir olduğunu kontrol et
|
||||
if (!is_readable($xlsx)) {
|
||||
throw new Exception("Excel dosyası okunamıyor: {$xlsx}");
|
||||
}
|
||||
|
||||
// Dosya uzantısını kontrol et
|
||||
$extension = strtolower(pathinfo($xlsx, PATHINFO_EXTENSION));
|
||||
if (!in_array($extension, ['xlsx', 'xls'])) {
|
||||
throw new Exception("Geçersiz dosya formatı. Sadece .xlsx ve .xls dosyaları desteklenir.");
|
||||
}
|
||||
|
||||
// PDF dizininin yazılabilir olduğunu kontrol et
|
||||
if (file_exists($pdf_dir) && !is_writable($pdf_dir)) {
|
||||
throw new Exception("PDF çıktı dizini yazılabilir değil: {$pdf_dir}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Çıktı dizinini oluşturur
|
||||
*/
|
||||
function create_output_directory($pdf_dir) {
|
||||
if (!is_dir($pdf_dir)) {
|
||||
if (!mkdir($pdf_dir, 0755, true)) {
|
||||
throw new Exception("PDF çıktı dizini oluşturulamadı: {$pdf_dir}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LibreOffice komutunu oluşturur
|
||||
*/
|
||||
function build_libreoffice_command($xlsx, $pdf_dir) {
|
||||
// Güvenli komut oluşturma
|
||||
$xlsx_escaped = escapeshellarg($xlsx);
|
||||
$pdf_dir_escaped = escapeshellarg($pdf_dir);
|
||||
|
||||
// LibreOffice komutunu oluştur (environment variable'ları export ile set et)
|
||||
$command = sprintf(
|
||||
'export LANG=en_US.UTF-8 && sudo -u root libreoffice --headless --convert-to pdf --outdir %s %s 2>&1',
|
||||
$pdf_dir_escaped,
|
||||
$xlsx_escaped
|
||||
);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Dönüşüm komutunu çalıştırır
|
||||
*/
|
||||
function execute_conversion_command($command, $timeout) {
|
||||
// Basit shell_exec kullanarak komutu çalıştır (proc_open ile environment variable sorunu var)
|
||||
$output = shell_exec($command);
|
||||
|
||||
// Hata kontrolü - shell_exec null dönerse komut çalışmamış demektir
|
||||
if ($output === null) {
|
||||
throw new Exception("LibreOffice komutu çalıştırılamadı. Komut: " . $command);
|
||||
}
|
||||
|
||||
// LibreOffice çıktısında hata var mı kontrol et
|
||||
if (strpos($output, 'Error') !== false || strpos($output, 'error') !== false) {
|
||||
throw new Exception("LibreOffice dönüşüm hatası: " . trim($output));
|
||||
}
|
||||
|
||||
// Çıktı boş mu kontrol et
|
||||
if (empty(trim($output))) {
|
||||
throw new Exception("LibreOffice çıktısı boş. Komut başarısız olmuş olabilir.");
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dönüşüm çıktısını işler
|
||||
*/
|
||||
function process_conversion_output($shell_output) {
|
||||
// Çıktıyı temizle
|
||||
$output = extract_between_markers_pdf($shell_output);
|
||||
|
||||
if (is_null($output)) {
|
||||
$output = trim($shell_output);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Başarılı dönüşüm logu
|
||||
*/
|
||||
function log_conversion_success($xlsx, $pdf_dir, $output) {
|
||||
$log_message = sprintf(
|
||||
"[SUCCESS] Excel to PDF conversion completed - File: %s, Output: %s, Result: %s",
|
||||
$xlsx,
|
||||
$pdf_dir,
|
||||
$output
|
||||
);
|
||||
|
||||
error_log($log_message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dönüşüm hatası logu
|
||||
*/
|
||||
function log_conversion_error($xlsx, $pdf_dir, $error_message) {
|
||||
$log_message = sprintf(
|
||||
"[ERROR] Excel to PDF conversion failed - File: %s, Output: %s, Error: %s",
|
||||
$xlsx,
|
||||
$pdf_dir,
|
||||
$error_message
|
||||
);
|
||||
|
||||
error_log($log_message);
|
||||
}
|
||||
|
||||
/**
|
||||
* PDF marker'ları arasındaki içeriği çıkarır
|
||||
*
|
||||
* @param string $input_str LibreOffice çıktısı
|
||||
* @return string|null Çıkarılan içeriği veya null
|
||||
*/
|
||||
function extract_between_markers_pdf($input_str) {
|
||||
// PDF export marker'ları arasındaki içeriği bul
|
||||
// Excel dosyaları Writer olarak algılanabilir, bu yüzden her iki filter'ı da kontrol et
|
||||
$patterns = [
|
||||
'/->\s*(.*?)\s*using filter : calc_pdf_Export/', // Calc (spreadsheet) için
|
||||
'/->\s*(.*?)\s*using filter : writer_pdf_Export/', // Writer (document) için
|
||||
'/convert\s+(.*?)\s+as\s+a\s+(.*?)\s+->\s+(.*?)\s+using filter : (.*?)_Export/' // Genel pattern
|
||||
];
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
if (preg_match($pattern, $input_str, $matches)) {
|
||||
// İlk pattern için dosya yolu, ikinci için de dosya yolu, üçüncü için tam çıktı
|
||||
if (count($patterns) === 3 && $pattern === $patterns[2]) {
|
||||
return trim($matches[3]); // PDF dosya yolu
|
||||
}
|
||||
return trim($matches[1]); // Dosya yolu
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eski fonksiyon için geriye uyumluluk
|
||||
* @deprecated Bu fonksiyon artık kullanılmamalı, xlsx_to_pdf() kullanın
|
||||
*/
|
||||
function xlsx_to_pdf_legacy($xlsx, $pdf_dir) {
|
||||
trigger_error(
|
||||
'xlsx_to_pdf_legacy() fonksiyonu deprecated. xlsx_to_pdf() kullanın.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
|
||||
$result = xlsx_to_pdf($xlsx, $pdf_dir);
|
||||
|
||||
if ($result['success']) {
|
||||
return $result['output_file'];
|
||||
}
|
||||
|
||||
return $result['error'];
|
||||
}
|
||||
|
||||
function xlsx_to_pdf2($xlsx, $pdf_dir) {
|
||||
// Ensure the LANG environment variable is set
|
||||
putenv('LANG=ru_RU.UTF-8');
|
||||
|
||||
// Ensure the output directory exists
|
||||
if (!is_dir($pdf_dir)) {
|
||||
mkdir($pdf_dir, 0777, true);
|
||||
}
|
||||
// Construct the command
|
||||
$command = "sudo -u root libreoffice --headless --convert-to pdf --outdir '" . ($pdf_dir) . "' '" . ($xlsx) . "' ";
|
||||
// Execute the command
|
||||
$shellOutput = shell_exec("$command 2>&1");
|
||||
$output = extract_between_markers_pdf($shellOutput);
|
||||
if(is_null($output)) {
|
||||
$output = $shellOutput;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
function extract_between_markers_pdf2($input_str) {
|
||||
// Define the regular expression pattern to match the content between the markers
|
||||
$pattern = '/->\s*(.*?)\s*using filter : calc_pdf_Export/';
|
||||
|
||||
// Perform the regex match
|
||||
if (preg_match($pattern, $input_str, $matches)) {
|
||||
// Return the matched content
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
// Return null if no match is found
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user