Files
WMS/Modules/M3/Http/Controllers/API/TransferAPI.php
T

306 lines
14 KiB
PHP
Executable File

<?php
namespace Modules\M3\Http\Controllers\API;
use Config;
use DateTime;
use DB;
use Http;
use Illuminate\Http\Request;
use Log;
use Modules\M3\Helpers\Helper;
use Modules\M3\Http\Controllers\Controller;
use Str;
class TransferAPI extends Controller
{
use TransferApiSupport;
private const ZERO_PAD = '000000';
private const JSON_CONTENT_TYPE = 'application/json';
private const ORDER_CATEGORY_LABEL = ' Order Category: ';
private const NO_URL_PARAMETERS = 'No URL Parameters Sent';
public function TransferAPIURL(Request $request)
{
$this->configureTimeouts();
$context = $this->transferContext($request);
try {
$response = $this->processTransfer($context);
} catch (\Throwable $throwable) {
$response = $this->exceptionResponse($context, $throwable, $context['json_in'] ?? '');
}
return $response;
}
public function UpdateShipmentNumber(Request $request)
{
$this->configureTimeouts();
$context = $this->shipmentContext($request);
try {
$response = $this->processShipmentUpdate($context);
} catch (\Throwable $throwable) {
$response = $this->exceptionResponse($context, $throwable, $context['json'] ?? '');
}
return $response;
}
private function transferContext(Request $request): array
{
$params = $request->all();
return [
'params' => $params,
'user' => m3User() !== '' ? Str::upper(m3User()) : 'WebUser',
'source' => 'TransferAPIURL',
'company' => $params['COMPANY'] ?? '',
'warehouse' => $params['WHS'] ?? '',
'delivery' => $params['DELIVERYNO'] ?? self::ZERO_PAD,
];
}
private function shipmentContext(Request $request): array
{
$params = $request->all();
return [
'params' => $params,
'user' => m3User() !== '' ? Str::upper(m3User()) : 'WebUser',
'source' => 'UpdateShipmentNumber',
'company' => $params['COMPANY'] ?? '',
'warehouse' => $params['WHS'] ?? '',
'plant' => $params['PLANT'] ?? '',
'delivery' => $params['DELIVERYNO'] ?? '',
];
}
private function processTransfer(array &$context)
{
if ($context['params'] === []) {
$this->log($context, self::NO_URL_PARAMETERS, 'X', 'M3-Res-out');
return $this->errorResponse('405', self::NO_URL_PARAMETERS);
}
$context = array_merge($context, $this->transferFields($context['params']));
$this->restoreRetryPayload($context);
if ($context['part'] === '') {
return $this->errorResponse('405', 'Json Payload Not Valid, possible cause: Retry butto was clicked by another user.');
}
return $this->executeTransfer($context);
}
private function transferFields(array $params): array
{
return [
'part' => $params['PART'] ?? '', 'from' => $params['LOCATIONFROM'] ?? '',
'to' => $params['LOCATIONTO'] ?? '', 'quantity' => $params['QUANTITY'] ?? '',
'order_category' => $params['ORDERCATEGORY'] ?? '', 'lot' => $params['LOTNUMBER'] ?? '',
'co_number' => $params['CONUMBER'] ?? '', 'co_line' => $params['COLINENO'] ?? '',
'delivery' => $params['DELIVERYNO'] ?? self::ZERO_PAD, 'pick_suffix' => $params['PICKLISTSUFFIX'] ?? '',
'end_flag' => $params['ENDFLAG'] ?? '', 'type' => $params['TYPE'] ?? '',
'co_line_suffix' => $params['COLINESUFFIX'] ?? '', 'trans_type' => $params['TRANSTYPE'] ?? '',
'shdt' => $params['SHDT'] ?? '', 'shtime' => $params['SHTIME'] ?? '', 'shtype' => $params['SHTYPE'] ?? '',
];
}
private function restoreRetryPayload(array &$context): void
{
if ($context['trans_type'] !== 'R') {
return;
}
$record = DB::connection(config('m3.connection', 'pgsql'))->table('icm699m')
->select('SHDATA')->where('SHMACPKR', $context['delivery'])->where('SHDT', $context['shdt'])
->where('SHTIME', $context['shtime'])->where('SHCO', $context['company'])->where('SHWHS', $context['warehouse'])
->where('SHSOURCE', $context['source'])->where('SHERROR', 'X')->where('SHTYPE', $context['shtype'])->first();
$payload = $this->retryPayload($record->SHDATA ?? '');
if ($payload !== []) {
$context = array_merge($context, $this->transferFields($payload));
}
DB::connection(config('m3.connection', 'pgsql'))->table('icm699m')
->where('SHMACPKR', $context['delivery'])->where('SHDT', $context['shdt'])->where('SHTIME', $context['shtime'])
->where('SHCO', $context['company'])->where('SHWHS', $context['warehouse'])->where('SHSOURCE', $context['source'])
->where('SHERROR', 'X')->where('SHTYPE', $context['shtype'])
->update(['SHERROR' => 'Z', 'SHACKUSER' => $context['user'], 'SHACKDATE' => date('Y-m-d'), 'SHACKTIME' => date('H:i:s')]);
}
private function executeTransfer(array &$context)
{
$line = $this->transferLine($context);
$context['brad_line'] = $line->A5BRADLN ?? '';
$context['co_line_suffix'] = $line->A5PKSFX ?? '';
$context['plant'] = $line->A5PLANT ?? '';
$context['sent_picker'] = $line->A5SENTPKR ?? '';
$context['json_in'] = $this->transferJson($context, false);
$json = $this->transferJson($context, true);
$this->log($context, $json, '', 'M3-Req-out');
$token = $this->token($context);
if (! is_string($token)) {
return $token;
}
$result = $this->callM3($token, $json);
return $this->transferResult($context, $result);
}
private function transferLine(array $context): ?object
{
$query = DB::connection(config('m3.connection', 'pgsql'))->table('icm688m2')
->select('A5BRADLN', 'A5PKSFX', 'A5PLANT', 'A5SENTPKR')->distinct()
->where('A5CO', $context['company'])->where('A5WHS', $context['warehouse'])->where('A5MACPKR', $context['delivery']);
if ($context['co_line'] !== '') {
$query->where('A5PKLN', $context['co_line']);
}
return $query->first();
}
private function transferJson(array $c, bool $useBradLine): string
{
return (string) json_encode([
'DIVI' => $c['company'], 'WHS' => $c['warehouse'], 'PART' => $c['part'], 'LOCATIONFROM' => $c['from'],
'LOCATIONTO' => $c['to'], 'QUANTITY' => $c['quantity'], 'ORDERCATEGORY' => $c['order_category'], 'LOTNUMBER' => $c['lot'],
'CONUMBER' => $c['co_number'], 'COLINENO' => $useBradLine ? $c['brad_line'] : $c['co_line'], 'DELIVERYNO' => $c['delivery'],
'PICKLISTSUFFIX' => $c['pick_suffix'], 'ENDFLAG' => $c['end_flag'], 'TYPE' => $c['type'], 'COLINESUFFIX' => $c['co_line_suffix'],
], JSON_UNESCAPED_SLASHES);
}
private function processShipmentUpdate(array &$context)
{
$shipment = $context['params']['A4SPR15A01'] ?? '';
$pickers = $this->shipmentPickers($context, $shipment);
$invalid = $this->shipmentValidationResponse($context, $shipment, $pickers);
if ($invalid !== null) {
return $invalid;
}
$context['type'] = 'UpdateShipmentNumber';
$context['json'] = (string) json_encode([
'DIVI' => $context['company'], 'WHS' => $context['warehouse'],
'ShipmentNumber' => ['Number' => $shipment, 'DeliveryNumbers' => $pickers],
'TYPE' => $context['type'], 'ENDFLAG' => '',
], JSON_UNESCAPED_SLASHES);
$this->log($context, $context['json'], '', 'M3-Req-out');
$token = $this->token($context);
if (! is_string($token)) {
return $token;
}
return $this->shipmentResult($context, $this->callM3($token, $context['json']));
}
private function shipmentValidationResponse(array $context, string $shipment, array $pickers)
{
if ($context['params'] === []) {
$this->log($context, self::NO_URL_PARAMETERS, 'X', 'M3-Res-out');
return $this->errorResponse('405', self::NO_URL_PARAMETERS);
}
if ($shipment === '' || $pickers === []) {
return $this->errorResponse('405', 'Json Payload Not Valid, missing Parameter or no Macpicker # found.');
}
return null;
}
private function shipmentPickers(array $context, string $shipment): array
{
if ($shipment === '') {
return [];
}
$query = DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1')->select('A4MACPKR')
->where('A4CO', $context['company'])->where('A4WHS', $context['warehouse'])->where('A4PLANT', $context['plant'])
->where('A4SPR15A01', $shipment);
if ($context['delivery'] !== '') {
$query->where('A4MACPKR', $context['delivery']);
}
return $query->get()->pluck('A4MACPKR')->all();
}
private function token(array $context)
{
$response = Helper::checkReceiveTokenV2();
$data = $response->getData();
if ((string) ($data->code ?? '') === '200') {
return (string) ($data->token ?? '');
}
$this->log($context, (string) ($data->message ?? ''), '', 'M3-Res-out');
return $response;
}
private function callM3(string $token, string $json): array
{
$response = Http::withHeaders(['accept' => self::JSON_CONTENT_TYPE, 'Content-Type' => self::JSON_CONTENT_TYPE])
->withToken($token)->withBody($json, self::JSON_CONTENT_TYPE)->timeout(Config::get('arrays.curlTimeOut'))
->post(env('ENDPOINTURL') . 'APIFLOWS/Sentinel/TransferAPI?ionapiRespStyle=sync');
$status = $response->getStatusCode();
$jsonResponse = '';
$errors = 'Error: No Response from M3';
if ((string) $status === '200') {
$contents = json_decode($response->getBody()->getContents());
$jsonResponse = json_encode($contents);
$errors = Helper::checkM3Errors($contents->result ?? null);
}
return ['status' => $status, 'json' => $jsonResponse, 'errors' => $errors, 'metrics' => $this->responseMetrics($response)];
}
private function transferResult(array $c, array $result)
{
$prefix = $result['status'] . 'TYPE :' . $c['type'] . self::ORDER_CATEGORY_LABEL . $c['order_category'] . '-';
if ($result['errors'] !== '') {
$this->log($c, $result['status'] . '-' . $result['errors'] . '-TYPE:' . $c['type'] . self::ORDER_CATEGORY_LABEL . $c['order_category'] . '-' . $result['json'] . 'M3-JSN-out' . $c['json_in'] . $result['metrics'], 'X', 'M3-Res-out');
return $this->errorResponse('206', $result['status'] . '-' . $result['errors'] . '- TYPE :' . $c['type'] . self::ORDER_CATEGORY_LABEL . $c['order_category'] . '-' . $result['json']);
}
$this->log($c, $prefix . $result['json'] . $result['metrics'], '', 'M3-Res-out');
$this->insertTransferAudit($c);
return response()->json(['code' => $result['status'], 'status' => 'Success']);
}
private function shipmentResult(array $c, array $result)
{
if ($result['errors'] !== '') {
$this->log($c, $result['status'] . '-' . $result['errors'] . '-TYPE:' . $c['type'] . '-' . $result['json'] . 'M3-JSN-out' . $c['json'] . $result['metrics'], 'X', 'M3-Res-out');
return $this->errorResponse('206', $result['status'] . '-' . $result['errors'] . '- TYPE :' . $c['type'] . '-' . $result['json']);
}
$this->log($c, $result['status'] . 'TYPE :' . $c['type'] . '-' . $result['json'] . $result['metrics'], '', 'M3-Res-out');
return response()->json(['code' => $result['status'], 'status' => 'Success']);
}
private function insertTransferAudit(array $c): void
{
DB::connection(config('m3.connection', 'pgsql'))->table('icm799m')->insert([
'IMDIV' => $c['company'], 'IMPLANT' => $c['plant'], 'IMWHS' => $c['warehouse'], 'IMSENTPKR' => $c['sent_picker'],
'IMDELNO' => $c['delivery'], 'IMORDER' => $c['co_number'], 'IMLINE' => $c['co_line'], 'IMBRADLN' => $c['brad_line'],
'IMSUFFIX' => $c['pick_suffix'], 'IMPART' => $c['part'], 'IMLOT' => $c['lot'], 'IMQTY' => $c['quantity'],
'IMFRLOC' => $c['from'], 'IMTOLOC' => $c['to'], 'IMDATE' => date('Ymd'), 'IMTIME' => date('His'),
]);
}
private function log(array $c, string $message, string $error, string $type): void
{
Helper::logToICM699M([
'SHMACPKR' => $c['delivery'] ?: self::ZERO_PAD, 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'),
'SHERROR' => $error, 'SHINTBOX' => '', 'SHTYPE' => $type, 'SHDATA' => $message,
'SHUSER' => $c['user'], 'SHSOURCE' => $c['source'], 'SHCO' => $c['company'], 'SHWHS' => $c['warehouse'],
]);
}
private function exceptionResponse(array $context, \Throwable $throwable, string $json)
{
if (str_contains($throwable->getMessage(), 'cURL error')) {
$this->log($context, 'Curl Error: Communication with M3 Timed Out M3-JSN-out' . $json, 'X', 'M3-Res-out');
return response()->json(['code' => '405', 'status' => 'error', 'message' => 'Curl Error: Communication with M3 Timed Out.']);
}
$this->log($context, 'An Error Occured - ' . substr((string) $throwable, 0, 300), 'X', 'M3-Err-out');
Log::error($throwable);
return response()->json(['code' => '405', 'status' => 'error', 'message' => 'Uncaught Error']);
}
}