diff --git a/Modules/M3/Http/Controllers/ExecSummaryController.php b/Modules/M3/Http/Controllers/ExecSummaryController.php
index 66c0f906..5574606d 100755
--- a/Modules/M3/Http/Controllers/ExecSummaryController.php
+++ b/Modules/M3/Http/Controllers/ExecSummaryController.php
@@ -134,20 +134,21 @@ class ExecSummaryController extends Controller
return null;
}
+ $range = null;
if ($period === 'custom') {
- return [(clone $from)->modify('first day of this month')->format('Ymd'), (clone $from)->modify('last day of this month')->format('Ymd')];
+ $range = [(clone $from)->modify('first day of this month')->format('Ymd'), (clone $from)->modify('last day of this month')->format('Ymd')];
+ } else {
+ $to = self::monthDate($request->input('TOREPORTDATE'));
+ if ($to !== null) {
+ $range = match ($period) {
+ 'year', 'quarter' => [(clone $from)->modify('first day of January')->format('Ymd'), (clone $to)->modify('last day of December')->format('Ymd')],
+ 'monthly' => [(clone $from)->modify('first day of this month')->format('Ymd'), (clone $to)->modify('last day of this month')->format('Ymd')],
+ default => null,
+ };
+ }
}
- $to = self::monthDate($request->input('TOREPORTDATE'));
- if ($to === null) {
- return null;
- }
-
- return match ($period) {
- 'year', 'quarter' => [(clone $from)->modify('first day of January')->format('Ymd'), (clone $to)->modify('last day of December')->format('Ymd')],
- 'monthly' => [(clone $from)->modify('first day of this month')->format('Ymd'), (clone $to)->modify('last day of this month')->format('Ymd')],
- default => null,
- };
+ return $range;
}
private static function monthDate(mixed $value): ?\DateTime
diff --git a/Modules/M3/Http/Controllers/UserPickingStats4.php b/Modules/M3/Http/Controllers/UserPickingStats4.php
index 15f037ce..dc4f3e04 100755
--- a/Modules/M3/Http/Controllers/UserPickingStats4.php
+++ b/Modules/M3/Http/Controllers/UserPickingStats4.php
@@ -11,287 +11,210 @@ class UserPickingStats4 extends Controller
{
public static function index(Request $request)
{
+ $context = self::buildContext($request);
+ self::loadPickingData($context);
+ self::calculatePerformance($context);
- // $start = microtime(true);
- // dd($request);
- // Filter by date
- if (isset($request->dates)) {
- $date = $request->dates;
- $starting = $date;
- } else {
- $starting = date('Y-m-d', strtotime('-1 days'));
- }
+ return $request->format === 'json'
+ ? self::jsonResponse($context)
+ : self::pageResponse($request, $context);
+ }
- // #$min_work_hours_for_break = 4;
-
- // #$ignore_picks_that_last_longer_than_this_many_hours = 8;
- $ignore_picks_that_last_longer_than_this_many_hours = implode(',', Config::get('arrays.ignore_picks_that_last_longer_than_this_many_hours'));
-
- // $user_array = Config::get('arrays.user_array');
- // 618
- // Get Logged User CO & WH
- // Get Users from ICM428M
- $co = '';
- $whs = '';
- $iCM428M = [];
+ 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'));
- if ($schema->hasTable('icm428m')) {
- $profile = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
- ->select('R428US', 'R428CO', 'R428WH')
- ->where('R428US', '=', strtoupper(m3User()))
- ->first();
- $co = $profile->R428CO ?? '';
- $whs = $profile->R428WH ?? '';
-
- $iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
- ->selectRaw("R428US as userprf, (trim(R428FIRST) || ' ' || trim(R428FAMILY)) as name, R428EMPCDE as empno")
- ->where('R428STS', 'A')->where('R428EMPCDE', '!=', 0)
- ->where('R428CO', $co)->where('R428WH', $whs)->get()->all();
+ $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;
+ }
}
- $user_array = [];
- // while($row = odbc_fetch_object($result)) {
- $x = 0;
- foreach ($iCM428M as $key => $row) {
- $user_array[$x]['userprf'] = trim($row->USERPRF);
- $user_array[$x]['name'] = trim($row->NAME);
- $user_array[$x]['empno'] = $row->EMPNO;
- $x++;
- }
- array_multisort(array_column($user_array, 'name'), SORT_ASC, $user_array);
+ 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' => [],
+ ];
+ }
- // fill array of Lines per Hour per Monitor
- $lph_per_monitor_array = Config::get('arrays_custom.lph_per_code_array');
- if (isset($request->user)) {
- $user = $request->user;
- $empno = 0;
- foreach ($user_array as $key => $val) {
- if ($user_array[$key]['userprf'] == $user) {
- $empno = $user_array[$key]['empno'];
- }
- }
- } else {
- $empno = 0;
- $user = '';
+ private static function users($schema): array
+ {
+ if (! $schema->hasTable('icm428m')) {
+ return [];
}
- // get data from LBPF for user and day
- $payrollCodes = '';
- ksort($lph_per_monitor_array);
- foreach ($lph_per_monitor_array as $key => $val) {
- $payrollCodes .= $key . ',';
+ $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];
}
- $payrollCodes = substr($payrollCodes, 0, -1);
+ usort($users, static fn (array $a, array $b): int => $a['name'] <=> $b['name']);
- $yr = substr($starting, 0, 4) - 2000;
- $mth = substr($starting, 5, 2);
- $day = substr($starting, 8, 2);
- $sqlstmt = "select oppno, sum(cast (hrs as integer)+ (hrs-cast (hrs as integer))/0.6) as hrs from LBPF
- where empno=$empno and lbyr=$yr and lbmo=$mth and lbdy=$day
- and oppno in ($payrollCodes)
- group by oppno";
+ return $users;
+ }
- $lbpf1 = $schema->hasTable('lbpf')
- ? DB::connection(config('m3.connection', 'pgsql'))->select($sqlstmt)
- : [];
-
- $lbpf = 0;
- foreach ($lbpf1 as $key => $val) {
- $lbpf += $val->HRS;
+ 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;
}
- $sql = "select * from perfstat where dt='$starting' and a5pickcomu='$user' ";
+ 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();
+ }
+ }
- if ((isset($request->dates) || isset($request->user)) && $schema->hasTable('perfstat')) {
- $statistic4 = DB::connection(config('m3.connection', 'pgsql'))->select($sql);
- } else {
- $statistic4 = [];
+ private static function calculatePerformance(array &$context): void
+ {
+ self::initializeMonitors($context);
+ if ($context['statistics'] === []) {
+ return;
}
- // initialize arrays
- $monitor_array = $totals_array = $perf_array = [];
- $totals_array['value'] = 0;
- $totals_array['weight'] = 0;
- $totals_array['timediff'] = 0;
- $totals_array['picked'] = 0;
- $totals_array['entries'] = 0;
- $diff = 0;
-
- foreach ($lbpf1 as $key => $val) {
- $monitor_array[$val->OPPNO]['tot_hours'] = $val->HRS;
- // Initialize these variables in case not existant in statistic4
- $monitor_array[$val->OPPNO]['header'] = 'Mon' . $val->OPPNO;
- $monitor_array[$val->OPPNO]['timediff'] = 0;
- $monitor_array[$val->OPPNO]['percent_per_monitor'] = 0;
- $monitor_array[$val->OPPNO]['percent_per_activity'] = 0;
- $monitor_array[$val->OPPNO]['lph_blended_per_activity'] = 0;
- $monitor_array[$val->OPPNO]['picked'] = 0;
- $monitor_array[$val->OPPNO]['weight'] = 0;
- $monitor_array[$val->OPPNO]['lines'] = 0;
-
+ 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;
}
- if (! empty($statistic4)) {
- // echo "in !empty
";
- // Initialize the Monitor array
- foreach ($statistic4 as $key => $val) {
-
- // Initialize these variables in case not existant in LBPF
- $monitor_array[$val->CODE]['header'] = 'Mon' . $statistic4[$key]->CODE;
- $monitor_array[$val->CODE]['timediff'] = 0;
- $monitor_array[$val->CODE]['percent_per_monitor'] = 0;
- $monitor_array[$val->CODE]['percent_per_activity'] = 0;
- $monitor_array[$val->CODE]['lph_blended_per_activity'] = 0;
- $monitor_array[$val->CODE]['picked'] = 0;
- $monitor_array[$val->CODE]['weight'] = 0;
- $monitor_array[$val->CODE]['lines'] = 0;
- }
-
- // add another element (0) in monitor_array to capture the total blended lph value expected
- $monitor_array[0]['lph_blended_per_activity'] = 0;
- $monitor_array[0]['header'] = '0';
-
- // cycle thru stats again, and accumulate totals at global level (totals_array) and at monitor level (monitor_array)
- foreach ($statistic4 as $key => $val) {
-
- $statistic4[$key]->WEIGHT = round($statistic4[$key]->WEIGHT);
- $statistic4[$key]->A5VALUE = round($statistic4[$key]->A5VALUE);
- $statistic4[$key]->A5PICKED = round($statistic4[$key]->A5PICKED);
-
- $statistic4[$key]->A5PICKCMTS = date('Y-m-d H:i', strtotime($statistic4[$key]->A5PICKCMTS));
-
- // Calculate difference from previous time entry in seconds and save in TIMEDIFF key of STATISTIC4 array
- // $time_now=strtotime($statistic4[$key]->A5PICKCMTSADJ);
- $time_now = strtotime($statistic4[$key]->A5CMTSADJ);
- if ($key > 0) {
- $diff = round(abs($time_now - $time_prev));
- if ($diff > $ignore_picks_that_last_longer_than_this_many_hours * 60 * 60) {
- $diff = -1;
- }
- }
-
- $statistic4[$key]->TIMEDIFF = $diff;
-
- if ($diff / 60 < 5) {
- $statistic4[$key]->COLOUR = '';
- }
- if ($diff / 60 >= 5 && $diff / 60 <= 10) {
- $statistic4[$key]->COLOUR = 'yellow';
- }
- if ($diff / 60 > 10 && $diff / 60 <= 15) {
- $statistic4[$key]->COLOUR = '#88ace0';
- }
- if ($diff / 60 > 15) {
- $statistic4[$key]->COLOUR = 'red';
- }
-
- // save the time for previous entry
- // $time_prev=strtotime($statistic4[$key]->A5PICKCMTSADJ);
- $time_prev = strtotime($statistic4[$key]->A5CMTSADJ);
-
- // accumulate totals at monitor level
- $monitor_array[$val->CODE]['timediff'] += $diff;
- $monitor_array[$val->CODE]['picked'] += $statistic4[$key]->A5PICKED;
- $monitor_array[$val->CODE]['weight'] += $statistic4[$key]->WEIGHT;
- $monitor_array[$val->CODE]['lines']++;
-
- // calculate totals at global level
- $totals_array['entries'] = count($statistic4);
- $totals_array['weight'] += $statistic4[$key]->WEIGHT;
- $totals_array['value'] += $statistic4[$key]->A5VALUE;
- $totals_array['timediff'] += $diff;
- $totals_array['picked'] += $statistic4[$key]->A5PICKED;
-
- }
- // echo "after 2
"; print_r($statistic4);
- // build array for Performance with Greg's time entry (at one point we had a [0] array as well)
-
- if (! is_null($lbpf)) {
-
- $perf_array['tot_hours'] = (isset($lbpf) ? $lbpf : 0);
-
- if ($perf_array['tot_hours'] != 0) {
- $perf_array['per_hour_actual'] = $totals_array['entries'] / $perf_array['tot_hours'];
- } else {
- $perf_array['per_hour_actual'] = 0;
- }
-
- }
-
- // cycle through monitors array and compute percentage to allocate to each monitor (code)
- ksort($monitor_array);
- foreach ($monitor_array as $key => $val) {
- if ($key != '0') {
- if (! isset($monitor_array[$key]['tot_hours'])) {
- $monitor_array[$key]['tot_hours'] = 0;
- }
-
- if ($totals_array['timediff'] != 0) {
- $monitor_array[$key]['percent_per_monitor'] = $monitor_array[$key]['timediff'] / $totals_array['timediff'];
- }
-
- if ($lbpf != 0) {
- $monitor_array[$key]['percent_per_activity'] = $monitor_array[$key]['tot_hours'] / $lbpf;
- }
- $monitor_array[$key]['lph_blended_per_activity'] = $monitor_array[$key]['percent_per_activity'] * (isset($lph_per_monitor_array[$key]) ? $lph_per_monitor_array[$key] : 0);
- $monitor_array[0]['lph_blended_per_activity'] += $monitor_array[$key]['lph_blended_per_activity'];
-
- }
- }
-
- if ($monitor_array[0]['lph_blended_per_activity'] != 0) {
- $perf_array['performance_activity'] = $perf_array['per_hour_actual'] / $monitor_array[0]['lph_blended_per_activity'];
- }
+ }
+ private static function initializeMonitors(array &$context): void
+ {
+ foreach ($context['lbpfRows'] as $row) {
+ $context['monitor'][$row->OPPNO] = self::monitorDefaults('Mon' . $row->OPPNO, $row->HRS);
}
-
- // return encoded json if input field named format is json
- if ($request->format == 'json') {
-
- if (! array_key_exists('performance_activity', $perf_array)) {
- $performance = 0;
- } else {
- $performance = number_format($perf_array['performance_activity'] * 100, 0);
- }
- if (! array_key_exists('0', $monitor_array)) {
- $blendedTargetLPH = 0;
- } else {
- $blendedTargetLPH = number_format($monitor_array[0]['lph_blended_per_activity'], 1);
- }
- if (! array_key_exists('per_hour_actual', $perf_array)) {
- $actualLPH = 0;
- } else {
- $actualLPH = number_format($perf_array['per_hour_actual'], 1);
- }
- if (! array_key_exists('tot_hours', $perf_array)) {
- $grossHours = 0;
- } else {
- $grossHours = $perf_array['tot_hours'];
- }
-
- $json_data = [
- 'day' => $starting,
- 'performance' => $performance,
- 'blendedTargetLPH' => $blendedTargetLPH,
- 'actualLPH' => $actualLPH,
- 'grossHours' => $grossHours,
- ];
-
- return json_encode($json_data);
-
- } else {
- // display webpage of statistic version 4
- $request->ports = Config::get('arrays.env_ports');
- $no_data = 'N';
- if (empty($statistic4) && $_SERVER['REQUEST_URI'] != '/UserPickingStats4') {
- $no_data = 'Y';
- }
-
- return view(
- 'm3::liberty-theme.pages.UserPickingStats4',
- compact('statistic4', 'starting', 'user', 'user_array', 'monitor_array', 'totals_array', 'perf_array', 'request', 'no_data'),
+ 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,
+ ]);
}
}