[], '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']]; } }