diff --git a/Modules/M3/Http/Controllers/API/CloseShipment.php b/Modules/M3/Http/Controllers/API/CloseShipment.php index 8691293d..8420dbd7 100644 --- a/Modules/M3/Http/Controllers/API/CloseShipment.php +++ b/Modules/M3/Http/Controllers/API/CloseShipment.php @@ -3,1048 +3,17 @@ namespace Modules\M3\Http\Controllers\API; use Config; -use DB; -use File; -use Http; use Illuminate\Http\Request; -use Illuminate\Http\Response; -use Log; -use Modules\M3\Helpers\Helper; use Modules\M3\Http\Controllers\Controller; -use Modules\M3\Http\Controllers\GetContentsController; -use Str; class CloseShipment extends Controller { - private const ZERO_PAD = '000000'; - - private const JSON_CONTENT_TYPE = 'application/json'; - - private const NULL_M3_RESPONSE = 'M3 API responded with null value'; - - // CloseShipmentCoChargeAPI : with URL PARAMS COCharge public static function CloseShipmentCoChargeAPI(Request $request) { 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')); - // dump($request->all()); - $nODEBUG = true; // ALWAYS set TRUE in Production - $pACKAGES = []; - $jSONCoCharge = []; - $jSONCS = []; - - // Get the Calling User - $sHUSER = m3_user() !== '' ? Str::upper(m3_user()) : 'WebUser'; - $sHSOURCE = 'CloseShipmentCoChargeAPI'; - - try { - // Get URL PARAMS - $urlParams = count($request->all()) > 0 ? $request->all() : ''; - $wHS = isset($urlParams['WHS']) ? $urlParams['WHS'] : ''; - $cOMPANY = isset($urlParams['COMPANY']) ? $urlParams['COMPANY'] : ''; - $mANIFEST = isset($urlParams['MANIFEST']) ? $urlParams['MANIFEST'] : ''; - $tRANSTYPE = isset($urlParams['TRANSTYPE']) ? $urlParams['TRANSTYPE'] : 'M'; // M , P , Z - $tRANSTYPE = $tRANSTYPE != '' ? $tRANSTYPE : 'M'; // M , P , Z - $sHDT = isset($urlParams['SHDT']) ? $urlParams['SHDT'] : ''; - $sHTIME = isset($urlParams['SHTIME']) ? $urlParams['SHTIME'] : ''; - $sHTYPE = isset($urlParams['SHTYPE']) ? $urlParams['SHTYPE'] : ''; - $allErrMsgs = ''; - $lineAck = []; - // PDF File PATH - $pdfFilePath = Config::get('arrays.PdfPath'); - $dELIVERYNO = $mANIFEST != '' ? $mANIFEST : self::ZERO_PAD; - - if ($urlParams != '') { - // Write to Logs : JSON - $jSONIN = json_encode([ - 'WHS' => $wHS, - 'COMPANY' => $cOMPANY, - 'MANIFEST-MACPKR' => $mANIFEST, - 'TRANSTYPE' => $tRANSTYPE, - ]); - - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => '', - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-Req-out', - 'SHDATA' => $jSONIN, - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - - // Get Token - $tokenResponse = Helper::checkReceiveTokenV2(); - - $tokenData = $tokenResponse->getData(); - - if ($tokenData->code == '200') { - $ionToken = isset($tokenData->token) ? $tokenData->token : ''; - } else { - $sHDATA = isset($tokenData->message) ? $tokenData->message : ''; - $dELIVERYNO = isset($aYMACPKR) ? $aYMACPKR : self::ZERO_PAD; - - // Write to Logs : Error - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => 'X', - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-Res-out', - 'SHDATA' => $sHDATA, - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - - return $tokenResponse; - } - - // Set Endpoint URL - $endPointURL = env('ENDPOINTURL') . 'APIFLOWS/Sentinel/TransferAPI?ionapiRespStyle=sync'; - $token = $ionToken; - - // Read from ICM695M1 - if ($tRANSTYPE == 'M') { - $iCM695M1PREP = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m1') - ->select('AYCO', 'AYWHS', 'AYMACPKR', 'AYRLNO', 'AYAPRF1551') - ->distinct() - ->where('AYCO', $cOMPANY) - ->where('AYAPRF1551', $mANIFEST) - ->where('AYWHS', $wHS) - ->orderBy('AYMACPKR'); - } elseif ($tRANSTYPE == 'P') { - $iCM695M1PREP = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m1') - ->select('AYCO', 'AYWHS', 'AYMACPKR', 'AYRLNO', 'AYAPRF1551') - ->distinct() - ->where('AYCO', $cOMPANY) - ->where('AYMACPKR', $mANIFEST) - ->where('AYWHS', $wHS) - ->orderBy('AYMACPKR'); - - // Check Date & Time Before Updating ICM699M - if ($sHDT != '' && $sHTIME != '' && $sHTYPE != '' && $nODEBUG) { - DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') - ->where('SHMACPKR', $mANIFEST) - ->where('SHDT', $sHDT) - ->where('SHTIME', $sHTIME) - ->where('SHCO', $cOMPANY) - ->where('SHWHS', $wHS) - ->where('SHSOURCE', $sHSOURCE) - ->where('SHERROR', 'X') - ->where('SHTYPE', $sHTYPE) - ->update(['SHERROR' => 'Z', 'SHACKUSER' => $sHUSER, 'SHACKDATE' => date('Y-m-d'), 'SHACKTIME' => date('H:i:s')]); - } - - // Get Acknowledged Record for M3-QtyChg PackSyst4tray - $iCM699MQtyChg = DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') - ->select() - ->where('SHMACPKR', $mANIFEST) - ->where('SHCO', $cOMPANY) - ->where('SHWHS', $wHS) - ->where('SHSOURCE', 'PackSyst4tray') - ->where('SHERROR', 'Z') - ->where('SHTYPE', 'M3-QtyChg') - ->get(); - foreach ($iCM699MQtyChg as $ICM699MQtyChgR) { - $string = $ICM699MQtyChgR->SHDATA; - $start = 'PickerLine:'; - $end = ' -'; - $lineAck[] = Helper::getSubstringBetween($string, $start, $end); - } - } elseif ($tRANSTYPE == 'Z') { - $iCM695M1PREP = DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1') - ->select() - ->distinct() - ->where('A4CO', $cOMPANY) - ->where('A4WHS', $wHS) - ->where('A4MACPKR', $mANIFEST) - ->orderBy('A4MACPKR'); - } - - $iCM695M1TMP = $iCM695M1PREP->get(); - - // PFC if MACKPKR already Closed : Case 671 - $iCM695M1TMPCOL = collect($iCM695M1TMP); - if ($tRANSTYPE == 'Z') { - $iCM695M1TMPCOLF = $iCM695M1TMPCOL->map(function ($post) { - return trim($post->A4MACPKR); - }); - } else { - $iCM695M1TMPCOLF = $iCM695M1TMPCOL->map(function ($post) { - return trim($post->AYMACPKR); - }); - } - - $iCM695M1TMPCOLFA = $iCM695M1TMPCOLF->toArray(); - - $iCM699MSuccess = DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') - ->select('SHMACPKR') - ->whereIn('SHMACPKR', $iCM695M1TMPCOLFA) - ->where('SHCO', $cOMPANY) - ->where('SHWHS', $wHS) - ->where('SHSOURCE', 'CloseShipmentCoChargeAPI') - ->where('SHERROR', '') - ->where('SHTYPE', 'M3-Res-out') - ->where('SHDATA', 'like', '%Success%') - ->get(); - $iCM699MSuccessCol = collect($iCM699MSuccess); - $iCM699MSuccessColF = $iCM699MSuccessCol->map(function ($post) { - return $post->SHMACPKR; - }); - $iCM699MSuccessColFAr = $iCM699MSuccessColF->toArray(); - - if ($tRANSTYPE == 'Z') { - // Use the reject method to remove items based on the condition - $iCM695M1TMPF = $iCM695M1TMP->reject(function ($post) use ($iCM699MSuccessColFAr) { - return in_array($post->A4MACPKR, $iCM699MSuccessColFAr); - }); - } else { - // Use the reject method to remove items based on the condition - $iCM695M1TMPF = $iCM695M1TMP->reject(function ($post) use ($iCM699MSuccessColFAr) { - return in_array($post->AYMACPKR, $iCM699MSuccessColFAr); - }); - } - $iCM695M1TMP = $iCM695M1TMPF; - - $freightTermsTMP = DB::connection(config('m3.connection', 'pgsql'))->table('icm321m') - ->selectRaw('TRIM(ARCODE) as FREIGHTTERMS,ARCHARGE as BILLABLE') - ->get(); - - // Close Shipment for Manifest or Single MacPKR - if (count($iCM695M1TMP) > 0 && ($tRANSTYPE == 'M' || $tRANSTYPE == 'P')) { - // Loop the Results from $ICM595M1TMP - foreach ($iCM695M1TMP as $ICM695M1R) { - $pACKAGES = []; - $aYWHS = trim($ICM695M1R->AYWHS); - $aYCO = trim($ICM695M1R->AYCO); - $aYMACPKR = trim($ICM695M1R->AYMACPKR); - $aYRLNO = trim($ICM695M1R->AYRLNO); - $mANIFEST = trim($ICM695M1R->AYAPRF1551); - // Reset Errors after each Loop - $errorMsgs = ''; - // Set Endflag for Short pick after each Loop - $endFlag = 0; - - // Precheck All Qty are Equal before Proceeding to Close - // Get Parts And Lots from ICM688M2 - $iCM688M2SL = DB::connection(config('m3.connection', 'pgsql'))->table('icm688m2') - ->select('A5PART', 'A5PACKED', 'A5PICKED', 'A5PKLN', 'A5RSVQTY') - ->distinct() - ->where('A5CO', $aYCO) - ->where('A5WHS', $aYWHS) - ->where('A5MACPKR', $aYMACPKR) - ->where('A5RLNO', $aYRLNO) - ->orderBy('A5PART') - ->get(); - // dump($iCM688M2SL); - // Get PACK/Dock from ICM799M - // $ICM799MSEL = DB::connection(config('m3.connection', 'pgsql'))->table('icm799m') - // ->groupBy('IMTOLOC') - // ->select('IMTOLOC',DB::raw('SUM(IMQTY) as IMQTYTOT') ) - // ->where('IMDIV',$aYCO) - // ->where('IMWHS',$aYWHS) - // ->where('IMDELNO',$aYMACPKR) - // ->where('IMLINE',$aYRLNO) - // ->whereIn('IMTOLOC',['DOCK','PACK']) - // ->get(); - - // PFC : Check that Picked / Packed are all Equal - foreach ($iCM688M2SL as $ICM688M2SLR) { - $a5PICKED = isset($ICM688M2SLR->A5PICKED) ? $ICM688M2SLR->A5PICKED : 0; - $a5RSVQTY = isset($ICM688M2SLR->A5RSVQTY) ? $ICM688M2SLR->A5RSVQTY : 0; - $a5ShortShipQty = (int) $a5RSVQTY - (int) $a5PICKED; - - // Set EndFLag=1 for short picks - if ($a5ShortShipQty > 0) { - $endFlag = 1; - } - } - - // Get TRAILERNUMBER SELECT APTRUCKID FROM ICM705M1 WHERE APCO=110 AND APWHS=321 AND APMANIFEST=22 - $tRAILERNUMBERS = DB::connection(config('m3.connection', 'pgsql'))->table('icm705m1') - ->select('APTRUCKID', 'APTRACKNO', 'APMANIFEST') - ->where('APCO', $cOMPANY) - ->where('APMANIFEST', $mANIFEST) - ->where('APWHS', $wHS) - ->first(); - - $tRAILERNUMBER = isset($tRAILERNUMBERS->APTRUCKID) ? trim($tRAILERNUMBERS->APTRUCKID) : ''; - $pRONUMBER = isset($tRAILERNUMBERS->APTRACKNO) ? trim($tRAILERNUMBERS->APTRACKNO) : ''; - - $iCM695M1JOINTMP = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m1') - ->selectRAW('AYMACPKR,AYINTBOX,AYHEIGHT,AYWIDTH,AYDEPTH,AYTYPE,AYLNWGHT,AYID,AYSPR1A01,TRIM(AYSPR15A01) AS SCAC , TRIM(AYSPR30A01) AS TRACKING,AYTRUCK AS AGGREGATION,A4RATETCP AS FREIGHT, A4OFSTRM AS FREIGHTTERMS,A4RATEM3,A4CLOSEM3, A4SHIPTYPE, A4REFORD,A4ONO,A4SHIPVIA,A42SSVCNAM,A4SHIPVIA1') - ->leftJoin('ICM688M1', function ($join) { - $join->on('AYCO', '=', 'A4CO'); - $join->on('AYWHS', '=', 'A4WHS'); - $join->on('AYMACPKR', '=', 'A4MACPKR'); - }) - ->where('AYMACPKR', $aYMACPKR) - ->where('AYCO', $aYCO) - ->where('AYWHS', $aYWHS) - ->orderBy('AYINTBOX') - ->get(); - - foreach ($iCM695M1JOINTMP as $ICM695M1JOINR) { - $a4SHIPVIA = isset($ICM695M1JOINR->A4SHIPVIA) ? trim(str_replace('&', '_', $ICM695M1JOINR->A4SHIPVIA)) : ''; - - $sHIPTYPE = trim($ICM695M1JOINR->A4SHIPTYPE); - $a42SSVCNAM = trim($ICM695M1JOINR->A42SSVCNAM); - $a4SHIPVIA1 = trim($ICM695M1JOINR->A4SHIPVIA1); - $fREIGHTTERMS = trim($ICM695M1JOINR->FREIGHTTERMS); - $a4RATEM3 = trim($ICM695M1JOINR->A4RATEM3); - $fREIGHT = trim($ICM695M1JOINR->FREIGHT); - $a4REFORD = trim($ICM695M1JOINR->A4REFORD); - $a4ONO = trim($ICM695M1JOINR->A4ONO); - $aYMACPKR = trim($ICM695M1JOINR->AYMACPKR); - $aYINTBOX = trim($ICM695M1JOINR->AYINTBOX); - $tRACKING = trim($ICM695M1JOINR->TRACKING); - $sCAC = trim($ICM695M1JOINR->SCAC); - $cARRIER = ''; - $aYTYPE = trim($ICM695M1JOINR->AYID) != '' ? trim($ICM695M1JOINR->AYID) : ''; - $aYLNWGHT = trim($ICM695M1JOINR->AYLNWGHT); - $aYHEIGHT = trim($ICM695M1JOINR->AYHEIGHT); - $aYWIDTH = trim($ICM695M1JOINR->AYWIDTH); - $aYDEPTH = trim($ICM695M1JOINR->AYDEPTH); - $bILLOFLADING = isset($ICM695M1JOINR->AYSPR1A01) ? trim($ICM695M1JOINR->AYSPR1A01) : ''; - $tRANSPORTMODE = $a4SHIPVIA; - $sERVICETYPE = $a4SHIPVIA; - - // Get Carrier Name from ICM160M - if ($sCAC != '') { - $sCACSub = substr($sCAC, 0, 4); - $iCM160M = DB::connection(config('m3.connection', 'pgsql'))->table('icm160m') - ->select('CANAM') - ->where('CANUM', $sCACSub) - ->where('CACO', $cOMPANY) - ->first(); - $cARRIER = isset($iCM160M->CANAM) ? trim(str_replace('&', '_', $iCM160M->CANAM)) : ''; - } - - // PFC Check BOL for LTL - if ($sHIPTYPE == 'LTL') { - $errorMsgs = $bILLOFLADING == '' || $sCAC == '' || $tRACKING == '' ? - $errorMsgs . " Missing one or more of tracking number, BOL, or carrier. Please enter this data manually in 'invoicing' screen and retry this API call;" : $errorMsgs . ''; - } else { - $errorMsgs = $sCAC == '' || $tRACKING == '' ? - $errorMsgs . " Missing one or more of tracking number, BOL, or carrier. Please enter this data manually in 'invoicing' screen and retry this API call; " : $errorMsgs . ''; - } - - if ($pRONUMBER == '' && $sCAC == 'RETR') { - $errorMsgs = $errorMsgs . ' Missing PARS info for this RETRans order. Please contact MPBA to ask them to enter the value for you, and then you can retry; '; - } - - // MAK : PFC Check for GS1-Label A1SPR1A01 in ICM666M and ICM695M3 - $gS1Label = ''; - // First Check if GS1 Label is required in ICM666M - $iCM666MSQLSel = DB::connection(config('m3.connection', 'pgsql'))->table('icm666m') - ->select('A1SPR1A01') - ->where('A1CO', $aYCO) - ->where('A1WHS', $aYWHS) - ->where('A1DELNO', $aYMACPKR) - ->first(); - $gS1LabelExist = isset($iCM666MSQLSel->A1SPR1A01) ? trim($iCM666MSQLSel->A1SPR1A01) : 0; - - // Case #566: BOL = PRONUMBER For SCAC=='RETR' - if ($sCAC == 'RETR') { - $bILLOFLADING = $pRONUMBER; - } - - // Get Commodities - $myRequest = new Request; - $myRequest->setMethod('POST'); - - $myRequest->request->add([ - 'MACPKR' => $aYMACPKR, - ]); - // Call processShipment - $controller = new GetContentsController; - $response = $controller->processShipment($myRequest); - $responseData = $response->getData(); - $error = isset($responseData->error) ? $responseData->error : ''; - - if ($error == '') { - // $commodities = json_encode($responseData->commodities); - // Get Commodities - $commoditiesTmp = isset($responseData->commodities) ? $responseData->commodities : ''; - if ($commoditiesTmp != '') { - $commodities = $commoditiesTmp; - } else { - $commodities = ''; - $errorMsgs = $errorMsgs . ' Could not find Commodities; '; - } - } else { - $commodities = ''; - $errorMsgs = $errorMsgs . ' Could not find Commodities; '; - } - // End Commodities - - // Check ICM699M for SHERROR=X - $iCM699MS = DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') - ->select('SHMACPKR') - ->where('SHMACPKR', $aYMACPKR) - ->where('SHCO', $aYCO) - ->where('SHWHS', $aYWHS) - ->whereIn('SHSOURCE', ['TransferAPIURL', 'CloseShipmentCoChargeAPI', 'PackSyst4tray']) - ->where('SHERROR', 'X') - ->whereIn('SHTYPE', ['M3-Res-out', 'M3-QtyChg']) - ->first(); - - $alreadySentToM3 = isset($iCM699MS->SHMACPKR) ? trim($iCM699MS->SHMACPKR) : ''; - - if ($alreadySentToM3 != '') { - // Add Message - $errorMsgs = $errorMsgs . ' There are previous M3 transmissions in error for this delivery note that have not been addressed; '; - } - - if ($aYTYPE == '') { - // Get AETYPE SELECT APTRUCKID FROM ICM705M1 WHERE APCO=110 AND APWHS=321 AND APMANIFEST=22 - $iCM693MS = DB::connection(config('m3.connection', 'pgsql'))->table('icm693m') - ->select('AEID') - ->where('AESPR1A01', 'D') - ->where('AETYPE', trim($ICM695M1JOINR->AYTYPE)) - ->first(); - $aYTYPE = isset($iCM693MS->AEID) ? trim($iCM693MS->AEID) : ''; - } - - $currentFreightTerms = $freightTermsTMP->where('FREIGHTTERMS', $fREIGHTTERMS)->first(); - $bILLABLE = isset($currentFreightTerms->BILLABLE) ? trim($currentFreightTerms->BILLABLE) : 'N'; - - // If billable=Y and a4ratetcp(FREIGHT)>0 and a4ratem3=blank, then call the freight API CoCharge - if ($bILLABLE == 'Y' && $fREIGHT > 0 && $a4RATEM3 == '') { - $dELIVERYNO = isset($aYMACPKR) ? $aYMACPKR : self::ZERO_PAD; - - if ($sHIPTYPE == 'LTL') { - $shippingToBill = $fREIGHT * (100.00 - Config::get('arrays.misc.discountCarrierRateForCustomerPriceLTL')) / 100; - } else { - $shippingToBill = $fREIGHT * (100.00 - Config::get('arrays.misc.discountCarrierRateForCustomerPriceParcel')) / 100; - } - // Construct Json for COCharge - $jSONCoCharge = [ - 'QUANTITY' => round($shippingToBill, 2), // $fREIGHT with modified Params - 'ORDERCATEGORY' => $a4REFORD, - 'CONUMBER' => $a4ONO, - ]; - } else { - $jSONCoCharge = []; - } - - // If billable=Y and a4ratetcp(FREIGHT)=0 and a4ratem3=blank, then we need to: - // Write a record to ICM699M to indicate that we are not calling the rate API because the $ are 0 - if ($bILLABLE == 'Y' && $fREIGHT == 0 && $a4RATEM3 == '') { - // Add Message - $errorMsgs = $errorMsgs . ' Please manually add a freight charge for this Prepaid and Add order; '; - } - - // Close Shipment - // If ( (billable=Y and a4RATEM3 (from array in memory)="X") OR (billable=N) ) and a4closeM3="" then call the close API - - // Set PDF URLs for Labels - $carrierLabel = ''; - $contentLabel = ''; - - $docTypes = ['ContentLabel', 'CarrierLabel']; - foreach ($docTypes as $value) { - switch ($value) { - case 'CarrierLabel': - $dOCTYPE = 'CarrierLabel'; - $dOCNUMT = $aYINTBOX; - $pDFKey = $value . '/' . $value . '_' . $aYMACPKR . '_' . $dOCNUMT . '_' . $cOMPANY . '_' . $wHS; - $pdfFileName = $pdfFilePath . $pDFKey . '.pdf'; - - if (File::exists($pdfFileName)) { - $carrierLabel = route('m3.M3GetPDFFromCache.index', ['MACPKR' => $aYMACPKR, 'DOCTYPE' => $dOCTYPE]); - } - break; - - case 'ContentLabel': - $dOCTYPE = 'ContentLabel'; - $dOCNUMT = $aYINTBOX; - $pDFKey = $value . '/' . $value . '_' . $aYMACPKR . '_' . $dOCNUMT . '_' . $cOMPANY . '_' . $wHS; - $pdfFileName = $pdfFilePath . $pDFKey . '.pdf'; - - if (File::exists($pdfFileName)) { - $contentLabel = route('m3.M3GetPDFFromCache.index', ['MACPKR' => $aYMACPKR, 'DOCTYPE' => $dOCTYPE]); - } - break; - - default: - break; - } - } - - // Second Check GS1 Label existence in ICM695M3 - if ($gS1LabelExist == 1) { - $iCM695M3SQLSel = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m3') - ->select('A2GS1LABEL') - ->where('A2CO', $aYCO) - ->where('A2WHS', $aYWHS) - // ->where('A2MACPKR',$aYMACPKR) - ->where('A2INTBOX', $aYINTBOX) - ->first(); - $gS1Label = isset($iCM695M3SQLSel->A2GS1LABEL) ? trim($iCM695M3SQLSel->A2GS1LABEL) : ''; - - if ($gS1Label == '') { - $errorMsgs = $errorMsgs . ' Missing G1-128 Label. Please contact MPBA to ask them to enter the value for you, and then you can retry; '; - } - } - - // Get Packages Array - $pACKAGES[] = [ - 'TRACKINGID' => $tRACKING, - 'BUNDLES' => $aYTYPE, - 'WEIGHT' => $aYLNWGHT, - 'HEIGHT' => $aYHEIGHT, - 'WIDTH' => $aYWIDTH, - 'LENGTH' => $aYDEPTH, - 'SSCC' => $gS1Label, - 'SHIPLABELDOC' => $carrierLabel, - 'CONTENTLABELDOC' => $contentLabel, - ]; - } - - // Check Packages array before proceeding with CloseShipment - if (! empty($pACKAGES)) { - // Get Packlist - $packingList = ''; - $dOCTYPE = 'PackingList'; - $dOCNUMT = $aYMACPKR; - $pDFKey = $dOCTYPE . '/' . $dOCTYPE . '_' . $aYMACPKR . '_' . $dOCNUMT . '_' . $cOMPANY . '_' . $wHS; - $pdfFileName = $pdfFilePath . $pDFKey . '.pdf'; - - if (File::exists($pdfFileName)) { - $packingList = route('m3.M3GetPDFFromCache.index', ['MACPKR' => $aYMACPKR, 'DOCTYPE' => $dOCTYPE]); - } - - // Add Cocharge - if (count($jSONCoCharge) > 0) { - // Construct Json for CloseShipment With PDF Files - $tempClose = [ - 'DIVI' => $aYCO, - 'WHS' => $aYWHS, - 'DELIVERYNO' => $aYMACPKR, - 'PICKLISTSUFFIX' => $aYRLNO, - 'TYPE' => 'CloseShipment', - 'SCAC' => $sCAC, - 'CARRIER' => $cARRIER, - 'TRANSPORTMODE' => $tRANSPORTMODE, - 'SERVICETYPE' => $sERVICETYPE, - 'TRACKINGNUMBER' => $tRACKING, - 'PRONUMBER' => $pRONUMBER, - 'BILLOFLADING' => $bILLOFLADING, - 'TRAILERNUMBER' => $tRAILERNUMBER, - 'PACKAGES' => $pACKAGES, - 'DELIVERYNOTEDOC' => $packingList, - 'shipType' => $sHIPTYPE, - 'carrierServiceDescription' => $a42SSVCNAM, - 'modeOfTransport' => $a4SHIPVIA1, - 'COMMODITIES' => $commodities, - 'ENDFLAG' => $endFlag, - ]; - $jSONCoChargeCS = array_merge($jSONCoCharge, $tempClose); - $jSONCS = json_encode($jSONCoChargeCS); - } else { - // Construct Json for CloseShipment With PDF Files - $jSONCS = json_encode([ - 'DIVI' => $aYCO, - 'WHS' => $aYWHS, - 'DELIVERYNO' => $aYMACPKR, - 'PICKLISTSUFFIX' => $aYRLNO, - 'TYPE' => 'CloseShipment', - 'SCAC' => $sCAC, - 'CARRIER' => $cARRIER, - 'TRANSPORTMODE' => $tRANSPORTMODE, - 'SERVICETYPE' => $sERVICETYPE, - 'TRACKINGNUMBER' => $tRACKING, - 'PRONUMBER' => $pRONUMBER, - 'BILLOFLADING' => $bILLOFLADING, - 'TRAILERNUMBER' => $tRAILERNUMBER, - 'PACKAGES' => $pACKAGES, - 'DELIVERYNOTEDOC' => $packingList, - 'ServiceType' => $sHIPTYPE, - 'ServiceLevelCode' => $a42SSVCNAM, - 'TransportationMode' => $a4SHIPVIA1, - 'COMMODITIES' => $commodities, - 'ENDFLAG' => $endFlag, - ]); - } - - // No Errors Proceed in Calling M3 CLose API - if ($errorMsgs == '') { - // Write to Logs Out : Send JSON Request To M3 - $dELIVERYNO = isset($aYMACPKR) ? $aYMACPKR : self::ZERO_PAD; - // dump($dELIVERYNO); - // MAK : Log JSON Manifest # and MACKPKR # - // Log::channel('dailyCron')->info('1 >>> JSON Sent for Manifest: '.$mANIFEST.' ,Macpicker: '.$aYMACPKR); - Log::channel('dailyCron')->info('1 >>> JSON Sent for Manifest: ' . (string) (int) $mANIFEST . ' ,Macpicker: ' . $aYMACPKR); - - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => '', - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-JSN-out', - 'SHDATA' => $jSONCS, - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - - $response = Http::withHeaders([ - 'accept' => self::JSON_CONTENT_TYPE, - 'Content-Type' => self::JSON_CONTENT_TYPE, - 'Connection' => 'close', - ]) - ->withToken($token) - ->withBody($jSONCS, self::JSON_CONTENT_TYPE) - ->timeout(Config::get('arrays.curlTimeOut')) - ->retry(3, 100) - ->post($endPointURL); - - $responseStatusCode = $response->getStatusCode(); - $m3SessionId = $response->hasHeader('x-transaction-id') ? '-sessionID:' . $response->header('x-transaction-id') : '-sessionID'; - $responseJSON = $response->getBody()->getContents(); - $jsonSanytized = Helper::sanityzeString($responseJSON); - $responseContents = json_decode($jsonSanytized); - - // MAK : Add response Time - // $M3ResponseTimeTmp = $response->hasHeader('x-response-time') ? ltrim($response->header('x-response-time'),"-") : ''; - // $M3ResponseTimeTmp2 = $M3ResponseTimeTmp /1000; - // $dateTime = new DateTime(); - // $dateTime->setTimestamp($M3ResponseTimeTmp2); - // // dump( $dateTime->format('d/m/Y H:i:s.v') ); - // $M3ResponseTime = $M3ResponseTimeTmp != '' ? '-M3ResponseTime:' . $dateTime->format('d/m/Y H:i:s.v') : '-M3ResponseTime'; - // // dump($M3ResponseTime); - // $transferStats = $response->transferStats; - // $M3transferTime = $transferStats->getTransferTime()!=null ? "-M3transferTime:".$transferStats->getTransferTime() : "-M3transferTime"; - // dd($M3transferTime); - - // Log M3 response - Log::channel('dailyCron')->info('2 >>> Close API M3 Responded...'); - - if ($responseContents != null && $responseStatusCode == '200') { - $responseMsg = $responseContents->result->CloseShipment; - $m3APIRESULT = $responseMsg->PickingListClose->Result; - - // Check M3 Response for Errors - $responseResult = $responseContents->result; - $m3Errors = Helper::checkM3Errors($responseResult); - - // If you get a successful response, update database file ICM688M1/A4RATEm3=X - // Update ICM688M1 : Change A4RATEM3 - if (count($jSONCoCharge) > 0 && $m3APIRESULT != 'Error') { - DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1') - ->where('A4MACPKR', $aYMACPKR) - ->where('A4CO', $aYCO) - ->where('A4WHS', $aYWHS) - ->update(['A4RATEM3' => 'X', 'A4PICKSTS' => 'A']); - } elseif (count($jSONCoCharge) == 0 && $m3APIRESULT != 'Error') { - // Update ICM688M1 : Change A4RATEM3 - DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1') - ->where('A4MACPKR', $aYMACPKR) - ->where('A4CO', $aYCO) - ->where('A4WHS', $aYWHS) - ->update(['A4PICKSTS' => 'A']); - } - } else { - $m3APIRESULT = 'Error'; - $responseMsg = self::NULL_M3_RESPONSE; - $responseResult = ''; - $m3Errors = $responseStatusCode; - } - - // If you get a successful response - if ($m3APIRESULT != 'Error') { - // Write to Logs Out : Success - $dELIVERYNO = isset($aYMACPKR) ? $aYMACPKR : self::ZERO_PAD; - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => '', - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-Res-out', - 'SHDATA' => 'Success...' . json_encode($responseResult) . $m3SessionId, - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - } - // If you get a failure, write a record to ICM699M to indicate that the CLOSE API call failed - else { - // Update ICM688M1 : Change A4PICKSTS - DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1') - ->where('A4MACPKR', $aYMACPKR) - ->where('A4CO', $aYCO) - ->where('A4WHS', $aYWHS) - ->update(['A4PICKSTS' => 'a']); - - // Write to Logs Out : Error - $dELIVERYNO = isset($aYMACPKR) ? $aYMACPKR : self::ZERO_PAD; - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => 'X', - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-Res-out', - 'SHDATA' => 'Important-Error: ' . $m3Errors . json_encode($responseMsg) . $m3SessionId, - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - - // Add Message - $errorMsgs = $errorMsgs . $m3Errors . ' '; - } - } - // Errors found Log to ICM699M and update A4PICKSTS - else { - // Write to Logs : Error - // Clear Duplicate messages - $errorMsgsC = Helper::removeDuplicateSubstrings($errorMsgs); - $dELIVERYNO = isset($aYMACPKR) ? $aYMACPKR : self::ZERO_PAD; - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => 'X', - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-Res-out', - 'SHDATA' => $errorMsgsC, - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - } - } - $allErrMsgs = $allErrMsgs . $errorMsgs; - } - - // Update ICM699M : Look for CommTCP_read and set SHERROR to Z Case # 580 - $sHACKNOTE = 'Sentinel automatically closed the error (false positive CommTCP_read)'; - DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') - ->where('SHMACPKR', $aYMACPKR) - ->where('SHCO', $cOMPANY) - ->where('SHWHS', $wHS) - ->where('SHSOURCE', $sHSOURCE) - ->where('SHERROR', 'X') - ->where('SHTYPE', 'M3-General') - ->where('SHDATA', 'like', '%CommTCP_read%') - ->update(['SHERROR' => 'Z', 'SHACKUSER' => $sHUSER, 'SHACKDATE' => date('Y-m-d'), 'SHACKTIME' => date('H:i:s'), 'SHACKNOTE' => $sHACKNOTE]); - - // Update ICM705M1 to say that we have processed this manifest (set APSPARE2='X' ) - if ($tRANSTYPE == 'M') { - DB::connection(config('m3.connection', 'pgsql'))->table('icm705m1') - ->where('APMANIFEST', $mANIFEST) - ->where('APCO', $cOMPANY) - ->where('APWHS', $wHS) - ->update(['APSPARE2' => 'X']); - } - - // Send Response - if ($allErrMsgs == '') { - return response()->json([ - 'code' => '200', - 'status' => 'Success', - 'message' => 'All Operations Successful', - ]); - } else { - $allErrMsgsC = Helper::removeDuplicateSubstrings($allErrMsgs); - - return response()->json([ - 'code' => '206', - 'status' => 'Success With Warnings', - 'message' => $allErrMsgsC . '; Check Transaction Logs for Errors or Warnings.', - ]); - } - - } - // Close Shipment for Zero Picks - elseif (count($iCM695M1TMP) > 0 && $tRANSTYPE == 'Z') { - $errorMsgs = ''; - - foreach ($iCM695M1TMP as $ICM695M1JOINR) { - $sHIPTYPE = trim($ICM695M1JOINR->A4SHIPTYPE); - $fREIGHTTERMS = trim($ICM695M1JOINR->A4OFSTRM); - $a4RATEM3 = trim($ICM695M1JOINR->A4RATEM3); - $fREIGHT = trim($ICM695M1JOINR->A4RATETCP); - $a4REFORD = trim($ICM695M1JOINR->A4REFORD); - $a4ONO = trim($ICM695M1JOINR->A4ONO); - $aYMACPKR = trim($ICM695M1JOINR->A4MACPKR); - $aYWHS = trim($ICM695M1JOINR->A4WHS); - $aYCO = trim($ICM695M1JOINR->A4CO); - - // Construct Json for CloseShipment Without PDF Files - $jSONCS = json_encode([ - 'DIVI' => $aYCO, - 'WHS' => $aYWHS, - 'DELIVERYNO' => $aYMACPKR, - 'TYPE' => 'CloseShipment', - 'PICKLISTSUFFIX' => '1', - 'ENDFLAG' => '1', - ]); - - // Write to Logs Out : JSON Request To M3 - $dELIVERYNO = isset($aYMACPKR) ? $aYMACPKR : self::ZERO_PAD; - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => '', - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-JSN-out', - 'SHDATA' => $jSONCS, - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - - $response = Http::withHeaders([ - 'accept' => self::JSON_CONTENT_TYPE, - 'Content-Type' => self::JSON_CONTENT_TYPE, - 'Connection' => 'close', - ]) - ->withToken($token) - ->withBody($jSONCS, self::JSON_CONTENT_TYPE) - ->timeout(Config::get('arrays.curlTimeOut')) - ->retry(2, 100) - ->post($endPointURL); - - $responseContents = json_decode($response->getBody()->getContents()); - $m3SessionId = $response->hasHeader('x-transaction-id') ? '-sessionID:' . $response->header('x-transaction-id') : '-sessionID'; - $m3Errors = ''; - - if ($responseContents != null) { - $responseMsg = $responseContents->result->CloseShipment; - $m3APIRESULT = $responseMsg->PickingListClose->Result; - - // Check M3 Response for Errors - $responseResult = $responseContents->result; - $m3Errors = Helper::checkM3Errors($responseResult); - - // If you get a successful response, update database file ICM688M1/A4PICKSTS=A - if ($m3APIRESULT != 'Error') { - // Update ICM688M1 : Change A4RATEM3 - DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1') - ->where('A4MACPKR', $aYMACPKR) - ->where('A4CO', $aYCO) - ->where('A4WHS', $aYWHS) - ->where('A4PICKSTS', '!=', 'X') - ->update(['A4PICKSTS' => 'A']); - } - - } else { - $m3APIRESULT = 'Error'; - $responseMsg = self::NULL_M3_RESPONSE; - } - - // If you get a successful response - if ($m3APIRESULT != 'Error') { - // Write to Logs Out : Success - $dELIVERYNO = isset($aYMACPKR) ? $aYMACPKR : self::ZERO_PAD; - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => '', - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-Res-out', - 'SHDATA' => 'Success' . $m3SessionId, - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - } - // If you get a failure, write a record to ICM699M to indicate that the CLOSE API call failed - else { - // Update ICM688M1 : Change A4PICKSTS - DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1') - ->where('A4MACPKR', $aYMACPKR) - ->where('A4CO', $aYCO) - ->where('A4WHS', $aYWHS) - ->where('A4PICKSTS', '!=', 'X') - ->update(['A4PICKSTS' => 'a']); - - // Write to Logs Out : Error - $dELIVERYNO = isset($aYMACPKR) ? $aYMACPKR : self::ZERO_PAD; - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => 'X', - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-Res-out', - 'SHDATA' => 'Important-Error: ' . $m3Errors . json_encode($responseMsg) . $m3SessionId, - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - // Add Message - $errorMsgs = $errorMsgs . $m3Errors . '-'; - } - - // Update ICM699M : Look for CommTCP_read and set SHERROR to Z Case # 580 - $sHACKNOTE = 'Sentinel automatically closed the error (false positive CommTCP_read)'; - DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') - ->where('SHMACPKR', $aYMACPKR) - ->where('SHCO', $cOMPANY) - ->where('SHWHS', $wHS) - ->where('SHSOURCE', $sHSOURCE) - ->where('SHERROR', 'X') - ->where('SHTYPE', 'M3-General') - ->where('SHDATA', 'like', '%CommTCP_read%') - ->update(['SHERROR' => 'Z', 'SHACKUSER' => $sHUSER, 'SHACKDATE' => date('Y-m-d'), 'SHACKTIME' => date('H:i:s'), 'SHACKNOTE' => $sHACKNOTE]); - } - - // Send Response - if ($errorMsgs == '') { - return response()->json([ - 'code' => '200', - 'status' => 'Success', - 'message' => 'All Operations Successful', - ]); - } else { - return response()->json([ - 'code' => '206', - 'status' => 'Success With Warnings', - 'message' => $errorMsgs . '; Check The Logs for Errors or Warnings.', - ]); - } - } - // ## End Zero Pick - else { - $dELIVERYNO = isset($mANIFEST) ? $mANIFEST : self::ZERO_PAD; - // # Set SHDATA Message - $sHDATAMSG = 'No records found in ICM695M1,or URL parameters incomplete'; - // count($iCM695M1TMP)==0 ? 'MacPkr already closed' : - $sHERROR = 'X'; - // count($iCM695M1TMP)==0 ? 'Z' : - - // Write to Logs Out : Error - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => $sHERROR, - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-Req-out', - 'SHDATA' => $sHDATAMSG, - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - - // Return Error - return response()->json([ - 'code' => '405', - 'status' => 'Error', - 'message' => 'No records found in ICM695M1,or URL parameters incomplete For MacPkr/Manifest:' . $dELIVERYNO, - ]); - } - } else { - // Write to Logs Out : Error - $dELIVERYNO = isset($aYMACPKR) ? $aYMACPKR : self::ZERO_PAD; - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => 'X', - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-Res-out', - 'SHDATA' => 'No URL Parameters Sent', - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - - // Return Error - return response()->json([ - 'code' => '405', - 'status' => 'Error', - 'message' => 'No URL Parameters Sent', - ]); - } - } catch (\Throwable $th) { - $getCurlErrors = str_contains($th->getMessage(), 'cURL error'); - if ($getCurlErrors) { - // dd($getCurlErrors); - // Write to Logs Out : Failed - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => 'X', - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-Res-out', - 'SHDATA' => 'Curl Error: Communication with M3 Timed Out' . ' M3-JSN-out' . $jSONIN, - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - - return response()->json([ - 'code' => '405', - 'status' => 'error', - 'message' => 'Curl Error: Communication with M3 Timed Out.', - ]); - } else { - // Write to Logs Out : Error - $dELIVERYNO = isset($aYMACPKR) ? $aYMACPKR : self::ZERO_PAD; - $data = [ - 'SHMACPKR' => $dELIVERYNO, - 'SHDT' => date('Y-m-d'), - 'SHTIME' => date('H:i:s'), - 'SHERROR' => 'X', - 'SHINTBOX' => '', - 'SHTYPE' => 'M3-Res-out', - 'SHDATA' => 'An Error Occured - ' . substr($th, 0, 300), - 'SHUSER' => $sHUSER, - 'SHSOURCE' => $sHSOURCE, - 'SHCO' => $cOMPANY, - 'SHWHS' => $wHS, - ]; - Helper::logToICM699M($data); - Log::error($th); - - return response()->json([ - 'code' => '405', - 'status' => 'error', - 'message' => 'Catched Error: ' . $th, - ]); - } - } + return (new CloseShipmentProcessor($request))->handle(); } - // End CloseShipmentCoChargeAPI } diff --git a/Modules/M3/Http/Controllers/API/CloseShipmentPackageBuilder.php b/Modules/M3/Http/Controllers/API/CloseShipmentPackageBuilder.php new file mode 100644 index 00000000..c6c52887 --- /dev/null +++ b/Modules/M3/Http/Controllers/API/CloseShipmentPackageBuilder.php @@ -0,0 +1,225 @@ + [], 'errors' => '', 'coCharge' => [], 'details' => []]; + foreach ($this->packageRows($shipment) as $row) { + $details = $this->packageDetails($shipment, $trailer, $row); + $state['errors'] .= $details['errors']; + $state['packages'][] = $details['package']; + $state['details'] = $details; + $state['coCharge'] = $this->coCharge($details); + } + + return $state; + } + + public function closeShipmentJson(array $shipment, array $trailer, array $state, int $endFlag): string + { + $details = $state['details']; + $payload = [ + 'DIVI' => $shipment['company'], 'WHS' => $shipment['whs'], 'DELIVERYNO' => $shipment['delivery'], + 'PICKLISTSUFFIX' => $shipment['release'], 'TYPE' => 'CloseShipment', 'SCAC' => $details['scac'], + 'CARRIER' => $details['carrier'], 'TRANSPORTMODE' => $details['transportMode'], + 'SERVICETYPE' => $details['serviceType'], 'TRACKINGNUMBER' => $details['tracking'], + 'PRONUMBER' => $trailer['pro'], 'BILLOFLADING' => $details['bol'], 'TRAILERNUMBER' => $trailer['trailer'], + 'PACKAGES' => $state['packages'], 'DELIVERYNOTEDOC' => $this->documentUrl('PackingList', $shipment['delivery'], $shipment['delivery']), + 'COMMODITIES' => $details['commodities']['value'], 'ENDFLAG' => $endFlag, + ]; + $serviceFields = $state['coCharge'] !== [] + ? ['shipType' => $details['shipType'], 'carrierServiceDescription' => $details['serviceName'], 'modeOfTransport' => $details['shipVia1']] + : ['ServiceType' => $details['shipType'], 'ServiceLevelCode' => $details['serviceName'], 'TransportationMode' => $details['shipVia1']]; + + return json_encode(array_merge($state['coCharge'], $payload, $serviceFields)); + } + + private function packageRows(array $shipment) + { + return DB::connection(config('m3.connection', 'pgsql'))->table('icm695m1') + ->selectRaw('AYMACPKR,AYINTBOX,AYHEIGHT,AYWIDTH,AYDEPTH,AYTYPE,AYLNWGHT,AYID,AYSPR1A01,TRIM(AYSPR15A01) AS SCAC,TRIM(AYSPR30A01) AS TRACKING,AYTRUCK AS AGGREGATION,A4RATETCP AS FREIGHT,A4OFSTRM AS FREIGHTTERMS,A4RATEM3,A4CLOSEM3,A4SHIPTYPE,A4REFORD,A4ONO,A4SHIPVIA,A42SSVCNAM,A4SHIPVIA1') + ->leftJoin('ICM688M1', function ($join) { + $join->on('AYCO', '=', 'A4CO')->on('AYWHS', '=', 'A4WHS')->on('AYMACPKR', '=', 'A4MACPKR'); + }) + ->where('AYMACPKR', $shipment['delivery'])->where('AYCO', $shipment['company']) + ->where('AYWHS', $shipment['whs'])->orderBy('AYINTBOX')->get(); + } + + private function packageDetails(array $shipment, array $trailer, object $row): array + { + $details = $this->rowDetails($row); + $details['carrier'] = $this->carrierName($details['scac']); + $details['bol'] = $details['scac'] === 'RETR' ? $trailer['pro'] : $details['bol']; + $details['errors'] = $this->shippingErrors($details, $trailer['pro']); + $details['errors'] .= $this->previousTransmissionError($shipment); + $details['bundle'] = $this->bundleType($details['bundle'], $row); + $details['commodities'] = $this->commodities($shipment['delivery'], $details['errors']); + $details['errors'] = $details['commodities']['errors']; + if ($details['billable'] === 'Y' && (float) $details['freight'] == 0 && $details['rateM3'] === '') { + $details['errors'] .= ' Please manually add a freight charge for this Prepaid and Add order; '; + } + $labels = $this->labels($shipment, $details['box'], $details['gs1Required']); + $details['errors'] .= $labels['error']; + $details['package'] = $this->packageArray($details, $labels); + + return $details; + } + + private function rowDetails(object $row): array + { + $freightTerms = trim($row->FREIGHTTERMS); + $currentFreightTerms = $this->freightTerms->where('FREIGHTTERMS', $freightTerms)->first(); + + return [ + 'shipType' => trim($row->A4SHIPTYPE), 'serviceName' => trim($row->A42SSVCNAM), + 'shipVia1' => trim($row->A4SHIPVIA1), 'freightTerms' => $freightTerms, + 'rateM3' => trim($row->A4RATEM3), 'freight' => trim($row->FREIGHT), + 'refOrder' => trim($row->A4REFORD), 'orderNo' => trim($row->A4ONO), + 'delivery' => trim($row->AYMACPKR), 'box' => trim($row->AYINTBOX), + 'tracking' => trim($row->TRACKING), 'scac' => trim($row->SCAC), + 'bundle' => trim($row->AYID) !== '' ? trim($row->AYID) : '', + 'weight' => trim($row->AYLNWGHT), 'height' => trim($row->AYHEIGHT), + 'width' => trim($row->AYWIDTH), 'depth' => trim($row->AYDEPTH), + 'bol' => isset($row->AYSPR1A01) ? trim($row->AYSPR1A01) : '', + 'transportMode' => trim(str_replace('&', '_', $row->A4SHIPVIA ?? '')), + 'serviceType' => trim(str_replace('&', '_', $row->A4SHIPVIA ?? '')), + 'billable' => isset($currentFreightTerms->BILLABLE) ? trim($currentFreightTerms->BILLABLE) : 'N', + 'gs1Required' => $this->gs1Required($row), 'errors' => '', + ]; + } + + private function shippingErrors(array $details, string $proNumber): string + { + $missingTracking = $details['scac'] === '' || $details['tracking'] === ''; + $missingLtl = $details['shipType'] === 'LTL' && ($missingTracking || $details['bol'] === ''); + $errors = ($missingTracking || $missingLtl) + ? " Missing one or more of tracking number, BOL, or carrier. Please enter this data manually in 'invoicing' screen and retry this API call;" + : ''; + + if ($proNumber === '' && $details['scac'] === 'RETR') { + $errors .= ' Missing PARS info for this RETRans order. Please contact MPBA to ask them to enter the value for you, and then you can retry; '; + } + return $errors; + } + + private function carrierName(string $scac): string + { + if ($scac === '') { + return ''; + } + $row = DB::connection(config('m3.connection', 'pgsql'))->table('icm160m') + ->select('CANAM')->where('CANUM', substr($scac, 0, 4))->where('CACO', $this->context['company'])->first(); + + return isset($row->CANAM) ? trim(str_replace('&', '_', $row->CANAM)) : ''; + } + + private function previousTransmissionError(array $shipment): string + { + $row = DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') + ->select('SHMACPKR')->where('SHMACPKR', $shipment['delivery']) + ->where('SHCO', $shipment['company'])->where('SHWHS', $shipment['whs']) + ->whereIn('SHSOURCE', ['TransferAPIURL', 'CloseShipmentCoChargeAPI', 'PackSyst4tray']) + ->where('SHERROR', 'X')->whereIn('SHTYPE', ['M3-Res-out', 'M3-QtyChg'])->first(); + + return isset($row->SHMACPKR) + ? ' There are previous M3 transmissions in error for this delivery note that have not been addressed; ' + : ''; + } + + private function bundleType(string $bundle, object $row): string + { + if ($bundle !== '') { + return $bundle; + } + $record = DB::connection(config('m3.connection', 'pgsql'))->table('icm693m') + ->select('AEID')->where('AESPR1A01', 'D')->where('AETYPE', trim($row->AYTYPE))->first(); + + return isset($record->AEID) ? trim($record->AEID) : ''; + } + + private function commodities(string $delivery, string $errors): array + { + $request = new Request; + $request->setMethod('POST'); + $request->request->add(['MACPKR' => $delivery]); + $responseData = (new GetContentsController)->processShipment($request)->getData(); + $commodities = empty($responseData->error) ? ($responseData->commodities ?? '') : ''; + + return ['value' => $commodities, 'errors' => $commodities !== '' ? $errors : $errors . ' Could not find Commodities; ']; + } + + private function labels(array $shipment, string $box, bool $gs1Required): array + { + $carrier = $this->documentUrl('CarrierLabel', $shipment['delivery'], $box); + $content = $this->documentUrl('ContentLabel', $shipment['delivery'], $box); + $gs1 = ''; + if ($gs1Required) { + $row = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m3') + ->select('A2GS1LABEL')->where('A2CO', $shipment['company'])->where('A2WHS', $shipment['whs']) + ->where('A2INTBOX', $box)->first(); + $gs1 = isset($row->A2GS1LABEL) ? trim($row->A2GS1LABEL) : ''; + } + + return [ + 'carrier' => $carrier, 'content' => $content, 'gs1' => $gs1, + 'error' => $gs1Required && $gs1 === '' + ? ' Missing G1-128 Label. Please contact MPBA to ask them to enter the value for you, and then you can retry; ' + : '', + ]; + } + + private function documentUrl(string $type, string $delivery, string $documentNumber): string + { + $key = $type . '/' . $type . '_' . $delivery . '_' . $documentNumber . '_' . $this->context['company'] . '_' . $this->context['whs']; + if (! File::exists(Config::get('arrays.PdfPath') . $key . '.pdf')) { + return ''; + } + + return route('m3.M3GetPDFFromCache.index', ['MACPKR' => $delivery, 'DOCTYPE' => $type]); + } + + private function gs1Required(object $row): bool + { + $record = DB::connection(config('m3.connection', 'pgsql'))->table('icm666m') + ->select('A1SPR1A01')->where('A1CO', $this->context['company'])->where('A1WHS', $this->context['whs']) + ->where('A1DELNO', trim($row->AYMACPKR))->first(); + + return (int) ($record->A1SPR1A01 ?? 0) === 1; + } + + private function packageArray(array $details, array $labels): array + { + return [ + 'TRACKINGID' => $details['tracking'], 'BUNDLES' => $details['bundle'], + 'WEIGHT' => $details['weight'], 'HEIGHT' => $details['height'], 'WIDTH' => $details['width'], + 'LENGTH' => $details['depth'], 'SSCC' => $labels['gs1'], + 'SHIPLABELDOC' => $labels['carrier'], 'CONTENTLABELDOC' => $labels['content'], + ]; + } + + private function coCharge(array $details): array + { + if ($details['billable'] !== 'Y' || (float) $details['freight'] <= 0 || $details['rateM3'] !== '') { + return []; + } + $discountKey = $details['shipType'] === 'LTL' + ? 'arrays.misc.discountCarrierRateForCustomerPriceLTL' + : 'arrays.misc.discountCarrierRateForCustomerPriceParcel'; + $shippingToBill = (float) $details['freight'] * (100.00 - Config::get($discountKey)) / 100; + + return ['QUANTITY' => round($shippingToBill, 2), 'ORDERCATEGORY' => $details['refOrder'], 'CONUMBER' => $details['orderNo']]; + } +} diff --git a/Modules/M3/Http/Controllers/API/CloseShipmentProcessor.php b/Modules/M3/Http/Controllers/API/CloseShipmentProcessor.php new file mode 100644 index 00000000..6b1e93e2 --- /dev/null +++ b/Modules/M3/Http/Controllers/API/CloseShipmentProcessor.php @@ -0,0 +1,258 @@ +context = $this->makeContext(); + } + + public function handle() + { + try { + return $this->process(); + } catch (Throwable $throwable) { + return $this->exceptionResponse($throwable); + } + } + + private function process() + { + if ($this->context['params'] === []) { + $this->log('M3-Res-out', 'No URL Parameters Sent', 'X'); + + return response()->json([ + 'code' => '405', + 'status' => 'Error', + 'message' => 'No URL Parameters Sent', + ]); + } + + $this->logInitialRequest(); + $tokenResult = $this->receiveToken(); + if ($tokenResult['response'] !== null) { + return $tokenResult['response']; + } + + $shipments = $this->loadShipments(); + $shipments = $this->removeAlreadyClosed($shipments); + $freightTerms = DB::connection(config('m3.connection', 'pgsql'))->table('icm321m') + ->selectRaw('TRIM(ARCODE) as FREIGHTTERMS,ARCHARGE as BILLABLE') + ->get(); + + return $this->dispatchShipments($shipments, $freightTerms, $tokenResult['token']); + } + + private function makeContext(): array + { + $params = $this->request->all(); + $manifest = (string) ($params['MANIFEST'] ?? ''); + $transType = (string) ($params['TRANSTYPE'] ?? 'M'); + + return [ + 'params' => $params, + 'whs' => (string) ($params['WHS'] ?? ''), + 'company' => (string) ($params['COMPANY'] ?? ''), + 'manifest' => $manifest, + 'transType' => $transType !== '' ? $transType : 'M', + 'shdt' => (string) ($params['SHDT'] ?? ''), + 'shtime' => (string) ($params['SHTIME'] ?? ''), + 'shtype' => (string) ($params['SHTYPE'] ?? ''), + 'user' => m3_user() !== '' ? Str::upper(m3_user()) : 'WebUser', + 'delivery' => $manifest !== '' ? $manifest : self::ZERO_PAD, + 'jsonIn' => '', + ]; + } + + private function logInitialRequest(): void + { + $this->context['jsonIn'] = json_encode([ + 'WHS' => $this->context['whs'], + 'COMPANY' => $this->context['company'], + 'MANIFEST-MACPKR' => $this->context['manifest'], + 'TRANSTYPE' => $this->context['transType'], + ]); + $this->log('M3-Req-out', $this->context['jsonIn']); + } + + private function receiveToken(): array + { + $response = Helper::checkReceiveTokenV2(); + $data = $response->getData(); + if ((string) ($data->code ?? '') === '200') { + return ['token' => (string) ($data->token ?? ''), 'response' => null]; + } + + $this->log('M3-Res-out', (string) ($data->message ?? ''), 'X'); + + return ['token' => '', 'response' => $response]; + } + + private function loadShipments() + { + $type = $this->context['transType']; + if (! in_array($type, ['M', 'P', 'Z'], true)) { + return collect(); + } + if ($type === 'P') { + $this->acknowledgeRetry(); + } + + $query = $type === 'Z' ? $this->zeroPickQuery() : $this->standardShipmentQuery($type); + + return $query->get(); + } + + private function standardShipmentQuery(string $type) + { + $query = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m1') + ->select('AYCO', 'AYWHS', 'AYMACPKR', 'AYRLNO', 'AYAPRF1551') + ->distinct() + ->where('AYCO', $this->context['company']) + ->where('AYWHS', $this->context['whs']) + ->orderBy('AYMACPKR'); + + $field = $type === 'P' ? 'AYMACPKR' : 'AYAPRF1551'; + + return $query->where($field, $this->context['manifest']); + } + + private function zeroPickQuery() + { + return DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1') + ->select()->distinct() + ->where('A4CO', $this->context['company']) + ->where('A4WHS', $this->context['whs']) + ->where('A4MACPKR', $this->context['manifest']) + ->orderBy('A4MACPKR'); + } + + private function acknowledgeRetry(): void + { + if ($this->context['shdt'] !== '' && $this->context['shtime'] !== '' && $this->context['shtype'] !== '') { + DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') + ->where('SHMACPKR', $this->context['manifest']) + ->where('SHDT', $this->context['shdt'])->where('SHTIME', $this->context['shtime']) + ->where('SHCO', $this->context['company'])->where('SHWHS', $this->context['whs']) + ->where('SHSOURCE', self::SOURCE)->where('SHERROR', 'X') + ->where('SHTYPE', $this->context['shtype']) + ->update($this->acknowledgementValues()); + } + + $this->context['lineAck'] = $this->acknowledgedLines(); + } + + private function acknowledgedLines(): array + { + $rows = DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') + ->where('SHMACPKR', $this->context['manifest']) + ->where('SHCO', $this->context['company'])->where('SHWHS', $this->context['whs']) + ->where('SHSOURCE', 'PackSyst4tray')->where('SHERROR', 'Z')->where('SHTYPE', 'M3-QtyChg') + ->get(); + + return $rows->map(fn ($row) => Helper::getSubstringBetween($row->SHDATA, 'PickerLine:', ' -'))->all(); + } + + private function removeAlreadyClosed($shipments) + { + $field = $this->context['transType'] === 'Z' ? 'A4MACPKR' : 'AYMACPKR'; + $deliveryNumbers = $shipments->map(fn ($row) => trim($row->{$field}))->all(); + if ($deliveryNumbers === []) { + return $shipments; + } + + $closed = DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') + ->whereIn('SHMACPKR', $deliveryNumbers) + ->where('SHCO', $this->context['company'])->where('SHWHS', $this->context['whs']) + ->where('SHSOURCE', self::SOURCE)->where('SHERROR', '') + ->where('SHTYPE', 'M3-Res-out')->where('SHDATA', 'like', '%Success%') + ->pluck('SHMACPKR')->all(); + + return $shipments->reject(fn ($row) => in_array($row->{$field}, $closed)); + } + + private function dispatchShipments($shipments, $freightTerms, string $token) + { + if ($shipments->isEmpty()) { + return $this->noRecordsResponse(); + } + + if ($this->context['transType'] === 'Z') { + return (new CloseShipmentZeroPickProcessor($this->context, $token))->process($shipments); + } + + return (new CloseShipmentStandardProcessor($this->context, $token, $freightTerms))->process($shipments); + } + + private function noRecordsResponse() + { + $delivery = $this->context['manifest'] !== '' ? $this->context['manifest'] : self::ZERO_PAD; + $this->context['delivery'] = $delivery; + $message = 'No records found in ICM695M1,or URL parameters incomplete'; + $this->log('M3-Req-out', $message, 'X'); + + return response()->json([ + 'code' => '405', + 'status' => 'Error', + 'message' => $message . ' For MacPkr/Manifest:' . $delivery, + ]); + } + + private function exceptionResponse(Throwable $throwable) + { + $isCurlError = str_contains($throwable->getMessage(), 'cURL error'); + $message = $isCurlError + ? 'Curl Error: Communication with M3 Timed Out' + : 'An Error Occured - ' . substr((string) $throwable, 0, 300); + $this->log('M3-Res-out', $message . ($isCurlError ? ' M3-JSN-out' . $this->context['jsonIn'] : ''), 'X'); + + if (! $isCurlError) { + Log::error($throwable); + } + + return response()->json([ + 'code' => '405', + 'status' => 'error', + 'message' => $isCurlError ? $message . '.' : 'Catched Error: ' . $throwable, + ]); + } + + private function log(string $type, string $message, string $error = ''): void + { + Helper::logToICM699M([ + 'SHMACPKR' => $this->context['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'], + ]); + } + + private function acknowledgementValues(): array + { + return [ + 'SHERROR' => 'Z', 'SHACKUSER' => $this->context['user'], + 'SHACKDATE' => date('Y-m-d'), 'SHACKTIME' => date('H:i:s'), + ]; + } +} diff --git a/Modules/M3/Http/Controllers/API/CloseShipmentStandardProcessor.php b/Modules/M3/Http/Controllers/API/CloseShipmentStandardProcessor.php new file mode 100644 index 00000000..3dfcc6d1 --- /dev/null +++ b/Modules/M3/Http/Controllers/API/CloseShipmentStandardProcessor.php @@ -0,0 +1,207 @@ +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'], + ]); + } +} diff --git a/Modules/M3/Http/Controllers/API/CloseShipmentZeroPickProcessor.php b/Modules/M3/Http/Controllers/API/CloseShipmentZeroPickProcessor.php new file mode 100644 index 00000000..4162d986 --- /dev/null +++ b/Modules/M3/Http/Controllers/API/CloseShipmentZeroPickProcessor.php @@ -0,0 +1,133 @@ +shipmentContext($row); + $errors .= $this->closeShipment($shipment); + $this->closeFalsePositiveErrors($shipment); + } + + return $this->resultResponse($errors); + } + + private function shipmentContext(object $row): array + { + return [ + 'delivery' => trim($row->A4MACPKR), + 'whs' => trim($row->A4WHS), + 'company' => trim($row->A4CO), + ]; + } + + private function closeShipment(array $shipment): string + { + $json = json_encode([ + 'DIVI' => $shipment['company'], 'WHS' => $shipment['whs'], + 'DELIVERYNO' => $shipment['delivery'], 'TYPE' => 'CloseShipment', + 'PICKLISTSUFFIX' => '1', 'ENDFLAG' => '1', + ]); + $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(2, 100) + ->post(env('ENDPOINTURL') . 'APIFLOWS/Sentinel/TransferAPI?ionapiRespStyle=sync'); + $result = $this->parseResponse($response, $shipment); + + if ($result['success']) { + $this->log($shipment, 'M3-Res-out', 'Success' . $result['session']); + + return ''; + } + + $this->markFailed($shipment); + $this->log($shipment, 'M3-Res-out', 'Important-Error: ' . $result['errors'] . json_encode($result['message']) . $result['session'], 'X'); + + return $result['errors'] . '-'; + } + + private function parseResponse($response, array $shipment): array + { + $contents = json_decode($response->getBody()->getContents()); + $session = $response->hasHeader('x-transaction-id') ? '-sessionID:' . $response->header('x-transaction-id') : '-sessionID'; + if ($contents === null) { + return ['success' => false, 'message' => self::NULL_M3_RESPONSE, 'errors' => '', 'session' => $session]; + } + + $message = $contents->result->CloseShipment; + $apiResult = $message->PickingListClose->Result; + $errors = Helper::checkM3Errors($contents->result); + if ($apiResult !== 'Error') { + $this->markSuccessful($shipment); + } + + return ['success' => $apiResult !== 'Error', 'message' => $message, 'errors' => $errors, 'session' => $session]; + } + + private function markSuccessful(array $shipment): void + { + DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1') + ->where('A4MACPKR', $shipment['delivery'])->where('A4CO', $shipment['company']) + ->where('A4WHS', $shipment['whs'])->where('A4PICKSTS', '!=', 'X')->update(['A4PICKSTS' => 'A']); + } + + private function markFailed(array $shipment): void + { + DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1') + ->where('A4MACPKR', $shipment['delivery'])->where('A4CO', $shipment['company']) + ->where('A4WHS', $shipment['whs'])->where('A4PICKSTS', '!=', 'X')->update(['A4PICKSTS' => 'a']); + } + + private function closeFalsePositiveErrors(array $shipment): void + { + DB::connection(config('m3.connection', 'pgsql'))->table('icm699m') + ->where('SHMACPKR', $shipment['delivery'])->where('SHCO', $shipment['company']) + ->where('SHWHS', $shipment['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 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' => $errors . '; Check The 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' => $shipment['company'], 'SHWHS' => $shipment['whs'], + ]); + } +}