Files
2026-09-22 12:06:13 +01:00

221 lines
9.0 KiB
PHP
Executable File

<?php
namespace Modules\M3\Http\Controllers;
use Config;
use DB;
use Illuminate\Support\Facades\Schema;
use Symfony\Component\HttpFoundation\Request;
class UserPickingStats4 extends Controller
{
public static function index(Request $request)
{
$context = self::buildContext($request);
self::loadPickingData($context);
self::calculatePerformance($context);
return $request->format === 'json'
? self::jsonResponse($context)
: self::pageResponse($request, $context);
}
private static function buildContext(Request $request): array
{
$starting = isset($request->dates) ? (string) $request->dates : date('Y-m-d', strtotime('-1 days'));
$schema = Schema::connection(config('m3.connection', 'pgsql'));
$users = self::users($schema);
$user = isset($request->user) ? (string) $request->user : '';
$empno = 0;
foreach ($users as $candidate) {
if ($candidate['userprf'] === $user) {
$empno = $candidate['empno'];
break;
}
}
return [
'starting' => $starting,
'schema' => $schema,
'users' => $users,
'user' => $user,
'empno' => $empno,
'targets' => Config::get('arrays_custom.lph_per_code_array', []),
'statistics' => [],
'lbpfRows' => [],
'lbpf' => 0,
'monitor' => [],
'totals' => ['value' => 0, 'weight' => 0, 'timediff' => 0, 'picked' => 0, 'entries' => 0],
'performance' => [],
];
}
private static function users($schema): array
{
if (! $schema->hasTable('icm428m')) {
return [];
}
$connection = DB::connection(config('m3.connection', 'pgsql'));
$profile = $connection->table('icm428m')->select('R428CO', 'R428WH')
->where('R428US', strtoupper(m3User()))->first();
$rows = $connection->table('icm428m')
->selectRaw("R428US as userprf, (trim(R428FIRST) || ' ' || trim(R428FAMILY)) as name, R428EMPCDE as empno")
->where('R428STS', 'A')->where('R428EMPCDE', '!=', 0)
->where('R428CO', $profile->R428CO ?? '')->where('R428WH', $profile->R428WH ?? '')->get();
$users = [];
foreach ($rows as $row) {
$users[] = ['userprf' => trim($row->USERPRF), 'name' => trim($row->NAME), 'empno' => $row->EMPNO];
}
usort($users, static fn (array $a, array $b): int => $a['name'] <=> $b['name']);
return $users;
}
private static function loadPickingData(array &$context): void
{
$targets = $context['targets'];
ksort($targets);
$codes = implode(',', array_keys($targets));
$date = $context['starting'];
$sql = sprintf(
'select oppno, sum(cast (hrs as integer)+ (hrs-cast (hrs as integer))/0.6) as hrs from LBPF where empno=%d and lbyr=%d and lbmo=%d and lbdy=%d and oppno in (%s) group by oppno',
(int) $context['empno'], (int) substr($date, 0, 4) - 2000, (int) substr($date, 5, 2), (int) substr($date, 8, 2), $codes
);
$context['lbpfRows'] = $context['schema']->hasTable('lbpf')
? DB::connection(config('m3.connection', 'pgsql'))->select($sql) : [];
foreach ($context['lbpfRows'] as $row) {
$context['lbpf'] += $row->HRS;
}
if ((isset(request()->dates) || isset(request()->user)) && $context['schema']->hasTable('perfstat')) {
$context['statistics'] = DB::connection(config('m3.connection', 'pgsql'))->table('perfstat')
->where('dt', $date)->where('a5pickcomu', $context['user'])->get()->all();
}
}
private static function calculatePerformance(array &$context): void
{
self::initializeMonitors($context);
if ($context['statistics'] === []) {
return;
}
self::accumulateStatistics($context);
$hours = $context['lbpf'];
$context['performance']['tot_hours'] = $hours;
$context['performance']['per_hour_actual'] = $hours != 0 ? $context['totals']['entries'] / $hours : 0;
self::calculateMonitorTargets($context);
$target = $context['monitor'][0]['lph_blended_per_activity'] ?? 0;
if ($target != 0) {
$context['performance']['performance_activity'] = $context['performance']['per_hour_actual'] / $target;
}
}
private static function initializeMonitors(array &$context): void
{
foreach ($context['lbpfRows'] as $row) {
$context['monitor'][$row->OPPNO] = self::monitorDefaults('Mon' . $row->OPPNO, $row->HRS);
}
foreach ($context['statistics'] as $row) {
$context['monitor'][$row->CODE] = array_replace(
self::monitorDefaults('Mon' . $row->CODE, 0),
$context['monitor'][$row->CODE] ?? []
);
}
if ($context['statistics'] !== []) {
$context['monitor'][0] = self::monitorDefaults('0', 0);
}
}
private static function monitorDefaults(string $header, float|int $hours): array
{
return ['tot_hours' => $hours, 'header' => $header, 'timediff' => 0, 'percent_per_monitor' => 0,
'percent_per_activity' => 0, 'lph_blended_per_activity' => 0, 'picked' => 0, 'weight' => 0, 'lines' => 0];
}
private static function accumulateStatistics(array &$context): void
{
$previous = null;
$limit = (float) Config::get('arrays.ignore_picks_that_last_longer_than_this_many_hours', 8);
foreach ($context['statistics'] as $row) {
$row->WEIGHT = round($row->WEIGHT);
$row->A5VALUE = round($row->A5VALUE);
$row->A5PICKED = round($row->A5PICKED);
$row->A5PICKCMTS = date('Y-m-d H:i', strtotime($row->A5PICKCMTS));
$now = strtotime($row->A5CMTSADJ);
$diff = $previous === null ? 0 : round(abs($now - $previous));
$diff = $diff > $limit * 3600 ? -1 : $diff;
$row->TIMEDIFF = $diff;
$row->COLOUR = self::durationColour($diff);
$previous = $now;
self::addRowTotals($context, $row, $diff);
}
}
private static function durationColour(float|int $diff): string
{
$minutes = $diff / 60;
return match (true) {
$minutes < 5 => '',
$minutes <= 10 => 'yellow',
$minutes <= 15 => '#88ace0',
default => 'red',
};
}
private static function addRowTotals(array &$context, object $row, float|int $diff): void
{
$monitor = &$context['monitor'][$row->CODE];
$monitor['timediff'] += $diff;
$monitor['picked'] += $row->A5PICKED;
$monitor['weight'] += $row->WEIGHT;
$monitor['lines']++;
$context['totals']['entries']++;
$context['totals']['weight'] += $row->WEIGHT;
$context['totals']['value'] += $row->A5VALUE;
$context['totals']['timediff'] += $diff;
$context['totals']['picked'] += $row->A5PICKED;
}
private static function calculateMonitorTargets(array &$context): void
{
ksort($context['monitor']);
foreach ($context['monitor'] as $code => &$monitor) {
if ((string) $code === '0') {
continue;
}
$monitor['percent_per_monitor'] = $context['totals']['timediff'] != 0
? $monitor['timediff'] / $context['totals']['timediff'] : 0;
$monitor['percent_per_activity'] = $context['lbpf'] != 0 ? $monitor['tot_hours'] / $context['lbpf'] : 0;
$monitor['lph_blended_per_activity'] = $monitor['percent_per_activity'] * ($context['targets'][$code] ?? 0);
$context['monitor'][0]['lph_blended_per_activity'] += $monitor['lph_blended_per_activity'];
}
unset($monitor);
}
private static function jsonResponse(array $context): string
{
return json_encode([
'day' => $context['starting'],
'performance' => number_format(($context['performance']['performance_activity'] ?? 0) * 100, 0),
'blendedTargetLPH' => number_format($context['monitor'][0]['lph_blended_per_activity'] ?? 0, 1),
'actualLPH' => number_format($context['performance']['per_hour_actual'] ?? 0, 1),
'grossHours' => $context['performance']['tot_hours'] ?? 0,
]);
}
private static function pageResponse(Request $request, array $context)
{
$request->ports = Config::get('arrays.env_ports');
$no_data = $context['statistics'] === [] && ($_SERVER['REQUEST_URI'] ?? '') !== '/UserPickingStats4' ? 'Y' : 'N';
return view('m3::liberty-theme.pages.UserPickingStats4', [
'statistic4' => $context['statistics'], 'starting' => $context['starting'], 'user' => $context['user'],
'user_array' => $context['users'], 'monitor_array' => $context['monitor'], 'totals_array' => $context['totals'],
'perf_array' => $context['performance'], 'request' => $request, 'no_data' => $no_data,
]);
}
}