From 9eb1e46164b35fdbebed627c2e88d11216f75268 Mon Sep 17 00:00:00 2001 From: Mark Gregory Date: Thu, 17 Sep 2026 11:23:51 +0100 Subject: [PATCH] M3 Security Fixes for scan command pass 32 --- Modules/M3/Console/ClosedOrderSaveXls.php | 375 +++++++++--------- .../Controllers/M3ErrorsDispController.php | 266 +++++++------ 2 files changed, 320 insertions(+), 321 deletions(-) diff --git a/Modules/M3/Console/ClosedOrderSaveXls.php b/Modules/M3/Console/ClosedOrderSaveXls.php index ce0d3d22..945a4a66 100644 --- a/Modules/M3/Console/ClosedOrderSaveXls.php +++ b/Modules/M3/Console/ClosedOrderSaveXls.php @@ -4,12 +4,10 @@ namespace Modules\M3\Console; use Config; use DB; -use Excel; use Illuminate\Console\Command; use Log; use Modules\M3\Services\SpreadsheetExport; use Storage; -use Str; class ClosedOrderSaveXls extends Command { @@ -45,204 +43,187 @@ class ClosedOrderSaveXls extends Command * @return int */ public function handle() + { + $this->configureRuntime(); + + try { + Log::channel('dailyCron')->info('Cron...Start Save Orders Closed Lines to Excel'); + [$company, $warehouse, $plant] = $this->argumentsForReport(); + + $this->generatePreviousMonthReport($company, $warehouse, $plant); + $this->generateCurrentMonthReport($company, $warehouse, $plant); + + Log::channel('dailyCron')->info('Cron...End Save Orders Closed Lines to Excel'); + $this->info('Cron...End Save Orders Closed Lines to Excel'); + } catch (\Throwable $th) { + Log::channel('dailyCron')->error($th); + + return self::FAILURE; + } + + return self::SUCCESS; + } + + private function configureRuntime(): void { ini_set('max_execution_time', Config::get('arrays.PHPTimeOutCL')); ini_set('max_input_time', Config::get('arrays.PHPTimeOutCL')); ini_set('default_socket_timeout', Config::get('arrays.PHPTimeOutCL')); ini_set('memory_limit', '1024M'); - - try { - Log::channel('dailyCron')->info('Cron...Start Save Orders Closed Lines to Excel'); - - // Get the Calling User - $userId = $this->argument('user'); - $SHUSER = isset($userId) ? $userId : (m3_user() !== '' ? Str::upper(trim(m3_user())) : ''); - - $CO = $this->argument('co'); - $COMPANY = isset($CO) ? trim($CO) : ''; - $PWHS = $this->argument('whs'); - $WHS = isset($PWHS) ? trim($PWHS) : ''; - $PPL = $this->argument('pl'); - $PLANT = isset($PPL) ? trim($PPL) : ''; - - // Generate last Month Report - $date = new \DateTime('FIRST DAY OF THIS MONTH'); - $date->modify('-1 month'); - $fromPreviousMonth = $date->format('Y-m-d'); - $toPreviousMonth = $date->modify('last day of this month')->format('Y-m-d'); - $reportDate = \DateTime::createFromFormat('Y-m-d', $fromPreviousMonth)->format('Ymd'); - $toreportDate = \DateTime::createFromFormat('Y-m-d', $toPreviousMonth)->format('Ymd'); - $reportDateWD = $fromPreviousMonth; - $toreportDateWD = $toPreviousMonth; - - if ($WHS == '321') { - $prevMonthFile = 'Closedorderlinesreport_' . $reportDateWD . '-' . $toreportDateWD . self::XLSX_EXTENSION; - } else { - $prevMonthFile = $WHS . '/Closedorderlinesreport_' . $reportDateWD . '-' . $toreportDateWD . '-' . $WHS . self::XLSX_EXTENSION; - } - - $this->info('Generate Last Month Report...'); - $this->info('From Date: ' . $reportDate); - $this->info('To Date: ' . $toreportDate); - - // Check that the Excel file Exist - $prevMonthFileExist = Storage::disk('publicCL')->exists($prevMonthFile) ? false : true; - $this->info('Prev Month File Exist: ' . $prevMonthFileExist); - - if ($reportDate != '' && $COMPANY != '' && $WHS != '' && $PLANT != '' && $prevMonthFileExist) { - // Case 729: Add Currency code A1SHCURR FROM ICM666M - $ICM688M2 = DB::connection(config('m3.connection', 'pgsql')) - ->select(" - SELECT (SHDT || ' ' || SHTIME) AS DATECLOSED, A5MACPKR, A5ONO, - A4OFSTRM, - A5PMPWHT*A5PACKED AS WEIGHT, - A4SCAC, - A4SHIPTYPE, - (SELECT A4REFORD FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) AS A4REFORD, - A5PART, A5RSVQTY, A5PACKED, A5RSVQTY - A5PACKED AS CALCULATED_COLUMN, - A5SLUNPR * A5PACKED AS ANOTHER_CALCULATED_COLUMN, - (SELECT A4SHSHNM FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) AS A4SHSHNM , - CASE WHEN SHDT IS NULL THEN (SELECT SHDATA FROM ICM699M WHERE SHMACPKR=A5MACPKR AND SHTYPE='M3-Res-out' AND SHSOURCE='CloseShipmentCoChargeAPI' ORDER BY SHDT DESC, SHTIME DESC FETCH FIRST 1 ROWS ONLY) ELSE '' END AS REASON, - A1SHCURR, - CASE - WHEN (SELECT A4SHIPTYPE FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) = 'LTL' - THEN (SELECT A4RATETCP FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) * " . (100.00 - Config::get('arrays.misc.discountCarrierRateForCustomerPriceLTL')) / 100 . ' - ELSE (SELECT A4RATETCP FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) * ' . (100.00 - Config::get('arrays.misc.discountCarrierRateForCustomerPriceParcel')) / 100 . " - END AS FREIGHT - FROM ICM688M2 - LEFT JOIN ICM699M ON SHMACPKR=A5MACPKR AND SHTYPE='M3-Res-out' AND SHDATA LIKE 'Success%' AND SHSOURCE='CloseShipmentCoChargeAPI' - LEFT JOIN ICM666M ON A1DELNO=A5MACPKR AND A1ONO=A5ONO AND A1PKLN=A5BRADLN - LEFT JOIN ICM688M1 ON A4MACPKR=A5MACPKR - WHERE A5MACPKR IN ( - SELECT DISTINCT AYMACPKR - FROM ICM695M1 - WHERE AYSTATUS IN ('Z','z') AND AYAPR8N002 BETWEEN $reportDate AND $toreportDate - ) - AND A5CO=$COMPANY AND A5WHS=$WHS AND A5PLANT=$PLANT - "); - - // "A5PACKED" => 'Packed',"CALCULATED_COLUMN" => 'Back Order Qty',"ANOTHER_CALCULATED_COLUMN" => 'Value Packed $',"A4SHSHNM" => 'Customer name', - // "SHDT" => 'Date',"SHTIME" => 'Time',"REASON" => 'Failure Reason','A1SHCURR'=> 'Currency Code','FREIGHT'=> 'Freight']; - - $newItem = ['DATECLOSED' => 'Close Date', 'A5MACPKR' => 'Delivery #', 'A5ONO' => 'Order #', - 'A4OFSTRM' => 'Terms', 'WEIGHT' => 'Weight', 'A4SCAC' => 'Carrier', 'A4SHIPTYPE' => 'Mode (Parcel, Air, TL or LTL)', - 'A4REFORD' => 'Order Type', 'A5PART' => 'Part #', 'A5RSVQTY' => 'Reserved', - 'A5PACKED' => 'Packed', 'CALCULATED_COLUMN' => 'Back Order Qty', 'ANOTHER_CALCULATED_COLUMN' => 'Value Packed $', 'A4SHSHNM' => 'Customer name', - 'REASON' => 'Failure Reason', 'A1SHCURR' => 'Currency Code', 'FREIGHT' => 'Freight']; - - $ICM688M2Col = collect($ICM688M2); - $ICM688M2Col->prepend($newItem); - - // Count records before exporting to excel : Max 55K records are allowed - $ICM688M2Count = $ICM688M2Col->count(); - // Set Max allowed records - $maxRecords = Config::get('arrays.maxRecCL'); - if ($ICM688M2Count > $maxRecords) { - Log::channel('dailyCron')->info('Maximum allowed records for Excel export is: ' . number_format($maxRecords) . ' current records: ' . number_format($ICM688M2Count)); - } - } else { - $ICM688M2Col = collect(); - } - - if ($ICM688M2Col->count() > 0) { - $this->info('Saving Last Month Excel Report to Disk'); - Log::channel('dailyCron')->info('Saving Last Month Excel Report to Disk'); - - // Store the File to Storage - app(SpreadsheetExport::class)->store($ICM688M2Col, $prevMonthFile, 'publicCL'); - // Other File Formats : \Maatwebsite\Excel\Excel::CSV , ,\Maatwebsite\Excel\Excel::ODS - } else { - Log::channel('dailyCron')->info('Monthly report, no records found: Nothing to save...'); - } - - // Generate current Month Report - $now = new \DateTime; - $first_day_of_month = $now->format('Y-m-01'); - $current_date = $now->format('Y-m-d'); - $reportDate2 = \DateTime::createFromFormat('Y-m-d', $first_day_of_month)->format('Ymd'); - $toreportDate2 = \DateTime::createFromFormat('Y-m-d', $current_date)->format('Ymd'); - - if ($WHS == '321') { - $currentMonthFile = 'first_of_month_to_current_date.xlsx'; - } else { - $currentMonthFile = $WHS . '/first_of_month_to_current_date_' . $WHS . self::XLSX_EXTENSION; - } - - $this->info('Generate Current Month Report...'); - $this->info('From Date: ' . $reportDate2); - $this->info('To Date : ' . $toreportDate2); - - if ($reportDate2 != '' && $COMPANY != '' && $WHS != '' && $PLANT != '') { - $this->info('>>> Proceed...'); - - // Case 729: Add Currency code A1SHCURR FROM ICM666M - $ICM688M2 = DB::connection(config('m3.connection', 'pgsql')) - ->select(" - SELECT (SHDT || ' ' || SHTIME) AS DATECLOSED, A5MACPKR, A5ONO, - A4OFSTRM, - A5PMPWHT*A5PACKED AS WEIGHT, - A4SCAC, - A4SHIPTYPE, - (SELECT A4REFORD FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) AS A4REFORD, - A5PART, A5RSVQTY, A5PACKED, A5RSVQTY - A5PACKED AS CALCULATED_COLUMN, - A5SLUNPR * A5PACKED AS ANOTHER_CALCULATED_COLUMN, - (SELECT A4SHSHNM FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) AS A4SHSHNM , - CASE WHEN SHDT IS NULL THEN (SELECT SHDATA FROM ICM699M WHERE SHMACPKR=A5MACPKR AND SHTYPE='M3-Res-out' AND SHSOURCE='CloseShipmentCoChargeAPI' ORDER BY SHDT DESC, SHTIME DESC FETCH FIRST 1 ROWS ONLY) ELSE '' END AS REASON, - A1SHCURR, - CASE - WHEN (SELECT A4SHIPTYPE FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) = 'LTL' - THEN (SELECT A4RATETCP FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) * " . (100.00 - Config::get('arrays.misc.discountCarrierRateForCustomerPriceLTL')) / 100 . ' - ELSE (SELECT A4RATETCP FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) * ' . (100.00 - Config::get('arrays.misc.discountCarrierRateForCustomerPriceParcel')) / 100 . " - END AS FREIGHT - FROM ICM688M2 - LEFT JOIN ICM699M ON SHMACPKR=A5MACPKR AND SHTYPE='M3-Res-out' AND SHDATA LIKE 'Success%' AND SHSOURCE='CloseShipmentCoChargeAPI' - LEFT JOIN ICM666M ON A1DELNO=A5MACPKR AND A1ONO=A5ONO AND A1PKLN=A5BRADLN - LEFT JOIN ICM688M1 ON A4MACPKR=A5MACPKR - WHERE A5MACPKR IN ( - SELECT DISTINCT AYMACPKR - FROM ICM695M1 - WHERE AYSTATUS IN ('Z','z') AND AYAPR8N002 BETWEEN $reportDate2 AND $toreportDate2 - ) - AND A5CO=$COMPANY AND A5WHS=$WHS AND A5PLANT=$PLANT - "); - - // "A5PACKED" => 'Packed',"CALCULATED_COLUMN" => 'Back Order Qty',"ANOTHER_CALCULATED_COLUMN" => 'Value Packed $',"A4SHSHNM" => 'Customer name', - // "SHDT" => 'Date',"SHTIME" => 'Time',"REASON" => 'Failure Reason','A1SHCURR'=> 'Currency Code','FREIGHT'=> 'Freight']; - - $newItem2 = ['DATECLOSED' => 'Close Date', 'A5MACPKR' => 'Delivery #', 'A5ONO' => 'Order #', - 'A4OFSTRM' => 'Terms', 'WEIGHT' => 'Weight', 'A4SCAC' => 'Carrier', 'A4SHIPTYPE' => 'Mode (Parcel, Air, TL or LTL)', - 'A4REFORD' => 'Order Type', 'A5PART' => 'Part #', 'A5RSVQTY' => 'Reserved', - 'A5PACKED' => 'Packed', 'CALCULATED_COLUMN' => 'Back Order Qty', 'ANOTHER_CALCULATED_COLUMN' => 'Value Packed $', 'A4SHSHNM' => 'Customer name', - 'REASON' => 'Failure Reason', 'A1SHCURR' => 'Currency Code', 'FREIGHT' => 'Freight']; - - $ICM688M2Col2 = collect($ICM688M2); - $ICM688M2Col2->prepend($newItem2); - - // Count records before exporting to excel : Max 55K records are allowed - $ICM688M2Count = $ICM688M2Col2->count(); - // Set Max allowed records - $maxRecords = Config::get('arrays.maxRecCL'); - if ($ICM688M2Count > $maxRecords) { - Log::channel('dailyCron')->info('Maximum allowed records for Excel export is: ' . number_format($maxRecords) . ' current records: ' . number_format($ICM688M2Count)); - } - } else { - $ICM688M2Col2 = collect(); - } - - if ($ICM688M2Col2->count() > 0) { - $this->info('Saving Current Month Excel Report to Disk'); - Log::channel('dailyCron')->info('Saving Current Month Excel Report to Disk'); - // Store the File to Storage - app(SpreadsheetExport::class)->store($ICM688M2Col2, $currentMonthFile, 'publicCL'); - } else { - Log::channel('dailyCron')->info('Daily Report, no records found: Nothing to save...'); - } - - Log::channel('dailyCron')->info('Cron...End Save Orders Closed Lines to Excel'); - $this->info('Cron...End Save Orders Closed Lines to Excel'); - - } catch (\Throwable $th) { - Log::channel('dailyCron')->error($th); - } } -} + + private function argumentsForReport(): array + { + return [ + trim((string) $this->argument('co')), + trim((string) $this->argument('whs')), + trim((string) $this->argument('pl')), + ]; + } + + private function generatePreviousMonthReport(string $company, string $warehouse, string $plant): void + { + $date = new \DateTime('FIRST DAY OF THIS MONTH'); + $date->modify('-1 month'); + $from = $date->format('Y-m-d'); + $to = $date->modify('last day of this month')->format('Y-m-d'); + $file = $warehouse === '321' + ? 'Closedorderlinesreport_' . $from . '-' . $to . self::XLSX_EXTENSION + : $warehouse . '/Closedorderlinesreport_' . $from . '-' . $to . '-' . $warehouse . self::XLSX_EXTENSION; + + $this->info('Generate Last Month Report...'); + $this->generateReport( + $company, + $warehouse, + $plant, + str_replace('-', '', $from), + str_replace('-', '', $to), + $file, + ! Storage::disk('publicCL')->exists($file), + 'Last Month' + ); + } + + private function generateCurrentMonthReport(string $company, string $warehouse, string $plant): void + { + $now = new \DateTime; + $from = $now->format('Y-m-01'); + $to = $now->format('Y-m-d'); + $file = $warehouse === '321' + ? 'first_of_month_to_current_date.xlsx' + : $warehouse . '/first_of_month_to_current_date_' . $warehouse . self::XLSX_EXTENSION; + + $this->info('Generate Current Month Report...'); + $this->generateReport( + $company, + $warehouse, + $plant, + str_replace('-', '', $from), + str_replace('-', '', $to), + $file, + true, + 'Current Month' + ); + } + + private function generateReport( + string $company, + string $warehouse, + string $plant, + string $from, + string $to, + string $file, + bool $shouldGenerate, + string $label + ): void { + $this->info('From Date: ' . $from); + $this->info('To Date: ' . $to); + + if (! $shouldGenerate || ! $this->hasReportScope($company, $warehouse, $plant)) { + return; + } + + $rows = $this->closedOrderRows($company, $warehouse, $plant, $from, $to); + if ($rows->isEmpty()) { + Log::channel('dailyCron')->info($label . ' report, no records found: Nothing to save...'); + + return; + } + + $rows->prepend($this->headers()); + $this->logRecordLimit($rows->count()); + $this->info('Saving ' . $label . ' Excel Report to Disk'); + Log::channel('dailyCron')->info('Saving ' . $label . ' Excel Report to Disk'); + app(SpreadsheetExport::class)->store($rows, $file, 'publicCL'); + } + + private function hasReportScope(string $company, string $warehouse, string $plant): bool + { + return $company !== '' && $warehouse !== '' && $plant !== ''; + } + + private function closedOrderRows(string $company, string $warehouse, string $plant, string $from, string $to) + { + $ltlFactor = (100.00 - Config::get('arrays.misc.discountCarrierRateForCustomerPriceLTL')) / 100; + $parcelFactor = (100.00 - Config::get('arrays.misc.discountCarrierRateForCustomerPriceParcel')) / 100; + + $sql = <<<'SQL' +SELECT (SHDT || ' ' || SHTIME) AS DATECLOSED, A5MACPKR, A5ONO, + A4OFSTRM, A5PMPWHT*A5PACKED AS WEIGHT, A4SCAC, A4SHIPTYPE, + (SELECT A4REFORD FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) AS A4REFORD, + A5PART, A5RSVQTY, A5PACKED, A5RSVQTY - A5PACKED AS CALCULATED_COLUMN, + A5SLUNPR * A5PACKED AS ANOTHER_CALCULATED_COLUMN, + (SELECT A4SHSHNM FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) AS A4SHSHNM, + CASE WHEN SHDT IS NULL THEN + (SELECT SHDATA FROM ICM699M WHERE SHMACPKR=A5MACPKR AND SHTYPE='M3-Res-out' + AND SHSOURCE='CloseShipmentCoChargeAPI' ORDER BY SHDT DESC, SHTIME DESC FETCH FIRST 1 ROWS ONLY) + ELSE '' END AS REASON, + A1SHCURR, + CASE WHEN (SELECT A4SHIPTYPE FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) = 'LTL' + THEN (SELECT A4RATETCP FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) * ? + ELSE (SELECT A4RATETCP FROM ICM688M1 WHERE A4MACPKR=A5MACPKR) * ? + END AS FREIGHT +FROM ICM688M2 +LEFT JOIN ICM699M ON SHMACPKR=A5MACPKR AND SHTYPE='M3-Res-out' AND SHDATA LIKE 'Success%' + AND SHSOURCE='CloseShipmentCoChargeAPI' +LEFT JOIN ICM666M ON A1DELNO=A5MACPKR AND A1ONO=A5ONO AND A1PKLN=A5BRADLN +LEFT JOIN ICM688M1 ON A4MACPKR=A5MACPKR +WHERE A5MACPKR IN ( + SELECT DISTINCT AYMACPKR FROM ICM695M1 + WHERE AYSTATUS IN ('Z','z') AND AYAPR8N002 BETWEEN ? AND ? +) +AND A5CO=? AND A5WHS=? AND A5PLANT=? +SQL; + + return collect(DB::connection(config('m3.connection', 'pgsql'))->select($sql, [ + $ltlFactor, $parcelFactor, $from, $to, $company, $warehouse, $plant, + ])); + } + + private function headers(): array + { + return [ + 'DATECLOSED' => 'Close Date', 'A5MACPKR' => 'Delivery #', 'A5ONO' => 'Order #', + 'A4OFSTRM' => 'Terms', 'WEIGHT' => 'Weight', 'A4SCAC' => 'Carrier', + 'A4SHIPTYPE' => 'Mode (Parcel, Air, TL or LTL)', 'A4REFORD' => 'Order Type', + 'A5PART' => 'Part #', 'A5RSVQTY' => 'Reserved', 'A5PACKED' => 'Packed', + 'CALCULATED_COLUMN' => 'Back Order Qty', 'ANOTHER_CALCULATED_COLUMN' => 'Value Packed $', + 'A4SHSHNM' => 'Customer name', 'REASON' => 'Failure Reason', + 'A1SHCURR' => 'Currency Code', 'FREIGHT' => 'Freight', + ]; + } + + private function logRecordLimit(int $count): void + { + $maxRecords = (int) Config::get('arrays.maxRecCL'); + if ($count <= $maxRecords) { + return; + } + + Log::channel('dailyCron')->info( + 'Maximum allowed records for Excel export is: ' . number_format($maxRecords) + . ' current records: ' . number_format($count) + ); + } + +} \ No newline at end of file diff --git a/Modules/M3/Http/Controllers/M3ErrorsDispController.php b/Modules/M3/Http/Controllers/M3ErrorsDispController.php index b442b978..985331ff 100644 --- a/Modules/M3/Http/Controllers/M3ErrorsDispController.php +++ b/Modules/M3/Http/Controllers/M3ErrorsDispController.php @@ -186,136 +186,154 @@ class M3ErrorsDispController extends Controller // Export To Excel public static function exporttoExcel(Request $request) + { + self::configureExportRuntime(); + + try { + $filters = self::exportFiltersFromRequest($request); + [$profileUser, $company, $warehouse] = self::exportUserScope($filters['user']); + $users = self::exportUsers(); + [$query, $countQuery] = self::exportQueries(); + + self::applyExportFilters($query, $countQuery, [ + 'profileUser' => $profileUser, + 'company' => $company, + 'warehouse' => $warehouse, + 'manifest' => $filters['manifest'], + 'source' => $filters['source'], + 'startDate' => $filters['startDate'], + 'endDate' => $filters['endDate'], + 'skipDates' => $filters['skipDates'], + 'showErrors' => $filters['showErrors'], + ]); + + $limitResponse = self::validateExportCount($countQuery->count()); + if ($limitResponse !== null) { + return $limitResponse; + } + + $rows = self::prepareExportRows($query->get(), $users); + + return app(SpreadsheetExport::class)->download( + $rows, + 'transactionLog_' . $filters['startDate'] . '-' . $filters['endDate'] . '.xlsx' + ); + } catch (\Throwable $th) { + Log::error($th); + + return redirect()->back()->withInput()->with('message', 'Unable to export the transaction log.'); + } + } + + private static function configureExportRuntime(): void { ini_set('max_execution_time', Config::get('arrays.PHPTimeOut')); ini_set('max_input_time', Config::get('arrays.PHPTimeOut')); ini_set('default_socket_timeout', Config::get('arrays.PHPTimeOut')); ini_set('memory_limit', '1024M'); - - try { - $SHMACPKR = $request->SHMACPKR != null ? trim($request->SHMACPKR) : ''; - $SHSOURCE = $request->SHSOURCE != null ? trim($request->SHSOURCE) : ''; - $STARTDATE = $request->STARTDATE != null ? trim($request->STARTDATE) : today()->subDays(1)->format('Y-m-d'); - $ENDDATE = $request->ENDDATE != null ? trim($request->ENDDATE) : today()->format('Y-m-d'); - $SHOWERRORS = $request->SHOWERRORS != null ? trim($request->SHOWERRORS) : 'N'; - $SHUSER = m3_user() !== '' ? Str::upper(trim(m3_user())) : ''; - $SKIPDATES = $request->SKIPDATES != null ? trim($request->SKIPDATES) : 'N'; - // Get Logged User CO & WH - // Get users from ICM428M - $ICM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m') - ->select('R428US', 'R428CO', 'R428WH') - ->where('R428US', '=', $SHUSER) - ->first(); - - $R428US = isset($ICM428M->R428US) ? $ICM428M->R428US : ''; - $USERCO = isset($ICM428M->R428CO) ? $ICM428M->R428CO : ''; - $USERWH = isset($ICM428M->R428WH) ? $ICM428M->R428WH : ''; - - // Get users from ICM428M - $ICM428MAll = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m') - ->select('R428US', 'R428FIRST', 'R428FAMILY') - ->get(); - $ICM428MCOL = collect($ICM428MAll); - $ICM428MCOL->filter(function ($value) { - return $value->R428US = trim($value->R428US); - }); - $ICM428MCOL->filter(function ($value) { - return $value->R428FIRST = trim($value->R428FIRST); - }); - $ICM428MCOL->filter(function ($value) { - return $value->R428FAMILY = trim($value->R428FAMILY); - }); - - // Merge date and time fields - $mergedDateTime = DB::raw(" ICM699M.SHDT || ' ' || ICM699M.SHTIME AS SHDATETIME"); - - $ICM699M = DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') - ->select( - DB::raw('COALESCE(ICM688M1.A4ONO, ICM666M.A1ONO) AS DELIVERY_NUM '), - 'ICM699M.SHMACPKR', - DB::raw('COALESCE(ICM688M1.A4SHSHNM, ICM666M.A1SHSHNM) AS CUSTOMER '), - $mergedDateTime, - DB::raw("CASE WHEN ICM699M.SHERROR !='Z' THEN TRIM(ICM699M.SHERROR) ELSE 'Closed' END AS ERROR"), - 'ICM699M.SHTYPE', - 'ICM699M.SHSOURCE', - DB::raw("CASE WHEN ICM428M.R428FIRST IS NOT NULL THEN TRIM(ICM428M.R428FIRST) ||' '|| TRIM(ICM428M.R428FAMILY) ELSE TRIM(ICM699M.SHUSER) END AS USER"), - 'ICM699M.SHCODE', - 'ICM699M.SHCO', - 'ICM699M.SHWHS', - DB::raw(" ICM699M.SHACKDATE ||' '||ICM699M.SHACKTIME AS ACKDATE"), - 'ICM699M.SHACKUSER', - 'ICM699M.SHINTBOX', - 'ICM699M.SHACKNOTE', - DB::raw('SUBSTR(ICM699M.SHDATA, 1, 200)'), - ) - ->distinct() - ->leftJoin('ICM428M', 'ICM699M.SHUSER', '=', 'ICM428M.R428US') - ->leftJoin('ICM688M1', 'ICM699M.SHMACPKR', '=', 'ICM688M1.A4MACPKR') - ->leftJoin('ICM666M', 'ICM699M.SHMACPKR', '=', 'ICM666M.A1DELNO'); - - // Get Records Count only - $ICM699MC = DB::connection(config('m3.connection', 'pgsql'))->table('icm699m'); - - self::applyExportFilters($ICM699M, $ICM699MC, [ - 'profileUser' => $R428US, 'company' => $USERCO, 'warehouse' => $USERWH, - 'manifest' => $SHMACPKR, 'source' => $SHSOURCE, 'startDate' => $STARTDATE, - 'endDate' => $ENDDATE, 'skipDates' => $SKIPDATES, 'showErrors' => $SHOWERRORS, - ]); - - // Count records before exporting to excel : Max 20K records are allowed - $ICM699MCount = $ICM699MC->count(); - // dd($ICM699MCount); - // Set Max allowed records - $maxRecords = Config::get('arrays.maxRecDL'); - if ($ICM699MCount > $maxRecords) { - return redirect()->back()->withInput()->with('message', 'Maximum allowed records for Excel Download is: ' . number_format($maxRecords) . - ' current records: ' . number_format($ICM699MCount) . ' , change your search criteria.'); - } - - // Select Records and export them to Excel - $ICM699MSel = $ICM699M->get(); - $ICM699MCol = collect($ICM699MSel); - - // Get Transaction Types - $transxTypes = Config::get('arrays.transxTypes'); - $ICM699MCol->filter(function ($value) use ($transxTypes) { - return $value->SHSOURCE = isset($transxTypes[trim($value->SHSOURCE)]) ? $transxTypes[trim($value->SHSOURCE)] : $value->SHSOURCE; - }); - - // Get User Names - $ICM699MCol->filter(function ($value) use ($ICM428MCOL) { - $UserTemp = $ICM428MCOL->firstWhere('R428US', trim($value->SHACKUSER)); - $SHACKUSER = isset($UserTemp->R428FIRST) ? $UserTemp->R428FIRST . ' ' . $UserTemp->R428FAMILY : trim($value->SHACKUSER); - - return $value->SHACKUSER = $SHACKUSER; - }); - - // Prepend Header To Excel - $newItem = ['SHMACPKR' => 'Delivery Note', - 'DELIVERY_NUM' => 'Order #', - 'CUSTOMER' => 'Customer', - 'SHDATETIME' => 'Date', - 'ERROR' => 'Error', - 'SHTYPE' => 'Request Type', - 'SHSOURCE' => 'Source of transaction', - 'USER' => 'User', - 'SHCODE' => 'Request or Response Data', - 'SHCO' => 'Division', - 'SHWHS' => 'Warehouse', - 'ACKDATE' => 'Acknowledge/Retry Date', - 'SHACKUSER' => 'Acknowledged/Retried by User', - 'SHINTBOX' => 'Internal Box Number', - 'SHACKNOTE' => 'Note', - 'SHDATA' => 'Error description', - ]; - $ICM699MCol->prepend($newItem); - - // Download Excel File - return app(SpreadsheetExport::class)->download($ICM699MCol, 'transactionLog_' . $STARTDATE . '-' . $ENDDATE . '.xlsx'); - } catch (\Throwable $th) { - Log::error($th); - } } + + private static function exportFiltersFromRequest(Request $request): array + { + return [ + 'manifest' => trim((string) $request->input('SHMACPKR', '')), + 'source' => trim((string) $request->input('SHSOURCE', '')), + 'startDate' => trim((string) $request->input('STARTDATE', today()->subDays(1)->format('Y-m-d'))), + 'endDate' => trim((string) $request->input('ENDDATE', today()->format('Y-m-d'))), + 'showErrors' => trim((string) $request->input('SHOWERRORS', 'N')), + 'skipDates' => trim((string) $request->input('SKIPDATES', 'N')), + 'user' => Str::upper(trim(m3_user())), + ]; + } + + private static function exportUserScope(string $user): array + { + $profile = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m') + ->select('R428US', 'R428CO', 'R428WH') + ->where('R428US', $user) + ->first(); + + return [ + trim((string) ($profile->R428US ?? '')), + trim((string) ($profile->R428CO ?? '')), + trim((string) ($profile->R428WH ?? '')), + ]; + } + + private static function exportUsers() + { + return DB::connection(config('m3.connection', 'pgsql'))->table('icm428m') + ->select('R428US', 'R428FIRST', 'R428FAMILY') + ->get() + ->each(function ($value): void { + $value->R428US = trim((string) $value->R428US); + $value->R428FIRST = trim((string) $value->R428FIRST); + $value->R428FAMILY = trim((string) $value->R428FAMILY); + }); + } + + private static function exportQueries(): array + { + $query = DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') + ->select( + DB::raw('COALESCE(ICM688M1.A4ONO, ICM666M.A1ONO) AS DELIVERY_NUM '), + 'ICM699M.SHMACPKR', + DB::raw('COALESCE(ICM688M1.A4SHSHNM, ICM666M.A1SHSHNM) AS CUSTOMER '), + DB::raw(" ICM699M.SHDT || ' ' || ICM699M.SHTIME AS SHDATETIME"), + DB::raw("CASE WHEN ICM699M.SHERROR !='Z' THEN TRIM(ICM699M.SHERROR) ELSE 'Closed' END AS ERROR"), + 'ICM699M.SHTYPE', 'ICM699M.SHSOURCE', + DB::raw("CASE WHEN ICM428M.R428FIRST IS NOT NULL THEN TRIM(ICM428M.R428FIRST) ||' '|| TRIM(ICM428M.R428FAMILY) ELSE TRIM(ICM699M.SHUSER) END AS USER"), + 'ICM699M.SHCODE', 'ICM699M.SHCO', 'ICM699M.SHWHS', + DB::raw(" ICM699M.SHACKDATE ||' '||ICM699M.SHACKTIME AS ACKDATE"), + 'ICM699M.SHACKUSER', 'ICM699M.SHINTBOX', 'ICM699M.SHACKNOTE', + DB::raw('SUBSTR(ICM699M.SHDATA, 1, 200)') + ) + ->distinct() + ->leftJoin('ICM428M', 'ICM699M.SHUSER', '=', 'ICM428M.R428US') + ->leftJoin('ICM688M1', 'ICM699M.SHMACPKR', '=', 'ICM688M1.A4MACPKR') + ->leftJoin('ICM666M', 'ICM699M.SHMACPKR', '=', 'ICM666M.A1DELNO'); + + return [$query, DB::connection(config('m3.connection', 'pgsql'))->table('icm699m')]; + } + + private static function validateExportCount(int $count) + { + $maxRecords = (int) Config::get('arrays.maxRecDL'); + if ($count <= $maxRecords) { + return null; + } + + return redirect()->back()->withInput()->with( + 'message', + 'Maximum allowed records for Excel Download is: ' . number_format($maxRecords) + . ' current records: ' . number_format($count) . ' , change your search criteria.' + ); + } + + private static function prepareExportRows($records, $users) + { + $transactionTypes = Config::get('arrays.transxTypes'); + $rows = collect($records)->each(function ($value) use ($transactionTypes, $users): void { + $source = trim((string) $value->SHSOURCE); + $value->SHSOURCE = $transactionTypes[$source] ?? $source; + $user = $users->firstWhere('R428US', trim((string) $value->SHACKUSER)); + $value->SHACKUSER = $user + ? trim($user->R428FIRST . ' ' . $user->R428FAMILY) + : trim((string) $value->SHACKUSER); + }); + + $rows->prepend([ + 'SHMACPKR' => 'Delivery Note', 'DELIVERY_NUM' => 'Order #', 'CUSTOMER' => 'Customer', + 'SHDATETIME' => 'Date', 'ERROR' => 'Error', 'SHTYPE' => 'Request Type', + 'SHSOURCE' => 'Source of transaction', 'USER' => 'User', 'SHCODE' => 'Request or Response Data', + 'SHCO' => 'Division', 'SHWHS' => 'Warehouse', 'ACKDATE' => 'Acknowledge/Retry Date', + 'SHACKUSER' => 'Acknowledged/Retried by User', 'SHINTBOX' => 'Internal Box Number', + 'SHACKNOTE' => 'Note', 'SHDATA' => 'Error description', + ]); + + return $rows; + } + private static function applyExportFilters($query, $countQuery, array $filters): void { $queries = [$query, $countQuery];