shipmentContext($shipment); $allErrors .= $this->processShipment($lastShipment); } if ($lastShipment !== null) { $this->closeFalsePositiveErrors($lastShipment); } $this->markManifestProcessed(); return $this->resultResponse($allErrors); } private function shipmentContext(object $shipment): array { return [ 'whs' => trim($shipment->AYWHS), 'company' => trim($shipment->AYCO), 'delivery' => trim($shipment->AYMACPKR), 'release' => trim($shipment->AYRLNO), 'manifest' => trim($shipment->AYAPRF1551), ]; } private function processShipment(array $shipment): string { $endFlag = $this->shortPickEndFlag($shipment); $trailer = $this->trailerContext($shipment); $builder = new CloseShipmentPackageBuilder($this->context, $this->freightTerms); $state = $builder->build($shipment, $trailer); if ($state['packages'] === []) { return $state['errors']; } $json = $builder->closeShipmentJson($shipment, $trailer, $state, $endFlag); if ($state['errors'] !== '') { $this->logValidationErrors($shipment, $state['errors']); return $state['errors']; } return $this->sendCloseRequest($shipment, $json, $state['coCharge']); } private function shortPickEndFlag(array $shipment): int { $rows = DB::connection(config('m3.connection', 'pgsql'))->table('icm688m2') ->select('A5PART', 'A5PACKED', 'A5PICKED', 'A5PKLN', 'A5RSVQTY')->distinct() ->where('A5CO', $shipment['company'])->where('A5WHS', $shipment['whs']) ->where('A5MACPKR', $shipment['delivery'])->where('A5RLNO', $shipment['release']) ->orderBy('A5PART')->get(); foreach ($rows as $row) { if ((int) ($row->A5RSVQTY ?? 0) - (int) ($row->A5PICKED ?? 0) > 0) { return 1; } } return 0; } private function trailerContext(array $shipment): array { $row = DB::connection(config('m3.connection', 'pgsql'))->table('icm705m1') ->select('APTRUCKID', 'APTRACKNO', 'APMANIFEST') ->where('APCO', $this->context['company'])->where('APMANIFEST', $shipment['manifest']) ->where('APWHS', $this->context['whs'])->first(); return [ 'trailer' => isset($row->APTRUCKID) ? trim($row->APTRUCKID) : '', 'pro' => isset($row->APTRACKNO) ? trim($row->APTRACKNO) : '', ]; } private function sendCloseRequest(array $shipment, string $json, array $coCharge): string { Log::channel('dailyCron')->info('1 >>> JSON Sent for Manifest: ' . (string) (int) $shipment['manifest'] . ' ,Macpicker: ' . $shipment['delivery']); $this->log($shipment, 'M3-JSN-out', $json); $response = Http::withHeaders(['accept' => self::JSON_CONTENT_TYPE, 'Content-Type' => self::JSON_CONTENT_TYPE, 'Connection' => 'close']) ->withToken($this->token)->withBody($json, self::JSON_CONTENT_TYPE) ->timeout(Config::get('arrays.curlTimeOut'))->retry(3, 100) ->post(env('ENDPOINTURL') . 'APIFLOWS/Sentinel/TransferAPI?ionapiRespStyle=sync'); Log::channel('dailyCron')->info('2 >>> Close API M3 Responded...'); $result = $this->parseM3Response($response, $shipment, $coCharge !== []); if ($result['success']) { $this->log($shipment, 'M3-Res-out', 'Success...' . json_encode($result['responseResult']) . $result['session']); return ''; } $this->markShipmentFailed($shipment); $this->log($shipment, 'M3-Res-out', 'Important-Error: ' . $result['errors'] . json_encode($result['message']) . $result['session'], 'X'); return $result['errors'] . ' '; } private function parseM3Response($response, array $shipment, bool $hasCoCharge): array { $status = $response->getStatusCode(); $session = $response->hasHeader('x-transaction-id') ? '-sessionID:' . $response->header('x-transaction-id') : '-sessionID'; $contents = json_decode(Helper::sanityzeString($response->getBody()->getContents())); if ($contents === null || (string) $status !== '200') { return ['success' => false, 'message' => self::NULL_M3_RESPONSE, 'responseResult' => '', 'errors' => $status, 'session' => $session]; } $message = $contents->result->CloseShipment; $apiResult = $message->PickingListClose->Result; $responseResult = $contents->result; $errors = Helper::checkM3Errors($responseResult); if ($apiResult !== 'Error') { $this->markShipmentSuccessful($shipment, $hasCoCharge); } return ['success' => $apiResult !== 'Error', 'message' => $message, 'responseResult' => $responseResult, 'errors' => $errors, 'session' => $session]; } private function markShipmentSuccessful(array $shipment, bool $hasCoCharge): void { $values = $hasCoCharge ? ['A4RATEM3' => 'X', 'A4PICKSTS' => 'A'] : ['A4PICKSTS' => 'A']; DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1') ->where('A4MACPKR', $shipment['delivery'])->where('A4CO', $shipment['company']) ->where('A4WHS', $shipment['whs'])->update($values); } private function markShipmentFailed(array $shipment): void { DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1') ->where('A4MACPKR', $shipment['delivery'])->where('A4CO', $shipment['company']) ->where('A4WHS', $shipment['whs'])->update(['A4PICKSTS' => 'a']); } private function logValidationErrors(array $shipment, string $errors): void { $this->log($shipment, 'M3-Res-out', Helper::removeDuplicateSubstrings($errors), 'X'); } private function closeFalsePositiveErrors(array $shipment): void { DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') ->where('SHMACPKR', $shipment['delivery'])->where('SHCO', $this->context['company']) ->where('SHWHS', $this->context['whs'])->where('SHSOURCE', self::SOURCE)->where('SHERROR', 'X') ->where('SHTYPE', 'M3-General')->where('SHDATA', 'like', '%CommTCP_read%') ->update(['SHERROR' => 'Z', 'SHACKUSER' => $this->context['user'], 'SHACKDATE' => date('Y-m-d'), 'SHACKTIME' => date('H:i:s'), 'SHACKNOTE' => 'Sentinel automatically closed the error (false positive CommTCP_read)']); } private function markManifestProcessed(): void { if ($this->context['transType'] !== 'M') { return; } DB::connection(config('m3.connection', 'pgsql'))->table('icm705m1') ->where('APMANIFEST', $this->context['manifest'])->where('APCO', $this->context['company']) ->where('APWHS', $this->context['whs'])->update(['APSPARE2' => 'X']); } private function resultResponse(string $errors) { if ($errors === '') { return response()->json(['code' => '200', 'status' => 'Success', 'message' => 'All Operations Successful']); } return response()->json([ 'code' => '206', 'status' => 'Success With Warnings', 'message' => Helper::removeDuplicateSubstrings($errors) . '; Check Transaction Logs for Errors or Warnings.', ]); } private function log(array $shipment, string $type, string $message, string $error = ''): void { Helper::logToICM699M([ 'SHMACPKR' => $shipment['delivery'], 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => $error, 'SHINTBOX' => '', 'SHTYPE' => $type, 'SHDATA' => $message, 'SHUSER' => $this->context['user'], 'SHSOURCE' => self::SOURCE, 'SHCO' => $this->context['company'], 'SHWHS' => $this->context['whs'], ]); } }