Files
WMS/Modules/M3/Http/Controllers/API/ReplenAPI.php
T
2026-09-21 14:57:06 +01:00

187 lines
8.3 KiB
PHP

<?php
namespace Modules\M3\Http\Controllers\API;
use Config;
use DB;
use Http;
use Illuminate\Http\Request;
use Modules\M3\Helpers\Helper;
use Modules\M3\Http\Controllers\Controller;
use Str;
class ReplenAPI extends Controller
{
private const ZERO_PAD = '000000';
private const JSON_CONTENT_TYPE = 'application/json';
private const SOURCE = 'M3InventoryReportReplen';
public function M3InventoryReportReplen(Request $request)
{
$this->configureTimeouts();
$context = $this->requestContext($request);
try {
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;
}
$result = $this->fetchInventory($context, (string) ($tokenData->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']);
} catch (\Throwable $throwable) {
return $this->exceptionResponse($context, $throwable);
}
}
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'],
]);
}
}