configureTimeouts(); $context = $this->requestContext($request); try { $response = $this->processInventoryRequest($context); } catch (\Throwable $throwable) { $response = $this->exceptionResponse($context, $throwable); } return $response; } private function processInventoryRequest(array $context) { if ($context['params'] === []) { return $this->missingParametersResponse($context); } $this->logRequest($context); $tokenResponse = Helper::checkReceiveTokenV2(); $tokenData = $tokenResponse->getData(); if ((string) ($tokenData->code ?? '') !== '200') { $this->log($context, (string) ($tokenData->message ?? ''), 'X', 'M3-Res-out'); return $tokenResponse; } return $this->inventoryResponse($context, (string) ($tokenData->token ?? '')); } private function inventoryResponse(array $context, string $token) { $result = $this->fetchInventory($context, $token); if ($result['error'] !== '') { $this->log($context, $result['status'] . '-' . $result['error'] . $result['session'], 'X', 'M3-Res-out'); return response()->json(['code' => '405', 'status' => 'error', 'message' => $result['error']]); } $this->log($context, $result['status'] . '-' . $result['json'] . $result['session'], '', 'M3-Res-out'); $rows = $this->flattenInventory($result['result']); $this->replaceInventory($context, $rows); return response()->json(['code' => '200', 'status' => 'Success']); } private function configureTimeouts(): void { $timeout = Config::get('arrays.PHPTimeOut'); ini_set('max_execution_time', $timeout); ini_set('max_input_time', $timeout); ini_set('default_socket_timeout', $timeout); } private function requestContext(Request $request): array { $params = $request->all(); return [ 'params' => $params, 'co' => (string) ($params['CO'] ?? ''), 'whs' => (string) ($params['WHS'] ?? ''), 'partNo' => (string) ($params['PARTNO'] ?? ''), 'pkln' => (string) ($params['PKLN'] ?? ''), 'reqPkws' => (string) ($params['REQPKWS'] ?? ''), 'reqKpkus' => (string) ($params['REQKPKUS'] ?? 'WebUser'), 'user' => m3User() !== '' ? Str::upper(m3User()) : 'WebUser', 'macpkr' => self::ZERO_PAD, ]; } private function logRequest(array $context): void { $incoming = json_encode([ 'CO' => $context['co'], 'WHS' => $context['whs'], 'PARTNO' => $context['partNo'], 'PKLN' => $context['pkln'], 'REQPKWS' => $context['reqPkws'], 'REQKPKUS' => $context['reqKpkus'], ]); $this->log($context, (string) $incoming, '', 'M3-Req-out'); $this->log($context, 'Sent To M3-' . $this->inventoryRequestJson($context), '', 'M3-Req-out'); } private function inventoryRequestJson(array $context): string { $parts = array_map(static fn (string $part): array => ['PART' => $part, 'LOT' => ''], explode(',', $context['partNo'])); return (string) json_encode(['WHS' => $context['whs'], 'PARTS' => $parts]); } private function fetchInventory(array $context, string $token): array { $response = Http::withHeaders(['accept' => self::JSON_CONTENT_TYPE, 'Content-Type' => self::JSON_CONTENT_TYPE]) ->withToken($token) ->withBody($this->inventoryRequestJson($context), self::JSON_CONTENT_TYPE) ->timeout(Config::get('arrays.curlTimeOut'))->retry(3, 100) ->post(env('ENDPOINTURL') . 'APIFLOWS/Sentinel/M3InventoryReportList?ionapiRespStyle=sync'); $status = $response->getStatusCode(); $session = $response->hasHeader('x-transaction-id') ? '-sessionID:' . $response->header('x-transaction-id') : '-sessionID'; if ((string) $status !== '200') { return ['status' => $status, 'session' => $session, 'error' => 'Error: No Response from M3', 'json' => '', 'result' => []]; } $json = Helper::sanityzeString($response->getBody()->getContents()); $decoded = json_decode($json, true); return ['status' => $status, 'session' => $session, 'error' => '', 'json' => $json, 'result' => $decoded['result'] ?? []]; } private function flattenInventory(array $result): array { $rows = []; foreach ($result as $item) { $base = array_diff_key($item, ['Locations' => true]); foreach (($item['Locations'] ?? []) as $location) { $rows[] = array_merge($base, $location); } } return $rows; } private function replaceInventory(array $context, array $rows): void { foreach ($rows as $row) { DB::connection(config('m3.connection', 'pgsql'))->table('ic630m') ->where('LLCO', $context['co'])->where('LLWHNO', $context['whs']) ->where('LLPPN', trim((string) ($row['PartNumber'] ?? '')))->delete(); } foreach ($rows as $row) { $this->upsertLocation($context, $row); $this->insertInventory($context, $row); } } private function upsertLocation(array $context, array $row): void { $connection = DB::connection(config('m3.connection', 'pgsql')); $query = $connection->table('de640m')->where('LVCO', $context['co']) ->where('WSELOC', $row['Warehouse'] ?? '')->where('VLOCID', $row['Location'] ?? ''); $values = ['LVSEQN' => $row['LocationSeq'] ?? '', 'LVUSD2' => $row['LocationType'] ?? '', 'LVZONE' => $row['Zone'] ?? '', 'LVMAINTTS' => now()]; if ($query->exists()) { $query->update($values); return; } $connection->table('de640m')->insert(array_merge($values, ['LVCO' => $context['co'], 'WSELOC' => $row['Warehouse'] ?? '', 'VLOCID' => $row['Location'] ?? ''])); } private function insertInventory(array $context, array $row): void { DB::connection(config('m3.connection', 'pgsql'))->table('ic630m')->insert([ 'LLCO' => $context['co'], 'LLWHNO' => $row['Warehouse'] ?? '', 'LLPPN' => $row['PartNumber'] ?? '', 'LLBALANCE' => $row['Quantity'] ?? 0, 'LLSTLC' => $row['Location'] ?? '', 'LLLTNO' => $row['LotNumber'] ?? '', 'LLMAINTTS' => now(), 'LLIZLCF' => trim((string) ($row['LotNumber'] ?? '')) !== '' ? '1' : '', 'LLSPR10A01' => $row['Allocation'] ?? '', 'LLSPR15A01' => $row['AllocatedTo'] ?? '', 'LLCMDESC' => Helper::sanityzeString((string) ($row['Description'] ?? '')), ]); } private function missingParametersResponse(array $context) { $this->log($context, 'No URL Parameters Sent', 'X', 'M3-Res-out'); return response()->json(['code' => '405', 'status' => 'Error', 'message' => 'No URL Parameters Sent']); } private function exceptionResponse(array $context, \Throwable $throwable) { if (str_contains($throwable->getMessage(), 'cURL error')) { $this->log($context, 'Curl Error: Communication with M3 Timed Out', 'X', 'M3-Res-out'); return response()->json(['code' => '405', 'status' => 'error', 'message' => 'Curl Error: Communication with M3 Timed Out.']); } $error = str_contains($throwable->getMessage(), 'Duplicate key value specified') ? 'Z' : 'X'; $this->log($context, 'An Error Occured - ' . substr($throwable->getMessage(), 0, 300), $error, 'M3-Res-out'); return response()->json(['code' => '405', 'status' => 'error', 'message' => 'Catched Error: ' . $throwable->getMessage()]); } private function log(array $context, string $message, string $error, string $type): void { Helper::logToICM699M([ 'SHMACPKR' => $context['macpkr'], 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => $error, 'SHINTBOX' => '', 'SHTYPE' => $type, 'SHDATA' => $message, 'SHUSER' => $context['user'], 'SHSOURCE' => self::SOURCE, 'SHCO' => $context['co'], 'SHWHS' => $context['whs'], ]); } }