Files
citrus-cms/app/Http/Controllers/Api/StatsController.php
T
2026-04-28 21:14:25 +03:00

657 lines
28 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Models\WeldLog;
use App\Models\Handover;
use App\Models\WeldingEquipment;
/**
* @group Stats
*
* İstatistikler ve Hesaplamalar ile ilgili endpointler.
*/
class StatsController extends Controller
{
/**
* NDT Calculation (General)
*
* Genel NDT hesaplama istatistiklerini getirir.
* Bu endpoint varsayılan 'ndt-calculation' blade cache sonucunu döndürür.
*
* @response 200 {
* "status": "success",
* "type": "general",
* "content": "..."
* }
*/
public function ndtCalculation()
{
// Varsayılan hesaplama (cacheBladeLoad('ndt-calculation'))
// cacheBladeLoad echo yaptığı için çıktıyı yakalıyoruz.
ob_start();
cacheBladeLoad('ndt-calculation');
$content = ob_get_clean();
// Eğer content bir JSON string ise decode et
$decoded = json_decode($content);
if (json_last_error() === JSON_ERROR_NONE) {
$content = $decoded;
}
return response()->json([
'status' => 'success',
'type' => 'general',
'content' => $content
]);
}
/**
* NDT Calculation (Test Packs)
*
* Test Paketleri için NDT hesaplama istatistiklerini getirir.
* 'ndtCalculationTestPack' ayarını döndürür.
*
* @response 200 {
* "status": "success",
* "type": "test_packs",
* "content": "..."
* }
*/
public function ndtCalculationTestPacks()
{
$content = setting('ndtCalculationTestPack');
// Eğer content bir JSON string ise decode et
$decoded = json_decode($content);
if (json_last_error() === JSON_ERROR_NONE) {
$content = $decoded;
}
return response()->json([
'status' => 'success',
'type' => 'test_packs',
'content' => $content
]);
}
/**
* NDT Calculation (Backlogs)
*
* Backloglar için NDT hesaplama istatistiklerini getirir.
* 'ndtCalculationBacklogs' ayarını döndürür.
*
* @queryParam type string Filtreleme türü (opsiyonel). Example: backlogs
*
* @response 200 {
* "status": "success",
* "type": "backlogs",
* "content": "..."
* }
*/
public function ndtCalculationBacklogs()
{
request()->merge(['type' => 'backlogs']);
$_GET['type'] = 'backlogs';
ob_start();
cacheBladeLoad('ndt-calculation');
$content = ob_get_clean();
// Eğer content bir JSON string ise decode et
$decoded = json_decode($content);
if (json_last_error() === JSON_ERROR_NONE) {
$content = $decoded;
}
return response()->json([
'status' => 'success',
'type' => 'backlogs',
'content' => $content
]);
}
/**
* Dashboard Overview Stats
*
* Get aggregated statistics for project overview dashboard.
* This endpoint is protected by a static hash.
* Includes:
* - WDI Monthly (Shop/Field/Total)
* - Spool Progress
* - NDT/Repair Backlog
* - Hand-over Status
* - Welding Equipment Status
*
* @header X-Api-Hash string required The static API hash for authentication. Example: your-secret-hash-key
*
* @response 200 {
* "status": "success",
* "data": {
* "wdi_monthly": [...],
* "spool_progress": [...],
* "ndt_backlog": [...],
* "handover_status": [...],
* "welding_equipment": [...]
* }
* }
*/
public function dashboardStats(\Illuminate\Http\Request $request)
{
$year = $request->input('year', date('Y'));
// 1. WDI Monthly Data (Global Aggregate) - Calendar Year
$wdiMonthly = WeldLog::selectRaw("
DATE_FORMAT(welding_date, '%Y-%m') as month,
MONTH(welding_date) as month_num,
SUM(CASE WHEN type_of_joint = 'S' THEN nps_1 ELSE 0 END) as shop,
SUM(CASE WHEN type_of_joint != 'S' OR type_of_joint IS NULL THEN nps_1 ELSE 0 END) as field,
SUM(nps_1) as total
")
->whereNotNull('welding_date')
// ->whereYear('welding_date', $year) // Removed to allow client-side filtering
->groupBy('month', 'month_num')
->orderBy('month', 'asc')
->get();
// 1b. WDI Monthly Data (By Project)
$wdiByProjectRaw = WeldLog::selectRaw("
project,
DATE_FORMAT(welding_date, '%Y-%m') as month,
MONTH(welding_date) as month_num,
SUM(CASE WHEN type_of_joint = 'S' THEN nps_1 ELSE 0 END) as shop,
SUM(CASE WHEN type_of_joint != 'S' OR type_of_joint IS NULL THEN nps_1 ELSE 0 END) as field,
SUM(nps_1) as total
")
->whereNotNull('welding_date')
->whereNotNull('project')
->where('project', '!=', '')
->whereYear('welding_date', $year) // Keep this for now or remove if needed, but it's unused by dashboard
->groupBy('project', 'month', 'month_num')
->get();
$wdiByProject = [];
foreach($wdiByProjectRaw as $row) {
// Use month_num (1-12) as key for the frontend table columns which expect 1..12
// For the new 'wdiByProject' which is custom for the table, we simply need the integer month key
// because the table logic iterates 1 through 12.
$wdiByProject[$row->project][$row->month_num] = [
'shop' => (float)$row->shop,
'field' => (float)$row->field,
'total' => (float)$row->total,
'month_str' => $row->month // Useful for debugging or generic logic
];
}
// 2. Spool Progress (Time-independent)
// Logic: Group by iso_number + spool_number (Shop only), find effective status based on priority logic.
// Priority: Waiting < Manufacturing < QC < Paint < Completed
$statusCase = "CASE spool_status
WHEN 'Waiting' THEN 1
WHEN 'Manufacturing' THEN 2
WHEN 'QC' THEN 3
WHEN 'Paint' THEN 4
WHEN 'Completed' THEN 5
ELSE 99 END";
$spoolStats = DB::table('weld_logs')
->selectRaw("status_val, COUNT(*) as count")
->fromSub(function($query) use ($statusCase) {
$query->select('iso_number', 'spool_number')
->selectRaw("MIN($statusCase) as status_order")
->selectRaw("
CASE MIN($statusCase)
WHEN 1 THEN 'Waiting'
WHEN 2 THEN 'Manufacturing'
WHEN 3 THEN 'QC'
WHEN 4 THEN 'Paint'
WHEN 5 THEN 'Completed'
ELSE 'Other'
END as status_val
")
->from('weld_logs')
->where('type_of_joint', 'S') // Shop joints drive spool status
->whereNotNull('spool_number')
->where('spool_number', '!=', '')
->whereNotNull('welding_date')
->groupBy('iso_number', 'spool_number');
}, 'sub')
->groupBy('status_val')
->get();
// Transform to array format for frontend
$spoolProgress = [];
foreach ($spoolStats as $row) {
$spoolProgress[] = [
'status' => $row->status_val,
'count' => (int)$row->count
];
}
// 3. NDT/Repair Backlog
// Using existing setting logic from ndt-backlog.blade.php
$ndtData = json_decode(setting("ndtCalculation"), true);
$ndtBacklogStats = [];
if (is_array($ndtData)) {
foreach($ndtData as $d) {
foreach($d as $field => $value) {
if(strpos($field, "backlog") !== false) {
$key = strtoupper(str_replace("_backlog", "", $field));
if(!isset($ndtBacklogStats[$key])) {
$ndtBacklogStats[$key] = 0;
}
if($value > 0) {
$ndtBacklogStats[$key] += $value;
}
}
}
}
}
// Add dynamic limits from Settings
$ndtBacklogStats['ndt_limit'] = setting('ndt_limit');
$ndtBacklogStats['ndt_wdi'] = setting('ndt_wdi');
$ndtBacklogStats['repair_limit'] = setting('repair_limit');
$ndtBacklogStats['repair_wdi'] = setting('repair_wdi');
// 4. Hand-over Status
// Statuses: Dynamically fetched from id_status
$handoverProgress = Handover::selectRaw('id_status, COUNT(*) as count')
->whereNotNull('id_status')
->where('id_status', '!=', '')
->groupBy('id_status')
->pluck('count', 'id_status')
->toArray();
// 5. Welding Equipment Status
// Statuses: Working, Repair, Out of use
$equipmentStats = WeldingEquipment::selectRaw('working_status, COUNT(*) as count')
->whereNotNull('working_status')
->groupBy('working_status')
->get()
->pluck('count', 'working_status');
$targetEquipmentStatuses = ['Working', 'Repair', 'Out of use'];
$equipmentProgress = [];
foreach ($targetEquipmentStatuses as $status) {
$equipmentProgress[$status] = $equipmentStats[$status] ?? 0;
}
// Add others
$otherEquipmentCount = 0;
foreach ($equipmentStats as $status => $count) {
if (!in_array($status, $targetEquipmentStatuses)) {
$otherEquipmentCount += $count;
}
}
if ($otherEquipmentCount > 0) {
$equipmentProgress['Other'] = $otherEquipmentCount;
}
// 6. Welding Status (Welder Distribution by Site)
// Logic: Group by project (Site).
// CS = distinct real_welder_1 & real_welder_2 where ru_material_group_1 matches 'M01'
// SS/AS = distinct real_welder_1 & real_welder_2 where ru_material_group_1 does NOT match 'M01'
$weldingStatusData = DB::table(function ($query) {
$query->select('project', 'type_of_joint', 'ru_material_group_1', 'real_welder_1 as welder', 'welding_date')
->from('weld_logs')
->whereNotNull('real_welder_1')
->where('real_welder_1', '!=', '')
->whereNotNull('welding_date')
->unionAll(
DB::table('weld_logs')
->select('project', 'type_of_joint', 'ru_material_group_2', 'real_welder_1 as welder', 'welding_date')
->from('weld_logs')
->whereNotNull('real_welder_2')
->where('real_welder_2', '!=', '')
->whereNotNull('welding_date')
);
}, 'u')
->select('project')
->selectRaw("YEAR(welding_date) as year")
->selectRaw("MONTH(welding_date) as month")
->selectRaw("COUNT(DISTINCT CASE WHEN type_of_joint = 'S' THEN welder END) as shop")
->selectRaw("COUNT(DISTINCT CASE WHEN type_of_joint != 'S' OR type_of_joint IS NULL THEN welder END) as field")
->selectRaw("COUNT(DISTINCT CASE WHEN (ru_material_group_1 LIKE '%M01%' OR ru_material_group_1 LIKE '%М01%') THEN welder END) as cs")
->selectRaw("COUNT(DISTINCT CASE WHEN (ru_material_group_1 NOT LIKE '%M01%' AND ru_material_group_1 NOT LIKE '%М01%') OR ru_material_group_1 IS NULL THEN welder END) as ss")
->selectRaw("COUNT(DISTINCT welder) as actual_total")
->whereNotNull('project')
->where('project', '!=', '')
->groupBy('project', 'year', 'month')
->get();
$weldingStatus = [];
foreach($weldingStatusData as $row) {
$weldingStatus[] = [
'site' => $row->project,
'year' => (int)$row->year,
'month' => (int)$row->month,
'shop' => (int)$row->shop,
'field' => (int)$row->field,
'cs' => (int)$row->cs,
'ss' => (int)$row->ss,
'total' => (int)$row->actual_total
];
}
// 7. Welding Status Overall Summary (No Site Breakdown)
// Count unique welders across ALL projects for Shop and Field
// 7. Welding Status Overall Summary (No Site Breakdown)
// Count unique welders across ALL projects for Shop and Field
$weldingSummaryRaw = DB::table(function ($query) {
$query->select('type_of_joint', 'real_welder_1 as welder')
->from('weld_logs')
->whereNotNull('real_welder_1')
->where('real_welder_1', '!=', '')
->whereNotNull('welding_date')
->unionAll(
DB::table('weld_logs')
->select('type_of_joint', 'real_welder_2 as welder')
->from('weld_logs')
->whereNotNull('real_welder_2')
->where('real_welder_2', '!=', '')
->whereNotNull('welding_date')
);
}, 'u')
->selectRaw("COUNT(DISTINCT CASE WHEN type_of_joint = 'S' THEN welder END) as shop")
->selectRaw("COUNT(DISTINCT CASE WHEN type_of_joint != 'S' OR type_of_joint IS NULL THEN welder END) as field")
->selectRaw("COUNT(DISTINCT welder) as actual_total")
->first();
$weldingStatusSummary = [
'shop' => (int)$weldingSummaryRaw->shop,
'field' => (int)$weldingSummaryRaw->field,
'total' => (int)$weldingSummaryRaw->actual_total
];
// 8. Welding Status Monthly (Shop/Field/Total per Month)
// Groups distinct welders by month and project
// 8. Welding Status Monthly (Shop/Field/Total per Month)
// Groups distinct welders by month (Global Site Scope)
$weldingStatusMonthly = DB::table(function ($query) use ($year) {
$query->select('project', 'welding_date', 'type_of_joint', 'real_welder_1 as welder')
->from('weld_logs')
->whereNotNull('real_welder_1')
->where('real_welder_1', '!=', '')
->whereNotNull('welding_date')
->unionAll(
DB::table('weld_logs')
->select('project', 'welding_date', 'type_of_joint', 'real_welder_2 as welder')
->from('weld_logs')
->whereNotNull('real_welder_2')
->where('real_welder_2', '!=', '')
->whereNotNull('welding_date')
);
}, 'u')
->selectRaw("
DATE_FORMAT(welding_date, '%Y-%m') as month_key,
MONTH(welding_date) as month,
YEAR(welding_date) as year,
COUNT(DISTINCT CASE WHEN type_of_joint = 'S' THEN welder END) as shop,
COUNT(DISTINCT CASE WHEN type_of_joint != 'S' OR type_of_joint IS NULL THEN welder END) as field,
COUNT(DISTINCT welder) as actual_total
")
->groupBy('month_key', 'month', 'year')
->orderBy('month_key', 'asc')
->get()
->map(function($item) {
return [
'project' => 'Total', // Value is now aggregated for the whole site
'month_key' => $item->month_key,
'month' => (int)$item->month,
'year' => (int)$item->year,
'shop' => (int)$item->shop,
'field' => (int)$item->field,
'total' => (int)$item->actual_total
];
});
// 9. NDT Summary (RT & UT)
// New calculation logic mirrored from summary-nocache.blade.php
$ndtSummary = [];
// RT Logic
$rtTotal = DB::table('radiographic_tests')->whereNotNull('rt_result')->count();
$rtWDI = DB::table('radiographic_tests')->whereNotNull('rt_result')->sum('nps_1');
$rtAccepted = DB::table('radiographic_tests')->where('rt_result', 'Accept / Годен')->count();
$rtRejected = DB::table('radiographic_tests')->whereNotNull('rt_result')->whereNotIn('rt_result', ['', 'Accept / Годен'])->count();
// RT Repair Rate logic: (ShopRepair + FieldRepair) / (ShopTotal + FieldTotal)
$rtShopTotal = DB::table('radiographic_tests')->where('type_of_joint', 'S')->whereNotIn('rt_result', [''])->count();
$rtShopRepair = DB::table('radiographic_tests')->where('type_of_joint', 'S')->whereNotIn('rt_result', ['', 'Accept / Годен'])->count();
$rtFieldTotal = DB::table('radiographic_tests')->where('type_of_joint', 'F')->whereNotIn('rt_result', [''])->count();
$rtFieldRepair = DB::table('radiographic_tests')->where('type_of_joint', 'F')->whereNotIn('rt_result', ['', 'Accept / Годен'])->count();
$rtRepairRate = ($rtShopTotal + $rtFieldTotal) > 0
? round(($rtShopRepair + $rtFieldRepair) * 100 / ($rtShopTotal + $rtFieldTotal), 2)
: 0;
$ndtSummary['rt'] = [
'total' => $rtTotal,
'wdi' => (float)$rtWDI,
'accepted' => $rtAccepted,
'rejected' => $rtRejected,
'repair_rate' => $rtRepairRate
];
// UT Logic
$utTotal = DB::table('ultrasonic_tests')->whereNotNull('ut_result')->count();
$utWDI = DB::table('ultrasonic_tests')->whereNotNull('ut_result')->sum('nps_1');
$utAccepted = DB::table('ultrasonic_tests')->where('ut_result', 'Accept / Годен')->count();
$utRejected = DB::table('ultrasonic_tests')->whereNotNull('ut_result')->where('ut_result', '!=', 'Accept / Годен')->count();
// UT Repair Rate
$utShopTotal = DB::table('ultrasonic_tests')->where('type_of_joint', 'S')->whereNotIn('ut_result', [''])->count();
$utShopRepair = DB::table('ultrasonic_tests')->where('type_of_joint', 'S')->whereNotIn('ut_result', ['', 'Accept / Годен'])->count();
$utFieldTotal = DB::table('ultrasonic_tests')->where('type_of_joint', 'F')->whereNotIn('ut_result', [''])->count();
$utFieldRepair = DB::table('ultrasonic_tests')->where('type_of_joint', 'F')->whereNotIn('ut_result', ['', 'Accept / Годен'])->count();
$utRepairRate = ($utShopTotal + $utFieldTotal) > 0
? round(($utShopRepair + $utFieldRepair) * 100 / ($utShopTotal + $utFieldTotal), 2)
: 0;
$ndtSummary['ut'] = [
'total' => $utTotal,
'wdi' => (float)$utWDI,
'accepted' => $utAccepted,
'rejected' => $utRejected,
'repair_rate' => $utRepairRate
];
// 10. WDI Statistics (CS vs SS/AS) by Project
// CS: Material Group contains M01
// SS: Material Group does not contain M01
$wdiStatsData = DB::table('weld_logs')
->select('project')
->selectRaw("YEAR(welding_date) as year")
->selectRaw("MONTH(welding_date) as month")
->selectRaw("SUM(CASE WHEN (ru_material_group_1 LIKE '%M01%' OR ru_material_group_1 LIKE '%М01%') THEN nps_1 ELSE 0 END) as cs_wdi")
->selectRaw("SUM(CASE WHEN (ru_material_group_1 NOT LIKE '%M01%' AND ru_material_group_1 NOT LIKE '%М01%') OR ru_material_group_1 IS NULL THEN nps_1 ELSE 0 END) as ss_wdi")
->whereNotNull('welding_date')
->where('project', '!=', '')
->whereNotNull('project')
->groupBy('project', 'year', 'month')
->get();
$wdiStats = [];
foreach($wdiStatsData as $row) {
$wdiStats[] = [
'project' => $row->project,
'year' => (int)$row->year,
'month' => (int)$row->month,
'cs' => (float)$row->cs_wdi,
'ss' => (float)$row->ss_wdi,
'total' => (float)$row->cs_wdi + (float)$row->ss_wdi
];
}
// 11. Weld Backlog (Prefab vs Field) by Project
// Backlog: Items with no welding date, grouped by year/month from fit_up_date for frontend filtering
$weldBacklogData = DB::table('weld_logs')
->select('project')
->selectRaw("SUM(CASE WHEN type_of_joint = 'S' THEN nps_1 ELSE 0 END) as prefab_backlog")
->selectRaw("SUM(CASE WHEN type_of_joint != 'S' OR type_of_joint IS NULL THEN nps_1 ELSE 0 END) as field_backlog")
->selectRaw("SUM(nps_1) as total_backlog")
->whereNull('welding_date')
->where('project', '!=', '')
->whereNotNull('project')
->groupBy('project')
->get();
$weldBacklog = [];
foreach($weldBacklogData as $row) {
$weldBacklog[] = [
'project' => $row->project,
'prefab' => (float)$row->prefab_backlog,
'field' => (float)$row->field_backlog,
'total' => (float)$row->total_backlog
];
}
// 12. Welder Current (from naks_welders table)
// Total unique welders at each site, categorized by CS/SS
// CS: material_1 contains М01 or M01
// SS: material_1 does NOT contain М01/M01
// No date filter - shows total registered welders per site
$welderCurrentData = DB::table('welder_tests')
->selectRaw("COUNT(DISTINCT CASE WHEN (material_group_1 LIKE '%M01%' OR material_group_1 LIKE '%М01%') THEN naks_id END) as cs")
->selectRaw("COUNT(DISTINCT CASE WHEN (material_group_1 NOT LIKE '%M01%' AND material_group_1 NOT LIKE '%М01%') OR material_group_1 IS NULL THEN naks_id END) as ss")
->selectRaw("COUNT(DISTINCT naks_id) as total")
->where('status', 'Active')
->get();
$welderCurrent = [];
foreach($welderCurrentData as $row) {
$welderCurrent[] = [
'project' => '',
'cs' => (int)$row->cs,
'ss' => (int)$row->ss,
'total' => (int)$row->total
];
}
return response()->json([
'status' => 'success',
'data' => [
'wdi_monthly' => $wdiMonthly,
'spool_progress' => $spoolProgress,
'ndt_backlog' => $ndtBacklogStats,
'handover_status' => $handoverProgress,
'welding_equipment' => $equipmentProgress,
'welding_status' => $weldingStatus,
'welding_status_monthly' => $weldingStatusMonthly,
'welding_status_summary' => $weldingStatusSummary,
'ndt_summary' => $ndtSummary,
'wdi_by_project' => $wdiByProject,
'wdi_stats' => $wdiStats,
'weld_backlog' => $weldBacklog,
'repair_stats_monthly' => DB::table('weld_logs')
->selectRaw("
DATE_FORMAT(welding_date, '%Y-%m') as month_key,
YEAR(welding_date) as year,
MONTH(welding_date) as month,
SUM(CASE WHEN type_of_joint = 'S' AND rt_result IS NOT NULL AND rt_result != '' THEN 1 ELSE 0 END) as rt_shop_total,
SUM(CASE WHEN type_of_joint = 'S' AND rt_result NOT IN ('', 'Accept / Годен') THEN 1 ELSE 0 END) as rt_shop_repair,
SUM(CASE WHEN type_of_joint = 'F' AND rt_result IS NOT NULL AND rt_result != '' THEN 1 ELSE 0 END) as rt_field_total,
SUM(CASE WHEN type_of_joint = 'F' AND rt_result NOT IN ('', 'Accept / Годен') THEN 1 ELSE 0 END) as rt_field_repair,
SUM(CASE WHEN type_of_joint = 'S' AND ut_result IS NOT NULL AND ut_result != '' THEN 1 ELSE 0 END) as ut_shop_total,
SUM(CASE WHEN type_of_joint = 'S' AND ut_result NOT IN ('', 'Accept / Годен') THEN 1 ELSE 0 END) as ut_shop_repair,
SUM(CASE WHEN type_of_joint = 'F' AND ut_result IS NOT NULL AND ut_result != '' THEN 1 ELSE 0 END) as ut_field_total,
SUM(CASE WHEN type_of_joint = 'F' AND ut_result NOT IN ('', 'Accept / Годен') THEN 1 ELSE 0 END) as ut_field_repair
")
->whereNotNull('welding_date')
->groupBy('month_key', 'year', 'month')
->get(),
'test_packages' => DB::table('test_packages')
->leftJoinSub(function ($query) {
$query->from('weld_logs')
->select(
'test_package_no',
DB::raw('MAX(project) as project'),
DB::raw('MAX(welding_date) as last_weld_date')
)
->whereNotNull('test_package_no')
->where('test_package_no', '!=', '')
->whereNotNull('welding_date')
->groupBy('test_package_no');
}, 'projects', 'projects.test_package_no', '=', 'test_packages.test_package_number')
->selectRaw("
COALESCE(projects.project, 'Unknown') as project,
count(test_packages.id) as total_tp,
SUM(CASE WHEN walkdown_date IS NOT NULL THEN 1 ELSE 0 END) as line_check,
SUM(COALESCE(a_punch_point_open, 0)) as punch_a,
SUM(CASE WHEN test_date IS NOT NULL THEN 1 ELSE 0 END) as test,
SUM(CASE WHEN reinstatement_date IS NOT NULL THEN 1 ELSE 0 END) as reinstatement
")
->groupBy(
DB::raw("COALESCE(projects.project, 'Unknown')")
)
->get(),
'welder_current' => $welderCurrent,
]
]);
}
/**
* Welding Status By Project
*
* Get summary data for "Sahaya Göre Kaynak Durumu" (Welding Status by Site).
* Breakdown of WDI (NPS-1) by project, grouped into SHOP and FIELD.
*
* @response 200 {
* "status": "success",
* "data": [
* {
* "project": "COOLER TOWER",
* "shop": 82,
* "field": 122,
* "total": 204,
* "percentage": 93
* },
* ...
* ]
* }
*/
public function weldingByProject()
{
$weldingData = DB::table('weld_logs')
->select('project')
->selectRaw("SUM(CASE WHEN type_of_joint = 'S' AND welding_date IS NOT NULL THEN nps_1 ELSE 0 END) as shop")
->selectRaw("SUM(CASE WHEN (type_of_joint != 'S' OR type_of_joint IS NULL) AND welding_date IS NOT NULL THEN nps_1 ELSE 0 END) as field")
->selectRaw("SUM(CASE WHEN welding_date IS NOT NULL THEN nps_1 ELSE 0 END) as total_welded")
->selectRaw("SUM(nps_1) as total_scope")
->whereNotNull('project')
->where('project', '!=', '')
->groupBy('project')
->get();
$result = $weldingData->map(function ($row) {
$totalWelded = (float)$row->total_welded;
$totalScope = (float)$row->total_scope;
$percentage = $totalScope > 0 ? round(($totalWelded / $totalScope) * 100) : 0;
return [
'project' => $row->project,
'shop' => (float)$row->shop,
'field' => (float)$row->field,
'total' => $totalWelded,
'percentage' => (int)$percentage
];
});
return response()->json([
'status' => 'success',
'data' => $result
]);
}
}