Compare commits
36
Commits
6d60cbff84
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1a8c0faf0 | ||
|
|
5c6fb470ca | ||
|
|
c5af9eb128 | ||
|
|
14fca2c548 | ||
|
|
f047f7897c | ||
|
|
adf2a45553 | ||
|
|
819d4eab78 | ||
|
|
56954d7a33 | ||
|
|
c878d4e49a | ||
|
|
3c236469e5 | ||
|
|
7765a57e22 | ||
|
|
90e6c80a61 | ||
|
|
5be9e9dbc8 | ||
|
|
e5d6ff68b2 | ||
|
|
17cfcf44b2 | ||
|
|
9f69743dd6 | ||
|
|
4be07c8456 | ||
|
|
9928750bc2 | ||
|
|
dc97598278 | ||
|
|
e4213d1fd6 | ||
|
|
3e714e9568 | ||
|
|
8ed4106ddf | ||
|
|
4108354935 | ||
|
|
bcbdd24f15 | ||
|
|
9167b11f8b | ||
|
|
2242106309 | ||
|
|
66aeefbba5 | ||
|
|
3521e47ef0 | ||
|
|
47085e5160 | ||
|
|
fc7abb3f64 | ||
|
|
e776eb0211 | ||
|
|
9368dd2f10 | ||
|
|
d8d970baad | ||
|
|
8f66223767 | ||
|
|
b849dd766b | ||
|
|
ec01bb75cd |
@@ -39,3 +39,4 @@ composer.lock
|
||||
/storage/framework/
|
||||
/storage/debugbar/
|
||||
/phpunit.dusk.xml
|
||||
sonarqube-issues.csv
|
||||
|
||||
Executable → Regular
+4
-3
@@ -215,7 +215,8 @@
|
||||
</div>
|
||||
<form method="POST" action="{{ route('platform.companies.warehouses.division.update', [$company, $warehouse]) }}" class="contents">
|
||||
@csrf @method('PUT')
|
||||
<select aria-label="Division Id" name="division_id" class="rounded-xl border-zinc-300 dark:border-zinc-700 dark:bg-zinc-950">
|
||||
<label class="sr-only" for="division_id">Division</label>
|
||||
<select id="division_id" name="division_id" class="rounded-xl border-zinc-300 dark:border-zinc-700 dark:bg-zinc-950">
|
||||
<option value="">Company-level warehouse</option>
|
||||
@foreach($company->divisions as $divisionOption)
|
||||
<option value="{{ $divisionOption->id }}" @selected($warehouse->division_id === $divisionOption->id)>{{ $divisionOption->name }}</option>
|
||||
@@ -275,8 +276,8 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">Description</label>
|
||||
<textarea aria-label="Description" name="description" rows="3" class="mt-2 w-full rounded-xl border-zinc-300 bg-white px-4 py-3 text-sm font-medium text-zinc-900 shadow-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white">{{ $division->description }}</textarea>
|
||||
<label for="division-description-{{ $division->id }}" class="block text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">Description</label>
|
||||
<textarea id="division-description-{{ $division->id }}" name="description" rows="3" class="mt-2 w-full rounded-xl border-zinc-300 bg-white px-4 py-3 text-sm font-medium text-zinc-900 shadow-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white">{{ $division->description }}</textarea>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-6"><h4 class="font-semibold">Division address</h4><form method="POST" action="{{ route('platform.companies.divisions.address.update', [$company, $division]) }}" class="mt-4">@csrf @method('PUT')@include('company::partials.address-form', ['address' => $division->address, 'defaultLabel' => 'Operating address'])</form></div>
|
||||
|
||||
@@ -5,9 +5,9 @@ use Modules\Countries\Http\Controllers\CountriesController;
|
||||
use Modules\Countries\Http\Controllers\CountrySyncController;
|
||||
use Modules\Countries\Http\Controllers\ReferenceDataController;
|
||||
|
||||
const COUNTRY_ROUTE = '/{country}';
|
||||
$countryRoute = '/{country}';
|
||||
|
||||
Route::prefix('countries')->name('countries.')->middleware(['web', 'auth'])->group(function (): void {
|
||||
Route::prefix('countries')->name('countries.')->middleware(['web', 'auth'])->group(function () use ($countryRoute): void {
|
||||
Route::get('/', CountriesController::class)->name('index');
|
||||
Route::get('/create', [CountriesController::class, 'create'])->name('create');
|
||||
Route::post('/', [CountriesController::class, 'store'])->name('store');
|
||||
@@ -17,8 +17,8 @@ Route::prefix('countries')->name('countries.')->middleware(['web', 'auth'])->gro
|
||||
Route::get('/reference/languages', [ReferenceDataController::class, 'languages'])->name('languages.index');
|
||||
Route::get('/reference/scripts', [ReferenceDataController::class, 'scripts'])->name('scripts.index');
|
||||
Route::get('/reference/locodes', [ReferenceDataController::class, 'locodes'])->name('locodes.index');
|
||||
Route::get(COUNTRY_ROUTE, [CountriesController::class, 'show'])->name('show');
|
||||
Route::get(COUNTRY_ROUTE . '/edit', [CountriesController::class, 'edit'])->name('edit');
|
||||
Route::put(COUNTRY_ROUTE, [CountriesController::class, 'update'])->name('update');
|
||||
Route::delete(COUNTRY_ROUTE, [CountriesController::class, 'destroy'])->name('destroy');
|
||||
Route::get($countryRoute, [CountriesController::class, 'show'])->name('show');
|
||||
Route::get($countryRoute . '/edit', [CountriesController::class, 'edit'])->name('edit');
|
||||
Route::put($countryRoute, [CountriesController::class, 'update'])->name('update');
|
||||
Route::delete($countryRoute, [CountriesController::class, 'destroy'])->name('destroy');
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ return [
|
||||
'name' => 'Documentation',
|
||||
'storage_disk' => env('DOCUMENTATION_DISK', 'public'),
|
||||
'upload_path' => env('DOCUMENTATION_UPLOAD_PATH', 'documentation'),
|
||||
'max_upload_kb' => (int) env('DOCUMENTATION_MAX_UPLOAD_KB', 20480),
|
||||
'max_upload_kb' => 1024,
|
||||
'max_markdown_import_bytes' => (int) env('DOCUMENTATION_MAX_MARKDOWN_IMPORT_BYTES', 1048576),
|
||||
'import_markdown_attachments' => true,
|
||||
'allowed_upload_mimes' => [
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
namespace Modules\Documentation\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Modules\Documentation\Models\DocumentationDocument;
|
||||
|
||||
class StoreDocumentationDocumentRequest extends FormRequest
|
||||
{
|
||||
private const MAX_UPLOAD_BYTES = 1_048_576;
|
||||
|
||||
/**
|
||||
* Determine whether the user is authorized to make this request.
|
||||
*/
|
||||
@@ -33,9 +36,29 @@ class StoreDocumentationDocumentRequest extends FormRequest
|
||||
'is_featured' => ['nullable', 'boolean'],
|
||||
'version' => ['required', 'string', 'max:50'],
|
||||
'reference' => ['nullable', 'string', 'max:100'],
|
||||
'attachment' => ['nullable', 'file', 'max:' . config('documentation.max_upload_kb', 20480), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'attachment' => ['nullable', 'file', $this->uploadSizeRule(), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'attachments' => ['nullable', 'array'],
|
||||
'attachments.*' => ['file', 'max:' . config('documentation.max_upload_kb', 20480), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'attachments.*' => ['file', $this->uploadSizeRule(), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce the upload ceiling in bytes instead of relying on Laravel's
|
||||
* file `max` rule, keeping the security boundary explicit.
|
||||
*
|
||||
* @return \Closure(string, mixed, \Closure(string): void): void
|
||||
*/
|
||||
private function uploadSizeRule(): \Closure
|
||||
{
|
||||
return static function (string $attribute, mixed $value, \Closure $fail): void {
|
||||
if (! $value instanceof UploadedFile || ! $value->isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$size = $value->getSize();
|
||||
if ($size === false || $size > self::MAX_UPLOAD_BYTES) {
|
||||
$fail(sprintf('The %s must not be larger than 1 MB.', $attribute));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
namespace Modules\Documentation\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Modules\Documentation\Models\DocumentationDocument;
|
||||
|
||||
class UpdateDocumentationDocumentRequest extends FormRequest
|
||||
{
|
||||
private const MAX_UPLOAD_BYTES = 1_048_576;
|
||||
|
||||
/**
|
||||
* Determine whether the user is authorized to make this request.
|
||||
*/
|
||||
@@ -36,10 +39,30 @@ class UpdateDocumentationDocumentRequest extends FormRequest
|
||||
'is_featured' => ['nullable', 'boolean'],
|
||||
'version' => ['required', 'string', 'max:50'],
|
||||
'reference' => ['nullable', 'string', 'max:100'],
|
||||
'attachment' => ['nullable', 'file', 'max:' . config('documentation.max_upload_kb', 20480), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'attachment' => ['nullable', 'file', $this->uploadSizeRule(), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'attachments' => ['nullable', 'array'],
|
||||
'attachments.*' => ['file', 'max:' . config('documentation.max_upload_kb', 20480), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'attachments.*' => ['file', $this->uploadSizeRule(), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'remove_attachment' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce the upload ceiling in bytes instead of relying on Laravel's
|
||||
* file `max` rule, keeping the security boundary explicit.
|
||||
*
|
||||
* @return \Closure(string, mixed, \Closure(string): void): void
|
||||
*/
|
||||
private function uploadSizeRule(): \Closure
|
||||
{
|
||||
return static function (string $attribute, mixed $value, \Closure $fail): void {
|
||||
if (! $value instanceof UploadedFile || ! $value->isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$size = $value->getSize();
|
||||
if ($size === false || $size > self::MAX_UPLOAD_BYTES) {
|
||||
$fail(sprintf('The %s must not be larger than 1 MB.', $attribute));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,13 +47,15 @@
|
||||
<label for="sonar-input-9f8539cc9d" class="visually-hidden">Search title, reference, summary or body</label>
|
||||
<input class="doc-input" name="search" value="{{ request('search') }}"
|
||||
placeholder="Search title, reference, summary or body" id="sonar-input-9f8539cc9d">
|
||||
<select aria-label="Status" class="doc-select" name="status">
|
||||
<label class="sr-only" for="document_status">Status</label>
|
||||
<select id="document_status" class="doc-select" name="status">
|
||||
<option value="">All statuses</option>
|
||||
@foreach ($statuses as $value => $label)
|
||||
<option value="{{ $value }}" @selected(request('status') === $value)>{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<select aria-label="Category" class="doc-select" name="category">
|
||||
<label class="sr-only" for="document_category">Category</label>
|
||||
<select id="document_category" class="doc-select" name="category">
|
||||
<option value="">All categories</option>
|
||||
@foreach ($categories as $category)
|
||||
<option value="{{ $category->id }}" @selected((string) request('category') === (string) $category->id)>{{ $category->name }}
|
||||
|
||||
@@ -6,24 +6,24 @@ use Illuminate\Support\Facades\Route;
|
||||
use Modules\Documentation\Http\Controllers\DocumentationCategoryController;
|
||||
use Modules\Documentation\Http\Controllers\DocumentationController;
|
||||
|
||||
const DOCUMENT_ROUTE = '/documents/{document}';
|
||||
$documentRoute = '/documents/{document}';
|
||||
|
||||
Route::middleware(['web', 'auth'])
|
||||
->prefix('documentation')
|
||||
->name('documentation.')
|
||||
->group(function (): void {
|
||||
->group(function () use ($documentRoute): void {
|
||||
Route::get('/', [DocumentationController::class, 'index'])->name('index');
|
||||
|
||||
Route::get('/documents', [DocumentationController::class, 'index'])->name('documents.index');
|
||||
Route::get('/documents/create', [DocumentationController::class, 'create'])->name('documents.create');
|
||||
Route::post('/documents', [DocumentationController::class, 'store'])->name('documents.store');
|
||||
Route::get(DOCUMENT_ROUTE, [DocumentationController::class, 'show'])->name('documents.show');
|
||||
Route::get(DOCUMENT_ROUTE . '/edit', [DocumentationController::class, 'edit'])->name('documents.edit');
|
||||
Route::put(DOCUMENT_ROUTE, [DocumentationController::class, 'update'])->name('documents.update');
|
||||
Route::delete(DOCUMENT_ROUTE, [DocumentationController::class, 'destroy'])->name('documents.destroy');
|
||||
Route::get(DOCUMENT_ROUTE . '/download', [DocumentationController::class, 'download'])->name('documents.download');
|
||||
Route::get(DOCUMENT_ROUTE . '/attachments/{attachment}/download', [DocumentationController::class, 'downloadAttachment'])->name('documents.attachments.download');
|
||||
Route::delete(DOCUMENT_ROUTE . '/attachments/{attachment}', [DocumentationController::class, 'destroyAttachment'])->name('documents.attachments.destroy');
|
||||
Route::get($documentRoute, [DocumentationController::class, 'show'])->name('documents.show');
|
||||
Route::get($documentRoute . '/edit', [DocumentationController::class, 'edit'])->name('documents.edit');
|
||||
Route::put($documentRoute, [DocumentationController::class, 'update'])->name('documents.update');
|
||||
Route::delete($documentRoute, [DocumentationController::class, 'destroy'])->name('documents.destroy');
|
||||
Route::get($documentRoute . '/download', [DocumentationController::class, 'download'])->name('documents.download');
|
||||
Route::get($documentRoute . '/attachments/{attachment}/download', [DocumentationController::class, 'downloadAttachment'])->name('documents.attachments.download');
|
||||
Route::delete($documentRoute . '/attachments/{attachment}', [DocumentationController::class, 'destroyAttachment'])->name('documents.attachments.destroy');
|
||||
|
||||
Route::resource('categories', DocumentationCategoryController::class)->except(['show']);
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@ use Modules\Helpdesk\Models\Ticket;
|
||||
*/
|
||||
final class TicketFactory extends Factory
|
||||
{
|
||||
private const FACTORY_BODY = self::FACTORY_BODY;
|
||||
private const FACTORY_BODY = 'Factory helpdesk ticket body';
|
||||
|
||||
/**
|
||||
* The model name for the factory.
|
||||
|
||||
@@ -17,7 +17,7 @@ use Modules\Helpdesk\Services\WorkflowNotificationService;
|
||||
|
||||
final class KanbanBoard extends Component
|
||||
{
|
||||
private const OWNER_RELATION = self::OWNER_RELATION;
|
||||
private const OWNER_RELATION = 'owner:id,name,email';
|
||||
|
||||
public ?int $board_id = null;
|
||||
|
||||
|
||||
@@ -31,11 +31,11 @@
|
||||
.hd-helpdesk-surface .hd-btn-blue:hover,
|
||||
.hd-btn-blue:hover { background: #1d4ed8 !important; }
|
||||
.hd-helpdesk-surface .hd-btn-green,
|
||||
.hd-btn-green { background: #16a34a !important; }
|
||||
.hd-btn-green { background: #15803d !important; }
|
||||
.hd-helpdesk-surface .hd-btn-green:hover,
|
||||
.hd-btn-green:hover { background: #15803d !important; }
|
||||
.hd-helpdesk-surface .hd-btn-amber,
|
||||
.hd-btn-amber { background: #f59e0b !important; }
|
||||
.hd-btn-amber { background: #92400e !important; }
|
||||
.hd-helpdesk-surface .hd-btn-amber:hover,
|
||||
.hd-btn-amber:hover { background: #d97706 !important; }
|
||||
.hd-helpdesk-surface .hd-btn-red,
|
||||
@@ -49,13 +49,13 @@
|
||||
|
||||
.hd-helpdesk-surface button[type="submit"],
|
||||
.hd-helpdesk-surface button[data-flux-button][type="submit"] {
|
||||
background: #16a34a !important;
|
||||
background: #15803d !important;
|
||||
color: #ffffff !important;
|
||||
border-color: rgba(255,255,255,.14) !important;
|
||||
}
|
||||
.hd-helpdesk-surface button[wire\:click^="reset"],
|
||||
.hd-helpdesk-surface button[wire\:target^="reset"] {
|
||||
background: #f59e0b !important;
|
||||
background: #92400e !important;
|
||||
color: #ffffff !important;
|
||||
border-color: rgba(255,255,255,.14) !important;
|
||||
}
|
||||
@@ -166,10 +166,10 @@
|
||||
.hd-btn-blue { background: #2563eb !important; }
|
||||
.hd-btn-blue:hover { background: #1d4ed8 !important; }
|
||||
|
||||
.hd-btn-green { background: #16a34a !important; }
|
||||
.hd-btn-green { background: #15803d !important; }
|
||||
.hd-btn-green:hover { background: #15803d !important; }
|
||||
|
||||
.hd-btn-amber { background: #f59e0b !important; }
|
||||
.hd-btn-amber { background: #92400e !important; }
|
||||
.hd-btn-amber:hover { background: #d97706 !important; }
|
||||
|
||||
.hd-btn-red { background: #dc2626 !important; }
|
||||
@@ -180,14 +180,14 @@
|
||||
|
||||
.hd-helpdesk-surface button[type="submit"],
|
||||
.hd-helpdesk-surface button[data-flux-button][type="submit"] {
|
||||
background: #16a34a !important;
|
||||
background: #15803d !important;
|
||||
color: #fff !important;
|
||||
border-color: rgba(255,255,255,.14) !important;
|
||||
}
|
||||
|
||||
.hd-helpdesk-surface button[wire\:click^="reset"],
|
||||
.hd-helpdesk-surface button[wire\:target^="reset"] {
|
||||
background: #f59e0b !important;
|
||||
background: #92400e !important;
|
||||
color: #fff !important;
|
||||
border-color: rgba(255,255,255,.14) !important;
|
||||
}
|
||||
@@ -673,11 +673,11 @@ span.flatpickr-weekday {
|
||||
.hd-helpdesk-surface .hd-btn-blue:hover,
|
||||
.hd-btn-blue:hover { background: #1d4ed8 !important; }
|
||||
.hd-helpdesk-surface .hd-btn-green,
|
||||
.hd-btn-green { background: #16a34a !important; }
|
||||
.hd-btn-green { background: #15803d !important; }
|
||||
.hd-helpdesk-surface .hd-btn-green:hover,
|
||||
.hd-btn-green:hover { background: #15803d !important; }
|
||||
.hd-helpdesk-surface .hd-btn-amber,
|
||||
.hd-btn-amber { background: #f59e0b !important; }
|
||||
.hd-btn-amber { background: #92400e !important; }
|
||||
.hd-helpdesk-surface .hd-btn-amber:hover,
|
||||
.hd-btn-amber:hover { background: #d97706 !important; }
|
||||
.hd-helpdesk-surface .hd-btn-red,
|
||||
@@ -691,13 +691,13 @@ span.flatpickr-weekday {
|
||||
|
||||
.hd-helpdesk-surface button[type="submit"],
|
||||
.hd-helpdesk-surface button[data-flux-button][type="submit"] {
|
||||
background: #16a34a !important;
|
||||
background: #15803d !important;
|
||||
color: #ffffff !important;
|
||||
border-color: rgba(255,255,255,.14) !important;
|
||||
}
|
||||
.hd-helpdesk-surface button[wire\:click^="reset"],
|
||||
.hd-helpdesk-surface button[wire\:target^="reset"] {
|
||||
background: #f59e0b !important;
|
||||
background: #92400e !important;
|
||||
color: #ffffff !important;
|
||||
border-color: rgba(255,255,255,.14) !important;
|
||||
}
|
||||
@@ -870,11 +870,11 @@ span.flatpickr-weekday {
|
||||
.hd-helpdesk-surface .hd-btn-blue:hover,
|
||||
.hd-btn-blue:hover { background: #1d4ed8 !important; }
|
||||
.hd-helpdesk-surface .hd-btn-green,
|
||||
.hd-btn-green { background: #16a34a !important; }
|
||||
.hd-btn-green { background: #15803d !important; }
|
||||
.hd-helpdesk-surface .hd-btn-green:hover,
|
||||
.hd-btn-green:hover { background: #15803d !important; }
|
||||
.hd-helpdesk-surface .hd-btn-amber,
|
||||
.hd-btn-amber { background: #f59e0b !important; }
|
||||
.hd-btn-amber { background: #92400e !important; }
|
||||
.hd-helpdesk-surface .hd-btn-amber:hover,
|
||||
.hd-btn-amber:hover { background: #d97706 !important; }
|
||||
.hd-helpdesk-surface .hd-btn-red,
|
||||
@@ -888,13 +888,13 @@ span.flatpickr-weekday {
|
||||
|
||||
.hd-helpdesk-surface button[type="submit"],
|
||||
.hd-helpdesk-surface button[data-flux-button][type="submit"] {
|
||||
background: #16a34a !important;
|
||||
background: #15803d !important;
|
||||
color: #ffffff !important;
|
||||
border-color: rgba(255,255,255,.14) !important;
|
||||
}
|
||||
.hd-helpdesk-surface button[wire\:click^="reset"],
|
||||
.hd-helpdesk-surface button[wire\:target^="reset"] {
|
||||
background: #f59e0b !important;
|
||||
background: #92400e !important;
|
||||
color: #ffffff !important;
|
||||
border-color: rgba(255,255,255,.14) !important;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ window.jQuery = $;
|
||||
select2(window, $);
|
||||
|
||||
function livewireComponentFor(element) {
|
||||
const componentRoot = element.closest('[wire\\:id]');
|
||||
const componentRoot = element.closest(String.raw`[wire\:id]`);
|
||||
|
||||
if (!componentRoot || ! window.Livewire) {
|
||||
return null;
|
||||
@@ -30,8 +30,7 @@ function setLivewireProperty(element, model, value) {
|
||||
}
|
||||
|
||||
function initialiseHelpdeskSelects() {
|
||||
$('[data-helpdesk-select2]').each(function () {
|
||||
const select = this;
|
||||
$('[data-helpdesk-select2]').each((_index, select) => {
|
||||
const $select = $(select);
|
||||
const placeholder = $select.data('placeholder') || $select.find('option[value=""]').first().text() || 'Select option';
|
||||
|
||||
|
||||
Executable → Regular
+7
-2
@@ -14,12 +14,13 @@
|
||||
<div {{ $attributes->class('rounded-xl border border-zinc-200 bg-white p-3 shadow-sm dark:border-zinc-700 dark:bg-zinc-950/50') }}>
|
||||
<div class="grid gap-3 lg:grid-cols-[minmax(0,1fr)_auto] lg:items-end">
|
||||
<div class="min-w-0 space-y-2">
|
||||
<label class="block text-xs font-bold uppercase tracking-wide text-zinc-600 dark:text-zinc-300">
|
||||
<label for="colour-select-{{ md5($model) }}" class="block text-xs font-bold uppercase tracking-wide text-zinc-600 dark:text-zinc-300">
|
||||
{{ $label }}
|
||||
</label>
|
||||
|
||||
<div class="grid gap-2 sm:grid-cols-[minmax(0,1fr)_auto] sm:items-center">
|
||||
<select aria-label="Form Field"
|
||||
<select
|
||||
id="colour-select-{{ md5($model) }}"
|
||||
wire:model.live="{{ $model }}"
|
||||
class="h-9 w-full rounded-lg border border-zinc-300 bg-white px-3 text-sm font-semibold text-zinc-900 shadow-sm outline-none transition-colors duration-150 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-100"
|
||||
>
|
||||
@@ -54,7 +55,9 @@
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-[2.75rem_minmax(0,11rem)] items-center gap-2 lg:justify-end">
|
||||
<label class="sr-only" for="custom-colour-picker">Choose a custom hex colour</label>
|
||||
<input
|
||||
id="custom-colour-picker"
|
||||
type="color"
|
||||
value="{{ $currentHex }}"
|
||||
wire:change="$set('{{ $model }}', $event.target.value)"
|
||||
@@ -62,7 +65,9 @@
|
||||
aria-label="Choose a custom hex colour"
|
||||
/>
|
||||
|
||||
<label class="sr-only" for="custom-colour-text">Custom hex colour</label>
|
||||
<input
|
||||
id="custom-colour-text"
|
||||
type="text"
|
||||
wire:model.live.debounce.500ms="{{ $model }}"
|
||||
class="h-9 w-full rounded-lg border border-zinc-300 bg-white px-3 text-xs font-semibold text-zinc-900 placeholder:text-zinc-400 shadow-sm outline-none transition-colors duration-150 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-100 dark:placeholder:text-zinc-500"
|
||||
|
||||
@@ -109,7 +109,6 @@
|
||||
autocomplete="on"
|
||||
autocapitalize="sentences"
|
||||
inputmode="text"
|
||||
role="textbox"
|
||||
aria-multiline="true"
|
||||
data-placeholder="{{ $placeholder }}"
|
||||
data-wire-model="{{ $model }}"
|
||||
|
||||
Executable → Regular
+7
-9
@@ -57,9 +57,10 @@
|
||||
</div>
|
||||
|
||||
<div class="hd-select-wrap shrink-0 md:w-72">
|
||||
<label for="kanban-board-select" class="sr-only">Kanban board</label>
|
||||
<select
|
||||
id="kanban-board-select"
|
||||
class="hd-select"
|
||||
aria-label="Select Kanban board"
|
||||
onchange="window.location.href = '{{ route('helpdesk.kanban') }}?board_id=' + encodeURIComponent(this.value)"
|
||||
>
|
||||
@foreach ($boards as $availableBoard)
|
||||
@@ -154,22 +155,19 @@
|
||||
|
||||
|
||||
<form method="POST" action="{{ route('helpdesk.tickets.board.update', $ticket) }}"
|
||||
class="mt-3 rounded-xl border border-emerald-500/20 bg-emerald-950/20 p-2"
|
||||
onclick="event.stopPropagation()"
|
||||
onmousedown="event.stopPropagation()"
|
||||
ondragstart="event.preventDefault(); event.stopPropagation();">
|
||||
class="mt-3 rounded-xl border border-emerald-500/20 bg-emerald-950/20 p-2">
|
||||
@csrf
|
||||
<input type="hidden" name="return_to_board_id" value="{{ $board?->id }}">
|
||||
<label
|
||||
class="mb-1 block text-[11px] font-bold uppercase tracking-wide text-emerald-200/80">Board</label>
|
||||
for="board_id_{{ $ticket->id }}" class="mb-1 block text-[11px] font-bold uppercase tracking-wide text-emerald-200/80">Board</label>
|
||||
<div class="hd-ticket-board-select-wrap">
|
||||
<select name="board_id"
|
||||
<select id="board_id_{{ $ticket->id }}" name="board_id"
|
||||
class="hd-ticket-board-select"
|
||||
draggable="false"
|
||||
onchange="this.form.requestSubmit ? this.form.requestSubmit() : this.form.submit()"
|
||||
onclick="event.stopPropagation()"
|
||||
onmousedown="event.stopPropagation()"
|
||||
aria-label="Move {{ $ticket->reference }} to another board">
|
||||
onkeydown="event.stopPropagation()"
|
||||
onmousedown="event.stopPropagation()">
|
||||
@foreach ($boards as $ticketBoard)
|
||||
<option value="{{ $ticketBoard->id }}"
|
||||
@selected((int) $ticket->board_id === (int) $ticketBoard->id)>{{ $ticketBoard->name }}</option>
|
||||
|
||||
@@ -371,7 +371,7 @@
|
||||
<flux:textarea wire:model="boardForm.description" label="Description" rows="2" />
|
||||
</div>
|
||||
<div class="md:col-span-full">
|
||||
<label class="mb-2 block text-sm font-medium text-zinc-700 dark:text-zinc-200">Board
|
||||
<label for="board-columns" class="mb-2 block text-sm font-medium text-zinc-700 dark:text-zinc-200">Board
|
||||
columns</label>
|
||||
<div class="grid gap-2 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
|
||||
@foreach ($statuses as $status)
|
||||
|
||||
@@ -211,11 +211,8 @@
|
||||
|
||||
<div class="lg:col-span-3 xl:col-span-6">
|
||||
<fieldset class="rounded-2xl border border-zinc-700 bg-zinc-950/70 p-4">
|
||||
<legend class="text-sm font-semibold text-zinc-200">Tags</legend>
|
||||
<div class="flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between">
|
||||
<legend class="text-sm font-semibold text-zinc-200">
|
||||
Tags
|
||||
</legend>
|
||||
|
||||
<span class="text-xs text-zinc-500">
|
||||
Optional · select all that apply
|
||||
</span>
|
||||
|
||||
@@ -241,11 +241,8 @@
|
||||
|
||||
<div class="lg:col-span-3 xl:col-span-6">
|
||||
<fieldset class="rounded-2xl border border-zinc-700 bg-zinc-950/70 p-4">
|
||||
<legend class="text-sm font-semibold text-zinc-200">Tags</legend>
|
||||
<div class="flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between">
|
||||
<legend class="text-sm font-semibold text-zinc-200">
|
||||
Tags
|
||||
</legend>
|
||||
|
||||
<span class="text-xs text-zinc-500">
|
||||
Optional · select all that apply
|
||||
</span>
|
||||
|
||||
@@ -157,8 +157,8 @@
|
||||
</div>
|
||||
|
||||
@if ($deleteModalOpen)
|
||||
<div class="fixed inset-0 z-[9998] flex items-center justify-center bg-black/75 px-4 py-6 backdrop-blur-sm"
|
||||
role="dialog" aria-modal="true" aria-labelledby="delete-ticket-modal-title"
|
||||
<dialog open class="fixed inset-0 z-[9998] flex items-center justify-center bg-black/75 px-4 py-6 backdrop-blur-sm"
|
||||
aria-modal="true" aria-labelledby="delete-ticket-modal-title"
|
||||
wire:key="ticket-delete-modal-{{ $pendingDeleteTicketId ?? 'none' }}"
|
||||
dusk="delete-ticket-confirmation-modal">
|
||||
<div
|
||||
@@ -215,6 +215,6 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
Executable → Regular
+5
-6
@@ -482,11 +482,12 @@
|
||||
|
||||
<div id="ticket-comment-body-editor" dusk="comment-body" data-dusk="comment-body"
|
||||
data-helpdesk-rich-editor data-helpdesk-sync-target="ticket-comment-body"
|
||||
contenteditable="true" role="textbox" aria-multiline="true" spellcheck="true" lang="en-GB" autocorrect="on" autocomplete="on" autocapitalize="sentences" inputmode="text"
|
||||
contenteditable="true" role="textbox" aria-multiline="true" spellcheck="true" lang="en-GB" aria-label="Write a public reply or internal note." autocorrect="on" autocomplete="on" autocapitalize="sentences" inputmode="text"
|
||||
class="prose prose-sm min-h-[12rem] max-w-none bg-white p-4 text-sm leading-6 text-zinc-900 outline-none dark:prose-invert dark:bg-zinc-950 dark:text-zinc-100"
|
||||
data-placeholder="Write a public reply or internal note. Right-click or Ctrl-click underlined words for spelling suggestions.">{!! $oldCommentBody !!}</div>
|
||||
|
||||
<textarea aria-label="Ticket Comment Body" id="ticket-comment-body" name="commentBody" required spellcheck="true" lang="en-GB" autocorrect="on" autocomplete="on" autocapitalize="sentences" inputmode="text" class="sr-only" tabindex="-1" aria-hidden="true">{{ $oldCommentBody }}</textarea>
|
||||
<label for="ticket-comment-body" class="sr-only">Public reply or internal note</label>
|
||||
<textarea id="ticket-comment-body" name="commentBody" required spellcheck="true" lang="en-GB" autocorrect="on" autocomplete="on" autocapitalize="sentences" inputmode="text" class="sr-only" tabindex="-1" aria-hidden="true">{{ $oldCommentBody }}</textarea>
|
||||
</div>
|
||||
|
||||
<p class="mt-2 flex items-center gap-2 text-xs font-medium text-zinc-500 dark:text-zinc-400">
|
||||
@@ -500,9 +501,7 @@
|
||||
class="rounded-xl border border-zinc-200 bg-zinc-50 p-3 dark:border-zinc-700 dark:bg-zinc-950">
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="min-w-0">
|
||||
<label class="block text-xs font-bold text-zinc-700 dark:text-zinc-200">Attach files
|
||||
to
|
||||
this reply</label>
|
||||
<span class="block text-xs font-bold text-zinc-700 dark:text-zinc-200">Attach files to this reply</span>
|
||||
<p class="mt-1 truncate text-xs font-semibold text-zinc-500 dark:text-zinc-400"
|
||||
data-helpdesk-file-label>No files selected</p>
|
||||
</div>
|
||||
@@ -1662,7 +1661,7 @@
|
||||
|
||||
<style>
|
||||
[data-helpdesk-sidebar-cards] details > summary::-webkit-details-marker {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
[data-helpdesk-sidebar-cards] details > summary {
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<textarea aria-label="Description" spellcheck="true" lang="en-GB" name="description" rows="2" placeholder="Optional work note"
|
||||
<label class="sr-only" for="time_log_description">Description</label>
|
||||
<textarea id="time_log_description" spellcheck="true" lang="en-GB" name="description" rows="2" placeholder="Optional work note"
|
||||
class="block w-full rounded-lg border border-zinc-300 bg-white p-2 text-xs font-semibold text-zinc-900 shadow-sm focus:border-emerald-500 focus:ring-emerald-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100"
|
||||
data-dusk="ticket-time-description">{{ old('description') }}</textarea>
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ final class GitWebhookIngestionTest extends TestCase
|
||||
$repository = $this->repository([
|
||||
'provider' => 'gitea',
|
||||
'project_id' => $fixtures['project']->id,
|
||||
'remote_url' => 'http://git.vm:3000/Admin/WMS-Core.git',
|
||||
'remote_url' => 'https://git.vm:3000/Admin/WMS-Core.git',
|
||||
'webhook_secret' => 'gitea-secret',
|
||||
]);
|
||||
$ticket = $this->ticket(['project_id' => $fixtures['project']->id]);
|
||||
@@ -178,14 +178,14 @@ final class GitWebhookIngestionTest extends TestCase
|
||||
'repository' => [
|
||||
'name' => 'WMS-Core',
|
||||
'full_name' => 'Admin/WMS-Core',
|
||||
'clone_url' => 'http://git.vm:3000/Admin/WMS-Core.git',
|
||||
'html_url' => 'http://git.vm:3000/Admin/WMS-Core',
|
||||
'clone_url' => 'https://git.vm:3000/Admin/WMS-Core.git',
|
||||
'html_url' => 'https://git.vm:3000/Admin/WMS-Core',
|
||||
],
|
||||
'commits' => [
|
||||
[
|
||||
'id' => str_repeat('d', 40),
|
||||
'message' => $ticket->reference . ' Fix local Gitea webhook ingestion',
|
||||
'url' => 'http://git.vm:3000/Admin/WMS-Core/commit/' . str_repeat('d', 40),
|
||||
'url' => 'https://git.vm:3000/Admin/WMS-Core/commit/' . str_repeat('d', 40),
|
||||
'timestamp' => '2026-06-24T14:20:00+00:00',
|
||||
'author' => ['name' => 'Mark Gregory', 'email' => 'mark@example.com'],
|
||||
],
|
||||
@@ -227,12 +227,12 @@ final class GitWebhookIngestionTest extends TestCase
|
||||
|
||||
$this->repository([
|
||||
'provider' => 'gitea',
|
||||
'remote_url' => 'http://git.vm:3000/Admin/WMS-Core.git',
|
||||
'remote_url' => 'https://git.vm:3000/Admin/WMS-Core.git',
|
||||
'webhook_secret' => 'gitea-secret',
|
||||
]);
|
||||
$payload = [
|
||||
'ref' => 'refs/heads/main',
|
||||
'repository' => ['clone_url' => 'http://git.vm:3000/Admin/WMS-Core.git'],
|
||||
'repository' => ['clone_url' => 'https://git.vm:3000/Admin/WMS-Core.git'],
|
||||
'commits' => [['id' => str_repeat('e', 40), 'message' => 'No auth']],
|
||||
];
|
||||
$json = json_encode($payload, JSON_THROW_ON_ERROR);
|
||||
@@ -256,12 +256,12 @@ final class GitWebhookIngestionTest extends TestCase
|
||||
|
||||
$repository = $this->repository([
|
||||
'provider' => 'gitea',
|
||||
'remote_url' => 'http://git.vm:3000/Admin/WMS-Core.git',
|
||||
'remote_url' => 'https://git.vm:3000/Admin/WMS-Core.git',
|
||||
'webhook_secret' => 'gitea-secret',
|
||||
]);
|
||||
$payload = [
|
||||
'ref' => 'refs/heads/main',
|
||||
'repository' => ['clone_url' => 'http://git.vm:3000/Admin/WMS-Core.git'],
|
||||
'repository' => ['clone_url' => 'https://git.vm:3000/Admin/WMS-Core.git'],
|
||||
'commits' => [['id' => str_repeat('b', 40), 'message' => 'Valid signed Gitea push']],
|
||||
];
|
||||
$json = json_encode($payload, JSON_THROW_ON_ERROR);
|
||||
@@ -291,7 +291,7 @@ final class GitWebhookIngestionTest extends TestCase
|
||||
'provider' => 'Gitea',
|
||||
'project_id' => $fixtures['project']->id,
|
||||
'name' => 'Local',
|
||||
'remote_url' => 'http://git.vm:3000/Admin/WMS-Core',
|
||||
'remote_url' => 'https://git.vm:3000/Admin/WMS-Core',
|
||||
'webhook_secret' => 'gitea-secret',
|
||||
]);
|
||||
$payload = [
|
||||
@@ -299,14 +299,14 @@ final class GitWebhookIngestionTest extends TestCase
|
||||
'repository' => [
|
||||
'name' => 'WMS-Core',
|
||||
'full_name' => 'Admin/WMS-Core',
|
||||
'clone_url' => 'http://git.vm:3000/Admin/WMS-Core.git',
|
||||
'html_url' => 'http://git.vm:3000/Admin/WMS-Core',
|
||||
'clone_url' => 'https://git.vm:3000/Admin/WMS-Core.git',
|
||||
'html_url' => 'https://git.vm:3000/Admin/WMS-Core',
|
||||
],
|
||||
'commits' => [
|
||||
[
|
||||
'id' => str_repeat('f', 40),
|
||||
'message' => 'Local Gitea push should be visible on the dashboard',
|
||||
'url' => 'http://git.vm:3000/Admin/WMS-Core/commit/' . str_repeat('f', 40),
|
||||
'url' => 'https://git.vm:3000/Admin/WMS-Core/commit/' . str_repeat('f', 40),
|
||||
'timestamp' => '2026-06-24T15:00:00+00:00',
|
||||
'author' => ['name' => 'Mark Gregory', 'email' => 'mark@example.com'],
|
||||
],
|
||||
|
||||
@@ -87,16 +87,13 @@ class ClosedOrderSaveXls extends Command
|
||||
: $warehouse . '/Closedorderlinesreport_' . $from . '-' . $to . '-' . $warehouse . self::XLSX_EXTENSION;
|
||||
|
||||
$this->info('Generate Last Month Report...');
|
||||
$this->generateReport(
|
||||
$company,
|
||||
$warehouse,
|
||||
$plant,
|
||||
str_replace('-', '', $from),
|
||||
str_replace('-', '', $to),
|
||||
$file,
|
||||
! Storage::disk('publicCL')->exists($file),
|
||||
'Last Month',
|
||||
);
|
||||
$this->generateReport($company, $warehouse, $plant, [
|
||||
'from' => str_replace('-', '', $from),
|
||||
'to' => str_replace('-', '', $to),
|
||||
'file' => $file,
|
||||
'shouldGenerate' => ! Storage::disk('publicCL')->exists($file),
|
||||
'label' => 'Last Month',
|
||||
]);
|
||||
}
|
||||
|
||||
private function generateCurrentMonthReport(string $company, string $warehouse, string $plant): void
|
||||
@@ -109,47 +106,40 @@ class ClosedOrderSaveXls extends Command
|
||||
: $warehouse . '/first_of_month_to_current_date_' . $warehouse . self::XLSX_EXTENSION;
|
||||
|
||||
$this->info('Generate Current Month Report...');
|
||||
$this->generateReport(
|
||||
$company,
|
||||
$warehouse,
|
||||
$plant,
|
||||
str_replace('-', '', $from),
|
||||
str_replace('-', '', $to),
|
||||
$file,
|
||||
true,
|
||||
'Current Month',
|
||||
);
|
||||
$this->generateReport($company, $warehouse, $plant, [
|
||||
'from' => str_replace('-', '', $from),
|
||||
'to' => str_replace('-', '', $to),
|
||||
'file' => $file,
|
||||
'shouldGenerate' => true,
|
||||
'label' => 'Current Month',
|
||||
]);
|
||||
}
|
||||
|
||||
private function generateReport(
|
||||
string $company,
|
||||
string $warehouse,
|
||||
string $plant,
|
||||
string $from,
|
||||
string $to,
|
||||
string $file,
|
||||
bool $shouldGenerate,
|
||||
string $label,
|
||||
array $report,
|
||||
): void {
|
||||
$this->info('From Date: ' . $from);
|
||||
$this->info('To Date: ' . $to);
|
||||
$this->info('From Date: ' . $report['from']);
|
||||
$this->info('To Date: ' . $report['to']);
|
||||
|
||||
if (! $shouldGenerate || ! $this->hasReportScope($company, $warehouse, $plant)) {
|
||||
if (! $report['shouldGenerate'] || ! $this->hasReportScope($company, $warehouse, $plant)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rows = $this->closedOrderRows($company, $warehouse, $plant, $from, $to);
|
||||
$rows = $this->closedOrderRows($company, $warehouse, $plant, $report['from'], $report['to']);
|
||||
if ($rows->isEmpty()) {
|
||||
Log::channel('dailyCron')->info($label . ' report, no records found: Nothing to save...');
|
||||
Log::channel('dailyCron')->info($report['label'] . ' report, no records found: Nothing to save...');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$rows->prepend($this->headers());
|
||||
$this->logRecordLimit($rows->count());
|
||||
$this->info('Saving ' . $label . ' Excel Report to Disk');
|
||||
Log::channel('dailyCron')->info('Saving ' . $label . ' Excel Report to Disk');
|
||||
app(SpreadsheetExport::class)->store($rows, $file, 'publicCL');
|
||||
$this->info('Saving ' . $report['label'] . ' Excel Report to Disk');
|
||||
Log::channel('dailyCron')->info('Saving ' . $report['label'] . ' Excel Report to Disk');
|
||||
app(SpreadsheetExport::class)->store($rows, $report['file'], 'publicCL');
|
||||
}
|
||||
|
||||
private function hasReportScope(string $company, string $warehouse, string $plant): bool
|
||||
|
||||
@@ -53,7 +53,7 @@ class GenerateGS1Cmd extends Command
|
||||
|
||||
// Get the Calling User
|
||||
$userId = $this->argument('user');
|
||||
$sHUSER = $userId ?? (m3_user() !== '' ? Str::upper(trim(m3_user())) : 'TWOSHIP');
|
||||
$sHUSER = $userId ?? (m3User() !== '' ? Str::upper(trim(m3User())) : 'TWOSHIP');
|
||||
$this->info('User: ' . $sHUSER);
|
||||
|
||||
// Get Manifest Array
|
||||
@@ -69,183 +69,8 @@ class GenerateGS1Cmd extends Command
|
||||
'PackagesArray' => ['package 1', 'package 2'],
|
||||
];
|
||||
|
||||
if ($sHUSER != '') {
|
||||
// Get User CO & WH from Table ICM428M
|
||||
$iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')
|
||||
->where('R428US', '=', $sHUSER)
|
||||
->first();
|
||||
|
||||
$cOMPANY = isset($iCM428M->R428CO) ? $iCM428M->R428CO : ''; // Company
|
||||
$wHS = isset($iCM428M->R428WH) ? $iCM428M->R428WH : ''; // WareHouse
|
||||
|
||||
$macpkr = $gSArray['Macpkr'];
|
||||
$packageType = '0';
|
||||
$manufactID = '0826528'; // MAK : get ID from Nvent and save to Config File
|
||||
$total_length = 9;
|
||||
|
||||
$html = '
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.border_btm {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
.border_rght {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
|
||||
.margin_t {
|
||||
padding-top : 10px;
|
||||
}
|
||||
|
||||
.align_lft {
|
||||
text-align: left;
|
||||
}
|
||||
.align_center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@page { margin: 5px; }
|
||||
body { margin: 0px; }
|
||||
</style>
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif;">';
|
||||
|
||||
// Get number of Pallets
|
||||
$packageCount = count($gSArray['PackagesArray']);
|
||||
$packageNum = 1;
|
||||
while ($packageNum <= $packageCount) {
|
||||
$table_style = $packageNum < $packageCount ? ' style="page-break-after: always;" ' : '';
|
||||
|
||||
if (Cache::has('GS1SEQUENCE')) {
|
||||
$gS1SEQUENCE = Cache::get('GS1SEQUENCE');
|
||||
$gS1SEQUENCE++;
|
||||
$gS1SEQUENCEID = str_pad($gS1SEQUENCE, $total_length, '0', STR_PAD_LEFT);
|
||||
}
|
||||
// Box Number Not Found Get it from DB
|
||||
else {
|
||||
$gS1SEQUENCE = 1;
|
||||
$gS1SEQUENCEID = str_pad($gS1SEQUENCE, $total_length, '0', STR_PAD_LEFT);
|
||||
}
|
||||
Cache::forever('GS1SEQUENCE', $gS1SEQUENCEID);
|
||||
$this->info('>>> GS1 sequence Id: ' . $gS1SEQUENCEID);
|
||||
|
||||
$gs1_128_bc_1 = '00' . $packageType . $manufactID . $gS1SEQUENCEID;
|
||||
|
||||
// Calculate Check Digit
|
||||
$digits = str_split($gs1_128_bc_1);
|
||||
$sum = 0;
|
||||
$length = count($digits);
|
||||
|
||||
// Loop through each digit starting from the right
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$digit = $digits[$length - $i - 1];
|
||||
// Assign a weight of 3 or 1 alternately
|
||||
$weight = ($i % 2 == 0) ? 3 : 1;
|
||||
// Add the product of the digit and its weight to the sum
|
||||
$sum += $digit * $weight;
|
||||
}
|
||||
// Calculate the remainder when sum is divided by 10
|
||||
$remainder = $sum % 10;
|
||||
// If remainder is 0, check digit is 0; otherwise, subtract remainder from 10
|
||||
$checkDigit = ($remainder == 0) ? 0 : 10 - $remainder;
|
||||
|
||||
$gs1_128_bc_desc = '(00)' . $packageType . $manufactID . $gS1SEQUENCEID . $checkDigit;
|
||||
|
||||
$data = [
|
||||
'ship_to' => $gSArray['Recipient_CompanyName'] . '<br>' . $gSArray['Recipient_Address1'] . '<br>' .
|
||||
$gSArray['Recipient_City'] . ',' . $gSArray['Recipient_State']
|
||||
. '<br>' . $gSArray['Recipient_PostalCode'],
|
||||
'from' => $gSArray['Sender_CompanyName'] . '<br>' . $gSArray['Sender_Address1'] . '<br>' .
|
||||
$gSArray['Sender_City'] . ',' . $gSArray['Sender_State']
|
||||
. '<br>' . $gSArray['Sender_PostalCode'],
|
||||
'ship_to_lbl' => '420' . $gSArray['Recipient_PostalCode'],
|
||||
'ship_to_desc' => '(420)' . $gSArray['Recipient_PostalCode'],
|
||||
'pro' => '190071217845706',
|
||||
'item_number' => '10000B',
|
||||
'upc' => '098506095310',
|
||||
'quantity' => '1',
|
||||
'serial_shipping_container' => $gs1_128_bc_desc,
|
||||
];
|
||||
|
||||
// Initialize barcode generator
|
||||
$generator = new BarcodeGeneratorPNG;
|
||||
|
||||
// Generate barcodes
|
||||
$shipToPostalCodeBarcode = $generator->getBarcode($data['ship_to_lbl'], $generator::TYPE_CODE_128);
|
||||
$serialShippingContainerBarcode = $generator->getBarcode($data['serial_shipping_container'], $generator::TYPE_CODE_128, 2, 50);
|
||||
|
||||
// HTML content for the label
|
||||
$html .= '
|
||||
<table ' . $table_style . '>
|
||||
<tr>
|
||||
<td colspan="2" class="border_btm border_rght align_lft">
|
||||
FROM:<br>' . $data['from'] . '
|
||||
</td>
|
||||
<td colspan="2" class="border_btm align_lft">
|
||||
SHIP TO:<br>' . $data['ship_to'] . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" class="border_btm border_rght margin_t align_center">
|
||||
<img src="data:image/png;base64,' . base64_encode($shipToPostalCodeBarcode) . '"> <br>
|
||||
' . $data['ship_to_desc'] . '
|
||||
</td>
|
||||
<td class="border_btm margin_t align_lft">
|
||||
Carrier: ' . $gSArray['CarrierName'] . ' <br>
|
||||
PRO #: ' . $gSArray['ShipmentPONumber'] . ' <br>
|
||||
B/L #: ' . $gSArray['BOLnumber'] . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="border_btm margin_t align_lft border_rght">
|
||||
PURCHASE ORDER: ' . $gSArray['Macpkr'] . ' <br>
|
||||
Vendor: ' . $manufactID . '
|
||||
</td>
|
||||
<td colspan="2" class="border_btm margin_t align_center">
|
||||
Pallet # : ' . $packageNum . ' of ' . $packageCount . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4" style="text-align: center;" class="margin_t">
|
||||
<img src="data:image/png;base64,' . base64_encode($serialShippingContainerBarcode) . '"><br>
|
||||
' . $data['serial_shipping_container'] . '
|
||||
</td>
|
||||
</tr>
|
||||
</table>';
|
||||
|
||||
$packageNum++;
|
||||
}
|
||||
|
||||
$html .= '</body> </html>';
|
||||
|
||||
ob_start();
|
||||
|
||||
// Initialize Dompdf
|
||||
$dompdf = new Dompdf;
|
||||
$dompdf->loadHtml($html);
|
||||
$dompdf->setPaper('a6', 'portrait');
|
||||
// Render the HTML as PDF
|
||||
$dompdf->render();
|
||||
|
||||
// Output the generated PDF to Browser
|
||||
// $dompdf->stream();
|
||||
|
||||
$pdfContent = $dompdf->output();
|
||||
|
||||
$labelsPath = Config::get('arrays.PdfPath');
|
||||
// Put the PDF in labels/CarrierLabel
|
||||
$gSFolder = 'GSLabel';
|
||||
$carrierFileName = $gSFolder . '_' . $macpkr . '_' . $cOMPANY . '_' . $wHS;
|
||||
file_put_contents($labelsPath . $gSFolder . '/' . $carrierFileName . '.pdf', $pdfContent);
|
||||
|
||||
// Check if the PDF was generated correctly
|
||||
// if (!file_exists($tempPdfPath) || filesize($tempPdfPath) === 0) {
|
||||
// throw new Exception('PDF generation failed.');
|
||||
// }
|
||||
|
||||
ob_end_clean();
|
||||
if ($sHUSER !== '') {
|
||||
$this->generateLabels($sHUSER, $gSArray);
|
||||
}
|
||||
|
||||
Log::channel('LabelCron')->info('<<< GS1-128...End of Label Creation');
|
||||
@@ -255,4 +80,194 @@ class GenerateGS1Cmd extends Command
|
||||
Log::channel('LabelCron')->error($th);
|
||||
}
|
||||
}
|
||||
|
||||
private function generateLabels(string $sHUSER, array $gSArray): void
|
||||
{
|
||||
// Get User CO & WH from Table ICM428M
|
||||
$iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')
|
||||
->where('R428US', '=', $sHUSER)
|
||||
->first();
|
||||
|
||||
$cOMPANY = isset($iCM428M->R428CO) ? $iCM428M->R428CO : ''; // Company
|
||||
$wHS = isset($iCM428M->R428WH) ? $iCM428M->R428WH : ''; // WareHouse
|
||||
|
||||
$macpkr = $gSArray['Macpkr'];
|
||||
$packageType = '0';
|
||||
$manufactID = '0826528'; // MAK : get ID from Nvent and save to Config File
|
||||
$total_length = 9;
|
||||
|
||||
$html = $this->buildLabelHtml($gSArray, $packageType, $manufactID, $total_length);
|
||||
|
||||
ob_start();
|
||||
|
||||
// Initialize Dompdf
|
||||
$dompdf = new Dompdf;
|
||||
$dompdf->loadHtml($html);
|
||||
$dompdf->setPaper('a6', 'portrait');
|
||||
// Render the HTML as PDF
|
||||
$dompdf->render();
|
||||
|
||||
// Output the generated PDF to Browser
|
||||
// $dompdf->stream();
|
||||
|
||||
$pdfContent = $dompdf->output();
|
||||
|
||||
$labelsPath = Config::get('arrays.PdfPath');
|
||||
// Put the PDF in labels/CarrierLabel
|
||||
$gSFolder = 'GSLabel';
|
||||
$carrierFileName = $gSFolder . '_' . $macpkr . '_' . $cOMPANY . '_' . $wHS;
|
||||
file_put_contents($labelsPath . $gSFolder . '/' . $carrierFileName . '.pdf', $pdfContent);
|
||||
|
||||
// Check if the PDF was generated correctly
|
||||
// if (!file_exists($tempPdfPath) || filesize($tempPdfPath) === 0) {
|
||||
// throw new Exception('PDF generation failed.');
|
||||
// }
|
||||
|
||||
ob_end_clean();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private function buildLabelHtml(array $gSArray, string $packageType, string $manufactID, int $totalLength): string
|
||||
{
|
||||
$html = '
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.border_btm {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
.border_rght {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
|
||||
.margin_t {
|
||||
padding-top : 10px;
|
||||
}
|
||||
|
||||
.align_lft {
|
||||
text-align: left;
|
||||
}
|
||||
.align_center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@page { margin: 5px; }
|
||||
body { margin: 0px; }
|
||||
</style>
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif;">';
|
||||
|
||||
// Get number of Pallets
|
||||
$packageCount = count($gSArray['PackagesArray']);
|
||||
$packageNum = 1;
|
||||
while ($packageNum <= $packageCount) {
|
||||
$table_style = $packageNum < $packageCount ? ' style="page-break-after: always;" ' : '';
|
||||
|
||||
if (Cache::has('GS1SEQUENCE')) {
|
||||
$gS1SEQUENCE = Cache::get('GS1SEQUENCE');
|
||||
$gS1SEQUENCE++;
|
||||
$gS1SEQUENCEID = str_pad($gS1SEQUENCE, $totalLength, '0', STR_PAD_LEFT);
|
||||
}
|
||||
// Box Number Not Found Get it from DB
|
||||
else {
|
||||
$gS1SEQUENCE = 1;
|
||||
$gS1SEQUENCEID = str_pad($gS1SEQUENCE, $totalLength, '0', STR_PAD_LEFT);
|
||||
}
|
||||
Cache::forever('GS1SEQUENCE', $gS1SEQUENCEID);
|
||||
$this->info('>>> GS1 sequence Id: ' . $gS1SEQUENCEID);
|
||||
|
||||
$gs1_128_bc_1 = '00' . $packageType . $manufactID . $gS1SEQUENCEID;
|
||||
|
||||
// Calculate Check Digit
|
||||
$digits = str_split($gs1_128_bc_1);
|
||||
$sum = 0;
|
||||
$length = count($digits);
|
||||
|
||||
// Loop through each digit starting from the right
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$digit = $digits[$length - $i - 1];
|
||||
// Assign a weight of 3 or 1 alternately
|
||||
$weight = ($i % 2 == 0) ? 3 : 1;
|
||||
// Add the product of the digit and its weight to the sum
|
||||
$sum += $digit * $weight;
|
||||
}
|
||||
// Calculate the remainder when sum is divided by 10
|
||||
$remainder = $sum % 10;
|
||||
// If remainder is 0, check digit is 0; otherwise, subtract remainder from 10
|
||||
$checkDigit = ($remainder == 0) ? 0 : 10 - $remainder;
|
||||
|
||||
$gs1_128_bc_desc = '(00)' . $packageType . $manufactID . $gS1SEQUENCEID . $checkDigit;
|
||||
|
||||
$data = [
|
||||
'ship_to' => $gSArray['Recipient_CompanyName'] . '<br>' . $gSArray['Recipient_Address1'] . '<br>' .
|
||||
$gSArray['Recipient_City'] . ',' . $gSArray['Recipient_State']
|
||||
. '<br>' . $gSArray['Recipient_PostalCode'],
|
||||
'from' => $gSArray['Sender_CompanyName'] . '<br>' . $gSArray['Sender_Address1'] . '<br>' .
|
||||
$gSArray['Sender_City'] . ',' . $gSArray['Sender_State']
|
||||
. '<br>' . $gSArray['Sender_PostalCode'],
|
||||
'ship_to_lbl' => '420' . $gSArray['Recipient_PostalCode'],
|
||||
'ship_to_desc' => '(420)' . $gSArray['Recipient_PostalCode'],
|
||||
'pro' => '190071217845706',
|
||||
'item_number' => '10000B',
|
||||
'upc' => '098506095310',
|
||||
'quantity' => '1',
|
||||
'serial_shipping_container' => $gs1_128_bc_desc,
|
||||
];
|
||||
|
||||
// Initialize barcode generator
|
||||
$generator = new BarcodeGeneratorPNG;
|
||||
|
||||
// Generate barcodes
|
||||
$shipToPostalCodeBarcode = $generator->getBarcode($data['ship_to_lbl'], $generator::TYPE_CODE_128);
|
||||
$serialShippingContainerBarcode = $generator->getBarcode($data['serial_shipping_container'], $generator::TYPE_CODE_128, 2, 50);
|
||||
|
||||
// HTML content for the label
|
||||
$html .= '
|
||||
<table ' . $table_style . '>
|
||||
<tr>
|
||||
<td colspan="2" class="border_btm border_rght align_lft">
|
||||
FROM:<br>' . $data['from'] . '
|
||||
</td>
|
||||
<td colspan="2" class="border_btm align_lft">
|
||||
SHIP TO:<br>' . $data['ship_to'] . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" class="border_btm border_rght margin_t align_center">
|
||||
<img src="data:image/png;base64,' . base64_encode($shipToPostalCodeBarcode) . '"> <br>
|
||||
' . $data['ship_to_desc'] . '
|
||||
</td>
|
||||
<td class="border_btm margin_t align_lft">
|
||||
Carrier: ' . $gSArray['CarrierName'] . ' <br>
|
||||
PRO #: ' . $gSArray['ShipmentPONumber'] . ' <br>
|
||||
B/L #: ' . $gSArray['BOLnumber'] . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="border_btm margin_t align_lft border_rght">
|
||||
PURCHASE ORDER: ' . $gSArray['Macpkr'] . ' <br>
|
||||
Vendor: ' . $manufactID . '
|
||||
</td>
|
||||
<td colspan="2" class="border_btm margin_t align_center">
|
||||
Pallet # : ' . $packageNum . ' of ' . $packageCount . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4" style="text-align: center;" class="margin_t">
|
||||
<img src="data:image/png;base64,' . base64_encode($serialShippingContainerBarcode) . '"><br>
|
||||
' . $data['serial_shipping_container'] . '
|
||||
</td>
|
||||
</tr>
|
||||
</table>';
|
||||
|
||||
$packageNum++;
|
||||
}
|
||||
|
||||
$html .= '</body> </html>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -313,40 +313,36 @@ class Helper
|
||||
|
||||
public static function getUserCOWHSPLT()
|
||||
{
|
||||
$defaults = [
|
||||
$result = [
|
||||
'UserCO' => '',
|
||||
'UserWHS' => '',
|
||||
'UserPL' => '',
|
||||
];
|
||||
|
||||
$loggedUser = strtoupper(trim((string) m3_user()));
|
||||
$loggedUser = strtoupper(trim((string) m3User()));
|
||||
if ($loggedUser === '') {
|
||||
return $defaults;
|
||||
return $result;
|
||||
}
|
||||
|
||||
try {
|
||||
if (! Schema::connection(config('m3.connection', 'pgsql'))->hasTable('icm428m')) {
|
||||
return $defaults;
|
||||
if (Schema::connection(config('m3.connection', 'pgsql'))->hasTable('icm428m')) {
|
||||
$user = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428ADMUSR', 'R428PWRUSR', 'R428CO', 'R428PL', 'R428WH', 'R42811A', 'R42821A')
|
||||
->where('R428US', $loggedUser)
|
||||
->first();
|
||||
|
||||
if ($user) {
|
||||
$result = [
|
||||
'UserCO' => trim((string) ($user->R428CO ?? '')),
|
||||
'UserWHS' => trim((string) ($user->R428WH ?? '')),
|
||||
'UserPL' => trim((string) ($user->R428PL ?? '')),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$user = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428ADMUSR', 'R428PWRUSR', 'R428CO', 'R428PL', 'R428WH', 'R42811A', 'R42821A')
|
||||
->where('R428US', $loggedUser)
|
||||
->first();
|
||||
|
||||
if (! $user) {
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
return [
|
||||
'UserCO' => trim((string) ($user->R428CO ?? '')),
|
||||
'UserWHS' => trim((string) ($user->R428WH ?? '')),
|
||||
'UserPL' => trim((string) ($user->R428PL ?? '')),
|
||||
];
|
||||
} catch (\Throwable $e) {
|
||||
\Illuminate\Support\Facades\Log::warning('M3 user context unavailable', ['exception' => $e->getMessage()]);
|
||||
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ if (! function_exists('m3_user')) {
|
||||
* Return the current Core username in the format expected by the legacy M3 data.
|
||||
* M3 previously depended on PHP Basic Auth and read PHP_AUTH_USER directly.
|
||||
*/
|
||||
function m3_user(): string
|
||||
function m3User(): string
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
@@ -29,7 +29,7 @@ if (! function_exists('m3_legacy_password')) {
|
||||
* Passwords are intentionally unavailable in Core. PostgreSQL access uses
|
||||
* Laravel's configured connection and never reuses a user's login password.
|
||||
*/
|
||||
function m3_legacy_password(): string
|
||||
function m3LegacyPassword(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
Executable → Regular
+1
-1032
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\M3\Http\Controllers\API;
|
||||
|
||||
use Config;
|
||||
use DB;
|
||||
use File;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\M3\Http\Controllers\GetContentsController;
|
||||
|
||||
final class CloseShipmentPackageBuilder
|
||||
{
|
||||
public function __construct(private readonly array $context, private readonly mixed $freightTerms)
|
||||
{
|
||||
}
|
||||
|
||||
public function build(array $shipment, array $trailer): array
|
||||
{
|
||||
$state = ['packages' => [], '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']];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\M3\Http\Controllers\API;
|
||||
|
||||
use Config;
|
||||
use DB;
|
||||
use File;
|
||||
use Http;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
use Modules\M3\Helpers\Helper;
|
||||
use Modules\M3\Http\Controllers\GetContentsController;
|
||||
use Str;
|
||||
use Throwable;
|
||||
|
||||
final class CloseShipmentProcessor
|
||||
{
|
||||
private const ZERO_PAD = '000000';
|
||||
private const SOURCE = 'CloseShipmentCoChargeAPI';
|
||||
|
||||
private array $context;
|
||||
|
||||
public function __construct(private readonly Request $request)
|
||||
{
|
||||
$this->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'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\M3\Http\Controllers\API;
|
||||
|
||||
use Config;
|
||||
use DB;
|
||||
use Http;
|
||||
use Log;
|
||||
use Modules\M3\Helpers\Helper;
|
||||
|
||||
final class CloseShipmentStandardProcessor
|
||||
{
|
||||
private const SOURCE = 'CloseShipmentCoChargeAPI';
|
||||
private const JSON_CONTENT_TYPE = 'application/json';
|
||||
private const NULL_M3_RESPONSE = 'M3 API responded with null value';
|
||||
|
||||
public function __construct(
|
||||
private array $context,
|
||||
private readonly string $token,
|
||||
private readonly mixed $freightTerms,
|
||||
) {
|
||||
}
|
||||
|
||||
public function process($shipments)
|
||||
{
|
||||
$allErrors = '';
|
||||
$lastShipment = null;
|
||||
foreach ($shipments as $shipment) {
|
||||
$lastShipment = $this->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'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\M3\Http\Controllers\API;
|
||||
|
||||
use Config;
|
||||
use DB;
|
||||
use Http;
|
||||
use Modules\M3\Helpers\Helper;
|
||||
|
||||
final class CloseShipmentZeroPickProcessor
|
||||
{
|
||||
private const SOURCE = 'CloseShipmentCoChargeAPI';
|
||||
private const JSON_CONTENT_TYPE = 'application/json';
|
||||
private const NULL_M3_RESPONSE = 'M3 API responded with null value';
|
||||
|
||||
public function __construct(private readonly array $context, private readonly string $token)
|
||||
{
|
||||
}
|
||||
|
||||
public function process($shipments)
|
||||
{
|
||||
$errors = '';
|
||||
foreach ($shipments as $row) {
|
||||
$shipment = $this->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'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
Executable → Regular
+207
-426
@@ -13,30 +13,16 @@ use Str;
|
||||
class M3Controller extends Controller
|
||||
{
|
||||
private const FIELD_PREFIX = 'Field: ';
|
||||
|
||||
private const M3_LIST_SUFFIX = ' M3-Lis-JSN';
|
||||
|
||||
// Split Data and Write to ICM666M2
|
||||
public function insertToICM666M2($dataSplit, $commentData)
|
||||
{
|
||||
|
||||
$commentDataSS = explode("\n", $dataSplit);
|
||||
$aXLINENO = 1;
|
||||
foreach ($commentDataSS as $substring) {
|
||||
// Process each substring
|
||||
$fullData = $commentData;
|
||||
$fullData['AXCOMMENT'] = $substring;
|
||||
$fullData['AXLINENO'] = $aXLINENO;
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('icm666m2')->insert($fullData);
|
||||
|
||||
$aXLINENO++;
|
||||
|
||||
// AXCO ICM666M2 CHARACTER 3
|
||||
// AXWHS ICM666M2 CHARACTER 3
|
||||
// AXPLANT ICM666M2 CHARACTER 3
|
||||
// AXDOCUMENT ICM666M2 CHARACTER 15
|
||||
// AXCOMMENT ICM666M2 CHARACTER 60
|
||||
// AXLINENO DECIMAL(3,0)
|
||||
$line = 1;
|
||||
foreach (explode("\n", $dataSplit) as $substring) {
|
||||
$data = $commentData;
|
||||
$data['AXCOMMENT'] = $substring;
|
||||
$data['AXLINENO'] = $line++;
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('icm666m2')->insert($data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,21 +31,216 @@ class M3Controller extends Controller
|
||||
dd('Index');
|
||||
}
|
||||
|
||||
public function create()
|
||||
public function store(Request $request)
|
||||
{
|
||||
// This API controller does not expose a create form.
|
||||
$this->configureTimeouts();
|
||||
$user = m3User() !== '' ? Str::upper(m3User()) : 'WEBUSER';
|
||||
$json = $request->json()->all();
|
||||
$context = $this->rootContext($json, $user);
|
||||
|
||||
try {
|
||||
$response = $json === [] ? $this->emptyPayloadResponse($context) : $this->processPayload($json, $context);
|
||||
} catch (\Throwable $throwable) {
|
||||
$response = $this->exceptionResponse($context, $json, $throwable);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
private function configureTimeouts(): void
|
||||
{
|
||||
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'));
|
||||
}
|
||||
|
||||
$rEQKPKUS = m3_user() !== '' ? Str::upper(m3_user()) : 'WEBUSER';
|
||||
$sHSOURCE = 'M3ReceiverAPI';
|
||||
private function rootContext(array $json, string $user): array
|
||||
{
|
||||
$carrier = $json['CarrierCode'] ?? '';
|
||||
if (($carrier === '' || $carrier === null) && ($json['Warehouse'] ?? '') === '111' && ($json['Company'] ?? '') === '410' && ($json['Plant'] ?? '') === '410') {
|
||||
$carrier = 'BWAY';
|
||||
}
|
||||
return [
|
||||
'user' => $user, 'source' => 'M3ReceiverAPI', 'company' => $json['Company'] ?? '', 'plant' => $json['Plant'] ?? '',
|
||||
'warehouse' => $json['Warehouse'] ?? '', 'order' => $json['OrderNumber'] ?? '', 'picker' => $json['PickerNumber'] ?? '',
|
||||
'prom_date' => $json['PromDate'] ?? '', 'route' => $json['RouteCode'] ?? '', 'category' => $json['OrderCategory'] ?? '',
|
||||
'release' => $json['ReleaseNumber'] ?? '', 'shipment' => $json['ShipmentNumber'] ?? '', 'currency' => $json['Currency'] ?? '',
|
||||
'carrier' => $carrier, 'po' => $json['ShipmentPONumber'] ?? '', 'terms' => $json['ShipTerms'] ?? '',
|
||||
'order_class' => $json['OrderClass'] ?? '', 'gs1' => $json['GS1-128Label'] ?? '0', 'exchange' => $json['CurrencyExchangeRate'] ?? '',
|
||||
'macpkr' => ($json['PickerNumber'] ?? '') !== '' ? $json['PickerNumber'] : '000000',
|
||||
];
|
||||
}
|
||||
|
||||
$iCM666MFields = [
|
||||
private function processPayload(array $json, array $context)
|
||||
{
|
||||
$recipient = $this->recipient($json['Recipient'] ?? []);
|
||||
$this->storeComments($json['Comments'] ?? [], $context);
|
||||
$validation = $this->storeProducts($json['Contents']['Commodities'] ?? [], $context, $recipient, $json);
|
||||
if ($validation !== null) {
|
||||
return $validation;
|
||||
}
|
||||
$this->callUpdateProgram($context, $json);
|
||||
$this->log($context, json_encode($json), '', 'M3-Lis-in');
|
||||
return response()->json(['code' => '200', 'status' => 'success', 'message' => 'File Received, DB Updated']);
|
||||
}
|
||||
|
||||
private function recipient(array $recipient): array
|
||||
{
|
||||
return [
|
||||
'CompanyName' => $recipient['CompanyName'] ?? '', 'Address1' => $recipient['Address1'] ?? '', 'Address2' => $recipient['Address2'] ?? '',
|
||||
'Address3' => $recipient['Address3'] ?? '', 'Address4' => $recipient['Address4'] ?? '', 'City' => $recipient['City'] ?? '',
|
||||
'State' => $recipient['State'] ?? '', 'PostalCode' => $recipient['PostalCode'] ?? '', 'Country' => $recipient['Country'] ?? '',
|
||||
'CountryName' => $recipient['CountryName'] ?? '', 'BillToId' => $recipient['BillToId'] ?? '', 'ShipToId' => $recipient['ShipToId'] ?? '',
|
||||
'PersonName' => $recipient['PersonName'] ?? '', 'AccountNo' => $recipient['AccountNo'] ?? '', 'Email' => $recipient['Email'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
private function storeComments(array $comments, array $c): void
|
||||
{
|
||||
foreach ($comments as $document => $comment) {
|
||||
$document = Helper::sanityzeString($document);
|
||||
if (! in_array($document, ['Picker', 'Packer', 'Carrier', 'Other'], true)) {
|
||||
continue;
|
||||
}
|
||||
$text = Helper::sanityzeString($comment ?? 'null');
|
||||
if ($text === 'null') {
|
||||
continue;
|
||||
}
|
||||
$this->insertToICM666M2($text, [
|
||||
'AXCO' => $c['company'], 'AXPLANT' => $c['plant'], 'AXWHS' => $c['warehouse'], 'AXDELNO' => $c['picker'],
|
||||
'AXONO' => $c['order'], 'AXRLNO' => $c['release'], 'AXSHNO' => $c['shipment'], 'AXDOCUMENT' => $document,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function storeProducts(array $products, array $c, array $recipient, array $json)
|
||||
{
|
||||
foreach ($products as $product) {
|
||||
$values = $this->productValues($product, $c, $recipient, $json);
|
||||
[$insert, $messages] = $this->validatedInsert($values);
|
||||
if ($messages !== []) {
|
||||
$this->log($c, json_encode($messages) . self::M3_LIST_SUFFIX . json_encode($json), 'X', 'M3-Lis-spl');
|
||||
return response()->json($messages);
|
||||
}
|
||||
$this->enrichProduct($insert, $c, (string) ($product['PartNumber'] ?? ''));
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('icm666m')->insert($insert);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function productValues(array $p, array $c, array $r, array $json): array
|
||||
{
|
||||
return array_merge($r, [
|
||||
'Company' => $c['company'], 'Warehouse' => $c['warehouse'], 'Plant' => $c['plant'], 'PickerNumber' => $c['picker'],
|
||||
'OrderNumber' => $c['order'], 'ReleaseNumber' => $c['release'], 'ShipmentNumber' => $c['shipment'],
|
||||
'OrderLine' => $p['OrderLine'] ?? '', 'PartNumber' => $p['PartNumber'] ?? '',
|
||||
'Description' => isset($p['Description']) ? Str::limit($p['Description'], 25, '') : '', 'Quantity' => $p['Quantity'] ?? '',
|
||||
'BaseUnitPrice' => $p['BaseUnitPrice'] ?? '', 'Currency' => $c['currency'], 'Zone' => $p['Zone'] ?? '', 'PromDate' => $c['prom_date'],
|
||||
'RouteCode' => $c['route'], 'PartWeight' => $p['PartWeight'] ?? '', 'SellUOM' => $p['SellUOM'] ?? '', 'PartConv' => $p['PartConv'] ?? '',
|
||||
'CarrierCode' => $c['carrier'], 'ShipVia' => $json['ShipVia'] ?? '', 'PrimaryLocation' => $p['PrimaryLocation'] ?? '',
|
||||
'Allocation' => $p['Allocation'] ?? '', 'AllocatedTo' => $p['AllocatedTo'] ?? '', 'LocationSeq' => $p['LocationSeq'] ?? '',
|
||||
'UOM' => $p['UOM'] ?? '', 'HazMat' => $p['HazMat'] ?? '', 'PartUPC' => $p['PartUPC'] ?? '', 'PartEAN' => $p['PartEAN'] ?? '',
|
||||
'LotFlag' => $p['LotFlag'] ?? '', 'ManOrd' => $p['ManOrd'] ?? '', 'LotNumber' => $p['LotNumber'] ?? '', 'ProductArea' => $p['ProductArea'] ?? '',
|
||||
'FreightClass' => $p['FreightClass'] ?? '', 'ShipmentPONumber' => $c['po'], 'ShipmentPOLine' => $p['ShipmentPOLine'] ?? '',
|
||||
'ShipTerms' => $c['terms'], 'OrderClass' => $c['order_class'], 'LocationType' => $p['LocationType'] ?? '', 'PallSize' => $p['PallSize'] ?? '',
|
||||
'MasterCarton' => $p['MasterCarton'] ?? '', 'MasterQty' => $p['MasterQty'] ?? '', 'InnerQty' => $p['InnerQty'] ?? '',
|
||||
'PalletQty' => $p['PalletQty'] ?? '', 'CartonQty' => $p['CartonQty'] ?? '', 'OrderCategory' => $c['category'],
|
||||
'A1DATEADD' => date('Ymd'), 'A1TIMEADD' => date('His'), 'KitPartNumber' => $p['KitPartNumber'] ?? '',
|
||||
'OrderLineSuffix' => $p['OrderLineSuffix'] ?? '', 'CustomerPartNumber' => isset($p['CustomerPartNumber']) ? substr($p['CustomerPartNumber'], 0, 20) : '',
|
||||
'GS1Label' => $c['gs1'], 'CurrencyExchangeRate' => $c['exchange'],
|
||||
]);
|
||||
}
|
||||
|
||||
private function validatedInsert(array $values): array
|
||||
{
|
||||
$insert = []; $messages = [];
|
||||
foreach ($this->fieldDefinitions() as $key => $definition) {
|
||||
$value = Helper::sanityzeString($values[$key] ?? '');
|
||||
$test = Helper::checkLength($value, $definition[1], $definition[2]);
|
||||
$this->appendValidationMessages($messages, $key, $definition[2], $test);
|
||||
if ($value !== '') {
|
||||
$insert[$definition[0]] = $value;
|
||||
}
|
||||
}
|
||||
return [$insert, $messages];
|
||||
}
|
||||
|
||||
private function appendValidationMessages(array &$messages, string $key, string $type, array $test): void
|
||||
{
|
||||
if (! ($test[413] ?? false)) {
|
||||
$messages[] = ['code' => '413', 'status' => 'error', 'message' => self::FIELD_PREFIX . $key . ' is larger then expected'];
|
||||
}
|
||||
if (! ($test[411] ?? false)) {
|
||||
$messages[] = ['code' => '411', 'status' => 'error', 'message' => self::FIELD_PREFIX . $key . ' is empty'];
|
||||
}
|
||||
if (! ($test[417] ?? false)) {
|
||||
$messages[] = ['code' => '417', 'status' => 'error', 'message' => self::FIELD_PREFIX . $key . 'type is different then Expected type: ' . $type];
|
||||
}
|
||||
}
|
||||
|
||||
private function enrichProduct(array &$insert, array $c, string $part): void
|
||||
{
|
||||
$row = DB::connection(config('m3.connection', 'pgsql'))->table('icm709m')->select()
|
||||
->where('AT9CO', $c['company'])->where('AT9PLT', $c['plant'])->where('AT9WHS', $c['warehouse'])->where('AT9PART', $part)->first();
|
||||
$insert['A1USRN01'] = $row->AT9QTY ?? 0;
|
||||
$insert['A1MATWRN'] = $row->AT9WRN ?? '';
|
||||
}
|
||||
|
||||
private function callUpdateProgram(array $c, array $json): void
|
||||
{
|
||||
if ($c['warehouse'] === '' || $c['picker'] === '' || $c['company'] === '') {
|
||||
return;
|
||||
}
|
||||
$error = '';
|
||||
try {
|
||||
$conn = app(PostgresProgramBridge::class);
|
||||
$conn->setOptions(['persistent' => false, 'stateless' => true, 'debug' => true, 'debugLogFile' => env('TOOLKIT_DEBUG_LOG')]);
|
||||
$params = [$conn->addParameterChar('in', 3, 'Company', '', $c['company']), $conn->addParameterChar('in', 3, 'Warehouse', '', $c['warehouse'])];
|
||||
$params[] = $conn->addParameterChar('in', 11, 'PickerNumber', '', ltrim(strval($c['picker']), '0'));
|
||||
if (! $conn->pgmCall('ICM700CSBM', env('OBJLIB'), $params, [], [])) {
|
||||
$error = 'Error calling program. Code: ' . $conn->getErrorCode() . ' - Msg: ' . $conn->getErrorMsg();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$error = $this->programConnectionError($e);
|
||||
}
|
||||
if ($error !== '') {
|
||||
$this->log($c, $error . self::M3_LIST_SUFFIX . json_encode($json), 'X', 'M3-Lis-spl');
|
||||
}
|
||||
}
|
||||
|
||||
private function programConnectionError(\Throwable $e): string
|
||||
{
|
||||
return match ((int) $e->getCode()) {
|
||||
8001 => 'Could not connect due to wrong user or password.',
|
||||
42705 => 'Database not found. Try WRKRDBDIRE to check.',
|
||||
default => 'Could not connect. Error: ' . $e->getCode() . ' ' . $e->getMessage(),
|
||||
};
|
||||
}
|
||||
|
||||
private function emptyPayloadResponse(array $c)
|
||||
{
|
||||
$data = 'No Json File Found...';
|
||||
Helper::logToICM699M(['SHMACPKR' => $c['macpkr'], 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => 'Z', 'SHINTBOX' => '',
|
||||
'SHTYPE' => 'M3-Lis-in', 'SHDATA' => $data, 'SHUSER' => $c['user'], 'SHSOURCE' => $c['source'], 'SHCO' => $c['company'], 'SHWHS' => $c['warehouse'],
|
||||
'SHACKNOTE' => 'Sentinel automatically closed the error related to this empty data set sent by M3']);
|
||||
return response()->json(['code' => '415', 'status' => 'error', 'message' => 'No Json File Found']);
|
||||
}
|
||||
|
||||
private function exceptionResponse(array $c, array $json, \Throwable $th)
|
||||
{
|
||||
$this->log($c, 'General Catchable Error - ' . substr((string) $th, 0, 300) . self::M3_LIST_SUFFIX . json_encode($json), 'X', 'M3-Lis-in');
|
||||
return response()->json(['code' => '405', 'status' => 'error', 'message' => 'An Error Occured...']);
|
||||
}
|
||||
|
||||
private function log(array $c, string $message, string $error, string $type): void
|
||||
{
|
||||
Helper::logToICM699M(['SHMACPKR' => $c['macpkr'], '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 fieldDefinitions(): array
|
||||
{
|
||||
return [
|
||||
'Company' => ['A1CO', 3, 'string'],
|
||||
'Warehouse' => ['A1WHS', 3, 'string'],
|
||||
'Plant' => ['A1PLANT', 3, 'string'],
|
||||
@@ -131,405 +312,5 @@ class M3Controller extends Controller
|
||||
'CurrencyExchangeRate' => ['A1EXGRATE', 18, 'DEC'],
|
||||
|
||||
];
|
||||
|
||||
try {
|
||||
$jsonFile = count($request->json()->all()) > 0 ? $request->json()->all() : '';
|
||||
|
||||
// Root
|
||||
$company = isset($jsonFile['Company']) ? $jsonFile['Company'] : '';
|
||||
$plant = isset($jsonFile['Plant']) ? $jsonFile['Plant'] : '';
|
||||
$warehouse = isset($jsonFile['Warehouse']) ? $jsonFile['Warehouse'] : '';
|
||||
$orderNumber = isset($jsonFile['OrderNumber']) ? $jsonFile['OrderNumber'] : '';
|
||||
$pickerNumber = isset($jsonFile['PickerNumber']) ? $jsonFile['PickerNumber'] : '';
|
||||
$promDate = isset($jsonFile['PromDate']) ? $jsonFile['PromDate'] : '';
|
||||
$routeCode = isset($jsonFile['RouteCode']) ? $jsonFile['RouteCode'] : '';
|
||||
$orderCategory = isset($jsonFile['OrderCategory']) ? $jsonFile['OrderCategory'] : '';
|
||||
$releaseNumber = isset($jsonFile['ReleaseNumber']) ? $jsonFile['ReleaseNumber'] : '';
|
||||
$shipmentNumber = isset($jsonFile['ShipmentNumber']) ? $jsonFile['ShipmentNumber'] : '';
|
||||
$currency = isset($jsonFile['Currency']) ? $jsonFile['Currency'] : '';
|
||||
$carrierCode = isset($jsonFile['CarrierCode']) ? $jsonFile['CarrierCode'] : '';
|
||||
$shipmentPONumber = isset($jsonFile['ShipmentPONumber']) ? $jsonFile['ShipmentPONumber'] : ''; // CustPo
|
||||
$shipTerms = isset($jsonFile['ShipTerms']) ? $jsonFile['ShipTerms'] : '';
|
||||
$orderClass = isset($jsonFile['OrderClass']) ? $jsonFile['OrderClass'] : '';
|
||||
$gS1Label = isset($jsonFile['GS1-128Label']) ? $jsonFile['GS1-128Label'] : '0';
|
||||
$currencyExchangeRate = isset($jsonFile['CurrencyExchangeRate']) ? $jsonFile['CurrencyExchangeRate'] : '';
|
||||
|
||||
// Set Carrier BWAY if it's empty for Tilburg only
|
||||
if (($carrierCode == '' || $carrierCode == null) && $warehouse == '111' && $company == '410' && $plant == '410') {
|
||||
$carrierCode = 'BWAY';
|
||||
}
|
||||
|
||||
$sHMACPKR = $pickerNumber != '' ? $pickerNumber : '000000';
|
||||
|
||||
if ($jsonFile != '') {
|
||||
// Order Category
|
||||
/*
|
||||
1 = Material to manufacturing order
|
||||
3 = Customer Order
|
||||
4 = Requisition Order
|
||||
5 = Distribution Order
|
||||
9 = Move order / Replenishment
|
||||
*/
|
||||
|
||||
// Recipient
|
||||
$recipient = $jsonFile['Recipient'];
|
||||
$companyName = isset($recipient['CompanyName']) ? $recipient['CompanyName'] : '';
|
||||
$address1 = isset($recipient['Address1']) ? $recipient['Address1'] : '';
|
||||
$address2 = isset($recipient['Address2']) ? $recipient['Address2'] : '';
|
||||
$city = isset($recipient['City']) ? $recipient['City'] : '';
|
||||
$state = isset($recipient['State']) ? $recipient['State'] : '';
|
||||
$postalCode = isset($recipient['PostalCode']) ? $recipient['PostalCode'] : '';
|
||||
$country = isset($recipient['Country']) ? $recipient['Country'] : '';
|
||||
$postalCode = isset($recipient['PostalCode']) ? $recipient['PostalCode'] : '';
|
||||
$billToId = isset($recipient['BillToId']) ? $recipient['BillToId'] : '';
|
||||
$shipToId = isset($recipient['ShipToId']) ? $recipient['ShipToId'] : '';
|
||||
$address3 = isset($recipient['Address3']) ? $recipient['Address3'] : '';
|
||||
$address4 = isset($recipient['Address4']) ? $recipient['Address4'] : '';
|
||||
$countryName = isset($recipient['CountryName']) ? $recipient['CountryName'] : '';
|
||||
$personName = isset($recipient['PersonName']) ? $recipient['PersonName'] : '';
|
||||
$accountNo = isset($recipient['AccountNo']) ? $recipient['AccountNo'] : '';
|
||||
$email = isset($recipient['Email']) ? $recipient['Email'] : '';
|
||||
$a1DATEADD = date('Ymd');
|
||||
$a1TIMEADD = date('His');
|
||||
|
||||
// MycarrierDetails
|
||||
$shipVia = isset($jsonFile['ShipVia']) ? $jsonFile['ShipVia'] : '';
|
||||
|
||||
// Comments
|
||||
$picker = $packer = $carrier = $other = '';
|
||||
$aXCO = $company;
|
||||
$aXPLANT = $plant;
|
||||
$aXWHS = $warehouse;
|
||||
$aXDELNO = $pickerNumber;
|
||||
$aXONO = $orderNumber;
|
||||
$aXRLNO = $releaseNumber;
|
||||
$aXSHNO = $shipmentNumber;
|
||||
|
||||
$comments = isset($jsonFile['Comments']) ? $jsonFile['Comments'] : '';
|
||||
|
||||
if ($comments != '') {
|
||||
foreach ($comments as $key => $comment) {
|
||||
$commentData = [];
|
||||
$aXDOCUMENT = Helper::sanityzeString($key);
|
||||
|
||||
$commentData = ['AXCO' => $aXCO, 'AXPLANT' => $aXPLANT, 'AXWHS' => $aXWHS, 'AXDELNO' => $aXDELNO, 'AXONO' => $aXONO,
|
||||
'AXRLNO' => $aXRLNO, 'AXSHNO' => $aXSHNO, 'AXDOCUMENT' => $aXDOCUMENT];
|
||||
|
||||
switch ($aXDOCUMENT) {
|
||||
case 'Picker':
|
||||
$picker = isset($comment) ? Helper::sanityzeString($comment) : 'null';
|
||||
if ($picker != 'null') {
|
||||
$this->insertToICM666M2($picker, $commentData);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Packer':
|
||||
$packer = isset($comment) ? Helper::sanityzeString($comment) : 'null';
|
||||
if ($packer != 'null') {
|
||||
$this->insertToICM666M2($packer, $commentData);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Carrier':
|
||||
$carrier = isset($comment) ? Helper::sanityzeString($comment) : 'null';
|
||||
if ($carrier != 'null') {
|
||||
$this->insertToICM666M2($carrier, $commentData);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Other':
|
||||
$other = isset($comment) ? Helper::sanityzeString($comment) : 'null';
|
||||
if ($other != 'null') {
|
||||
$this->insertToICM666M2($other, $commentData);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get Products : commodities And Write ICM666M
|
||||
$products = $jsonFile['Contents']['Commodities'];
|
||||
foreach ($products as $key => $product) {
|
||||
$quantity = isset($product['Quantity']) ? $product['Quantity'] : '';
|
||||
$description = isset($product['Description']) ? Str::limit($product['Description'], 25, '') : '';
|
||||
$partNumber = isset($product['PartNumber']) ? $product['PartNumber'] : '';
|
||||
$orderLine = isset($product['OrderLine']) ? $product['OrderLine'] : '';
|
||||
$partWeight = isset($product['PartWeight']) ? $product['PartWeight'] : '';
|
||||
$primaryLocation = isset($product['PrimaryLocation']) ? $product['PrimaryLocation'] : '';
|
||||
$allocation = isset($product['Allocation']) ? $product['Allocation'] : '';
|
||||
$allocatedTo = isset($product['AllocatedTo']) ? $product['AllocatedTo'] : '';
|
||||
$locationSeq = isset($product['LocationSeq']) ? $product['LocationSeq'] : '';
|
||||
$zone = isset($product['Zone']) ? $product['Zone'] : '';
|
||||
$baseUnitPrice = isset($product['BaseUnitPrice']) ? $product['BaseUnitPrice'] : '';
|
||||
$sellUOM = isset($product['SellUOM']) ? $product['SellUOM'] : '';
|
||||
$partConv = isset($product['PartConv']) ? $product['PartConv'] : '';
|
||||
$uOM = isset($product['UOM']) ? $product['UOM'] : '';
|
||||
$hazMat = isset($product['HazMat']) ? $product['HazMat'] : '';
|
||||
$partUPC = isset($product['PartUPC']) ? $product['PartUPC'] : '';
|
||||
$partEAN = isset($product['PartEAN']) ? $product['PartEAN'] : '';
|
||||
$lotFlag = isset($product['LotFlag']) ? $product['LotFlag'] : '';
|
||||
$manOrd = isset($product['ManOrd']) ? $product['ManOrd'] : '';
|
||||
$lotNumber = isset($product['LotNumber']) ? $product['LotNumber'] : '';
|
||||
$productArea = isset($product['ProductArea']) ? $product['ProductArea'] : '';
|
||||
$freightClass = isset($product['FreightClass']) ? $product['FreightClass'] : '';
|
||||
$shipmentPOLine = isset($product['ShipmentPOLine']) ? $product['ShipmentPOLine'] : '';
|
||||
$locationType = isset($product['LocationType']) ? $product['LocationType'] : '';
|
||||
$pallSize = isset($product['PallSize']) ? $product['PallSize'] : '';
|
||||
$masterCarton = isset($product['MasterCarton']) ? $product['MasterCarton'] : '';
|
||||
$masterQty = isset($product['MasterQty']) ? $product['MasterQty'] : '';
|
||||
$innerQty = isset($product['InnerQty']) ? $product['InnerQty'] : '';
|
||||
$sonar_pallet_qty = isset($product['PalletQty']) ? $product['PalletQty'] : '';
|
||||
$cartonQty = isset($product['CartonQty']) ? $product['CartonQty'] : '';
|
||||
$kitPartNumber = isset($product['KitPartNumber']) ? $product['KitPartNumber'] : '';
|
||||
$orderLineSuffix = isset($product['OrderLineSuffix']) ? $product['OrderLineSuffix'] : '';
|
||||
$customerPartNumber = isset($product['CustomerPartNumber']) ? substr($product['CustomerPartNumber'], 0, 20) : ''; // Limit to 20 Chars
|
||||
|
||||
// Initialise Table Fields to be filled
|
||||
$insertArray = [];
|
||||
$fieldValues = [
|
||||
'Company' => $company,
|
||||
'Warehouse' => $warehouse,
|
||||
'Plant' => $plant,
|
||||
'PickerNumber' => $pickerNumber,
|
||||
'OrderNumber' => $orderNumber,
|
||||
'ReleaseNumber' => $releaseNumber,
|
||||
'ShipmentNumber' => $shipmentNumber,
|
||||
'OrderLine' => $orderLine,
|
||||
'PartNumber' => $partNumber,
|
||||
'Description' => $description,
|
||||
'Quantity' => $quantity,
|
||||
'BaseUnitPrice' => $baseUnitPrice,
|
||||
'Currency' => $currency,
|
||||
'Zone' => $zone,
|
||||
'PromDate' => $promDate,
|
||||
'RouteCode' => $routeCode,
|
||||
'BillToId' => $billToId,
|
||||
'ShipToId' => $shipToId,
|
||||
'CompanyName' => $companyName,
|
||||
'Address1' => $address1,
|
||||
'Address2' => $address2,
|
||||
'Address3' => $address3,
|
||||
'Address4' => $address4,
|
||||
'City' => $city,
|
||||
'State' => $state,
|
||||
'PostalCode' => $postalCode,
|
||||
'Country' => $country,
|
||||
'CountryName' => $countryName,
|
||||
'PartWeight' => $partWeight,
|
||||
'SellUOM' => $sellUOM,
|
||||
'PartConv' => $partConv,
|
||||
'CarrierCode' => $carrierCode,
|
||||
'ShipVia' => $shipVia,
|
||||
'PrimaryLocation' => $primaryLocation,
|
||||
'Allocation' => $allocation,
|
||||
'AllocatedTo' => $allocatedTo,
|
||||
'LocationSeq' => $locationSeq,
|
||||
'UOM' => $uOM,
|
||||
'HazMat' => $hazMat,
|
||||
'PartUPC' => $partUPC,
|
||||
'PartEAN' => $partEAN,
|
||||
'LotFlag' => $lotFlag,
|
||||
'ManOrd' => $manOrd,
|
||||
'LotNumber' => $lotNumber,
|
||||
'ProductArea' => $productArea,
|
||||
'FreightClass' => $freightClass,
|
||||
'ShipmentPONumber' => $shipmentPONumber,
|
||||
'ShipmentPOLine' => $shipmentPOLine,
|
||||
'ShipTerms' => $shipTerms,
|
||||
'OrderClass' => $orderClass,
|
||||
'LocationType' => $locationType,
|
||||
'PallSize' => $pallSize,
|
||||
'MasterCarton' => $masterCarton,
|
||||
'MasterQty' => $masterQty,
|
||||
'InnerQty' => $innerQty,
|
||||
'PalletQty' => $sonar_pallet_qty,
|
||||
'CartonQty' => $cartonQty,
|
||||
'PersonName' => $personName,
|
||||
'AccountNo' => $accountNo,
|
||||
'Email' => $email,
|
||||
'OrderCategory' => $orderCategory,
|
||||
'A1DATEADD' => $a1DATEADD,
|
||||
'A1TIMEADD' => $a1TIMEADD,
|
||||
'KitPartNumber' => $kitPartNumber,
|
||||
'OrderLineSuffix' => $orderLineSuffix,
|
||||
'CustomerPartNumber' => $customerPartNumber,
|
||||
'GS1Label' => $gS1Label,
|
||||
'CurrencyExchangeRate' => $currencyExchangeRate,
|
||||
];
|
||||
|
||||
// Check JSON fields if empty or > DB Fields
|
||||
foreach ($iCM666MFields as $key => $value) {
|
||||
// Sanitize String
|
||||
$fieldValue = Helper::sanityzeString($fieldValues[$key] ?? '');
|
||||
// Check Var Types & Length
|
||||
$lengthTest = Helper::checkLength($fieldValue, $value[1], $value[2]);
|
||||
|
||||
if (! $lengthTest[413] || ! $lengthTest[411] || ! $lengthTest[417]) {
|
||||
if (! $lengthTest[413]) {
|
||||
$message[] = ['code' => '413', 'status' => 'error', 'message' => self::FIELD_PREFIX . $key . ' is larger then expected'];
|
||||
}
|
||||
if (! $lengthTest[411]) {
|
||||
$message[] = ['code' => '411', 'status' => 'error', 'message' => self::FIELD_PREFIX . $key . ' is empty'];
|
||||
}
|
||||
if (! $lengthTest[417]) {
|
||||
$message[] = ['code' => '417', 'status' => 'error', 'message' => self::FIELD_PREFIX . $key . 'type is different then Expected type: ' . $value[2]];
|
||||
}
|
||||
|
||||
// Write to Logs Out : Error & JSON
|
||||
$data = ['SHMACPKR' => $sHMACPKR, 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => 'X', 'SHINTBOX' => '', 'SHTYPE' => 'M3-Lis-spl',
|
||||
'SHDATA' => json_encode($message) . self::M3_LIST_SUFFIX . json_encode($jsonFile), 'SHUSER' => $rEQKPKUS, 'SHSOURCE' => $sHSOURCE, 'SHCO' => $company, 'SHWHS' => $warehouse];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
return response()->json($message);
|
||||
} elseif ($fieldValue != '') {
|
||||
$insertArray[$value[0]] = $fieldValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check ICM709M
|
||||
$iCM709MSEL = DB::connection(config('m3.connection', 'pgsql'))->table('icm709m')
|
||||
->select()
|
||||
->where('AT9CO', $aXCO)
|
||||
->where('AT9PLT', $aXPLANT)
|
||||
->where('AT9WHS', $aXWHS)
|
||||
->where('AT9PART', $partNumber)
|
||||
->first();
|
||||
$palletQty = isset($iCM709MSEL->AT9QTY) ? $iCM709MSEL->AT9QTY : 0;
|
||||
// dd($palletQty);
|
||||
// Get Pallet Qty
|
||||
$insertArray['A1USRN01'] = $palletQty;
|
||||
|
||||
// Hazard Material
|
||||
$hazMat = isset($iCM709MSEL->AT9WRN) ? $iCM709MSEL->AT9WRN : '';
|
||||
$insertArray['A1MATWRN'] = $hazMat;
|
||||
|
||||
// }
|
||||
|
||||
// SQL Insert to ICM666M
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('icm666m')->insert($insertArray);
|
||||
}
|
||||
|
||||
// Call PGM ICM700CSBM
|
||||
if ($warehouse != '' && $pickerNumber != '' && $company != '') {
|
||||
$pGMERRORS = '';
|
||||
|
||||
// connect to toolkit using DB2 credentials (can also leave blank for default authority)
|
||||
try {
|
||||
$conn = app(PostgresProgramBridge::class);
|
||||
} catch (\Throwable $e) {
|
||||
// Determine reason for failure.
|
||||
// Probably database authentication error or invalid or unreachable database.
|
||||
$code = $e->getCode();
|
||||
$msg = $e->getMessage();
|
||||
|
||||
switch ($code) {
|
||||
case 8001:
|
||||
// "Authorization failure on distributed database connection attempt"
|
||||
// Usually means a wrong DB2 user or password
|
||||
$pGMERRORS = 'Could not connect due to wrong user or password.';
|
||||
break;
|
||||
case 42705:
|
||||
$pGMERRORS = 'Database not found. Try WRKRDBDIRE to check.';
|
||||
break;
|
||||
default:
|
||||
$pGMERRORS = 'Could not connect. Error: ' . $code . ' ' . $msg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$conn->setOptions(['persistent' => false, 'stateless' => true, 'debug' => true, 'debugLogFile' => env('TOOLKIT_DEBUG_LOG')]);
|
||||
|
||||
// Add LIB
|
||||
// $result = $conn->CLCommand('ADDLIBLE LIB(MPDAT10)');
|
||||
|
||||
// define several input/output params
|
||||
$params = [];
|
||||
|
||||
// AddParameterChar($io, $size, $comment, $varName, $value, $varying, $dimension)
|
||||
// Add Warehouse Param
|
||||
$params[] = $conn->AddParameterChar('in', 3, 'Company', '', $company);
|
||||
|
||||
$params[] = $conn->AddParameterChar('in', 3, 'Warehouse', '', $warehouse);
|
||||
|
||||
// AddParameterPackDec($io, $length, $scale, $comment, $varName, $value,$dimension)
|
||||
// Add Delivery Note Param
|
||||
$pickerNumberNoZero = ltrim(strval($pickerNumber), '0');
|
||||
$params[] = $conn->AddParameterChar('in', 11, 'PickerNumber', '', $pickerNumberNoZero);
|
||||
|
||||
// Start Time Tracking
|
||||
|
||||
// ICM700C EWOBJTST ICM700C ICM700CSBM
|
||||
$result = $conn->PgmCall('ICM700CSBM', env('OBJLIB'), $params, [], []);
|
||||
|
||||
if (! $result) {
|
||||
$pGMERRORS = 'Error calling program. Code: ' . $conn->getErrorCode() . ' - Msg: ' . $conn->getErrorMsg();
|
||||
}
|
||||
|
||||
if ($pGMERRORS != '') {
|
||||
// Write to Logs Out : Error & JSON
|
||||
$data = ['SHMACPKR' => $sHMACPKR, 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => 'X', 'SHINTBOX' => '', 'SHTYPE' => 'M3-Lis-spl',
|
||||
'SHDATA' => $pGMERRORS . self::M3_LIST_SUFFIX . json_encode($jsonFile), 'SHUSER' => $rEQKPKUS, 'SHSOURCE' => $sHSOURCE, 'SHCO' => $company, 'SHWHS' => $warehouse];
|
||||
Helper::logToICM699M($data);
|
||||
}
|
||||
}
|
||||
|
||||
// Write to Logs Out : Success
|
||||
$data = ['SHMACPKR' => $sHMACPKR, 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => '', 'SHINTBOX' => '', 'SHTYPE' => 'M3-Lis-in',
|
||||
'SHDATA' => json_encode($jsonFile), 'SHUSER' => $rEQKPKUS, 'SHSOURCE' => $sHSOURCE, 'SHCO' => $company, 'SHWHS' => $warehouse];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
return response()->json([
|
||||
'code' => '200',
|
||||
'status' => 'success',
|
||||
'message' => 'File Received, DB Updated',
|
||||
]);
|
||||
} else {
|
||||
// Write to Logs Out : Error & JSON
|
||||
$sHACKNOTE = 'Sentinel automatically closed the error related to this empty data set sent by M3';
|
||||
|
||||
$data = ['SHMACPKR' => $sHMACPKR, 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => 'Z', 'SHINTBOX' => '', 'SHTYPE' => 'M3-Lis-in',
|
||||
'SHDATA' => 'No Json File Found...', 'SHUSER' => $rEQKPKUS, 'SHSOURCE' => $sHSOURCE, 'SHCO' => $company, 'SHWHS' => $warehouse, 'SHACKNOTE' => $sHACKNOTE];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
return response()->json([
|
||||
'code' => '415',
|
||||
'status' => 'error',
|
||||
'message' => 'No Json File Found',
|
||||
]);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
// Write to Logs Out : Error & JSON
|
||||
$data = ['SHMACPKR' => $sHMACPKR, 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => 'X', 'SHINTBOX' => '', 'SHTYPE' => 'M3-Lis-in',
|
||||
'SHDATA' => 'General Catchable Error - ' . substr($th, 0, 300) . self::M3_LIST_SUFFIX . json_encode($jsonFile), 'SHUSER' => $rEQKPKUS, 'SHSOURCE' => $sHSOURCE, 'SHCO' => $company, 'SHWHS' => $warehouse];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
return response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'error',
|
||||
'message' => 'An Error Occured...',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
// This resource endpoint is intentionally unsupported.
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
// This resource endpoint is intentionally unsupported.
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
// This resource endpoint is intentionally unsupported.
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
// This resource endpoint is intentionally unsupported.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,37 +18,36 @@ class PdfStorage extends Controller
|
||||
public function PdfStorageAPI(Request $request): JsonResponse
|
||||
{
|
||||
$this->configureTimeouts();
|
||||
|
||||
$context = $this->requestContext($request);
|
||||
|
||||
if ($context === null) {
|
||||
return $this->errorResponse('No URL Parameters Sent', self::ZERO_PAD, '', '', '');
|
||||
}
|
||||
$result = $this->errorResponse('No URL Parameters Sent', self::ZERO_PAD, '', '', '');
|
||||
} else {
|
||||
try {
|
||||
$this->logRequest($context);
|
||||
$cacheKey = $this->buildCacheKey($context);
|
||||
$pdfFileName = (string) Config::get('arrays.PdfPath') . $context['FILENAME'] . '.pdf';
|
||||
$error = $this->validateStorageRequest($pdfFileName, $cacheKey);
|
||||
|
||||
try {
|
||||
$this->logRequest($context);
|
||||
|
||||
$cacheKey = $this->buildCacheKey($context);
|
||||
$pdfFileName = (string) Config::get('arrays.PdfPath') . $context['FILENAME'] . '.pdf';
|
||||
$error = $this->validateStorageRequest($pdfFileName, $cacheKey);
|
||||
|
||||
if ($error !== null) {
|
||||
return $this->errorResponse($error, $context['DELIVERYNO'], $context['DOCNUM'], $context['COMPANY'], $context['WHS']);
|
||||
if ($error !== null) {
|
||||
$result = $this->errorResponse($error, $context['DELIVERYNO'], $context['DOCNUM'], $context['COMPANY'], $context['WHS']);
|
||||
} else {
|
||||
Cache::forever($cacheKey, base64_encode(File::get($pdfFileName)));
|
||||
$this->logResult($context, 'PDF File converted to Base64 and Saved to Cache.Key: ' . $cacheKey);
|
||||
$result = response()->json(['code' => '200', 'status' => 'Success', 'cacheKey' => $cacheKey]);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$message = 'An Error Occured - ' . substr($exception->getMessage(), 0, 300);
|
||||
$this->safeLog($context, $message, true);
|
||||
$result = response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'error',
|
||||
'message' => 'Catched Error: ' . $exception->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
Cache::forever($cacheKey, base64_encode(File::get($pdfFileName)));
|
||||
$this->logResult($context, 'PDF File converted to Base64 and Saved to Cache.Key: ' . $cacheKey);
|
||||
|
||||
return response()->json(['code' => '200', 'status' => 'Success', 'cacheKey' => $cacheKey]);
|
||||
} catch (\Throwable $exception) {
|
||||
$message = 'An Error Occured - ' . substr($exception->getMessage(), 0, 300);
|
||||
$this->safeLog($context, $message, true);
|
||||
|
||||
return response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'error',
|
||||
'message' => 'Catched Error: ' . $exception->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function configureTimeouts(): void
|
||||
@@ -71,7 +70,7 @@ class PdfStorage extends Controller
|
||||
}
|
||||
|
||||
$context['DELIVERYNO'] = $context['A4MACPKR'] !== '' ? $context['A4MACPKR'] : self::ZERO_PAD;
|
||||
$context['SHUSER'] = m3_user() !== '' ? Str::upper(m3_user()) : 'WebUser';
|
||||
$context['SHUSER'] = m3User() !== '' ? Str::upper(m3User()) : 'WebUser';
|
||||
$context['SHSOURCE'] = 'PdfStorageAPI';
|
||||
|
||||
return $context;
|
||||
@@ -123,7 +122,7 @@ class PdfStorage extends Controller
|
||||
'SHINTBOX' => $context['DOCNUM'] ?? '',
|
||||
'SHTYPE' => $type,
|
||||
'SHDATA' => $message,
|
||||
'SHUSER' => $context['SHUSER'] ?? (m3_user() !== '' ? Str::upper(m3_user()) : 'WebUser'),
|
||||
'SHUSER' => $context['SHUSER'] ?? (m3User() !== '' ? Str::upper(m3User()) : 'WebUser'),
|
||||
'SHSOURCE' => $context['SHSOURCE'] ?? 'PdfStorageAPI',
|
||||
'SHCO' => $context['COMPANY'] ?? '',
|
||||
'SHWHS' => $context['WHS'] ?? '',
|
||||
@@ -140,7 +139,7 @@ class PdfStorage extends Controller
|
||||
'DOCNUM' => $docNum,
|
||||
'COMPANY' => $company,
|
||||
'WHS' => $warehouse,
|
||||
'SHUSER' => m3_user() !== '' ? Str::upper(m3_user()) : 'WebUser',
|
||||
'SHUSER' => m3User() !== '' ? Str::upper(m3User()) : 'WebUser',
|
||||
'SHSOURCE' => 'PdfStorageAPI',
|
||||
];
|
||||
$this->safeLog($context, 'An Error Occured -' . $message, true);
|
||||
|
||||
Executable → Regular
+158
-236
@@ -6,8 +6,6 @@ use Config;
|
||||
use DB;
|
||||
use Http;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Log;
|
||||
use Modules\M3\Helpers\Helper;
|
||||
use Modules\M3\Http\Controllers\Controller;
|
||||
use Str;
|
||||
@@ -15,262 +13,186 @@ use Str;
|
||||
class ReplenAPI extends Controller
|
||||
{
|
||||
private const ZERO_PAD = '000000';
|
||||
|
||||
private const JSON_CONTENT_TYPE = 'application/json';
|
||||
private const SOURCE = 'M3InventoryReportReplen';
|
||||
|
||||
// M3Replenishement with URL Params
|
||||
public function M3InventoryReportReplen(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'));
|
||||
|
||||
// dd($request->all());
|
||||
// Log::info( $request->all() );
|
||||
// Get The Calling User
|
||||
$sHUSER = m3_user() !== '' ? Str::upper(m3_user()) : 'WebUser';
|
||||
$mACPKR = isset($mACPKR) ? $mACPKR : self::ZERO_PAD;
|
||||
$sHSOURCE = 'M3InventoryReportReplen';
|
||||
$m3Errors = '';
|
||||
$this->configureTimeouts();
|
||||
$context = $this->requestContext($request);
|
||||
|
||||
try {
|
||||
// Get Json Contents
|
||||
$urlParams = count($request->all()) > 0 ? $request->all() : '';
|
||||
$response = $this->processInventoryRequest($context);
|
||||
} catch (\Throwable $throwable) {
|
||||
$response = $this->exceptionResponse($context, $throwable);
|
||||
}
|
||||
|
||||
$cO = isset($urlParams['CO']) ? $urlParams['CO'] : '';
|
||||
$wHS = isset($urlParams['WHS']) ? $urlParams['WHS'] : '';
|
||||
$pARTNO = isset($urlParams['PARTNO']) ? $urlParams['PARTNO'] : '';
|
||||
$pKLN = isset($urlParams['PKLN']) ? $urlParams['PKLN'] : '';
|
||||
$rEQPKWS = isset($urlParams['REQPKWS']) ? $urlParams['REQPKWS'] : '';
|
||||
$rEQKPKUS = isset($urlParams['REQKPKUS']) ? $urlParams['REQKPKUS'] : 'WebUser';
|
||||
return $response;
|
||||
}
|
||||
|
||||
if ($urlParams != '') {
|
||||
$incomingParams = ['CO' => $cO, 'WHS' => $wHS, 'PARTNO' => $pARTNO, 'PKLN' => $pKLN, 'REQPKWS' => $rEQPKWS, 'REQKPKUS' => $rEQKPKUS];
|
||||
$incomingParams = json_encode($incomingParams);
|
||||
private function processInventoryRequest(array $context)
|
||||
{
|
||||
if ($context['params'] === []) {
|
||||
return $this->missingParametersResponse($context);
|
||||
}
|
||||
|
||||
// Write to Logs : Params In
|
||||
$data = ['SHMACPKR' => $mACPKR, 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => '', 'SHINTBOX' => '', 'SHTYPE' => 'M3-Req-out',
|
||||
'SHDATA' => $incomingParams, 'SHUSER' => $sHUSER, 'SHSOURCE' => $sHSOURCE, 'SHCO' => $cO, 'SHWHS' => $wHS];
|
||||
Helper::logToICM699M($data);
|
||||
$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;
|
||||
}
|
||||
|
||||
$pART = explode(',', $pARTNO);
|
||||
foreach ($pART as $value) {
|
||||
$pARTS[] = ['PART' => $value, 'LOT' => ''];
|
||||
}
|
||||
return $this->inventoryResponse($context, (string) ($tokenData->token ?? ''));
|
||||
}
|
||||
|
||||
$jSON = json_encode(['WHS' => $wHS, 'PARTS' => $pARTS]);
|
||||
private function inventoryResponse(array $context, string $token)
|
||||
{
|
||||
$result = $this->fetchInventory($context, $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']]);
|
||||
}
|
||||
|
||||
// Write to Logs : Params Sent To M3
|
||||
$data = ['SHMACPKR' => $mACPKR, 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => '', 'SHINTBOX' => '', 'SHTYPE' => 'M3-Req-out',
|
||||
'SHDATA' => 'Sent To M3-' . $jSON, 'SHUSER' => $sHUSER, 'SHSOURCE' => $sHSOURCE, 'SHCO' => $cO, 'SHWHS' => $wHS];
|
||||
Helper::logToICM699M($data);
|
||||
$this->log($context, $result['status'] . '-' . $result['json'] . $result['session'], '', 'M3-Res-out');
|
||||
$rows = $this->flattenInventory($result['result']);
|
||||
$this->replaceInventory($context, $rows);
|
||||
|
||||
// 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 : '';
|
||||
// Write to Logs : Error
|
||||
$data = ['SHMACPKR' => $mACPKR, 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => 'X', 'SHINTBOX' => '', 'SHTYPE' => 'M3-Res-out',
|
||||
'SHDATA' => $sHDATA, 'SHUSER' => $sHUSER, 'SHSOURCE' => $sHSOURCE, 'SHCO' => $cO, 'SHWHS' => $wHS];
|
||||
Helper::logToICM699M($data);
|
||||
return response()->json(['code' => '200', 'status' => 'Success']);
|
||||
}
|
||||
|
||||
return $tokenResponse;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// Call ionapi with Params
|
||||
$endPointURL = env('ENDPOINTURL') . 'APIFLOWS/Sentinel/M3InventoryReportList?ionapiRespStyle=sync';
|
||||
$token = $ionToken;
|
||||
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,
|
||||
];
|
||||
}
|
||||
|
||||
$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'))
|
||||
->retry(3, 100)
|
||||
->post($endPointURL);
|
||||
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');
|
||||
}
|
||||
|
||||
$responseStatusCode = $response->getStatusCode();
|
||||
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]);
|
||||
}
|
||||
|
||||
$m3SessionId = $response->hasHeader('x-transaction-id') ? '-sessionID:' . $response->header('x-transaction-id') : '-sessionID';
|
||||
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');
|
||||
|
||||
if ($responseStatusCode == '200') {
|
||||
// Check M3 Response for Errors
|
||||
$m3Errors = '';
|
||||
$responseJSON = $response->getBody()->getContents();
|
||||
$jsonSanytized = Helper::sanityzeString($responseJSON);
|
||||
// Array
|
||||
$responseArray = json_decode($jsonSanytized, true);
|
||||
$responseTMP = $responseArray['result'];
|
||||
} else {
|
||||
$m3Errors = 'Error: No Response from M3';
|
||||
}
|
||||
$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' => []];
|
||||
}
|
||||
|
||||
// Validate response From M3
|
||||
if ($m3Errors != '') {
|
||||
// Write to Logs : Error
|
||||
$data = ['SHMACPKR' => $mACPKR, 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => 'X', 'SHINTBOX' => '', 'SHTYPE' => 'M3-Res-out',
|
||||
'SHDATA' => $responseStatusCode . '-' . $m3Errors . $m3SessionId, 'SHUSER' => $sHUSER, 'SHSOURCE' => $sHSOURCE, 'SHCO' => $cO, 'SHWHS' => $wHS];
|
||||
Helper::logToICM699M($data);
|
||||
$json = Helper::sanityzeString($response->getBody()->getContents());
|
||||
$decoded = json_decode($json, true);
|
||||
return ['status' => $status, 'session' => $session, 'error' => '', 'json' => $json, 'result' => $decoded['result'] ?? []];
|
||||
}
|
||||
|
||||
// Send Response
|
||||
return response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'error',
|
||||
'message' => 'Error: No Response from M3',
|
||||
]);
|
||||
} else {
|
||||
// Write to Logs : JSON
|
||||
$data = ['SHMACPKR' => $mACPKR, 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => '', 'SHINTBOX' => '', 'SHTYPE' => 'M3-Res-out',
|
||||
'SHDATA' => $responseStatusCode . '-' . $jsonSanytized . $m3SessionId, 'SHUSER' => $sHUSER, 'SHSOURCE' => $sHSOURCE, 'SHCO' => $cO, 'SHWHS' => $wHS];
|
||||
Helper::logToICM699M($data);
|
||||
}
|
||||
|
||||
$dataToWrite2 = [];
|
||||
foreach ($responseTMP as $value) {
|
||||
$dataToWrite = [];
|
||||
|
||||
foreach ($value as $key2 => $content) {
|
||||
if ($key2 != 'Locations') {
|
||||
$dataToWrite[$key2] = $content;
|
||||
} else {
|
||||
foreach ($content as $content2) {
|
||||
$dataToWrite2[] = array_merge($dataToWrite, $content2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete Old Records from IC630M
|
||||
foreach ($dataToWrite2 as $value) {
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('ic630m')
|
||||
->where('LLCO', $cO)
|
||||
->where('LLWHNO', $wHS)
|
||||
->where('LLPPN', trim($value['PartNumber']))
|
||||
->delete();
|
||||
}
|
||||
|
||||
foreach ($dataToWrite2 as $value) {
|
||||
// Check if Location exist in DE640M $value['Location']
|
||||
$dE640MSQLSEL = DB::connection(config('m3.connection', 'pgsql'))->table('de640m')
|
||||
->where('LVCO', $cO)
|
||||
->where('WSELOC', $value['Warehouse'])
|
||||
->where('VLOCID', $value['Location'])
|
||||
->first();
|
||||
|
||||
$locationExist = isset($dE640MSQLSEL->VLOCID) ? trim($dE640MSQLSEL->VLOCID) : '';
|
||||
$wHExist = isset($dE640MSQLSEL->WSELOC) ? trim($dE640MSQLSEL->WSELOC) : '';
|
||||
$cOExist = isset($dE640MSQLSEL->LVCO) ? trim($dE640MSQLSEL->LVCO) : '';
|
||||
|
||||
// if No records Founds insert New Record
|
||||
if ($locationExist == '' && $wHExist == '' && $cOExist == '') {
|
||||
$sQLInsertPrep640M['LVCO'] = $cO; // Company
|
||||
$sQLInsertPrep640M['WSELOC'] = $value['Warehouse'];
|
||||
// $sQLInsertPrep640M['LVUSD3'] = $value['']; // Pallet Size : Not Found in M3 JSON
|
||||
$sQLInsertPrep640M['VLOCID'] = $value['Location']; // Stock location
|
||||
$sQLInsertPrep640M['LVSEQN'] = $value['LocationSeq'];
|
||||
$sQLInsertPrep640M['LVUSD2'] = $value['LocationType'];
|
||||
$sQLInsertPrep640M['LVZONE'] = $value['Zone']; // Warehouse zone
|
||||
$sQLInsertPrep640M['LVMAINTTS'] = now(); // Last maintained time stamp
|
||||
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('de640m')->insert($sQLInsertPrep640M);
|
||||
}
|
||||
// Update
|
||||
else {
|
||||
$sQLUpdatePrep640M['LVSEQN'] = $value['LocationSeq'];
|
||||
$sQLUpdatePrep640M['LVUSD2'] = $value['LocationType'];
|
||||
$sQLUpdatePrep640M['LVZONE'] = $value['Zone'];
|
||||
$sQLUpdatePrep640M['LVMAINTTS'] = now();
|
||||
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('de640m')
|
||||
->where('LVCO', $cO)
|
||||
->where('WSELOC', $value['Warehouse'])
|
||||
->where('VLOCID', $value['Location'])
|
||||
->update($sQLUpdatePrep640M);
|
||||
}
|
||||
|
||||
// Insert New Records to IC630M
|
||||
$sQLInsertPrep630M = [];
|
||||
$sQLInsertPrep630M['LLCO'] = $cO; // Company
|
||||
$sQLInsertPrep630M['LLWHNO'] = $value['Warehouse']; // Warehouse
|
||||
$sQLInsertPrep630M['LLPPN'] = $value['PartNumber']; // Part Number
|
||||
$sQLInsertPrep630M['LLBALANCE'] = $value['Quantity']; // Quantity
|
||||
$sQLInsertPrep630M['LLSTLC'] = $value['Location']; // Stock location
|
||||
$sQLInsertPrep630M['LLLTNO'] = $value['LotNumber']; // Lot Number
|
||||
$sQLInsertPrep630M['LLMAINTTS'] = now(); // Request time timestamp
|
||||
$sQLInsertPrep630M['LLIZLCF'] = trim($value['LotNumber']) != '' ? '1' : ''; // Lot control flag
|
||||
$sQLInsertPrep630M['LLSPR10A01'] = $value['Allocation']; // Allocation
|
||||
$sQLInsertPrep630M['LLSPR15A01'] = $value['AllocatedTo']; // AllocatedTo
|
||||
|
||||
$descSanytized = Helper::sanityzeString($value['Description']);
|
||||
// $descSanytized = str_replace(['–','\u20131'], '-',$value['Description']);
|
||||
$sQLInsertPrep630M['LLCMDESC'] = $descSanytized; // Description
|
||||
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('ic630m')->insert($sQLInsertPrep630M);
|
||||
}
|
||||
|
||||
// Send Response
|
||||
return response()->json([
|
||||
'code' => '200',
|
||||
'status' => 'Success',
|
||||
]);
|
||||
} else {
|
||||
// Write to Logs Out : Error
|
||||
$mACPKR = isset($mACPKR) ? $mACPKR : self::ZERO_PAD;
|
||||
$data = ['SHMACPKR' => $mACPKR, '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' => $cO, 'SHWHS' => $wHS];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
// Return Error
|
||||
return response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'Error',
|
||||
'message' => 'No URL Parameters Sent',
|
||||
]);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
// Write to Logs Out : Error
|
||||
$mACPKR = isset($mACPKR) ? $mACPKR : self::ZERO_PAD;
|
||||
|
||||
$getCurlErrors = str_contains($th->getMessage(), 'cURL error');
|
||||
if ($getCurlErrors) {
|
||||
// dd($getCurlErrors);
|
||||
// Write to Logs Out : Failed
|
||||
$data = ['SHMACPKR' => $mACPKR, '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' . $incomingParams, 'SHUSER' => $sHUSER, 'SHSOURCE' => $sHSOURCE, 'SHCO' => $cO, 'SHWHS' => $wHS];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
return response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'error',
|
||||
'message' => 'Curl Error: Communication with M3 Timed Out.',
|
||||
]);
|
||||
} else {
|
||||
// Set SHERROR To Z if Duplicate Key Detected $th
|
||||
// Read The substring from SHDATA after M3-JSN-out
|
||||
$sHERROR = 'X';
|
||||
$word = 'Duplicate key value specified';
|
||||
$position = strpos($th, $word);
|
||||
|
||||
if ($position !== false) {
|
||||
$sHERROR = 'Z';
|
||||
}
|
||||
|
||||
$data = ['SHMACPKR' => $mACPKR, 'SHDT' => date('Y-m-d'), 'SHTIME' => date('H:i:s'), 'SHERROR' => $sHERROR, 'SHINTBOX' => '', 'SHTYPE' => 'M3-Res-out',
|
||||
'SHDATA' => 'An Error Occured - ' . substr($th, 0, 300), 'SHUSER' => $sHUSER, 'SHSOURCE' => $sHSOURCE, 'SHCO' => $cO, 'SHWHS' => $wHS];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
return response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'error',
|
||||
'message' => 'Catched Error: ' . $th,
|
||||
]);
|
||||
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'],
|
||||
]);
|
||||
}
|
||||
// End M3InventoryReportReplen
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ use DateTime;
|
||||
use DB;
|
||||
use Http;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Log;
|
||||
use Modules\M3\Helpers\Helper;
|
||||
use Modules\M3\Http\Controllers\Controller;
|
||||
@@ -15,684 +14,292 @@ 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';
|
||||
|
||||
// TransferAPIURL : with URL PARAMS
|
||||
public function TransferAPIURL(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'));
|
||||
|
||||
// Get the Calling User
|
||||
$sHUSER = m3_user() !== '' ? Str::upper(m3_user()) : 'WebUser';
|
||||
// Set SHSOURCE
|
||||
$sHSOURCE = 'TransferAPIURL';
|
||||
$m3Errors = '';
|
||||
|
||||
// Get URL PARAMS
|
||||
$urlParams = count($request->all()) > 0 ? $request->all() : '';
|
||||
$dIVI = isset($urlParams['COMPANY']) ? $urlParams['COMPANY'] : '';
|
||||
$wHS = isset($urlParams['WHS']) ? $urlParams['WHS'] : '';
|
||||
$this->configureTimeouts();
|
||||
$context = $this->transferContext($request);
|
||||
|
||||
try {
|
||||
if ($urlParams != '') {
|
||||
$pART = isset($urlParams['PART']) ? $urlParams['PART'] : '';
|
||||
$lOCATIONFROM = isset($urlParams['LOCATIONFROM']) ? $urlParams['LOCATIONFROM'] : '';
|
||||
$lOCATIONTO = isset($urlParams['LOCATIONTO']) ? $urlParams['LOCATIONTO'] : '';
|
||||
$qUANTITY = isset($urlParams['QUANTITY']) ? $urlParams['QUANTITY'] : '';
|
||||
$oRDERCATEGORY = isset($urlParams['ORDERCATEGORY']) ? $urlParams['ORDERCATEGORY'] : '';
|
||||
$lOTNUMBER = isset($urlParams['LOTNUMBER']) ? $urlParams['LOTNUMBER'] : '';
|
||||
$cONUMBER = isset($urlParams['CONUMBER']) ? $urlParams['CONUMBER'] : '';
|
||||
$cOLINENO = isset($urlParams['COLINENO']) ? $urlParams['COLINENO'] : '';
|
||||
$dELIVERYNO = isset($urlParams['DELIVERYNO']) ? $urlParams['DELIVERYNO'] : self::ZERO_PAD;
|
||||
$pICKLISTSUFFIX = isset($urlParams['PICKLISTSUFFIX']) ? $urlParams['PICKLISTSUFFIX'] : '';
|
||||
$eNDFLAG = isset($urlParams['ENDFLAG']) ? $urlParams['ENDFLAG'] : '';
|
||||
$tYPE = isset($urlParams['TYPE']) ? $urlParams['TYPE'] : '';
|
||||
$cOLINESUFFIX = isset($urlParams['COLINESUFFIX']) ? $urlParams['COLINESUFFIX'] : '';
|
||||
|
||||
// TYPE :
|
||||
// DeliveryNote
|
||||
// S15
|
||||
// CloseShipment
|
||||
// COCharge
|
||||
// Replenishment
|
||||
// Move
|
||||
|
||||
// ORDERCATEGORY : Order Category
|
||||
// 1 = Material to manufacturing order
|
||||
// 3 = Customer Order
|
||||
// 4 = Requisition Order
|
||||
// 5 = Distribution Order
|
||||
// 9 = Move order
|
||||
|
||||
$dELIVERYNO = isset($dELIVERYNO) ? $dELIVERYNO : self::ZERO_PAD;
|
||||
|
||||
$tRANSTYPE = isset($urlParams['TRANSTYPE']) ? $urlParams['TRANSTYPE'] : ''; // R for Retry
|
||||
$sHDT = isset($urlParams['SHDT']) ? $urlParams['SHDT'] : '';
|
||||
$sHTIME = isset($urlParams['SHTIME']) ? $urlParams['SHTIME'] : '';
|
||||
$sHTYPE = isset($urlParams['SHTYPE']) ? $urlParams['SHTYPE'] : '';
|
||||
|
||||
// Retry Transfer
|
||||
if ($tRANSTYPE == 'R') {
|
||||
// $t = strtotime($sHTIME);
|
||||
// $SHTIMEHM = date('H:i',$t);
|
||||
// dd($SHTIMEHM);
|
||||
// Get the record that contain the payload
|
||||
$iCM699MS = DB::connection(config('m3.connection', 'pgsql'))->table('icm699m')
|
||||
->select('SHDATA')
|
||||
->where('SHMACPKR', $dELIVERYNO)
|
||||
->where('SHDT', $sHDT)
|
||||
->where('SHTIME', $sHTIME)
|
||||
// ->whereRaw("VARCHAR_FORMAT (TIMESTAMP (CURRENT DATE) + MIDNIGHT_SECONDS (SHTIME) SECONDS, 'HH24:MI') = ?", [$SHTIMEHM])
|
||||
->where('SHCO', $dIVI)
|
||||
->where('SHWHS', $wHS)
|
||||
->where('SHSOURCE', $sHSOURCE)
|
||||
->where('SHERROR', 'X')
|
||||
->where('SHTYPE', $sHTYPE)
|
||||
->first();
|
||||
|
||||
// Read The substring from SHDATA after M3-JSN-out
|
||||
$word = 'M3-JSN-out';
|
||||
$sHDATA = isset($iCM699MS->SHDATA) ? $iCM699MS->SHDATA : '';
|
||||
$sHDATAJSON = '';
|
||||
$position = strpos($sHDATA, $word);
|
||||
// Also Read CommTCP_read
|
||||
$word2 = 'url:http://127.0.0.1:10005/api/TransferAPIURL?';
|
||||
$sHDATA2 = isset($iCM699MS->SHDATA) ? $iCM699MS->SHDATA : '';
|
||||
$position2 = strpos($sHDATA2, $word2);
|
||||
|
||||
if ($position !== false) {
|
||||
$sHDATAJSON = substr($sHDATA, $position + strlen($word));
|
||||
} elseif ($position2 !== false) {
|
||||
$sHDATAJSONS = substr($sHDATA2, $position2 + strlen($word2));
|
||||
$sHDATAJSONA = [];
|
||||
parse_str($sHDATAJSONS, $sHDATAJSONA);
|
||||
$sHDATAJSON = json_encode($sHDATAJSONA);
|
||||
}
|
||||
// Find the position of the opening and closing curly braces
|
||||
$startPos = strpos($sHDATAJSON, '{');
|
||||
$endPos = strrpos($sHDATAJSON, '}');
|
||||
// Extract the substring within the curly braces
|
||||
$sHDATAJSON = substr($sHDATAJSON, $startPos, $endPos - $startPos + 1);
|
||||
|
||||
$jSONTR = $sHDATAJSON != '' ? json_decode($sHDATAJSON) : '';
|
||||
|
||||
if ($jSONTR != '') {
|
||||
$pART = isset($jSONTR->PART) ? $jSONTR->PART : '';
|
||||
$lOCATIONFROM = isset($jSONTR->LOCATIONFROM) ? $jSONTR->LOCATIONFROM : '';
|
||||
$lOCATIONTO = isset($jSONTR->LOCATIONTO) ? $jSONTR->LOCATIONTO : '';
|
||||
$qUANTITY = isset($jSONTR->QUANTITY) ? $jSONTR->QUANTITY : '';
|
||||
$oRDERCATEGORY = isset($jSONTR->ORDERCATEGORY) ? $jSONTR->ORDERCATEGORY : '';
|
||||
$lOTNUMBER = isset($jSONTR->LOTNUMBER) ? $jSONTR->LOTNUMBER : '';
|
||||
$cONUMBER = isset($jSONTR->CONUMBER) ? $jSONTR->CONUMBER : '';
|
||||
$cOLINENO = isset($jSONTR->COLINENO) ? $jSONTR->COLINENO : '';
|
||||
$dELIVERYNO = isset($jSONTR->DELIVERYNO) ? $jSONTR->DELIVERYNO : self::ZERO_PAD;
|
||||
$pICKLISTSUFFIX = isset($jSONTR->PICKLISTSUFFIX) ? $jSONTR->PICKLISTSUFFIX : '';
|
||||
$eNDFLAG = isset($jSONTR->ENDFLAG) ? $jSONTR->ENDFLAG : '';
|
||||
$tYPE = isset($jSONTR->TYPE) ? $jSONTR->TYPE : '';
|
||||
$cOLINESUFFIX = isset($jSONTR->COLINESUFFIX) ? $jSONTR->COLINESUFFIX : '';
|
||||
}
|
||||
|
||||
// Set SHERROR to Z in ICM699M
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('icm699m')
|
||||
->where('SHMACPKR', $dELIVERYNO)
|
||||
->where('SHDT', $sHDT)
|
||||
->where('SHTIME', $sHTIME)
|
||||
->where('SHCO', $dIVI)
|
||||
->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')]);
|
||||
}
|
||||
|
||||
// Part Exists : proceed
|
||||
if ($pART != '') {
|
||||
// Read from ICM688M2
|
||||
// Get Parts And Lots from ICM688M2
|
||||
$iCM688M2SLTMP = DB::connection(config('m3.connection', 'pgsql'))->table('icm688m2')
|
||||
->select('A5BRADLN', 'A5PKSFX', 'A5PLANT', 'A5SENTPKR')
|
||||
->distinct()
|
||||
->where('A5CO', $dIVI)
|
||||
->where('A5WHS', $wHS)
|
||||
->where('A5MACPKR', $dELIVERYNO);
|
||||
|
||||
// Get Pack Lines
|
||||
if ($cOLINENO != '') {
|
||||
$iCM688M2SLTMP->where('A5PKLN', $cOLINENO);
|
||||
}
|
||||
$iCM688M2SL = $iCM688M2SLTMP->first();
|
||||
|
||||
$a5BRADLINE = isset($iCM688M2SL->A5BRADLN) ? $iCM688M2SL->A5BRADLN : '';
|
||||
$cOLINESUFFIX = isset($iCM688M2SL->A5PKSFX) ? $iCM688M2SL->A5PKSFX : ''; // Case 551 : $cOLINESUFFIX
|
||||
$a5PLANT = isset($iCM688M2SL->A5PLANT) ? $iCM688M2SL->A5PLANT : '';
|
||||
$a5SENTPKR = isset($iCM688M2SL->A5SENTPKR) ? $iCM688M2SL->A5SENTPKR : '';
|
||||
|
||||
$jSONIN = json_encode([
|
||||
'DIVI' => $dIVI,
|
||||
'WHS' => $wHS,
|
||||
'PART' => $pART,
|
||||
'LOCATIONFROM' => $lOCATIONFROM,
|
||||
'LOCATIONTO' => $lOCATIONTO,
|
||||
'QUANTITY' => $qUANTITY,
|
||||
'ORDERCATEGORY' => $oRDERCATEGORY,
|
||||
'LOTNUMBER' => $lOTNUMBER,
|
||||
'CONUMBER' => $cONUMBER,
|
||||
'COLINENO' => $cOLINENO,
|
||||
'DELIVERYNO' => $dELIVERYNO,
|
||||
'PICKLISTSUFFIX' => $pICKLISTSUFFIX,
|
||||
'ENDFLAG' => $eNDFLAG,
|
||||
'TYPE' => $tYPE,
|
||||
'COLINESUFFIX' => $cOLINESUFFIX,
|
||||
], JSON_UNESCAPED_SLASHES);
|
||||
|
||||
$jSON = json_encode([
|
||||
'DIVI' => $dIVI,
|
||||
'WHS' => $wHS,
|
||||
'PART' => $pART,
|
||||
'LOCATIONFROM' => $lOCATIONFROM,
|
||||
'LOCATIONTO' => $lOCATIONTO,
|
||||
'QUANTITY' => $qUANTITY,
|
||||
'ORDERCATEGORY' => $oRDERCATEGORY,
|
||||
'LOTNUMBER' => $lOTNUMBER,
|
||||
'CONUMBER' => $cONUMBER,
|
||||
'COLINENO' => $a5BRADLINE,
|
||||
'DELIVERYNO' => $dELIVERYNO,
|
||||
'PICKLISTSUFFIX' => $pICKLISTSUFFIX,
|
||||
'ENDFLAG' => $eNDFLAG,
|
||||
'TYPE' => $tYPE,
|
||||
'COLINESUFFIX' => $cOLINESUFFIX,
|
||||
], JSON_UNESCAPED_SLASHES);
|
||||
|
||||
// Write JSON Params to Logs Out
|
||||
$data = ['SHMACPKR' => $dELIVERYNO,
|
||||
'SHDT' => date('Y-m-d'),
|
||||
'SHTIME' => date('H:i:s'),
|
||||
'SHERROR' => '',
|
||||
'SHINTBOX' => '',
|
||||
'SHTYPE' => 'M3-Req-out',
|
||||
'SHDATA' => $jSON,
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'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 : '';
|
||||
// Write to Logs : Error
|
||||
$data = ['SHMACPKR' => $dELIVERYNO,
|
||||
'SHDT' => date('Y-m-d'),
|
||||
'SHTIME' => date('H:i:s'),
|
||||
'SHERROR' => '',
|
||||
'SHINTBOX' => '',
|
||||
'SHTYPE' => 'M3-Res-out',
|
||||
'SHDATA' => $sHDATA,
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'SHWHS' => $wHS,
|
||||
];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
return $tokenResponse;
|
||||
}
|
||||
|
||||
// Call ionapi with Params
|
||||
$endPointURL = env('ENDPOINTURL') . 'APIFLOWS/Sentinel/TransferAPI?ionapiRespStyle=sync';
|
||||
$token = $ionToken;
|
||||
|
||||
$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($endPointURL);
|
||||
$responseStatusCode = $response->getStatusCode();
|
||||
$m3SessionId = $response->hasHeader('x-transaction-id') ? '-sessionID:' . $response->header('x-transaction-id') : '-sessionID';
|
||||
$m3ResponseTimeTmp = $response->hasHeader('x-response-time') ? ltrim($response->header('x-response-time'), '-') : '0';
|
||||
$m3ResponseTimeTmp2 = floatval($m3ResponseTimeTmp) / 1000;
|
||||
$dateTime = new DateTime;
|
||||
$dateTime->setTimestamp($m3ResponseTimeTmp2);
|
||||
$m3ResponseTime = $m3ResponseTimeTmp != '' ? '-M3ResponseTime:' . $dateTime->format('d/m/Y H:i:s.v') : '-M3ResponseTime';
|
||||
$transferStats = $response->transferStats;
|
||||
$m3transferTime = $transferStats->getTransferTime() != null ? '-M3transferTime:' . $transferStats->getTransferTime() : '-M3transferTime';
|
||||
|
||||
if ($responseStatusCode == '200') {
|
||||
$responseContents = json_decode($response->getBody()->getContents());
|
||||
$responseResult = $responseContents->result;
|
||||
$m3JSONResponse = json_encode($responseContents);
|
||||
// Check M3 Response for Errors
|
||||
$m3Errors = Helper::checkM3Errors($responseResult);
|
||||
} else {
|
||||
$m3JSONResponse = '';
|
||||
$m3Errors = 'Error: No Response from M3';
|
||||
}
|
||||
|
||||
if ($m3Errors == '') {
|
||||
// Write to Logs Out : Success
|
||||
$data = ['SHMACPKR' => $dELIVERYNO,
|
||||
'SHDT' => date('Y-m-d'),
|
||||
'SHTIME' => date('H:i:s'),
|
||||
'SHERROR' => '',
|
||||
'SHINTBOX' => '',
|
||||
'SHTYPE' => 'M3-Res-out',
|
||||
'SHDATA' => $responseStatusCode . 'TYPE :' . $tYPE . self::ORDER_CATEGORY_LABEL . $oRDERCATEGORY . '-' . $m3JSONResponse . $m3SessionId . $m3ResponseTime . $m3transferTime,
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'SHWHS' => $wHS,
|
||||
];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
// Log to ICM799M
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('icm799m')
|
||||
->insert(['IMDIV' => $dIVI,
|
||||
'IMPLANT' => $a5PLANT,
|
||||
'IMWHS' => $wHS,
|
||||
'IMSENTPKR' => $a5SENTPKR,
|
||||
'IMDELNO' => $dELIVERYNO,
|
||||
'IMORDER' => $cONUMBER,
|
||||
'IMLINE' => $cOLINENO,
|
||||
'IMBRADLN' => $a5BRADLINE,
|
||||
'IMSUFFIX' => $pICKLISTSUFFIX,
|
||||
'IMPART' => $pART,
|
||||
'IMLOT' => $lOTNUMBER,
|
||||
'IMQTY' => $qUANTITY,
|
||||
'IMFRLOC' => $lOCATIONFROM,
|
||||
'IMTOLOC' => $lOCATIONTO,
|
||||
'IMDATE' => date('Ymd'),
|
||||
'IMTIME' => date('His'),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'code' => $responseStatusCode,
|
||||
'status' => 'Success',
|
||||
]);
|
||||
} else {
|
||||
// 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' => $responseStatusCode . '-' . $m3Errors . '-TYPE:' . $tYPE . self::ORDER_CATEGORY_LABEL . $oRDERCATEGORY . '-' . $m3JSONResponse .
|
||||
'M3-JSN-out' . $jSONIN . $m3SessionId . $m3ResponseTime . $m3transferTime,
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'SHWHS' => $wHS,
|
||||
];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
return response()->json([
|
||||
'code' => '206',
|
||||
'status' => 'Error',
|
||||
'message' => $responseStatusCode . '-' . $m3Errors . '- TYPE :' . $tYPE . self::ORDER_CATEGORY_LABEL . $oRDERCATEGORY . '-' . $m3JSONResponse,
|
||||
]);
|
||||
}
|
||||
}
|
||||
// Part Does not Exist : Failure
|
||||
else {
|
||||
// Return Error
|
||||
return response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'Error',
|
||||
'message' => 'Json Payload Not Valid, possible cause: Retry butto was clicked by another user.',
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
// Write to Logs Out : Error
|
||||
$dELIVERYNO = isset($dELIVERYNO) ? $dELIVERYNO : self::ZERO_PAD;
|
||||
$data = ['SHMACPKR' => $dELIVERYNO,
|
||||
'SHDT' => date('Y-m-d'),
|
||||
'SHTIME' => date('H:i:s'),
|
||||
'SHERROR' => 'X',
|
||||
'SHINTBOX' => '',
|
||||
'SHTYPE' => 'M3-Res-out',
|
||||
'SHDATA' => self::NO_URL_PARAMETERS,
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'SHWHS' => $wHS,
|
||||
];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
// Return Error
|
||||
return response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'Error',
|
||||
'message' => self::NO_URL_PARAMETERS,
|
||||
]);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$getCurlErrors = str_contains($th->getMessage(), 'cURL error');
|
||||
if ($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' => $dIVI,
|
||||
'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($dELIVERYNO) ? $dELIVERYNO : self::ZERO_PAD;
|
||||
$data = ['SHMACPKR' => $dELIVERYNO,
|
||||
'SHDT' => date('Y-m-d'),
|
||||
'SHTIME' => date('H:i:s'),
|
||||
'SHERROR' => 'X',
|
||||
'SHINTBOX' => '',
|
||||
'SHTYPE' => 'M3-Err-out',
|
||||
'SHDATA' => 'An Error Occured - ' . substr($th, 0, 300),
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'SHWHS' => $wHS,
|
||||
];
|
||||
Helper::logToICM699M($data);
|
||||
Log::error($th);
|
||||
|
||||
return response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'error',
|
||||
'message' => 'Uncaught Error',
|
||||
]);
|
||||
}
|
||||
|
||||
$response = $this->processTransfer($context);
|
||||
} catch (\Throwable $throwable) {
|
||||
$response = $this->exceptionResponse($context, $throwable, $context['json_in'] ?? '');
|
||||
}
|
||||
}
|
||||
// End TransferAPIURL
|
||||
|
||||
// UpdateShipmentNumber : with URL PARAMS
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function UpdateShipmentNumber(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'));
|
||||
|
||||
// Get the Calling User
|
||||
$sHUSER = m3_user() !== '' ? Str::upper(m3_user()) : 'WebUser';
|
||||
// Set SHSOURCE
|
||||
$sHSOURCE = 'UpdateShipmentNumber';
|
||||
$m3Errors = '';
|
||||
|
||||
// Get URL PARAMS
|
||||
$urlParams = count($request->all()) > 0 ? $request->all() : '';
|
||||
$dIVI = isset($urlParams['COMPANY']) ? $urlParams['COMPANY'] : '';
|
||||
$wHS = isset($urlParams['WHS']) ? $urlParams['WHS'] : '';
|
||||
$pLANT = isset($urlParams['PLANT']) ? $urlParams['PLANT'] : '';
|
||||
$this->configureTimeouts();
|
||||
$context = $this->shipmentContext($request);
|
||||
|
||||
try {
|
||||
if ($urlParams != '') {
|
||||
$a4SPR15A01 = isset($urlParams['A4SPR15A01']) ? $urlParams['A4SPR15A01'] : '';
|
||||
$dELIVERYNO = isset($urlParams['DELIVERYNO']) ? $urlParams['DELIVERYNO'] : '';
|
||||
$tYPE = 'UpdateShipmentNumber';
|
||||
$allMacpkrs = [];
|
||||
|
||||
if ($a4SPR15A01 != '') {
|
||||
// Read from ICM688M1
|
||||
$iCM688M1SLTMP = DB::connection(config('m3.connection', 'pgsql'))->table('icm688m1')
|
||||
->select('A4MACPKR')
|
||||
->where('A4CO', $dIVI)
|
||||
->where('A4WHS', $wHS)
|
||||
->where('A4PLANT', $pLANT)
|
||||
->where('A4SPR15A01', $a4SPR15A01);
|
||||
|
||||
// Get Macpikers also if sent as Parameter
|
||||
if ($dELIVERYNO != '') {
|
||||
$iCM688M1SLTMP->where('A4MACPKR', $dELIVERYNO);
|
||||
}
|
||||
$iCM688M1SL = $iCM688M1SLTMP->get();
|
||||
// Loop ICM688M1 to get all A4MACPKR
|
||||
foreach ($iCM688M1SL as $ICM688M1) {
|
||||
$allMacpkrs[] = $ICM688M1->A4MACPKR;
|
||||
}
|
||||
}
|
||||
|
||||
// A4SPR15A01 Exists : proceed
|
||||
if ($a4SPR15A01 != '' && ! empty($allMacpkrs)) {
|
||||
$jSON = json_encode([
|
||||
'DIVI' => $dIVI,
|
||||
'WHS' => $wHS,
|
||||
'ShipmentNumber' => [
|
||||
'Number' => $a4SPR15A01,
|
||||
'DeliveryNumbers' => $allMacpkrs,
|
||||
],
|
||||
'TYPE' => $tYPE,
|
||||
'ENDFLAG' => '',
|
||||
|
||||
], JSON_UNESCAPED_SLASHES);
|
||||
|
||||
// Write JSON Params to Logs Out
|
||||
$data = ['SHMACPKR' => $dELIVERYNO,
|
||||
'SHDT' => date('Y-m-d'),
|
||||
'SHTIME' => date('H:i:s'),
|
||||
'SHERROR' => '',
|
||||
'SHINTBOX' => '',
|
||||
'SHTYPE' => 'M3-Req-out',
|
||||
'SHDATA' => $jSON,
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'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 : '';
|
||||
// Write to Logs : Error
|
||||
$data = ['SHMACPKR' => $dELIVERYNO,
|
||||
'SHDT' => date('Y-m-d'),
|
||||
'SHTIME' => date('H:i:s'),
|
||||
'SHERROR' => '',
|
||||
'SHINTBOX' => '',
|
||||
'SHTYPE' => 'M3-Res-out',
|
||||
'SHDATA' => $sHDATA,
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'SHWHS' => $wHS,
|
||||
];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
return $tokenResponse;
|
||||
}
|
||||
|
||||
// Call ionapi with Params
|
||||
$endPointURL = env('ENDPOINTURL') . 'APIFLOWS/Sentinel/TransferAPI?ionapiRespStyle=sync';
|
||||
$token = $ionToken;
|
||||
|
||||
$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($endPointURL);
|
||||
$responseStatusCode = $response->getStatusCode();
|
||||
$m3SessionId = $response->hasHeader('x-transaction-id') ? '-sessionID:' . $response->header('x-transaction-id') : '-sessionID';
|
||||
$m3ResponseTimeTmp = $response->hasHeader('x-response-time') ? ltrim($response->header('x-response-time'), '-') : '0';
|
||||
$m3ResponseTimeTmp2 = floatval($m3ResponseTimeTmp) / 1000;
|
||||
$dateTime = new DateTime;
|
||||
$dateTime->setTimestamp($m3ResponseTimeTmp2);
|
||||
$m3ResponseTime = $m3ResponseTimeTmp != '' ? '-M3ResponseTime:' . $dateTime->format('d/m/Y H:i:s.v') : '-M3ResponseTime';
|
||||
$transferStats = $response->transferStats;
|
||||
$m3transferTime = $transferStats->getTransferTime() != null ? '-M3transferTime:' . $transferStats->getTransferTime() : '-M3transferTime';
|
||||
|
||||
if ($responseStatusCode == '200') {
|
||||
$responseContents = json_decode($response->getBody()->getContents());
|
||||
$responseResult = $responseContents->result;
|
||||
$m3JSONResponse = json_encode($responseContents);
|
||||
// Check M3 Response for Errors
|
||||
$m3Errors = Helper::checkM3Errors($responseResult);
|
||||
} else {
|
||||
$m3JSONResponse = '';
|
||||
$m3Errors = 'Error: No Response from M3';
|
||||
}
|
||||
|
||||
if ($m3Errors == '') {
|
||||
// Write to Logs Out : Success
|
||||
$data = ['SHMACPKR' => $dELIVERYNO,
|
||||
'SHDT' => date('Y-m-d'),
|
||||
'SHTIME' => date('H:i:s'),
|
||||
'SHERROR' => '',
|
||||
'SHINTBOX' => '',
|
||||
'SHTYPE' => 'M3-Res-out',
|
||||
'SHDATA' => $responseStatusCode . 'TYPE :' . $tYPE . '-' . $m3JSONResponse . $m3SessionId . $m3ResponseTime . $m3transferTime,
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'SHWHS' => $wHS,
|
||||
];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
return response()->json([
|
||||
'code' => $responseStatusCode,
|
||||
'status' => 'Success',
|
||||
]);
|
||||
} else {
|
||||
// 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' => $responseStatusCode . '-' . $m3Errors . '-TYPE:' . $tYPE . '-' . $m3JSONResponse .
|
||||
'M3-JSN-out' . $jSON . $m3SessionId . $m3ResponseTime . $m3transferTime,
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'SHWHS' => $wHS,
|
||||
];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
return response()->json([
|
||||
'code' => '206',
|
||||
'status' => 'Error',
|
||||
'message' => $responseStatusCode . '-' . $m3Errors . '- TYPE :' . $tYPE . '-' . $m3JSONResponse,
|
||||
]);
|
||||
}
|
||||
}
|
||||
// A4SPR15A01 Does not Exist : Failure
|
||||
else {
|
||||
// Return Error
|
||||
return response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'Error',
|
||||
'message' => 'Json Payload Not Valid, missing Parameter or no Macpicker # found.',
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
// Write to Logs Out : Error
|
||||
$dELIVERYNO = isset($dELIVERYNO) ? $dELIVERYNO : self::ZERO_PAD;
|
||||
$data = ['SHMACPKR' => $dELIVERYNO,
|
||||
'SHDT' => date('Y-m-d'),
|
||||
'SHTIME' => date('H:i:s'),
|
||||
'SHERROR' => 'X',
|
||||
'SHINTBOX' => '',
|
||||
'SHTYPE' => 'M3-Res-out',
|
||||
'SHDATA' => self::NO_URL_PARAMETERS,
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'SHWHS' => $wHS,
|
||||
];
|
||||
Helper::logToICM699M($data);
|
||||
|
||||
// Return Error
|
||||
return response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'Error',
|
||||
'message' => self::NO_URL_PARAMETERS,
|
||||
]);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$getCurlErrors = str_contains($th->getMessage(), 'cURL error');
|
||||
if ($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' . $jSON,
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'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($dELIVERYNO) ? $dELIVERYNO : self::ZERO_PAD;
|
||||
$data = ['SHMACPKR' => $dELIVERYNO,
|
||||
'SHDT' => date('Y-m-d'),
|
||||
'SHTIME' => date('H:i:s'),
|
||||
'SHERROR' => 'X',
|
||||
'SHINTBOX' => '',
|
||||
'SHTYPE' => 'M3-Err-out',
|
||||
'SHDATA' => 'An Error Occured - ' . substr($th, 0, 300),
|
||||
'SHUSER' => $sHUSER,
|
||||
'SHSOURCE' => $sHSOURCE,
|
||||
'SHCO' => $dIVI,
|
||||
'SHWHS' => $wHS,
|
||||
];
|
||||
Helper::logToICM699M($data);
|
||||
Log::error($th);
|
||||
|
||||
return response()->json([
|
||||
'code' => '405',
|
||||
'status' => 'error',
|
||||
'message' => 'Uncaught Error',
|
||||
]);
|
||||
}
|
||||
|
||||
$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']);
|
||||
}
|
||||
// End UpdateShipmentNumber
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\M3\Http\Controllers\API;
|
||||
|
||||
use Config;
|
||||
|
||||
trait TransferApiSupport
|
||||
{
|
||||
private function configureTimeouts(): void
|
||||
{
|
||||
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'));
|
||||
}
|
||||
|
||||
private function retryPayload(string $data): array
|
||||
{
|
||||
$decoded = json_decode($data, true);
|
||||
|
||||
return is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
|
||||
private function responseMetrics($response): string
|
||||
{
|
||||
return json_encode([
|
||||
'status' => $response->status(),
|
||||
'successful' => $response->successful(),
|
||||
'failed' => $response->failed(),
|
||||
'clientError' => $response->clientError(),
|
||||
'serverError' => $response->serverError(),
|
||||
]);
|
||||
}
|
||||
|
||||
private function errorResponse(string $code, string $message)
|
||||
{
|
||||
return response()->json([
|
||||
'code' => $code,
|
||||
'status' => 'error',
|
||||
'message' => $message,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ class TwoShipAPIs extends Controller
|
||||
public function TwoShipUpdateHold(Request $request)
|
||||
{
|
||||
$this->configureTimeouts();
|
||||
$user = m3_user() !== '' ? Str::upper(m3_user()) : 'WebUser';
|
||||
$user = m3User() !== '' ? Str::upper(m3User()) : 'WebUser';
|
||||
$params = $request->all();
|
||||
$whs = (string) ($params['WHS'] ?? '');
|
||||
$co = (string) ($params['COMPANY'] ?? '');
|
||||
@@ -28,33 +28,32 @@ class TwoShipAPIs extends Controller
|
||||
|
||||
if ($params === []) {
|
||||
$this->log($macpkr ?: '000000', $co, $whs, $user, 'X', 'No URL Parameters Sent');
|
||||
$result = response()->json(['code' => '405', 'status' => 'Error', 'message' => 'No URL Parameters Sent']);
|
||||
} else {
|
||||
try {
|
||||
$this->logRequest($macpkr, $co, $whs, $user);
|
||||
$orders = $this->aggregationOrders($macpkr, $co, $whs);
|
||||
$response = $this->callTwoShip($orders);
|
||||
$error = $this->responseError($response);
|
||||
|
||||
return response()->json(['code' => '405', 'status' => 'Error', 'message' => 'No URL Parameters Sent']);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->logRequest($macpkr, $co, $whs, $user);
|
||||
$orders = $this->aggregationOrders($macpkr, $co, $whs);
|
||||
$response = $this->callTwoShip($orders);
|
||||
$error = $this->responseError($response);
|
||||
if ($error !== '') {
|
||||
$this->log($macpkr, $co, $whs, $user, 'X', $response->status() . '-' . $error);
|
||||
|
||||
return response()->json(['code' => '405', 'status' => 'error', 'message' => 'Status: ' . $response->status() . '-' . $error]);
|
||||
if ($error !== '') {
|
||||
$this->log($macpkr, $co, $whs, $user, 'X', $response->status() . '-' . $error);
|
||||
$result = response()->json(['code' => '405', 'status' => 'error', 'message' => 'Status: ' . $response->status() . '-' . $error]);
|
||||
} else {
|
||||
$this->log($macpkr, $co, $whs, $user, '', $response->body());
|
||||
$this->markAggregationComplete($orders, $co, $whs);
|
||||
$result = response()->json(['code' => '200', 'status' => 'Success']);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$message = str_contains($th->getMessage(), 'cURL error')
|
||||
? 'Curl Error: Communication with 2Ship Timed Out.'
|
||||
: '2Ship communication failed.';
|
||||
$this->log($macpkr, $co, $whs, $user, 'X', $message);
|
||||
$result = response()->json(['code' => '405', 'status' => 'error', 'message' => $message]);
|
||||
}
|
||||
|
||||
$this->log($macpkr, $co, $whs, $user, '', $response->body());
|
||||
$this->markAggregationComplete($orders, $co, $whs);
|
||||
|
||||
return response()->json(['code' => '200', 'status' => 'Success']);
|
||||
} catch (\Throwable $th) {
|
||||
$message = str_contains($th->getMessage(), 'cURL error')
|
||||
? 'Curl Error: Communication with 2Ship Timed Out.'
|
||||
: '2Ship communication failed.';
|
||||
$this->log($macpkr, $co, $whs, $user, 'X', $message);
|
||||
|
||||
return response()->json(['code' => '405', 'status' => 'error', 'message' => $message]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function configureTimeouts(): void
|
||||
|
||||
@@ -77,7 +77,7 @@ class BoxPackToPalletController extends Controller
|
||||
$box = trim((string) ($request->R659BOX ?? ''));
|
||||
abort_if($box === '', 400, 'Box Not Found');
|
||||
|
||||
$user = m3_user() !== '' ? Str::upper(m3_user()) : 'WebUser';
|
||||
$user = m3User() !== '' ? Str::upper(m3User()) : 'WebUser';
|
||||
$profile = self::getUserWhsCoPlant();
|
||||
$validation = self::validateScannedBox($pallet, $box, $profile);
|
||||
|
||||
@@ -268,7 +268,7 @@ class BoxPackToPalletController extends Controller
|
||||
// Get Logged User CO/WHS/PLANT
|
||||
public static function getUserWhsCoPlant()
|
||||
{
|
||||
$sHUSER = m3_user() !== '' ? Str::upper(trim(m3_user())) : '';
|
||||
$sHUSER = m3User() !== '' ? Str::upper(trim(m3User())) : '';
|
||||
// Get users from ICM428M
|
||||
$iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')
|
||||
|
||||
@@ -25,7 +25,7 @@ class CarrierMaintController extends Controller
|
||||
if ($schema->hasTable('icm428m')) {
|
||||
$power_user = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428PWRUSR', 'R428CO', 'R428PL', 'R428WH')
|
||||
->where('R428US', strtoupper(m3_user()))->get()->all();
|
||||
->where('R428US', strtoupper(m3User()))->get()->all();
|
||||
}
|
||||
|
||||
return view('m3::liberty-theme.pages.carrierMaint', ['ICM160M' => $iCM160M, 'power_user' => $power_user]);
|
||||
|
||||
@@ -9,155 +9,156 @@ use Str;
|
||||
|
||||
class ExecSummaryController extends Controller
|
||||
{
|
||||
private const WAREHOUSE_IN_CLAUSE = "' and a5whs in (";
|
||||
|
||||
public static function index(Request $request)
|
||||
{
|
||||
$iC670M = collect();
|
||||
$wHDDA = '';
|
||||
$cOMPANY = '110';
|
||||
$pLANT = '144';
|
||||
$wHS = '322';
|
||||
|
||||
try {
|
||||
// Ajax Call
|
||||
if ($request->ajax()) {
|
||||
$wHDDA = isset($request->WHDDA) ? $request->WHDDA : [];
|
||||
$wHArr = [];
|
||||
foreach ($wHDDA as $WHDDAV) {
|
||||
$cO = substr($WHDDAV, 0, 3);
|
||||
$wHArr[] = substr($WHDDAV, 6, 3);
|
||||
}
|
||||
|
||||
$reportPeriod = isset($request->reportPeriod) ? $request->reportPeriod : ''; // monthly , quarter , year , daily
|
||||
// Current
|
||||
$checkSales = isset($request->checkSales) ? $request->checkSales : ''; // on
|
||||
$checkWeight = isset($request->checkWeight) ? $request->checkWeight : ''; // on
|
||||
$checkLines = isset($request->checkLines) ? $request->checkLines : ''; // on
|
||||
|
||||
if (! empty($wHArr) && $cO != '' && $reportPeriod != '') {
|
||||
switch ($reportPeriod) {
|
||||
case 'year':
|
||||
// Set Dates based on reportPeriod type
|
||||
$firstDay = isset($request->REPORTDATE) ? \DateTime::createFromFormat('Y-m', $request->REPORTDATE) : '';
|
||||
$reportDate = $firstDay->modify('first day of January')->format('Ymd');
|
||||
|
||||
$lastDay = isset($request->TOREPORTDATE) ? \DateTime::createFromFormat('Y-m', trim($request->TOREPORTDATE)) : '';
|
||||
$toreportDate = $lastDay->modify('last day of December')->format('Ymd');
|
||||
|
||||
// Build SQL
|
||||
$selectContent = "with tempfile as (
|
||||
select a5rsvqty,a5packed,a5slunpr*a5packed as dollars,a5lnwght,a5whs,
|
||||
(select max(ayapr8N002) as ayapr8N002 from icm695m1 where a5macpkr=aymacpkr fetch first 1 rows only)
|
||||
from icm688m2 where a5macpkr in (
|
||||
select distinct aymacpkr from icm695m1 where (AYSTATUS in ('Z','z') and ayapr8N002>=$reportDate and ayapr8N002<=$toreportDate )
|
||||
) and a5co='" . $cO . "' and a5whs in(" . implode(',', $wHArr) . ')
|
||||
)
|
||||
select substr(ayapr8N002,1,4) as years,count(*) as lines,sum(a5rsvqty) as reserveqty,sum(a5packed) as packed,sum(a5lnwght*a5packed/a5rsvqty) as weight,sum(dollars) as dollars,a5whs as whs from tempfile
|
||||
group by substr(ayapr8N002,1,4),a5whs order by 1 ';
|
||||
break;
|
||||
|
||||
case 'quarter':
|
||||
// Set Dates based on reportPeriod type
|
||||
$firstDay = isset($request->REPORTDATE) ? \DateTime::createFromFormat('Y-m', $request->REPORTDATE) : '';
|
||||
$reportDate = $firstDay->modify('first day of January')->format('Ymd');
|
||||
|
||||
$lastDay = isset($request->TOREPORTDATE) ? \DateTime::createFromFormat('Y-m', trim($request->TOREPORTDATE)) : '';
|
||||
$toreportDate = $lastDay->modify('last day of December')->format('Ymd');
|
||||
|
||||
// Build SQL
|
||||
$selectContent = "with tempfile as (
|
||||
select a5rsvqty,a5packed,a5slunpr*a5packed as dollars,a5lnwght,a5whs,
|
||||
(select max(ayapr8N002) as ayapr8N002 from icm695m1 where a5macpkr=aymacpkr fetch first 1 rows only)
|
||||
from icm688m2 where a5macpkr in (
|
||||
select distinct aymacpkr from icm695m1 where (AYSTATUS in ('Z','z') and ayapr8N002>=$reportDate and ayapr8N002<=$toreportDate )
|
||||
) and a5co='" . $cO . self::WAREHOUSE_IN_CLAUSE . implode(',', $wHArr) . ")
|
||||
)
|
||||
select substr(ayapr8N002,3,2) ||'-' || 'Q' || EXTRACT(QUARTER FROM TO_DATE(CAST(ayapr8n002 AS TEXT),'YYYYMMDD')) as years,count(*) as lines,
|
||||
sum(a5rsvqty) as reserveqty, sum(a5packed) as packed,sum (a5lnwght*a5packed/a5rsvqty) as weight,sum(dollars) as dollars, a5whs as whs
|
||||
from tempfile
|
||||
group by substr(ayapr8N002,3,2) ||'-' || 'Q' || EXTRACT(QUARTER FROM TO_DATE(CAST(ayapr8n002 AS TEXT),'YYYYMMDD')),a5whs order by 1 ";
|
||||
break;
|
||||
|
||||
case 'monthly':
|
||||
// Set Dates based on reportPeriod type
|
||||
$firstDay = isset($request->REPORTDATE) ? \DateTime::createFromFormat('Y-m', $request->REPORTDATE) : '';
|
||||
$reportDate = $firstDay->modify('first day of this month')->format('Ymd');
|
||||
|
||||
$lastDay = isset($request->TOREPORTDATE) ? \DateTime::createFromFormat('Y-m', trim($request->TOREPORTDATE)) : '';
|
||||
$toreportDate = $lastDay->modify('last day of this month')->format('Ymd');
|
||||
|
||||
// Build SQL
|
||||
$selectContent = "with tempfile as (
|
||||
select a5rsvqty,a5packed,a5slunpr*a5packed as dollars,a5lnwght,a5whs,
|
||||
(select max(ayapr8N002) as ayapr8N002 from icm695m1 where a5macpkr=aymacpkr fetch first 1 rows only)
|
||||
from icm688m2 where a5macpkr in (
|
||||
select distinct aymacpkr from icm695m1 where (AYSTATUS in ('Z','z') and ayapr8N002>=$reportDate and ayapr8N002<=$toreportDate )
|
||||
) and a5co='" . $cO . self::WAREHOUSE_IN_CLAUSE . implode(',', $wHArr) . ")
|
||||
)
|
||||
select substr(ayapr8N002,1,4) || '-' || substr(ayapr8N002,5,2) as years,count(*) as lines,sum(a5rsvqty) as reserveqty,sum(a5packed) as packed,
|
||||
sum(a5lnwght*a5packed/a5rsvqty) as weight,sum(dollars) as dollars, a5whs as whs
|
||||
from tempfile
|
||||
group by substr(ayapr8N002,1,4) || '-' || substr(ayapr8N002,5,2),a5whs order by 1 ";
|
||||
break;
|
||||
|
||||
case 'custom':
|
||||
// Set Dates based on reportPeriod type
|
||||
$firstDay = isset($request->REPORTDATE) ? \DateTime::createFromFormat('Y-m', $request->REPORTDATE) : '';
|
||||
$reportDate = $firstDay->modify('first day of this month')->format('Ymd');
|
||||
|
||||
$toreportDate = $firstDay->modify('last day of this month')->format('Ymd');
|
||||
|
||||
// Build SQL
|
||||
$selectContent = "with tempfile as (
|
||||
select a5rsvqty,a5packed,a5slunpr*a5packed as dollars,a5lnwght,a5whs,
|
||||
(select max(ayapr8N002) as ayapr8N002 from icm695m1 where a5macpkr=aymacpkr fetch first 1 rows only)
|
||||
from icm688m2 where a5macpkr in (
|
||||
select distinct aymacpkr from icm695m1 where (AYSTATUS in ('Z','z') and ayapr8N002>=$reportDate and ayapr8N002<=$toreportDate )
|
||||
) and a5co='" . $cO . self::WAREHOUSE_IN_CLAUSE . implode(',', $wHArr) . ')
|
||||
)
|
||||
select substr(ayapr8N002,7,2) as years,count(*) as lines,sum(a5rsvqty) as reserveqty,sum(a5packed) as packed,
|
||||
sum(a5lnwght*a5packed/a5rsvqty) as weight, sum(dollars) as dollars, a5whs as whs
|
||||
from tempfile
|
||||
group by substr(ayapr8N002,7,2),a5whs order by 1 ';
|
||||
break;
|
||||
|
||||
default:
|
||||
$selectContent = '';
|
||||
break;
|
||||
}
|
||||
|
||||
$execSummaryRes = DB::connection(config('m3.connection', 'pgsql'))->select($selectContent);
|
||||
} else {
|
||||
$execSummaryRes = collect();
|
||||
}
|
||||
|
||||
return response()->json(['success' => true, 'reportPeriod' => $reportPeriod, 'result' => $execSummaryRes, 'checkSales' => $checkSales,
|
||||
'checkWeight' => $checkWeight, 'checkLines' => $checkLines]);
|
||||
}
|
||||
|
||||
// Init Page
|
||||
$sHUSER = m3_user() !== '' ? Str::upper(trim(m3_user())) : '';
|
||||
if ($sHUSER != '') {
|
||||
// Get User CO & WH from Table ICM428M
|
||||
$iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')
|
||||
->where('R428US', '=', $sHUSER)
|
||||
->first();
|
||||
|
||||
$cOMPANY = isset($iCM428M->R428CO) ? $iCM428M->R428CO : '110'; // Company
|
||||
$pLANT = isset($iCM428M->R428PL) ? $iCM428M->R428PL : '144'; // Plant
|
||||
$wHS = isset($iCM428M->R428WH) ? $iCM428M->R428WH : '322'; // WareHouse
|
||||
}
|
||||
$wHDDA = $cOMPANY . $pLANT . $wHS;
|
||||
// dump($wHDDA);
|
||||
// Warehouse Table
|
||||
$iC670M = DB::connection(config('m3.connection', 'pgsql'))->table('ic670m')->get();
|
||||
} catch (\Throwable $th) {
|
||||
Log::error($th);
|
||||
if ($request->ajax()) {
|
||||
return self::ajaxResponse($request);
|
||||
}
|
||||
|
||||
return view('m3::liberty-theme.pages.execSummary', ['IC670M' => $iC670M, 'WHDDA' => $wHDDA]);
|
||||
// ,'ICM688M2',,'COMPANY','PLANT','WHS','reportDate'
|
||||
return self::pageResponse();
|
||||
}
|
||||
|
||||
private static function ajaxResponse(Request $request)
|
||||
{
|
||||
[$company, $warehouses] = self::warehouseSelection((array) $request->input('WHDDA', []));
|
||||
$reportPeriod = (string) $request->input('reportPeriod', '');
|
||||
$result = collect();
|
||||
|
||||
try {
|
||||
if ($company !== '' && $warehouses !== [] && $reportPeriod !== '') {
|
||||
$sql = self::summarySql($reportPeriod, $request, $company, $warehouses);
|
||||
$result = $sql === '' ? collect() : DB::connection(config('m3.connection', 'pgsql'))->select($sql);
|
||||
}
|
||||
} catch (\Throwable $throwable) {
|
||||
Log::error($throwable);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'reportPeriod' => $reportPeriod,
|
||||
'result' => $result,
|
||||
'checkSales' => $request->input('checkSales', ''),
|
||||
'checkWeight' => $request->input('checkWeight', ''),
|
||||
'checkLines' => $request->input('checkLines', ''),
|
||||
]);
|
||||
}
|
||||
|
||||
private static function pageResponse()
|
||||
{
|
||||
$warehouses = collect();
|
||||
$company = '110';
|
||||
$plant = '144';
|
||||
$warehouse = '322';
|
||||
|
||||
try {
|
||||
$profile = self::currentUserProfile();
|
||||
if ($profile !== null) {
|
||||
$company = $profile->R428CO ?? $company;
|
||||
$plant = $profile->R428PL ?? $plant;
|
||||
$warehouse = $profile->R428WH ?? $warehouse;
|
||||
}
|
||||
$warehouses = DB::connection(config('m3.connection', 'pgsql'))->table('ic670m')->get();
|
||||
} catch (\Throwable $throwable) {
|
||||
Log::error($throwable);
|
||||
}
|
||||
|
||||
return view('m3::liberty-theme.pages.execSummary', [
|
||||
'IC670M' => $warehouses,
|
||||
'WHDDA' => $company . $plant . $warehouse,
|
||||
]);
|
||||
}
|
||||
|
||||
private static function currentUserProfile(): ?object
|
||||
{
|
||||
$user = m3User() !== '' ? Str::upper(trim(m3User())) : '';
|
||||
if ($user === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')
|
||||
->where('R428US', $user)
|
||||
->first();
|
||||
}
|
||||
|
||||
private static function warehouseSelection(array $selection): array
|
||||
{
|
||||
$company = '';
|
||||
$warehouses = [];
|
||||
foreach ($selection as $value) {
|
||||
$company = substr((string) $value, 0, 3);
|
||||
$warehouses[] = substr((string) $value, 6, 3);
|
||||
}
|
||||
|
||||
return [$company, $warehouses];
|
||||
}
|
||||
|
||||
private static function summarySql(string $period, Request $request, string $company, array $warehouses): string
|
||||
{
|
||||
$range = self::dateRange($period, $request);
|
||||
if ($range === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
[$from, $to] = $range;
|
||||
$warehouseList = implode(',', $warehouses);
|
||||
$groupExpression = match ($period) {
|
||||
'year' => 'substr(ayapr8N002,1,4)',
|
||||
'quarter' => "substr(ayapr8N002,3,2) ||'-' || 'Q' || EXTRACT(QUARTER FROM TO_DATE(CAST(ayapr8n002 AS TEXT),'YYYYMMDD'))",
|
||||
'monthly' => "substr(ayapr8N002,1,4) || '-' || substr(ayapr8N002,5,2)",
|
||||
'custom' => 'substr(ayapr8N002,7,2)',
|
||||
default => '',
|
||||
};
|
||||
if ($groupExpression === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return "with tempfile as (
|
||||
select a5rsvqty,a5packed,a5slunpr*a5packed as dollars,a5lnwght,a5whs,
|
||||
(select max(ayapr8N002) from icm695m1 where a5macpkr=aymacpkr fetch first 1 rows only) as ayapr8N002
|
||||
from icm688m2 where a5macpkr in (
|
||||
select distinct aymacpkr from icm695m1
|
||||
where AYSTATUS in ('Z','z') and ayapr8N002>=$from and ayapr8N002<=$to
|
||||
) and a5co='$company' and a5whs in($warehouseList)
|
||||
)
|
||||
select $groupExpression as years,count(*) as lines,sum(a5rsvqty) as reserveqty,
|
||||
sum(a5packed) as packed,sum(a5lnwght*a5packed/a5rsvqty) as weight,
|
||||
sum(dollars) as dollars,a5whs as whs
|
||||
from tempfile group by $groupExpression,a5whs order by 1";
|
||||
}
|
||||
|
||||
private static function dateRange(string $period, Request $request): ?array
|
||||
{
|
||||
$from = self::monthDate($request->input('REPORTDATE'));
|
||||
if ($from === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$range = null;
|
||||
if ($period === 'custom') {
|
||||
$range = [(clone $from)->modify('first day of this month')->format('Ymd'), (clone $from)->modify('last day of this month')->format('Ymd')];
|
||||
} else {
|
||||
$to = self::monthDate($request->input('TOREPORTDATE'));
|
||||
if ($to !== null) {
|
||||
$range = match ($period) {
|
||||
'year', 'quarter' => [(clone $from)->modify('first day of January')->format('Ymd'), (clone $to)->modify('last day of December')->format('Ymd')],
|
||||
'monthly' => [(clone $from)->modify('first day of this month')->format('Ymd'), (clone $to)->modify('last day of this month')->format('Ymd')],
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return $range;
|
||||
}
|
||||
|
||||
private static function monthDate(mixed $value): ?\DateTime
|
||||
{
|
||||
if (! is_string($value) || trim($value) === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$date = \DateTime::createFromFormat('Y-m', trim($value));
|
||||
|
||||
return $date instanceof \DateTime ? $date : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ use Str;
|
||||
|
||||
class ExecSummaryLineController extends Controller
|
||||
{
|
||||
private const WAREHOUSE_IN_CLAUSE = "' and a5whs in (";
|
||||
|
||||
private const FIRST_DAY_THIS_MONTH = 'first day of this month';
|
||||
|
||||
@@ -19,186 +18,158 @@ class ExecSummaryLineController extends Controller
|
||||
|
||||
public static function index(Request $request)
|
||||
{
|
||||
try {
|
||||
// Ajax Call
|
||||
if ($request->ajax()) {
|
||||
$wHDDA = isset($request->WHDDA) ? $request->WHDDA : [];
|
||||
$wHArr = [];
|
||||
foreach ($wHDDA as $WHDDAV) {
|
||||
$cO = substr($WHDDAV, 0, 3);
|
||||
$wHArr[] = substr($WHDDAV, 6, 3);
|
||||
}
|
||||
|
||||
$reportPeriod = isset($request->reportPeriod) ? $request->reportPeriod : ''; // monthly , quarter , year , daily
|
||||
// Current
|
||||
$checkSales = isset($request->checkSales) ? $request->checkSales : ''; // on
|
||||
$checkWeight = isset($request->checkWeight) ? $request->checkWeight : ''; // on
|
||||
$checkLines = isset($request->checkLines) ? $request->checkLines : ''; // on
|
||||
|
||||
if (! empty($wHArr) && $cO != '' && $reportPeriod != '') {
|
||||
switch ($reportPeriod) {
|
||||
case 'year':
|
||||
// Set Dates based on reportPeriod type
|
||||
$firstDay = isset($request->REPORTDATE) ? \DateTime::createFromFormat('Y-m', $request->REPORTDATE) : '';
|
||||
$reportDate = $firstDay->modify('first day of January')->format('Ymd');
|
||||
|
||||
$lastDay = isset($request->TOREPORTDATE) ? \DateTime::createFromFormat('Y-m', trim($request->TOREPORTDATE)) : '';
|
||||
$toreportDate = $lastDay->modify('last day of December')->format('Ymd');
|
||||
|
||||
// Build SQL
|
||||
$selectContent = "with tempfile as (
|
||||
select a5rsvqty,a5packed,a5slunpr*a5packed as dollars,a5lnwght,a5whs,
|
||||
(select max(ayapr8N002) as ayapr8N002 from icm695m1 where a5macpkr=aymacpkr fetch first 1 rows only)
|
||||
from icm688m2 where a5macpkr in (
|
||||
select distinct aymacpkr from icm695m1 where (AYSTATUS in ('Z','z') and ayapr8N002>=$reportDate and ayapr8N002<=$toreportDate )
|
||||
) and a5co='" . $cO . "' and a5whs in(" . implode(',', $wHArr) . ')
|
||||
)
|
||||
select substr(ayapr8N002,1,4) as years,count(*) as lines,sum(a5rsvqty) as reserveqty,sum(a5packed) as packed,sum(a5lnwght*a5packed/a5rsvqty) as weight,sum(dollars) as dollars,a5whs as whs from tempfile
|
||||
group by substr(ayapr8N002,1,4),a5whs order by 1 ';
|
||||
|
||||
$execSummaryResLY = [];
|
||||
break;
|
||||
|
||||
case 'quarter':
|
||||
// Set Dates based on reportPeriod type
|
||||
$firstDay = isset($request->REPORTDATE) ? \DateTime::createFromFormat('Y-m', $request->REPORTDATE) : '';
|
||||
$reportDate = $firstDay->modify('first day of January')->format('Ymd');
|
||||
|
||||
$lastDay = isset($request->TOREPORTDATE) ? \DateTime::createFromFormat('Y-m', trim($request->TOREPORTDATE)) : '';
|
||||
$toreportDate = $lastDay->modify('last day of December')->format('Ymd');
|
||||
// Build SQL
|
||||
$selectContent = "with tempfile as (
|
||||
select a5rsvqty,a5packed,a5slunpr*a5packed as dollars,a5lnwght,a5whs,
|
||||
(select max(ayapr8N002) as ayapr8N002 from icm695m1 where a5macpkr=aymacpkr fetch first 1 rows only)
|
||||
from icm688m2 where a5macpkr in (
|
||||
select distinct aymacpkr from icm695m1 where (AYSTATUS in ('Z','z') and ayapr8N002>=$reportDate and ayapr8N002<=$toreportDate )
|
||||
) and a5co='" . $cO . self::WAREHOUSE_IN_CLAUSE . implode(',', $wHArr) . ")
|
||||
)
|
||||
select 'Q' || EXTRACT(QUARTER FROM TO_DATE(CAST(ayapr8n002 AS TEXT),'YYYYMMDD')) ||'-' || substr(ayapr8N002,3,2) as years,count(*) as lines,
|
||||
sum(a5rsvqty) as reserveqty, sum(a5packed) as packed,sum (a5lnwght*a5packed/a5rsvqty) as weight,sum(dollars) as dollars, a5whs as whs
|
||||
from tempfile
|
||||
group by 'Q' || EXTRACT(QUARTER FROM TO_DATE(CAST(ayapr8n002 AS TEXT),'YYYYMMDD')) ||'-' || substr(ayapr8N002,3,2),a5whs order by 1 ";
|
||||
|
||||
$execSummaryResLY = [];
|
||||
|
||||
break;
|
||||
|
||||
case 'monthly':
|
||||
// Set Dates based on reportPeriod type
|
||||
$firstDay = isset($request->REPORTDATE) ? \DateTime::createFromFormat('Y-m', $request->REPORTDATE) : null;
|
||||
|
||||
$lastDay = (clone $firstDay);
|
||||
$reportDate = $firstDay->modify('-11 months')->modify(self::FIRST_DAY_THIS_MONTH)->format('Ymd'); //
|
||||
$toreportDate = $lastDay ? $lastDay->modify(self::LAST_DAY_THIS_MONTH)->format('Ymd') : '';
|
||||
// Last Year Dates
|
||||
// Same period, but for Last Year (LY)
|
||||
$reportDateLY = (clone $firstDay)->modify(self::ONE_YEAR_AGO)->modify(self::FIRST_DAY_THIS_MONTH)->format('Ymd');
|
||||
$toreportDateLY = (clone $lastDay)->modify(self::ONE_YEAR_AGO)->modify(self::LAST_DAY_THIS_MONTH)->format('Ymd');
|
||||
|
||||
// Build SQL
|
||||
$selectContent = "with tempfile as (
|
||||
select a5rsvqty,a5packed,a5slunpr*a5packed as dollars,a5lnwght,a5whs,
|
||||
(select max(ayapr8N002) as ayapr8N002 from icm695m1 where a5macpkr=aymacpkr fetch first 1 rows only)
|
||||
from icm688m2 where a5macpkr in (
|
||||
select distinct aymacpkr from icm695m1 where (AYSTATUS in ('Z','z') and ayapr8N002>=$reportDate and ayapr8N002<=$toreportDate )
|
||||
) and a5co='" . $cO . self::WAREHOUSE_IN_CLAUSE . implode(',', $wHArr) . ")
|
||||
)
|
||||
select substr(ayapr8N002,1,4) || '-' || substr(ayapr8N002,5,2) as years,count(*) as lines,sum(a5rsvqty) as reserveqty,sum(a5packed) as packed,
|
||||
sum(a5lnwght*a5packed/a5rsvqty) as weight,sum(dollars) as dollars, a5whs as whs
|
||||
from tempfile
|
||||
group by substr(ayapr8N002,1,4) || '-' || substr(ayapr8N002,5,2),a5whs order by 1 ";
|
||||
|
||||
$selectContentLY = "with tempfile as (
|
||||
select a5rsvqty,a5packed,a5slunpr*a5packed as dollars,a5lnwght,a5whs,
|
||||
(select max(ayapr8N002) as ayapr8N002 from icm695m1 where a5macpkr=aymacpkr fetch first 1 rows only)
|
||||
from icm688m2 where a5macpkr in (
|
||||
select distinct aymacpkr from icm695m1 where (AYSTATUS in ('Z','z') and ayapr8N002>=$reportDateLY and ayapr8N002<=$toreportDateLY )
|
||||
) and a5co='" . $cO . self::WAREHOUSE_IN_CLAUSE . implode(',', $wHArr) . ")
|
||||
)
|
||||
select substr(ayapr8N002,1,4) || '-' || substr(ayapr8N002,5,2) as years,count(*) as lines,sum(a5rsvqty) as reserveqty,sum(a5packed) as packed,
|
||||
sum(a5lnwght*a5packed/a5rsvqty) as weight,sum(dollars) as dollars, a5whs as whs
|
||||
from tempfile
|
||||
group by substr(ayapr8N002,1,4) || '-' || substr(ayapr8N002,5,2),a5whs order by 1 ";
|
||||
|
||||
$execSummaryResLY = DB::connection(config('m3.connection', 'pgsql'))->select($selectContentLY);
|
||||
|
||||
break;
|
||||
|
||||
case 'custom':
|
||||
// Set Dates based on reportPeriod type
|
||||
$firstDay = isset($request->REPORTDATE) ? \DateTime::createFromFormat('Y-m', $request->REPORTDATE) : '';
|
||||
$reportDate = $firstDay->modify(self::FIRST_DAY_THIS_MONTH)->format('Ymd');
|
||||
$toreportDate = $firstDay->modify(self::LAST_DAY_THIS_MONTH)->format('Ymd');
|
||||
|
||||
// Last Year Dates
|
||||
$reportDateLY = (clone $firstDay)->modify(self::ONE_YEAR_AGO)->modify(self::FIRST_DAY_THIS_MONTH)->format('Ymd');
|
||||
$toreportDateLY = (clone $firstDay)->modify(self::ONE_YEAR_AGO)->modify(self::LAST_DAY_THIS_MONTH)->format('Ymd');
|
||||
|
||||
// Build SQL
|
||||
$selectContent = "with tempfile as (
|
||||
select a5rsvqty,a5packed,a5slunpr*a5packed as dollars,a5lnwght,a5whs,
|
||||
(select max(ayapr8N002) as ayapr8N002 from icm695m1 where a5macpkr=aymacpkr fetch first 1 rows only)
|
||||
from icm688m2 where a5macpkr in (
|
||||
select distinct aymacpkr from icm695m1 where (AYSTATUS in ('Z','z') and ayapr8N002>=$reportDate and ayapr8N002<=$toreportDate )
|
||||
) and a5co='" . $cO . self::WAREHOUSE_IN_CLAUSE . implode(',', $wHArr) . ')
|
||||
)
|
||||
select substr(ayapr8N002,7,2) as years,count(*) as lines,sum(a5rsvqty) as reserveqty,sum(a5packed) as packed,
|
||||
sum(a5lnwght*a5packed/a5rsvqty) as weight, sum(dollars) as dollars, a5whs as whs
|
||||
from tempfile
|
||||
group by substr(ayapr8N002,7,2),a5whs order by 1 ';
|
||||
|
||||
$selectContentLY = "with tempfile as (
|
||||
select a5rsvqty,a5packed,a5slunpr*a5packed as dollars,a5lnwght,a5whs,
|
||||
(select max(ayapr8N002) as ayapr8N002 from icm695m1 where a5macpkr=aymacpkr fetch first 1 rows only)
|
||||
from icm688m2 where a5macpkr in (
|
||||
select distinct aymacpkr from icm695m1 where (AYSTATUS in ('Z','z') and ayapr8N002>=$reportDateLY and ayapr8N002<=$toreportDateLY )
|
||||
) and a5co='" . $cO . self::WAREHOUSE_IN_CLAUSE . implode(',', $wHArr) . ')
|
||||
)
|
||||
select substr(ayapr8N002,7,2) as years,count(*) as lines,sum(a5rsvqty) as reserveqty,sum(a5packed) as packed,
|
||||
sum(a5lnwght*a5packed/a5rsvqty) as weight, sum(dollars) as dollars, a5whs as whs
|
||||
from tempfile
|
||||
group by substr(ayapr8N002,7,2),a5whs order by 1 ';
|
||||
|
||||
$execSummaryResLY = DB::connection(config('m3.connection', 'pgsql'))->select($selectContentLY);
|
||||
break;
|
||||
|
||||
default:
|
||||
$selectContent = '';
|
||||
break;
|
||||
}
|
||||
|
||||
$execSummaryRes = DB::connection(config('m3.connection', 'pgsql'))->select($selectContent);
|
||||
} else {
|
||||
$execSummaryRes = collect();
|
||||
$execSummaryResLY = collect();
|
||||
}
|
||||
|
||||
return response()->json(['success' => true, 'reportPeriod' => $reportPeriod, 'result' => $execSummaryRes, 'resultLY' => $execSummaryResLY,
|
||||
'checkSales' => $checkSales, 'checkWeight' => $checkWeight, 'checkLines' => $checkLines]);
|
||||
}
|
||||
|
||||
// Init Page
|
||||
$sHUSER = m3_user() !== '' ? Str::upper(trim(m3_user())) : '';
|
||||
if ($sHUSER != '') {
|
||||
// Get User CO & WH from Table ICM428M
|
||||
$iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')
|
||||
->where('R428US', '=', $sHUSER)
|
||||
->first();
|
||||
|
||||
$cOMPANY = isset($iCM428M->R428CO) ? $iCM428M->R428CO : '110'; // Company
|
||||
$pLANT = isset($iCM428M->R428PL) ? $iCM428M->R428PL : '144'; // Plant
|
||||
$wHS = isset($iCM428M->R428WH) ? $iCM428M->R428WH : '322'; // WareHouse
|
||||
}
|
||||
$wHDDA = $cOMPANY . $pLANT . $wHS;
|
||||
// dump($wHDDA);
|
||||
// Warehouse Table
|
||||
$iC670M = DB::connection(config('m3.connection', 'pgsql'))->table('ic670m')->get();
|
||||
} catch (\Throwable $th) {
|
||||
Log::error($th);
|
||||
if ($request->ajax()) {
|
||||
return self::ajaxResponse($request);
|
||||
}
|
||||
|
||||
return view('m3::liberty-theme.pages.execSummaryLine', ['IC670M' => $iC670M, 'WHDDA' => $wHDDA]);
|
||||
// ,'ICM688M2',,'COMPANY','PLANT','WHS','reportDate'
|
||||
return self::pageResponse();
|
||||
}
|
||||
|
||||
private static function ajaxResponse(Request $request)
|
||||
{
|
||||
[$company, $warehouses] = self::warehouseSelection((array) $request->input('WHDDA', []));
|
||||
$period = (string) $request->input('reportPeriod', '');
|
||||
$result = collect();
|
||||
$lastYear = collect();
|
||||
|
||||
try {
|
||||
if ($company !== '' && $warehouses !== [] && $period !== '') {
|
||||
[$sql, $lastYearSql] = self::periodSql($period, $request, $company, $warehouses);
|
||||
$result = $sql === '' ? collect() : DB::connection(config('m3.connection', 'pgsql'))->select($sql);
|
||||
$lastYear = $lastYearSql === '' ? [] : DB::connection(config('m3.connection', 'pgsql'))->select($lastYearSql);
|
||||
}
|
||||
} catch (\Throwable $throwable) {
|
||||
Log::error($throwable);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true, 'reportPeriod' => $period, 'result' => $result, 'resultLY' => $lastYear,
|
||||
'checkSales' => $request->input('checkSales', ''), 'checkWeight' => $request->input('checkWeight', ''),
|
||||
'checkLines' => $request->input('checkLines', ''),
|
||||
]);
|
||||
}
|
||||
|
||||
private static function pageResponse()
|
||||
{
|
||||
$company = '110';
|
||||
$plant = '144';
|
||||
$warehouse = '322';
|
||||
$warehouses = collect();
|
||||
try {
|
||||
$user = m3User() !== '' ? Str::upper(trim(m3User())) : '';
|
||||
if ($user !== '') {
|
||||
$profile = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')->where('R428US', $user)->first();
|
||||
$company = $profile->R428CO ?? $company;
|
||||
$plant = $profile->R428PL ?? $plant;
|
||||
$warehouse = $profile->R428WH ?? $warehouse;
|
||||
}
|
||||
$warehouses = DB::connection(config('m3.connection', 'pgsql'))->table('ic670m')->get();
|
||||
} catch (\Throwable $throwable) {
|
||||
Log::error($throwable);
|
||||
}
|
||||
|
||||
return view('m3::liberty-theme.pages.execSummaryLine', ['IC670M' => $warehouses, 'WHDDA' => $company . $plant . $warehouse]);
|
||||
}
|
||||
|
||||
private static function warehouseSelection(array $selection): array
|
||||
{
|
||||
$company = '';
|
||||
$warehouses = [];
|
||||
foreach ($selection as $value) {
|
||||
$company = substr((string) $value, 0, 3);
|
||||
$warehouses[] = substr((string) $value, 6, 3);
|
||||
}
|
||||
|
||||
return [$company, $warehouses];
|
||||
}
|
||||
|
||||
private static function periodSql(string $period, Request $request, string $company, array $warehouses): array
|
||||
{
|
||||
return match ($period) {
|
||||
'year' => self::yearSql($request, $company, $warehouses),
|
||||
'quarter' => self::quarterSql($request, $company, $warehouses),
|
||||
'monthly' => self::monthlySql($request, $company, $warehouses),
|
||||
'custom' => self::customSql($request, $company, $warehouses),
|
||||
default => ['', ''],
|
||||
};
|
||||
}
|
||||
|
||||
private static function yearSql(Request $request, string $company, array $warehouses): array
|
||||
{
|
||||
$range = self::range($request, 'first day of January', 'last day of December');
|
||||
return $range === null ? ['', ''] : [self::summarySql($range[0], $range[1], $company, $warehouses, 'substr(ayapr8N002,1,4)'), ''];
|
||||
}
|
||||
|
||||
private static function quarterSql(Request $request, string $company, array $warehouses): array
|
||||
{
|
||||
$range = self::range($request, 'first day of January', 'last day of December');
|
||||
$group = "'Q' || EXTRACT(QUARTER FROM TO_DATE(CAST(ayapr8n002 AS TEXT),'YYYYMMDD')) ||'-' || substr(ayapr8N002,3,2)";
|
||||
return $range === null ? ['', ''] : [self::summarySql($range[0], $range[1], $company, $warehouses, $group), ''];
|
||||
}
|
||||
|
||||
private static function monthlySql(Request $request, string $company, array $warehouses): array
|
||||
{
|
||||
$date = self::monthDate($request->input('REPORTDATE'));
|
||||
if ($date === null) {
|
||||
return ['', ''];
|
||||
}
|
||||
$end = clone $date;
|
||||
$from = (clone $date)->modify('-11 months')->modify(self::FIRST_DAY_THIS_MONTH)->format('Ymd');
|
||||
$to = $end->modify(self::LAST_DAY_THIS_MONTH)->format('Ymd');
|
||||
$lastFrom = (clone $date)->modify(self::ONE_YEAR_AGO)->modify('-11 months')->modify(self::FIRST_DAY_THIS_MONTH)->format('Ymd');
|
||||
$lastTo = (clone $date)->modify(self::ONE_YEAR_AGO)->modify(self::LAST_DAY_THIS_MONTH)->format('Ymd');
|
||||
$group = "substr(ayapr8N002,1,4) || '-' || substr(ayapr8N002,5,2)";
|
||||
|
||||
return [self::summarySql($from, $to, $company, $warehouses, $group), self::summarySql($lastFrom, $lastTo, $company, $warehouses, $group)];
|
||||
}
|
||||
|
||||
private static function customSql(Request $request, string $company, array $warehouses): array
|
||||
{
|
||||
$date = self::monthDate($request->input('REPORTDATE'));
|
||||
if ($date === null) {
|
||||
return ['', ''];
|
||||
}
|
||||
$from = (clone $date)->modify(self::FIRST_DAY_THIS_MONTH)->format('Ymd');
|
||||
$to = (clone $date)->modify(self::LAST_DAY_THIS_MONTH)->format('Ymd');
|
||||
$lastFrom = (clone $date)->modify(self::ONE_YEAR_AGO)->modify(self::FIRST_DAY_THIS_MONTH)->format('Ymd');
|
||||
$lastTo = (clone $date)->modify(self::ONE_YEAR_AGO)->modify(self::LAST_DAY_THIS_MONTH)->format('Ymd');
|
||||
$group = 'substr(ayapr8N002,7,2)';
|
||||
|
||||
return [self::summarySql($from, $to, $company, $warehouses, $group), self::summarySql($lastFrom, $lastTo, $company, $warehouses, $group)];
|
||||
}
|
||||
|
||||
private static function range(Request $request, string $fromModifier, string $toModifier): ?array
|
||||
{
|
||||
$from = self::monthDate($request->input('REPORTDATE'));
|
||||
$to = self::monthDate($request->input('TOREPORTDATE'));
|
||||
if ($from === null || $to === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [(clone $from)->modify($fromModifier)->format('Ymd'), (clone $to)->modify($toModifier)->format('Ymd')];
|
||||
}
|
||||
|
||||
private static function monthDate(mixed $value): ?\DateTime
|
||||
{
|
||||
if (! is_string($value) || trim($value) === '') {
|
||||
return null;
|
||||
}
|
||||
$date = \DateTime::createFromFormat('Y-m', trim($value));
|
||||
return $date instanceof \DateTime ? $date : null;
|
||||
}
|
||||
|
||||
private static function summarySql(string $from, string $to, string $company, array $warehouses, string $group): string
|
||||
{
|
||||
$warehouseList = implode(',', $warehouses);
|
||||
return "with tempfile as (
|
||||
select a5rsvqty,a5packed,a5slunpr*a5packed as dollars,a5lnwght,a5whs,
|
||||
(select max(ayapr8N002) from icm695m1 where a5macpkr=aymacpkr fetch first 1 rows only) as ayapr8N002
|
||||
from icm688m2 where a5macpkr in (
|
||||
select distinct aymacpkr from icm695m1 where AYSTATUS in ('Z','z') and ayapr8N002>=$from and ayapr8N002<=$to
|
||||
) and a5co='$company' and a5whs in($warehouseList)
|
||||
) select $group as years,count(*) as lines,sum(a5rsvqty) as reserveqty,sum(a5packed) as packed,
|
||||
sum(a5lnwght*a5packed/a5rsvqty) as weight,sum(dollars) as dollars,a5whs as whs
|
||||
from tempfile group by $group,a5whs order by 1";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,28 @@ class FillBOL2Controller extends Controller
|
||||
// # $bOL = BOL::findOrFail($request);
|
||||
$bOL = $request;
|
||||
|
||||
$data = [
|
||||
$data = $this->bolData($request, $bOL);
|
||||
|
||||
try {
|
||||
$filledPdf = $this->bolService->fillBillOfLading($data);
|
||||
|
||||
return response()->download($filledPdf)->deleteFileAfterSend(true);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json(['error' => $e->getMessage()], 500);
|
||||
}
|
||||
|
||||
}
|
||||
private function bolData(Request $request, Request $bOL): array
|
||||
{
|
||||
return array_merge(
|
||||
$this->bolPrimaryData($request, $bOL),
|
||||
$this->bolRemainingData()
|
||||
);
|
||||
}
|
||||
|
||||
private function bolPrimaryData(Request $request, Request $bOL): array
|
||||
{
|
||||
return [
|
||||
'bol_number' => $request->input('BOL_number') ?? '1234567890',
|
||||
'shipper_no' => $request->input('shipper_no') ?? '1234567890',
|
||||
'date' => now()->format('m/d/Y') ?? '01/01/2000',
|
||||
@@ -125,7 +146,13 @@ Line 5',
|
||||
'LNITEMCLAS17' => '',
|
||||
'TYPEANDESCPTN.17' => '',
|
||||
'PKGTYPECOUNT17' => '',
|
||||
'LNITEMWT16' => '',
|
||||
];
|
||||
}
|
||||
|
||||
private function bolRemainingData(): array
|
||||
{
|
||||
return [
|
||||
'LNITEMWT16' => '',
|
||||
'CLASSORATE16' => '',
|
||||
'LNITEMCLAS16' => '',
|
||||
'TYPEANDESCPTN.16' => '',
|
||||
@@ -212,15 +239,7 @@ Line 5',
|
||||
'BILLTOADDR' => '',
|
||||
'NUMDROPS' => '',
|
||||
|
||||
|
||||
];
|
||||
|
||||
try {
|
||||
$filledPdf = $this->bolService->fillBillOfLading($data);
|
||||
|
||||
return response()->download($filledPdf)->deleteFileAfterSend(true);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json(['error' => $e->getMessage()], 500);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,30 @@ class FillBOLController extends Controller
|
||||
dd($error);
|
||||
}
|
||||
|
||||
$result = $pdf->fillForm([
|
||||
$result = $pdf->fillForm(self::bolFormData($bOL))
|
||||
->needAppearances() // ensures values are visible in viewer
|
||||
->saveAs(Storage::disk('public')->path($newfile));
|
||||
// Always check for errors
|
||||
if ($result === false) {
|
||||
var_dump('step 3');
|
||||
$error = $pdf->getError();
|
||||
dd($error);
|
||||
} else {
|
||||
return response()->file(Storage::disk('public')->path($newfile));
|
||||
}
|
||||
|
||||
}
|
||||
private static function bolFormData(Request $bOL): array
|
||||
{
|
||||
return array_merge(
|
||||
self::bolPrimaryFields($bOL),
|
||||
self::bolRemainingFields()
|
||||
);
|
||||
}
|
||||
|
||||
private static function bolPrimaryFields(Request $bOL): array
|
||||
{
|
||||
return [
|
||||
'DTESHIPED.1' => date('d/m/Y'),
|
||||
'invoice_number' => $bOL['BOL_number'],
|
||||
'amount_due' => number_format($bOL['amount'], 2),
|
||||
@@ -110,7 +133,13 @@ class FillBOLController extends Controller
|
||||
'LNITEMCLAS17' => '',
|
||||
'TYPEANDESCPTN.17' => '',
|
||||
'PKGTYPECOUNT17' => '',
|
||||
'LNITEMWT16' => '',
|
||||
];
|
||||
}
|
||||
|
||||
private static function bolRemainingFields(): array
|
||||
{
|
||||
return [
|
||||
'LNITEMWT16' => '',
|
||||
'CLASSORATE16' => '',
|
||||
'LNITEMCLAS16' => '',
|
||||
'TYPEANDESCPTN.16' => '',
|
||||
@@ -197,17 +226,7 @@ class FillBOLController extends Controller
|
||||
'BILLTOADDR' => '',
|
||||
'NUMDROPS' => '',
|
||||
|
||||
])
|
||||
->needAppearances() // ensures values are visible in viewer
|
||||
->saveAs(Storage::disk('public')->path($newfile));
|
||||
// Always check for errors
|
||||
if ($result === false) {
|
||||
var_dump('step 3');
|
||||
$error = $pdf->getError();
|
||||
dd($error);
|
||||
} else {
|
||||
return response()->file(Storage::disk('public')->path($newfile));
|
||||
}
|
||||
|
||||
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,31 +16,31 @@ class M3CallCloseAPIController extends Controller
|
||||
{
|
||||
self::configureTimeouts();
|
||||
$params = self::validatedParams($request);
|
||||
$response = null;
|
||||
|
||||
if ($params === null) {
|
||||
Log::channel('dailyCron')->error('Manifest CloseAPI: Manifest, company and warehouse must be defined.');
|
||||
|
||||
return self::errorResponse('Manifest CloseAPI: Manifest, company and warehouse must be defined.');
|
||||
}
|
||||
|
||||
try {
|
||||
$records = self::findOpenManifestRecords($params);
|
||||
if ($records->isEmpty()) {
|
||||
Log::channel('dailyCron')->info('Manifest CloseAPI: No records found in ICM705M1.');
|
||||
|
||||
return self::errorResponse('Manifest CloseAPI: No records found in ICM705M1.');
|
||||
$response = self::errorResponse('Manifest CloseAPI: Manifest, company and warehouse must be defined.');
|
||||
} else {
|
||||
try {
|
||||
$records = self::findOpenManifestRecords($params);
|
||||
if ($records->isEmpty()) {
|
||||
Log::channel('dailyCron')->info('Manifest CloseAPI: No records found in ICM705M1.');
|
||||
$response = self::errorResponse('Manifest CloseAPI: No records found in ICM705M1.');
|
||||
} else {
|
||||
$response = self::submitManifest($records->first(), $params['SHUSER']);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
Log::error($exception);
|
||||
$response = response()->json([
|
||||
'code' => '500',
|
||||
'status' => 'Error',
|
||||
'message' => 'Manifest Closing failed unexpectedly.',
|
||||
], 500);
|
||||
}
|
||||
|
||||
return self::submitManifest($records->first(), $params['SHUSER']);
|
||||
} catch (\Throwable $exception) {
|
||||
Log::error($exception);
|
||||
|
||||
return response()->json([
|
||||
'code' => '500',
|
||||
'status' => 'Error',
|
||||
'message' => 'Manifest Closing failed unexpectedly.',
|
||||
], 500);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private static function configureTimeouts(): void
|
||||
|
||||
@@ -12,10 +12,10 @@ class M3DeliveryController extends Controller
|
||||
public static function index(Request $request)
|
||||
{
|
||||
$connection = config('m3.connection', 'pgsql');
|
||||
$power_user = (object) ['R428PWRUSR' => 'N', 'R428US' => strtoupper(m3_user()), 'R428CO' => '', 'R428PL' => '', 'R428WH' => ''];
|
||||
$power_user = (object) ['R428PWRUSR' => 'N', 'R428US' => strtoupper(m3User()), 'R428CO' => '', 'R428PL' => '', 'R428WH' => ''];
|
||||
if (Schema::connection($connection)->hasTable('icm428m')) {
|
||||
$power_user = DB::connection($connection)->table('icm428m')->select('R428PWRUSR', 'R428US', 'R428CO', 'R428PL', 'R428WH')
|
||||
->where('R428US', strtoupper(m3_user()))->first() ?? $power_user;
|
||||
->where('R428US', strtoupper(m3User()))->first() ?? $power_user;
|
||||
}
|
||||
$co = $power_user->R428CO;
|
||||
$plant = $power_user->R428PL;
|
||||
|
||||
@@ -73,7 +73,7 @@ class M3ErrorsDispController extends Controller
|
||||
'STARTDATE' => trim((string) $request->input('STARTDATE', today()->subDays(1)->format('Y-m-d'))),
|
||||
'ENDDATE' => trim((string) $request->input('ENDDATE', today()->format('Y-m-d'))),
|
||||
'SHOWERRORS' => trim((string) $request->input('SHOWERRORS', 'N')),
|
||||
'SHUSER' => m3_user() !== '' ? Str::upper(trim(m3_user())) : '',
|
||||
'SHUSER' => m3User() !== '' ? Str::upper(trim(m3User())) : '',
|
||||
'SKIPDATES' => trim((string) $request->input('SKIPDATES', 'N')),
|
||||
];
|
||||
}
|
||||
@@ -147,7 +147,7 @@ class M3ErrorsDispController extends Controller
|
||||
$sHTIME = $request->SHTIME != null ? trim($request->SHTIME) : '';
|
||||
$sHTYPE = $request->SHTYPE != null ? trim($request->SHTYPE) : '';
|
||||
$sHACKNOTE = $request->SHACKNOTE != null ? trim(substr($request->SHACKNOTE, 0, 99)) : '';
|
||||
$sHUSER = m3_user() !== '' ? Str::upper(m3_user()) : '';
|
||||
$sHUSER = m3User() !== '' ? Str::upper(m3User()) : '';
|
||||
$cLOSESIM = $request->CLOSESIM != null ? trim($request->CLOSESIM) : 'N';
|
||||
|
||||
if ($cLOSESIM == 'N') {
|
||||
@@ -242,7 +242,7 @@ class M3ErrorsDispController extends Controller
|
||||
'endDate' => trim((string) $request->input('ENDDATE', today()->format('Y-m-d'))),
|
||||
'showErrors' => trim((string) $request->input('SHOWERRORS', 'N')),
|
||||
'skipDates' => trim((string) $request->input('SKIPDATES', 'N')),
|
||||
'user' => Str::upper(trim(m3_user())),
|
||||
'user' => Str::upper(trim(m3User())),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -12,169 +12,161 @@ class M3GetPDFFromCacheController extends Controller
|
||||
{
|
||||
public static function index(Request $request)
|
||||
{
|
||||
// Parse PDF file and build necessary objects.
|
||||
$state = self::initialState();
|
||||
|
||||
$aggno = $aggmsg = '';
|
||||
$iC670M = $pDFArray = $carrier = $trackingno = $iCM688M1 = [];
|
||||
$aYMACPKR = $wHDDA = $cOMPANY = $pLANT = $wHS = '';
|
||||
|
||||
// PDF File PATH
|
||||
$pdfFilePath = Config::get('arrays.PdfPath');
|
||||
try {
|
||||
// Initialise Vars
|
||||
$pDFArray = $trackingno = $carrier = $iCM688M1 = [];
|
||||
|
||||
$sHUSER = m3_user() !== '' ? Str::upper(trim(m3_user())) : '';
|
||||
|
||||
if ($sHUSER != '') {
|
||||
// Get User CO & WH
|
||||
// Get user from ICM428M
|
||||
$iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')
|
||||
->where('R428US', '=', $sHUSER)
|
||||
->first();
|
||||
|
||||
$cOMPANY = isset($iCM428M->R428CO) ? $iCM428M->R428CO : ''; // Company
|
||||
$pLANT = isset($iCM428M->R428PL) ? $iCM428M->R428PL : ''; // Plant
|
||||
$wHS = isset($iCM428M->R428WH) ? $iCM428M->R428WH : ''; // WareHouse
|
||||
}
|
||||
|
||||
// Warehouse Table
|
||||
$iC670M = DB::connection(config('m3.connection', 'pgsql'))->table('ic670m')->get();
|
||||
// ->where('WDCO',$userCO)->where('WDPL',$userPL)->where('WDWHS',$userWH)
|
||||
|
||||
// Get URL PARAMS
|
||||
$urlParams = count($request->all()) > 0 ? $request->all() : '';
|
||||
// dump($urlParams);
|
||||
$aYMACPKR = isset($urlParams['MACPKR']) ? trim($urlParams['MACPKR']) : ''; // Delivery note number
|
||||
$dOCTYPE = isset($urlParams['DOCTYPE']) ? trim($urlParams['DOCTYPE']) : ''; // Document type (PackingList, CarrierLabel, ContentLabel)
|
||||
$wHDDA = $cOMPANY . $pLANT . $wHS;
|
||||
|
||||
// Check Doctype fisrt
|
||||
$docTypes = $dOCTYPE != '' ? [$dOCTYPE] : ['PackingList', 'ContentLabel', 'CarrierLabel', 'GSLabel']; // document type (PackingList, CarrierLabel, ContentLabel)
|
||||
|
||||
if ($urlParams != '') {
|
||||
// dump($urlParams);
|
||||
// document number (ie the internal box number, the pick list number)
|
||||
// Key Combination : COMPANY WHS A4MACPKR DOCTYPE DOCNUM
|
||||
// Document type (PackingList, CarrierLabel, ContentLabel)
|
||||
|
||||
// Get Aggregation Number if it exists
|
||||
$iCM695M1Agg = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m1')
|
||||
->select('AYTRUCK')
|
||||
->where('AYCO', $cOMPANY)
|
||||
->where('AYWHS', $wHS)
|
||||
->where('AYMACPKR', $aYMACPKR)
|
||||
->first();
|
||||
$aggno = isset($iCM695M1Agg->AYTRUCK) ? trim($iCM695M1Agg->AYTRUCK) : '';
|
||||
|
||||
if ($aggno != '' && $aggno != '0') {
|
||||
|
||||
$aggmsg = "This delivery note is part of aggregation $aggno ";
|
||||
$iCM688M1 = DB::connection(config('m3.connection', 'pgsql'))->select("select A4MACPKR from ICM688M1 where A4SHPAGGCD='$aggno'");
|
||||
|
||||
// 654 add 'AYSPR15A01', 'AYSPR30A01', 'AYTRUCK' carrier and tracking# and agg#
|
||||
$iCM695M1 = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m1')
|
||||
->select('AYCO', 'AYWHS', 'AYMACPKR', 'AYINTBOX', 'AYSPR15A01', 'AYSPR30A01', 'AYTRUCK')
|
||||
->distinct()
|
||||
->where('AYCO', $cOMPANY)
|
||||
->where('AYWHS', $wHS)
|
||||
// ->where('AYMACPKR',$aYMACPKR)
|
||||
->where('AYTRUCK', $aggno)
|
||||
->orderBy('AYMACPKR')
|
||||
->get();
|
||||
} else {
|
||||
// 654 add 'AYSPR15A01', 'AYSPR30A01', 'AYTRUCK' carrier and tracking# and agg#
|
||||
$iCM695M1 = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m1')
|
||||
->select('AYCO', 'AYWHS', 'AYMACPKR', 'AYINTBOX', 'AYSPR15A01', 'AYSPR30A01', 'AYTRUCK')
|
||||
->distinct()
|
||||
->where('AYCO', $cOMPANY)
|
||||
->where('AYWHS', $wHS)
|
||||
->where('AYMACPKR', $aYMACPKR)
|
||||
->orderBy('AYMACPKR')
|
||||
->get();
|
||||
}
|
||||
|
||||
if (count($iCM695M1) > 0) {
|
||||
$tmpCacheArr = $carrier = $trackingno = [];
|
||||
// Loop the Results from $ICM595M1TMP
|
||||
foreach ($iCM695M1 as $ICM695M1R) {
|
||||
$wHS = trim($ICM695M1R->AYWHS);
|
||||
$cOMPANY = trim($ICM695M1R->AYCO);
|
||||
$aYMACPKR = trim($ICM695M1R->AYMACPKR);
|
||||
$dOCNUM = trim($ICM695M1R->AYINTBOX);
|
||||
// 654
|
||||
$carrier[] = trim($ICM695M1R->AYSPR15A01);
|
||||
$trackingno[] = trim($ICM695M1R->AYSPR30A01);
|
||||
$aggno = trim($ICM695M1R->AYTRUCK);
|
||||
|
||||
// Make Key and Test Validity
|
||||
if ($aYMACPKR != '' && $cOMPANY != '' && $wHS != '') {
|
||||
$contentLabel = '';
|
||||
|
||||
// Get Unique Keys
|
||||
foreach ($docTypes as $value) {
|
||||
// Check Parcel vs LTL
|
||||
if ($value == 'ContentLabel') {
|
||||
$dOCNUMT = $dOCNUM;
|
||||
$contentLabel = ! is_numeric($dOCNUM) ? 'LTL' : '';
|
||||
}
|
||||
|
||||
if ($value == 'CarrierLabel') {
|
||||
$dOCNUMT = $dOCNUM;
|
||||
|
||||
// Keep Solon Logic to read LTL
|
||||
$dOCNUMT2 = $contentLabel == 'LTL' ? $aYMACPKR : $dOCNUM;
|
||||
if ($dOCNUMT2 != $dOCNUMT) {
|
||||
$pDFKey2 = $value . '/' . $value . '_' . $aYMACPKR . '_' . $dOCNUMT2 . '_' . $cOMPANY . '_' . $wHS;
|
||||
$tmpCacheArr[] = $pDFKey2;
|
||||
}
|
||||
}
|
||||
|
||||
if ($value == 'PackingList') {
|
||||
$dOCNUMT = $aYMACPKR;
|
||||
}
|
||||
|
||||
// Get GS1 Labels
|
||||
if ($value == 'GSLabel') {
|
||||
$pDFKey = $value . '/' . $value . '_' . $aYMACPKR . '_' . $cOMPANY . '_' . $wHS . '_' . $dOCNUM;
|
||||
|
||||
// $pDFKey = $value.'/'.$value.'_'.$aYMACPKR.'_'.$cOMPANY.'_'.$wHS;
|
||||
// }
|
||||
// else{
|
||||
// $pDFKey = $value.'/'.$value.'_'.$aYMACPKR.'_'.$cOMPANY.'_'.$wHS.'_'.$dOCNUM;
|
||||
// }
|
||||
} else {
|
||||
$pDFKey = $value . '/' . $value . '_' . $aYMACPKR . '_' . $dOCNUMT . '_' . $cOMPANY . '_' . $wHS;
|
||||
}
|
||||
$tmpCacheArr[] = $pDFKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get unique values from array $pDFArray
|
||||
$tmpCacheArr = collect($tmpCacheArr)->unique();
|
||||
foreach ($tmpCacheArr as $value) {
|
||||
|
||||
$pdfFileName = $pdfFilePath . $value . '.pdf';
|
||||
if (File::exists($pdfFileName)) {
|
||||
|
||||
$pdfFile = File::get($pdfFileName);
|
||||
// Transform content to base64
|
||||
// $base64PDF = $pdfFile;
|
||||
$base64PDF = base64_encode($pdfFile);
|
||||
$pDFArray[] = $base64PDF;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Nothing Found
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
report($th);
|
||||
self::loadUserContext($state);
|
||||
self::loadDocuments($request, $state);
|
||||
} catch (\Throwable $throwable) {
|
||||
report($throwable);
|
||||
}
|
||||
|
||||
return view('m3::liberty-theme.pages.M3GetPDF', ['IC670M' => $iC670M, 'PDFArray' => $pDFArray, 'AYMACPKR' => $aYMACPKR, 'WHDDA' => $wHDDA, 'aggmsg' => $aggmsg, 'carrier' => $carrier, 'trackingno' => $trackingno, 'ICM688M1' => $iCM688M1, 'COMPANY' => $cOMPANY, 'PLANT' => $pLANT, 'WHS' => $wHS]);
|
||||
// compact('IC670M','ViewTitle')
|
||||
return view('m3::liberty-theme.pages.M3GetPDF', self::viewData($state));
|
||||
}
|
||||
|
||||
private static function initialState(): array
|
||||
{
|
||||
return [
|
||||
'aggmsg' => '', 'IC670M' => collect(), 'PDFArray' => [], 'carrier' => [],
|
||||
'trackingno' => [], 'ICM688M1' => [], 'AYMACPKR' => '', 'WHDDA' => '',
|
||||
'COMPANY' => '', 'PLANT' => '', 'WHS' => '',
|
||||
];
|
||||
}
|
||||
|
||||
private static function loadUserContext(array &$state): void
|
||||
{
|
||||
$user = m3User() !== '' ? Str::upper(trim(m3User())) : '';
|
||||
if ($user !== '') {
|
||||
$profile = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')->where('R428US', $user)->first();
|
||||
$state['COMPANY'] = $profile->R428CO ?? '';
|
||||
$state['PLANT'] = $profile->R428PL ?? '';
|
||||
$state['WHS'] = $profile->R428WH ?? '';
|
||||
}
|
||||
|
||||
$state['WHDDA'] = $state['COMPANY'] . $state['PLANT'] . $state['WHS'];
|
||||
$state['IC670M'] = DB::connection(config('m3.connection', 'pgsql'))->table('ic670m')->get();
|
||||
}
|
||||
|
||||
private static function loadDocuments(Request $request, array &$state): void
|
||||
{
|
||||
$params = $request->all();
|
||||
if ($params === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$state['AYMACPKR'] = trim((string) ($params['MACPKR'] ?? ''));
|
||||
$documentType = trim((string) ($params['DOCTYPE'] ?? ''));
|
||||
$documentTypes = $documentType !== '' ? [$documentType] : ['PackingList', 'ContentLabel', 'CarrierLabel', 'GSLabel'];
|
||||
$aggregation = self::aggregationNumber($state);
|
||||
$rows = self::documentRows($state, $aggregation);
|
||||
if ($rows->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$keys = self::cacheKeys($rows, $documentTypes, $state);
|
||||
$state['PDFArray'] = self::readCachedPdfs($keys);
|
||||
}
|
||||
|
||||
private static function aggregationNumber(array &$state): string
|
||||
{
|
||||
$row = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m1')
|
||||
->select('AYTRUCK')->where('AYCO', $state['COMPANY'])->where('AYWHS', $state['WHS'])
|
||||
->where('AYMACPKR', $state['AYMACPKR'])->first();
|
||||
$aggregation = trim((string) ($row->AYTRUCK ?? ''));
|
||||
if ($aggregation !== '' && $aggregation !== '0') {
|
||||
$state['aggmsg'] = "This delivery note is part of aggregation $aggregation ";
|
||||
$state['ICM688M1'] = DB::connection(config('m3.connection', 'pgsql'))
|
||||
->table('icm688m1')->select('A4MACPKR')->where('A4SHPAGGCD', $aggregation)->get()->all();
|
||||
}
|
||||
|
||||
return $aggregation;
|
||||
}
|
||||
|
||||
private static function documentRows(array $state, string $aggregation)
|
||||
{
|
||||
$query = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m1')
|
||||
->select('AYCO', 'AYWHS', 'AYMACPKR', 'AYINTBOX', 'AYSPR15A01', 'AYSPR30A01', 'AYTRUCK')
|
||||
->distinct()->where('AYCO', $state['COMPANY'])->where('AYWHS', $state['WHS']);
|
||||
|
||||
$aggregation !== '' && $aggregation !== '0'
|
||||
? $query->where('AYTRUCK', $aggregation)
|
||||
: $query->where('AYMACPKR', $state['AYMACPKR']);
|
||||
|
||||
return $query->orderBy('AYMACPKR')->get();
|
||||
}
|
||||
|
||||
private static function cacheKeys(iterable $rows, array $documentTypes, array &$state): array
|
||||
{
|
||||
$keys = [];
|
||||
foreach ($rows as $row) {
|
||||
self::appendRowKeys($keys, $row, $documentTypes, $state);
|
||||
}
|
||||
|
||||
return array_values(array_unique($keys));
|
||||
}
|
||||
|
||||
private static function appendRowKeys(array &$keys, object $row, array $documentTypes, array &$state): void
|
||||
{
|
||||
$warehouse = trim((string) $row->AYWHS);
|
||||
$company = trim((string) $row->AYCO);
|
||||
$picker = trim((string) $row->AYMACPKR);
|
||||
$documentNumber = trim((string) $row->AYINTBOX);
|
||||
$state['WHS'] = $warehouse;
|
||||
$state['COMPANY'] = $company;
|
||||
$state['AYMACPKR'] = $picker;
|
||||
$state['carrier'][] = trim((string) $row->AYSPR15A01);
|
||||
$state['trackingno'][] = trim((string) $row->AYSPR30A01);
|
||||
|
||||
if ($picker === '' || $company === '' || $warehouse === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$contentLabel = '';
|
||||
foreach ($documentTypes as $type) {
|
||||
[$key, $extraKey, $contentLabel] = self::documentKey($type, $picker, $documentNumber, $company, $warehouse, $contentLabel);
|
||||
if ($extraKey !== null) {
|
||||
$keys[] = $extraKey;
|
||||
}
|
||||
$keys[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
private static function documentKey(string $type, string $picker, string $number, string $company, string $warehouse, string $contentLabel): array
|
||||
{
|
||||
$documentNumber = $number;
|
||||
$extraKey = null;
|
||||
if ($type === 'ContentLabel') {
|
||||
$contentLabel = is_numeric($number) ? '' : 'LTL';
|
||||
} elseif ($type === 'PackingList') {
|
||||
$documentNumber = $picker;
|
||||
} elseif ($type === 'CarrierLabel' && $contentLabel === 'LTL') {
|
||||
$extraKey = "$type/{$type}_{$picker}_{$picker}_{$company}_{$warehouse}";
|
||||
}
|
||||
|
||||
$key = $type === 'GSLabel'
|
||||
? "$type/{$type}_{$picker}_{$company}_{$warehouse}_{$number}"
|
||||
: "$type/{$type}_{$picker}_{$documentNumber}_{$company}_{$warehouse}";
|
||||
|
||||
return [$key, $extraKey, $contentLabel];
|
||||
}
|
||||
|
||||
private static function readCachedPdfs(array $keys): array
|
||||
{
|
||||
$result = [];
|
||||
$path = (string) Config::get('arrays.PdfPath');
|
||||
foreach ($keys as $key) {
|
||||
$fileName = $path . $key . '.pdf';
|
||||
if (File::exists($fileName)) {
|
||||
$result[] = base64_encode(File::get($fileName));
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function viewData(array $state): array
|
||||
{
|
||||
return $state;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ class MFOrdersController extends Controller
|
||||
// Get Users from ICM428M
|
||||
$iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')
|
||||
->where('R428US', '=', strtoupper(m3_user()))
|
||||
->where('R428US', '=', strtoupper(m3User()))
|
||||
->first();
|
||||
$co = $iCM428M->R428CO;
|
||||
$whs = $iCM428M->R428WH;
|
||||
|
||||
@@ -18,6 +18,10 @@ class OrderLinesOfClosedOrder extends Controller
|
||||
public static function index(Request $request)
|
||||
{
|
||||
$iC670M = $iCM688M2 = [];
|
||||
$wHDDA = '';
|
||||
$cOMPANY = '110';
|
||||
$pLANT = '144';
|
||||
$wHS = '322';
|
||||
$rEPORTDATEDisp = today()->format('Ymd');
|
||||
$allReportsUrls = [];
|
||||
try {
|
||||
@@ -283,7 +287,7 @@ class OrderLinesOfClosedOrder extends Controller
|
||||
if (Storage::disk('publicCL')->exists($fileName)) {
|
||||
// File exists, retrieve content or URL
|
||||
// $content = Storage::disk('publicCL')->get($fileName);
|
||||
$fileNameOnly = strpos($fileName, '/') != false ? substr($fileName, strpos($fileName, '/') + 1) : $fileName;
|
||||
$fileNameOnly = strpos($fileName, '/') !== false ? substr($fileName, strpos($fileName, '/') + 1) : $fileName;
|
||||
|
||||
// Download the file
|
||||
return Storage::disk('publicCL')->download($fileName, $fileNameOnly);
|
||||
|
||||
@@ -13,11 +13,11 @@ class PalletQtyController extends Controller
|
||||
public static function index(Request $request)
|
||||
{
|
||||
$connection = config('m3.connection', 'pgsql');
|
||||
$power_user = (object) ['R428PWRUSR' => 'N', 'R428US' => strtoupper(m3_user()), 'R428CO' => '', 'R428PL' => '', 'R428WH' => ''];
|
||||
$power_user = (object) ['R428PWRUSR' => 'N', 'R428US' => strtoupper(m3User()), 'R428CO' => '', 'R428PL' => '', 'R428WH' => ''];
|
||||
if (Schema::connection($connection)->hasTable('icm428m')) {
|
||||
$power_user = DB::connection($connection)->table('icm428m')
|
||||
->select('R428PWRUSR', 'R428US', 'R428CO', 'R428PL', 'R428WH')
|
||||
->where('R428US', '=', strtoupper(m3_user()))->first() ?? $power_user;
|
||||
->where('R428US', '=', strtoupper(m3User()))->first() ?? $power_user;
|
||||
}
|
||||
$co = $power_user->R428CO;
|
||||
$plant = $power_user->R428PL;
|
||||
|
||||
@@ -15,7 +15,7 @@ class PendingClosureController extends Controller
|
||||
// Get Users from ICM428M
|
||||
$iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')
|
||||
->where('R428US', '=', strtoupper(m3_user()))
|
||||
->where('R428US', '=', strtoupper(m3User()))
|
||||
->first();
|
||||
$user = $iCM428M->R428US;
|
||||
$co = $iCM428M->R428CO;
|
||||
|
||||
@@ -19,7 +19,7 @@ class ReplenishSettingsController extends Controller
|
||||
// $iC670M = DB::connection(config('m3.connection', 'pgsql'))->table('ic670m')->get();
|
||||
|
||||
// Get Logged user Id
|
||||
$userId = m3_user() !== '' ? strtoupper(m3_user()) : '';
|
||||
$userId = m3User() !== '' ? strtoupper(m3User()) : '';
|
||||
// $userId = 'E1135818'; // Brad : E1135818 Malak : E2011812 ACOM_PDF
|
||||
$connection = config('m3.connection', 'pgsql');
|
||||
$iCM428M = Schema::connection($connection)->hasTable('icm428m')
|
||||
@@ -140,7 +140,7 @@ class ReplenishSettingsController extends Controller
|
||||
// $iC670M = DB::connection(config('m3.connection', 'pgsql'))->table('ic670m')->get();
|
||||
|
||||
// Get Logged user Id
|
||||
$userId = m3_user() !== '' ? strtoupper(m3_user()) : '';
|
||||
$userId = m3User() !== '' ? strtoupper(m3User()) : '';
|
||||
// $userId = 'E1135818'; // Brad : E1135818 Malak : E2011812 ACOM_PDF
|
||||
$connection = config('m3.connection', 'pgsql');
|
||||
$iCM428M = Schema::connection($connection)->hasTable('icm428m')
|
||||
|
||||
@@ -17,7 +17,7 @@ class ShipToController extends Controller
|
||||
|
||||
return Datatables::of($data)
|
||||
->addIndexColumn()
|
||||
->addColumn('checkbox', function ($row) {
|
||||
->addColumn('checkbox', function () {
|
||||
return '';
|
||||
})
|
||||
->addColumn('action', function ($row) {
|
||||
|
||||
@@ -11,15 +11,10 @@ use Modules\M3\Services\PostgresProgramBridge;
|
||||
|
||||
class UserControlController extends Controller
|
||||
{
|
||||
private const AUTH_FAILURE_MESSAGE = 'Could not connect due to wrong user or password.';
|
||||
|
||||
private const DATABASE_NOT_FOUND_MESSAGE = 'Database not found. Try WRKRDBDIRE to check.';
|
||||
|
||||
private const CONNECTION_ERROR_PREFIX = 'Could not connect. Error: ';
|
||||
|
||||
private const PROGRAM_ERROR_PREFIX = 'Error calling program. Code: ';
|
||||
|
||||
private const MESSAGE_SEPARATOR = ' Msg: ';
|
||||
|
||||
public static function index(Request $request)
|
||||
{
|
||||
@@ -46,81 +41,80 @@ class UserControlController extends Controller
|
||||
//
|
||||
public static function saveUserAdd(Request $request)
|
||||
{
|
||||
|
||||
if ($request->R428EMPCDE == '') {
|
||||
$request->R428EMPCDE = 0;
|
||||
}
|
||||
|
||||
// Insert record to ICM428M
|
||||
// dump($request);
|
||||
// Validate user profile exists on the system
|
||||
$usrprf = [(object) ['COUNT' => 0]]; // PostgreSQL/Core owns M3 profiles; no QSYS2 lookup.
|
||||
|
||||
// Validate employee code exists in LBPF file
|
||||
// if($request->R428EMPCDE>0) {
|
||||
// $empcde=DB::connection(config('m3.connection', 'pgsql'))->select("select count(*) as COUNT2 from LBPF where EMPNO='$request->R428EMPCDE'");
|
||||
// if($empcde[0]->COUNT2=="0") {
|
||||
// #echo "<script>alert('Employee code entered does not exist, please try again');</script>";
|
||||
// return "error empcd";
|
||||
// }
|
||||
// }
|
||||
$icm428m = DB::connection(config('m3.connection', 'pgsql'))->select("select count(*) as COUNT1 from ICM428M where R428US='$request->R428US'");
|
||||
if ($icm428m[0]->COUNT1 == '1') {
|
||||
$connection = DB::connection(config('m3.connection', 'pgsql'));
|
||||
$existing = $connection->select("select count(*) as COUNT1 from ICM428M where R428US='$request->R428US'");
|
||||
if (($existing[0]->COUNT1 ?? 0) == '1') {
|
||||
return 'error exists';
|
||||
} else {
|
||||
|
||||
if ($usrprf[0]->COUNT == '1') {
|
||||
DB::connection(config('m3.connection', 'pgsql'))->insert("insert into ICM428M
|
||||
(R428CO, R428PL, R428WH, R428STS, R428US, R428FIRST, R428FAMILY, R428EMAIL, R428EMPCDE, R428ADMUSR, R428PWRUSR, MENU2OPT, MENU3OPT, MENU4OPT, MENU5OPT, MENU6OPT, R42811A)
|
||||
values ('$request->R428CO', '$request->R428PL', '$request->R428WH', '$request->R428STS', '$request->R428US', '$request->R428FIRST',
|
||||
'$request->R428FAMILY', '$request->R428EMAIL', $request->R428EMPCDE, '$request->R428ADMUSR', '$request->R428PWRUSR',
|
||||
'NN" . $request->MENU2OPT3 . 'NNN' . $request->MENU2OPT7 . $request->MENU2OPT8 . "N', '" . $request->MENU3OPT1 . $request->MENU3OPT2 . "NNNNNNN',
|
||||
'" . $request->MENU4OPT1 . $request->MENU4OPT2 . $request->MENU4OPT3 . "NNNNNN',
|
||||
'" . $request->MENU5OPT1 . $request->MENU5OPT2 . $request->MENU5OPT3 . 'N' . $request->MENU5OPT5 . "NNNN','" . $request->MENU6OPT1 . $request->MENU6OPT2 . $request->MENU6OPT3 . "','" . $request->R42811A . "')");
|
||||
|
||||
return 'success';
|
||||
} else {
|
||||
|
||||
// CL program call here (ewobjtst.)ICMUSRPRF parms(R428US, R428FIRST, R428FAMILY)
|
||||
// connect to toolkit using DB2 credentials (can also leave blank for default authority)
|
||||
try {
|
||||
$conn = app(PostgresProgramBridge::class);
|
||||
} catch (\Throwable $e) {
|
||||
// Determine reason for failure.
|
||||
// Probably database authentication error or invalid or unreachable database.
|
||||
return self::programBridgeConnectionError($e);
|
||||
}
|
||||
$conn->setOptions(['persistent' => false, 'stateless' => true, 'debug' => true, 'debugLogFile' => '/www/sentm3test/htdocs/M3/storage/logs/toolkit_debug.log']);
|
||||
// Add LIB
|
||||
// $result = $conn->CLCommand('ADDLIBLE LIB(MPDAT10)');
|
||||
// define several input/output params
|
||||
$params = [];
|
||||
$params[] = $conn->AddParameterChar('in', 10, 'User profile', 'E#iUsrPrf', $request->R428US);
|
||||
$params[] = $conn->AddParameterChar('in', 20, 'First name', 'FIRST', $request->R428FIRST);
|
||||
$params[] = $conn->AddParameterChar('in', 30, 'Family name', 'FAMILY', $request->R428FAMILY);
|
||||
// # $result = $conn->PgmCall(Config::get('eproconf.misc.PGM1'), Config::get('eproconf.misc.libname4'), $params, array(), array());
|
||||
$result = $conn->PgmCall('ICMUSRPRF', 'EWOBJ', $params, [], []);
|
||||
if (! $result) {
|
||||
|
||||
return 'error profile2';
|
||||
} else {
|
||||
// Successful Call : User profile created with default password
|
||||
// dd($result);
|
||||
// echo "<script>alert('User profile $request->R428US was created on the system with default password.');</script>";
|
||||
DB::connection(config('m3.connection', 'pgsql'))->insert("insert into ICM428M
|
||||
(R428CO, R428PL, R428WH, R428STS, R428US, R428FIRST, R428FAMILY, R428EMAIL, R428EMPCDE, R428ADMUSR, R428PWRUSR, MENU2OPT, MENU3OPT, MENU4OPT, MENU5OPT, MENU6OPT, R42811A,R42821A)
|
||||
values ('$request->R428CO', '$request->R428PL', '$request->R428WH', '$request->R428STS', '$request->R428US', '$request->R428FIRST',
|
||||
'$request->R428FAMILY', '$request->R428EMAIL', $request->R428EMPCDE, '$request->R428ADMUSR', '$request->R428PWRUSR',
|
||||
'NN" . $request->MENU2OPT3 . 'NNN' . $request->MENU2OPT7 . $request->MENU2OPT8 . "N', '" . $request->MENU3OPT1 . $request->MENU3OPT2 . "NNNNNNN',
|
||||
'" . $request->MENU4OPT1 . $request->MENU4OPT2 . $request->MENU4OPT3 . "NNNNNN',
|
||||
'" . $request->MENU5OPT1 . $request->MENU5OPT2 . $request->MENU5OPT3 . 'N' . $request->MENU5OPT5 . "NNNN','" . $request->MENU6OPT1 . $request->MENU6OPT2 . $request->MENU6OPT3 . "','" . $request->R42811A . "','" . $request->R42821A . "')");
|
||||
|
||||
return 'success2';
|
||||
}
|
||||
// #kd return "error profile";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// PostgreSQL/Core owns M3 profiles; no QSYS2 lookup is currently available.
|
||||
$profileExists = false;
|
||||
if ($profileExists) {
|
||||
self::insertUser($request, false);
|
||||
return 'success';
|
||||
}
|
||||
|
||||
return self::createSystemProfileAndUser($request);
|
||||
}
|
||||
|
||||
private static function createSystemProfileAndUser(Request $request): string
|
||||
{
|
||||
try {
|
||||
$conn = app(PostgresProgramBridge::class);
|
||||
} catch (\Throwable $e) {
|
||||
return self::programBridgeConnectionError($e);
|
||||
}
|
||||
|
||||
$conn->setOptions([
|
||||
'persistent' => false,
|
||||
'stateless' => true,
|
||||
'debug' => true,
|
||||
'debugLogFile' => '/www/sentm3test/htdocs/M3/storage/logs/toolkit_debug.log',
|
||||
]);
|
||||
$params = [
|
||||
$conn->AddParameterChar('in', 10, 'User profile', 'E#iUsrPrf', $request->R428US),
|
||||
$conn->AddParameterChar('in', 20, 'First name', 'FIRST', $request->R428FIRST),
|
||||
$conn->AddParameterChar('in', 30, 'Family name', 'FAMILY', $request->R428FAMILY),
|
||||
];
|
||||
|
||||
if (! $conn->PgmCall('ICMUSRPRF', 'EWOBJ', $params, [], [])) {
|
||||
return 'error profile2';
|
||||
}
|
||||
|
||||
self::insertUser($request, true);
|
||||
return 'success2';
|
||||
}
|
||||
|
||||
private static function insertUser(Request $request, bool $includeR42821A): void
|
||||
{
|
||||
$values = [
|
||||
'R428CO' => $request->R428CO,
|
||||
'R428PL' => $request->R428PL,
|
||||
'R428WH' => $request->R428WH,
|
||||
'R428STS' => $request->R428STS,
|
||||
'R428US' => $request->R428US,
|
||||
'R428FIRST' => $request->R428FIRST,
|
||||
'R428FAMILY' => $request->R428FAMILY,
|
||||
'R428EMAIL' => $request->R428EMAIL,
|
||||
'R428EMPCDE' => $request->R428EMPCDE,
|
||||
'R428ADMUSR' => $request->R428ADMUSR,
|
||||
'R428PWRUSR' => $request->R428PWRUSR,
|
||||
'MENU2OPT' => 'NN' . $request->MENU2OPT3 . 'NNN' . $request->MENU2OPT7 . $request->MENU2OPT8 . 'N',
|
||||
'MENU3OPT' => $request->MENU3OPT1 . $request->MENU3OPT2 . 'NNNNNNN',
|
||||
'MENU4OPT' => $request->MENU4OPT1 . $request->MENU4OPT2 . $request->MENU4OPT3 . 'NNNNNN',
|
||||
'MENU5OPT' => $request->MENU5OPT1 . $request->MENU5OPT2 . $request->MENU5OPT3 . 'N' . $request->MENU5OPT5 . 'NNNN',
|
||||
'MENU6OPT' => $request->MENU6OPT1 . $request->MENU6OPT2 . $request->MENU6OPT3,
|
||||
'R42811A' => $request->R42811A,
|
||||
];
|
||||
if ($includeR42821A) {
|
||||
$values['R42821A'] = $request->R42821A;
|
||||
}
|
||||
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')->insert($values);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -176,19 +170,7 @@ class UserControlController extends Controller
|
||||
} catch (\Throwable $e) {
|
||||
// Determine reason for failure.
|
||||
// Probably database authentication error or invalid or unreachable database.
|
||||
$code = $e->getCode();
|
||||
$msg = $e->getMessage();
|
||||
|
||||
switch ($code) {
|
||||
case 8001:
|
||||
// "Authorization failure on distributed database connection attempt"
|
||||
// Usually means a wrong DB2 user or password
|
||||
break;
|
||||
case 42705:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return self::programBridgeConnectionError($e);
|
||||
}
|
||||
|
||||
// Add LIB
|
||||
@@ -213,7 +195,7 @@ class UserControlController extends Controller
|
||||
$result = $conn->PgmCall('ICMCHGPRF', 'EWOBJ', $params, [], []);
|
||||
|
||||
if (! $result) {
|
||||
echo "<script>alert($pGMERRORS);</script>";
|
||||
echo "<script>alert(" . json_encode($conn->getErrorMsg()) . ");</script>";
|
||||
|
||||
return 'error';
|
||||
}
|
||||
@@ -250,26 +232,14 @@ class UserControlController extends Controller
|
||||
try {
|
||||
$conn = app(PostgresProgramBridge::class);
|
||||
} catch (\Throwable $e) {
|
||||
$code = $e->getCode();
|
||||
$msg = $e->getMessage();
|
||||
|
||||
switch ($code) {
|
||||
case 8001:
|
||||
// "Authorization failure on distributed database connection attempt"
|
||||
// Usually means a wrong DB2 user or password
|
||||
break;
|
||||
case 42705:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return self::programBridgeConnectionError($e);
|
||||
}
|
||||
|
||||
$result = $conn->CLCommand('QSYS/CHGUSRPRF USRPRF(' . $request->R428US_PWD . ') PASSWORD(' . $request->NEW_PASSWORD . ') STATUS(*ENABLED) PWDEXP(*NO)');
|
||||
|
||||
if (! $result) {
|
||||
dump($pGMERRORS);
|
||||
echo "<script>alert($pGMERRORS);</script>";
|
||||
dump($conn->getErrorMsg());
|
||||
echo "<script>alert(" . json_encode($conn->getErrorMsg()) . ");</script>";
|
||||
|
||||
return 'error pwd';
|
||||
}
|
||||
|
||||
@@ -11,287 +11,210 @@ class UserPickingStats4 extends Controller
|
||||
{
|
||||
public static function index(Request $request)
|
||||
{
|
||||
$context = self::buildContext($request);
|
||||
self::loadPickingData($context);
|
||||
self::calculatePerformance($context);
|
||||
|
||||
// $start = microtime(true);
|
||||
// dd($request);
|
||||
// Filter by date
|
||||
if (isset($request->dates)) {
|
||||
$date = $request->dates;
|
||||
$starting = $date;
|
||||
} else {
|
||||
$starting = date('Y-m-d', strtotime('-1 days'));
|
||||
}
|
||||
return $request->format === 'json'
|
||||
? self::jsonResponse($context)
|
||||
: self::pageResponse($request, $context);
|
||||
}
|
||||
|
||||
// #$min_work_hours_for_break = 4;
|
||||
|
||||
// #$ignore_picks_that_last_longer_than_this_many_hours = 8;
|
||||
$ignore_picks_that_last_longer_than_this_many_hours = implode(',', Config::get('arrays.ignore_picks_that_last_longer_than_this_many_hours'));
|
||||
|
||||
// $user_array = Config::get('arrays.user_array');
|
||||
// 618
|
||||
// Get Logged User CO & WH
|
||||
// Get Users from ICM428M
|
||||
$co = '';
|
||||
$whs = '';
|
||||
$iCM428M = [];
|
||||
private static function buildContext(Request $request): array
|
||||
{
|
||||
$starting = isset($request->dates) ? (string) $request->dates : date('Y-m-d', strtotime('-1 days'));
|
||||
$schema = Schema::connection(config('m3.connection', 'pgsql'));
|
||||
if ($schema->hasTable('icm428m')) {
|
||||
$profile = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH')
|
||||
->where('R428US', '=', strtoupper(m3_user()))
|
||||
->first();
|
||||
$co = $profile->R428CO ?? '';
|
||||
$whs = $profile->R428WH ?? '';
|
||||
|
||||
$iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->selectRaw("R428US as userprf, (trim(R428FIRST) || ' ' || trim(R428FAMILY)) as name, R428EMPCDE as empno")
|
||||
->where('R428STS', 'A')->where('R428EMPCDE', '!=', 0)
|
||||
->where('R428CO', $co)->where('R428WH', $whs)->get()->all();
|
||||
$users = self::users($schema);
|
||||
$user = isset($request->user) ? (string) $request->user : '';
|
||||
$empno = 0;
|
||||
foreach ($users as $candidate) {
|
||||
if ($candidate['userprf'] === $user) {
|
||||
$empno = $candidate['empno'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$user_array = [];
|
||||
// while($row = odbc_fetch_object($result)) {
|
||||
$x = 0;
|
||||
foreach ($iCM428M as $key => $row) {
|
||||
$user_array[$x]['userprf'] = trim($row->USERPRF);
|
||||
$user_array[$x]['name'] = trim($row->NAME);
|
||||
$user_array[$x]['empno'] = $row->EMPNO;
|
||||
$x++;
|
||||
}
|
||||
array_multisort(array_column($user_array, 'name'), SORT_ASC, $user_array);
|
||||
return [
|
||||
'starting' => $starting,
|
||||
'schema' => $schema,
|
||||
'users' => $users,
|
||||
'user' => $user,
|
||||
'empno' => $empno,
|
||||
'targets' => Config::get('arrays_custom.lph_per_code_array', []),
|
||||
'statistics' => [],
|
||||
'lbpfRows' => [],
|
||||
'lbpf' => 0,
|
||||
'monitor' => [],
|
||||
'totals' => ['value' => 0, 'weight' => 0, 'timediff' => 0, 'picked' => 0, 'entries' => 0],
|
||||
'performance' => [],
|
||||
];
|
||||
}
|
||||
|
||||
// fill array of Lines per Hour per Monitor
|
||||
$lph_per_monitor_array = Config::get('arrays_custom.lph_per_code_array');
|
||||
if (isset($request->user)) {
|
||||
$user = $request->user;
|
||||
$empno = 0;
|
||||
foreach ($user_array as $key => $val) {
|
||||
if ($user_array[$key]['userprf'] == $user) {
|
||||
$empno = $user_array[$key]['empno'];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$empno = 0;
|
||||
$user = '';
|
||||
private static function users($schema): array
|
||||
{
|
||||
if (! $schema->hasTable('icm428m')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// get data from LBPF for user and day
|
||||
$payrollCodes = '';
|
||||
ksort($lph_per_monitor_array);
|
||||
foreach ($lph_per_monitor_array as $key => $val) {
|
||||
$payrollCodes .= $key . ',';
|
||||
$connection = DB::connection(config('m3.connection', 'pgsql'));
|
||||
$profile = $connection->table('icm428m')->select('R428CO', 'R428WH')
|
||||
->where('R428US', strtoupper(m3User()))->first();
|
||||
$rows = $connection->table('icm428m')
|
||||
->selectRaw("R428US as userprf, (trim(R428FIRST) || ' ' || trim(R428FAMILY)) as name, R428EMPCDE as empno")
|
||||
->where('R428STS', 'A')->where('R428EMPCDE', '!=', 0)
|
||||
->where('R428CO', $profile->R428CO ?? '')->where('R428WH', $profile->R428WH ?? '')->get();
|
||||
|
||||
$users = [];
|
||||
foreach ($rows as $row) {
|
||||
$users[] = ['userprf' => trim($row->USERPRF), 'name' => trim($row->NAME), 'empno' => $row->EMPNO];
|
||||
}
|
||||
$payrollCodes = substr($payrollCodes, 0, -1);
|
||||
usort($users, static fn (array $a, array $b): int => $a['name'] <=> $b['name']);
|
||||
|
||||
$yr = substr($starting, 0, 4) - 2000;
|
||||
$mth = substr($starting, 5, 2);
|
||||
$day = substr($starting, 8, 2);
|
||||
$sqlstmt = "select oppno, sum(cast (hrs as integer)+ (hrs-cast (hrs as integer))/0.6) as hrs from LBPF
|
||||
where empno=$empno and lbyr=$yr and lbmo=$mth and lbdy=$day
|
||||
and oppno in ($payrollCodes)
|
||||
group by oppno";
|
||||
return $users;
|
||||
}
|
||||
|
||||
$lbpf1 = $schema->hasTable('lbpf')
|
||||
? DB::connection(config('m3.connection', 'pgsql'))->select($sqlstmt)
|
||||
: [];
|
||||
|
||||
$lbpf = 0;
|
||||
foreach ($lbpf1 as $key => $val) {
|
||||
$lbpf += $val->HRS;
|
||||
private static function loadPickingData(array &$context): void
|
||||
{
|
||||
$targets = $context['targets'];
|
||||
ksort($targets);
|
||||
$codes = implode(',', array_keys($targets));
|
||||
$date = $context['starting'];
|
||||
$sql = sprintf(
|
||||
'select oppno, sum(cast (hrs as integer)+ (hrs-cast (hrs as integer))/0.6) as hrs from LBPF where empno=%d and lbyr=%d and lbmo=%d and lbdy=%d and oppno in (%s) group by oppno',
|
||||
(int) $context['empno'], (int) substr($date, 0, 4) - 2000, (int) substr($date, 5, 2), (int) substr($date, 8, 2), $codes
|
||||
);
|
||||
$context['lbpfRows'] = $context['schema']->hasTable('lbpf')
|
||||
? DB::connection(config('m3.connection', 'pgsql'))->select($sql) : [];
|
||||
foreach ($context['lbpfRows'] as $row) {
|
||||
$context['lbpf'] += $row->HRS;
|
||||
}
|
||||
|
||||
$sql = "select * from perfstat where dt='$starting' and a5pickcomu='$user' ";
|
||||
if ((isset(request()->dates) || isset(request()->user)) && $context['schema']->hasTable('perfstat')) {
|
||||
$context['statistics'] = DB::connection(config('m3.connection', 'pgsql'))->table('perfstat')
|
||||
->where('dt', $date)->where('a5pickcomu', $context['user'])->get()->all();
|
||||
}
|
||||
}
|
||||
|
||||
if ((isset($request->dates) || isset($request->user)) && $schema->hasTable('perfstat')) {
|
||||
$statistic4 = DB::connection(config('m3.connection', 'pgsql'))->select($sql);
|
||||
} else {
|
||||
$statistic4 = [];
|
||||
private static function calculatePerformance(array &$context): void
|
||||
{
|
||||
self::initializeMonitors($context);
|
||||
if ($context['statistics'] === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
// initialize arrays
|
||||
$monitor_array = $totals_array = $perf_array = [];
|
||||
$totals_array['value'] = 0;
|
||||
$totals_array['weight'] = 0;
|
||||
$totals_array['timediff'] = 0;
|
||||
$totals_array['picked'] = 0;
|
||||
$totals_array['entries'] = 0;
|
||||
$diff = 0;
|
||||
|
||||
foreach ($lbpf1 as $key => $val) {
|
||||
$monitor_array[$val->OPPNO]['tot_hours'] = $val->HRS;
|
||||
// Initialize these variables in case not existant in statistic4
|
||||
$monitor_array[$val->OPPNO]['header'] = 'Mon' . $val->OPPNO;
|
||||
$monitor_array[$val->OPPNO]['timediff'] = 0;
|
||||
$monitor_array[$val->OPPNO]['percent_per_monitor'] = 0;
|
||||
$monitor_array[$val->OPPNO]['percent_per_activity'] = 0;
|
||||
$monitor_array[$val->OPPNO]['lph_blended_per_activity'] = 0;
|
||||
$monitor_array[$val->OPPNO]['picked'] = 0;
|
||||
$monitor_array[$val->OPPNO]['weight'] = 0;
|
||||
$monitor_array[$val->OPPNO]['lines'] = 0;
|
||||
|
||||
self::accumulateStatistics($context);
|
||||
$hours = $context['lbpf'];
|
||||
$context['performance']['tot_hours'] = $hours;
|
||||
$context['performance']['per_hour_actual'] = $hours != 0 ? $context['totals']['entries'] / $hours : 0;
|
||||
self::calculateMonitorTargets($context);
|
||||
$target = $context['monitor'][0]['lph_blended_per_activity'] ?? 0;
|
||||
if ($target != 0) {
|
||||
$context['performance']['performance_activity'] = $context['performance']['per_hour_actual'] / $target;
|
||||
}
|
||||
if (! empty($statistic4)) {
|
||||
// echo "in !empty<br>";
|
||||
// Initialize the Monitor array
|
||||
foreach ($statistic4 as $key => $val) {
|
||||
|
||||
// Initialize these variables in case not existant in LBPF
|
||||
$monitor_array[$val->CODE]['header'] = 'Mon' . $statistic4[$key]->CODE;
|
||||
$monitor_array[$val->CODE]['timediff'] = 0;
|
||||
$monitor_array[$val->CODE]['percent_per_monitor'] = 0;
|
||||
$monitor_array[$val->CODE]['percent_per_activity'] = 0;
|
||||
$monitor_array[$val->CODE]['lph_blended_per_activity'] = 0;
|
||||
$monitor_array[$val->CODE]['picked'] = 0;
|
||||
$monitor_array[$val->CODE]['weight'] = 0;
|
||||
$monitor_array[$val->CODE]['lines'] = 0;
|
||||
}
|
||||
|
||||
// add another element (0) in monitor_array to capture the total blended lph value expected
|
||||
$monitor_array[0]['lph_blended_per_activity'] = 0;
|
||||
$monitor_array[0]['header'] = '0';
|
||||
|
||||
// cycle thru stats again, and accumulate totals at global level (totals_array) and at monitor level (monitor_array)
|
||||
foreach ($statistic4 as $key => $val) {
|
||||
|
||||
$statistic4[$key]->WEIGHT = round($statistic4[$key]->WEIGHT);
|
||||
$statistic4[$key]->A5VALUE = round($statistic4[$key]->A5VALUE);
|
||||
$statistic4[$key]->A5PICKED = round($statistic4[$key]->A5PICKED);
|
||||
|
||||
$statistic4[$key]->A5PICKCMTS = date('Y-m-d H:i', strtotime($statistic4[$key]->A5PICKCMTS));
|
||||
|
||||
// Calculate difference from previous time entry in seconds and save in TIMEDIFF key of STATISTIC4 array
|
||||
// $time_now=strtotime($statistic4[$key]->A5PICKCMTSADJ);
|
||||
$time_now = strtotime($statistic4[$key]->A5CMTSADJ);
|
||||
if ($key > 0) {
|
||||
$diff = round(abs($time_now - $time_prev));
|
||||
if ($diff > $ignore_picks_that_last_longer_than_this_many_hours * 60 * 60) {
|
||||
$diff = -1;
|
||||
}
|
||||
}
|
||||
|
||||
$statistic4[$key]->TIMEDIFF = $diff;
|
||||
|
||||
if ($diff / 60 < 5) {
|
||||
$statistic4[$key]->COLOUR = '';
|
||||
}
|
||||
if ($diff / 60 >= 5 && $diff / 60 <= 10) {
|
||||
$statistic4[$key]->COLOUR = 'yellow';
|
||||
}
|
||||
if ($diff / 60 > 10 && $diff / 60 <= 15) {
|
||||
$statistic4[$key]->COLOUR = '#88ace0';
|
||||
}
|
||||
if ($diff / 60 > 15) {
|
||||
$statistic4[$key]->COLOUR = 'red';
|
||||
}
|
||||
|
||||
// save the time for previous entry
|
||||
// $time_prev=strtotime($statistic4[$key]->A5PICKCMTSADJ);
|
||||
$time_prev = strtotime($statistic4[$key]->A5CMTSADJ);
|
||||
|
||||
// accumulate totals at monitor level
|
||||
$monitor_array[$val->CODE]['timediff'] += $diff;
|
||||
$monitor_array[$val->CODE]['picked'] += $statistic4[$key]->A5PICKED;
|
||||
$monitor_array[$val->CODE]['weight'] += $statistic4[$key]->WEIGHT;
|
||||
$monitor_array[$val->CODE]['lines']++;
|
||||
|
||||
// calculate totals at global level
|
||||
$totals_array['entries'] = count($statistic4);
|
||||
$totals_array['weight'] += $statistic4[$key]->WEIGHT;
|
||||
$totals_array['value'] += $statistic4[$key]->A5VALUE;
|
||||
$totals_array['timediff'] += $diff;
|
||||
$totals_array['picked'] += $statistic4[$key]->A5PICKED;
|
||||
|
||||
}
|
||||
// echo "after 2<pre>"; print_r($statistic4);
|
||||
// build array for Performance with Greg's time entry (at one point we had a [0] array as well)
|
||||
|
||||
if (! is_null($lbpf)) {
|
||||
|
||||
$perf_array['tot_hours'] = (isset($lbpf) ? $lbpf : 0);
|
||||
|
||||
if ($perf_array['tot_hours'] != 0) {
|
||||
$perf_array['per_hour_actual'] = $totals_array['entries'] / $perf_array['tot_hours'];
|
||||
} else {
|
||||
$perf_array['per_hour_actual'] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// cycle through monitors array and compute percentage to allocate to each monitor (code)
|
||||
ksort($monitor_array);
|
||||
foreach ($monitor_array as $key => $val) {
|
||||
if ($key != '0') {
|
||||
if (! isset($monitor_array[$key]['tot_hours'])) {
|
||||
$monitor_array[$key]['tot_hours'] = 0;
|
||||
}
|
||||
|
||||
if ($totals_array['timediff'] != 0) {
|
||||
$monitor_array[$key]['percent_per_monitor'] = $monitor_array[$key]['timediff'] / $totals_array['timediff'];
|
||||
}
|
||||
|
||||
if ($lbpf != 0) {
|
||||
$monitor_array[$key]['percent_per_activity'] = $monitor_array[$key]['tot_hours'] / $lbpf;
|
||||
}
|
||||
$monitor_array[$key]['lph_blended_per_activity'] = $monitor_array[$key]['percent_per_activity'] * (isset($lph_per_monitor_array[$key]) ? $lph_per_monitor_array[$key] : 0);
|
||||
$monitor_array[0]['lph_blended_per_activity'] += $monitor_array[$key]['lph_blended_per_activity'];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ($monitor_array[0]['lph_blended_per_activity'] != 0) {
|
||||
$perf_array['performance_activity'] = $perf_array['per_hour_actual'] / $monitor_array[0]['lph_blended_per_activity'];
|
||||
}
|
||||
}
|
||||
|
||||
private static function initializeMonitors(array &$context): void
|
||||
{
|
||||
foreach ($context['lbpfRows'] as $row) {
|
||||
$context['monitor'][$row->OPPNO] = self::monitorDefaults('Mon' . $row->OPPNO, $row->HRS);
|
||||
}
|
||||
|
||||
// return encoded json if input field named format is json
|
||||
if ($request->format == 'json') {
|
||||
|
||||
if (! array_key_exists('performance_activity', $perf_array)) {
|
||||
$performance = 0;
|
||||
} else {
|
||||
$performance = number_format($perf_array['performance_activity'] * 100, 0);
|
||||
}
|
||||
if (! array_key_exists('0', $monitor_array)) {
|
||||
$blendedTargetLPH = 0;
|
||||
} else {
|
||||
$blendedTargetLPH = number_format($monitor_array[0]['lph_blended_per_activity'], 1);
|
||||
}
|
||||
if (! array_key_exists('per_hour_actual', $perf_array)) {
|
||||
$actualLPH = 0;
|
||||
} else {
|
||||
$actualLPH = number_format($perf_array['per_hour_actual'], 1);
|
||||
}
|
||||
if (! array_key_exists('tot_hours', $perf_array)) {
|
||||
$grossHours = 0;
|
||||
} else {
|
||||
$grossHours = $perf_array['tot_hours'];
|
||||
}
|
||||
|
||||
$json_data = [
|
||||
'day' => $starting,
|
||||
'performance' => $performance,
|
||||
'blendedTargetLPH' => $blendedTargetLPH,
|
||||
'actualLPH' => $actualLPH,
|
||||
'grossHours' => $grossHours,
|
||||
];
|
||||
|
||||
return json_encode($json_data);
|
||||
|
||||
} else {
|
||||
// display webpage of statistic version 4
|
||||
$request->ports = Config::get('arrays.env_ports');
|
||||
$no_data = 'N';
|
||||
if (empty($statistic4) && $_SERVER['REQUEST_URI'] != '/UserPickingStats4') {
|
||||
$no_data = 'Y';
|
||||
}
|
||||
|
||||
return view(
|
||||
'm3::liberty-theme.pages.UserPickingStats4',
|
||||
compact('statistic4', 'starting', 'user', 'user_array', 'monitor_array', 'totals_array', 'perf_array', 'request', 'no_data'),
|
||||
foreach ($context['statistics'] as $row) {
|
||||
$context['monitor'][$row->CODE] = array_replace(
|
||||
self::monitorDefaults('Mon' . $row->CODE, 0),
|
||||
$context['monitor'][$row->CODE] ?? []
|
||||
);
|
||||
|
||||
}
|
||||
if ($context['statistics'] !== []) {
|
||||
$context['monitor'][0] = self::monitorDefaults('0', 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static function monitorDefaults(string $header, float|int $hours): array
|
||||
{
|
||||
return ['tot_hours' => $hours, 'header' => $header, 'timediff' => 0, 'percent_per_monitor' => 0,
|
||||
'percent_per_activity' => 0, 'lph_blended_per_activity' => 0, 'picked' => 0, 'weight' => 0, 'lines' => 0];
|
||||
}
|
||||
|
||||
private static function accumulateStatistics(array &$context): void
|
||||
{
|
||||
$previous = null;
|
||||
$limit = (float) Config::get('arrays.ignore_picks_that_last_longer_than_this_many_hours', 8);
|
||||
foreach ($context['statistics'] as $row) {
|
||||
$row->WEIGHT = round($row->WEIGHT);
|
||||
$row->A5VALUE = round($row->A5VALUE);
|
||||
$row->A5PICKED = round($row->A5PICKED);
|
||||
$row->A5PICKCMTS = date('Y-m-d H:i', strtotime($row->A5PICKCMTS));
|
||||
$now = strtotime($row->A5CMTSADJ);
|
||||
$diff = $previous === null ? 0 : round(abs($now - $previous));
|
||||
$diff = $diff > $limit * 3600 ? -1 : $diff;
|
||||
$row->TIMEDIFF = $diff;
|
||||
$row->COLOUR = self::durationColour($diff);
|
||||
$previous = $now;
|
||||
self::addRowTotals($context, $row, $diff);
|
||||
}
|
||||
}
|
||||
|
||||
private static function durationColour(float|int $diff): string
|
||||
{
|
||||
$minutes = $diff / 60;
|
||||
|
||||
return match (true) {
|
||||
$minutes < 5 => '',
|
||||
$minutes <= 10 => 'yellow',
|
||||
$minutes <= 15 => '#88ace0',
|
||||
default => 'red',
|
||||
};
|
||||
}
|
||||
|
||||
private static function addRowTotals(array &$context, object $row, float|int $diff): void
|
||||
{
|
||||
$monitor = &$context['monitor'][$row->CODE];
|
||||
$monitor['timediff'] += $diff;
|
||||
$monitor['picked'] += $row->A5PICKED;
|
||||
$monitor['weight'] += $row->WEIGHT;
|
||||
$monitor['lines']++;
|
||||
$context['totals']['entries']++;
|
||||
$context['totals']['weight'] += $row->WEIGHT;
|
||||
$context['totals']['value'] += $row->A5VALUE;
|
||||
$context['totals']['timediff'] += $diff;
|
||||
$context['totals']['picked'] += $row->A5PICKED;
|
||||
}
|
||||
|
||||
private static function calculateMonitorTargets(array &$context): void
|
||||
{
|
||||
ksort($context['monitor']);
|
||||
foreach ($context['monitor'] as $code => &$monitor) {
|
||||
if ((string) $code === '0') {
|
||||
continue;
|
||||
}
|
||||
$monitor['percent_per_monitor'] = $context['totals']['timediff'] != 0
|
||||
? $monitor['timediff'] / $context['totals']['timediff'] : 0;
|
||||
$monitor['percent_per_activity'] = $context['lbpf'] != 0 ? $monitor['tot_hours'] / $context['lbpf'] : 0;
|
||||
$monitor['lph_blended_per_activity'] = $monitor['percent_per_activity'] * ($context['targets'][$code] ?? 0);
|
||||
$context['monitor'][0]['lph_blended_per_activity'] += $monitor['lph_blended_per_activity'];
|
||||
}
|
||||
unset($monitor);
|
||||
}
|
||||
|
||||
private static function jsonResponse(array $context): string
|
||||
{
|
||||
return json_encode([
|
||||
'day' => $context['starting'],
|
||||
'performance' => number_format(($context['performance']['performance_activity'] ?? 0) * 100, 0),
|
||||
'blendedTargetLPH' => number_format($context['monitor'][0]['lph_blended_per_activity'] ?? 0, 1),
|
||||
'actualLPH' => number_format($context['performance']['per_hour_actual'] ?? 0, 1),
|
||||
'grossHours' => $context['performance']['tot_hours'] ?? 0,
|
||||
]);
|
||||
}
|
||||
|
||||
private static function pageResponse(Request $request, array $context)
|
||||
{
|
||||
$request->ports = Config::get('arrays.env_ports');
|
||||
$no_data = $context['statistics'] === [] && ($_SERVER['REQUEST_URI'] ?? '') !== '/UserPickingStats4' ? 'Y' : 'N';
|
||||
return view('m3::liberty-theme.pages.UserPickingStats4', [
|
||||
'statistic4' => $context['statistics'], 'starting' => $context['starting'], 'user' => $context['user'],
|
||||
'user_array' => $context['users'], 'monitor_array' => $context['monitor'], 'totals_array' => $context['totals'],
|
||||
'perf_array' => $context['performance'], 'request' => $request, 'no_data' => $no_data,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ class UserPickingStats5 extends Controller
|
||||
|
||||
$profile = DB::connection($connection)->table('icm428m')
|
||||
->select('R428CO', 'R428WH')
|
||||
->where('R428US', strtoupper((string) m3_user()))
|
||||
->where('R428US', strtoupper((string) m3User()))
|
||||
->first();
|
||||
$co = trim((string) ($profile->R428CO ?? ''));
|
||||
$whs = trim((string) ($profile->R428WH ?? ''));
|
||||
@@ -128,7 +128,11 @@ class UserPickingStats5 extends Controller
|
||||
try {
|
||||
$response = Http::withBasicAuth((string) $request->header('php-auth-user'), (string) $request->header('php-auth-pw'))
|
||||
->get($url, ['dates' => $date, 'user' => $request->user, 'format' => 'json']);
|
||||
$data = $response->successful() ? (json_decode($response->body(), true) ?: []) : [];
|
||||
$data = [];
|
||||
if ($response->successful()) {
|
||||
$decoded = json_decode($response->body(), true);
|
||||
$data = is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('M3 picking statistics unavailable', ['date' => $date, 'exception' => $e->getMessage()]);
|
||||
$data = [];
|
||||
|
||||
@@ -12,7 +12,7 @@ class UserProfileController extends Controller
|
||||
{
|
||||
|
||||
// Get Current USER
|
||||
$loggedUser = strtoupper(m3_user());
|
||||
$loggedUser = strtoupper(m3User());
|
||||
|
||||
$iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL', 'R428FIRST', 'R428FAMILY')
|
||||
|
||||
@@ -29,19 +29,9 @@ class UtilitiesController extends Controller
|
||||
} catch (\Throwable $e) {
|
||||
// Determine reason for failure.
|
||||
// Probably database authentication error or invalid or unreachable database.
|
||||
$code = $e->getCode();
|
||||
$msg = $e->getMessage();
|
||||
Log::error('Unable to connect to the program bridge.', ['exception' => $e]);
|
||||
|
||||
switch ($code) {
|
||||
case 8001:
|
||||
// "Authorization failure on distributed database connection attempt"
|
||||
// Usually means a wrong DB2 user or password
|
||||
break;
|
||||
case 42705:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return response()->json(['error' => 'Program bridge connection failed.'], 503);
|
||||
}
|
||||
$conn->setOptions(['persistent' => false, 'stateless' => true, 'debug' => true, 'debugLogFile' => '/www/sentustesx/htdocs/storage/logs/toolkit_debug.log']);
|
||||
|
||||
@@ -68,16 +58,10 @@ class UtilitiesController extends Controller
|
||||
// ICM700C EWOBJTST ICM700C ICM700CSBM
|
||||
$result = $conn->PgmCall('ICM700CSBM', 'EWOBJTST', $params, [], []);
|
||||
|
||||
if (! $result) {
|
||||
}
|
||||
// Successful Call
|
||||
else {
|
||||
if ($result) {
|
||||
dump($result);
|
||||
}
|
||||
|
||||
if ($pGMERRORS != '') {
|
||||
dump($pGMERRORS);
|
||||
}
|
||||
// Get Execution Time
|
||||
$time = microtime(true) - $start;
|
||||
dump($time);
|
||||
@@ -171,228 +155,250 @@ class UtilitiesController extends Controller
|
||||
|
||||
try {
|
||||
Log::channel('LabelCron')->info('>>> Run GS1 Label creation Command...');
|
||||
|
||||
// Get the Calling User
|
||||
// $userId = 'TWOSHIP';
|
||||
// $sHUSER = isset($userId) ? $userId : (m3_user() !== '' ? Str::upper(trim(m3_user())) : '');
|
||||
|
||||
// Get Manifest Array
|
||||
$gSArray = $request->query();
|
||||
$sHUSER = trim((string) ($gSArray['User'] ?? ''));
|
||||
$gS1FileNameNoRoot = '';
|
||||
|
||||
$sHUSER = isset($gSArray['User']) ? trim($gSArray['User']) : '';
|
||||
|
||||
if ($sHUSER != '') {
|
||||
// Get User CO & WH from Table ICM428M
|
||||
$iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')
|
||||
->where('R428US', '=', $sHUSER)
|
||||
->first();
|
||||
|
||||
$cOMPANY = isset($iCM428M->R428CO) ? $iCM428M->R428CO : ''; // Company
|
||||
$pLANT = isset($iCM428M->R428PL) ? $iCM428M->R428PL : ''; // Plant
|
||||
$wHS = isset($iCM428M->R428WH) ? $iCM428M->R428WH : ''; // WareHouse
|
||||
|
||||
$macpkr = $gSArray['Macpkr'];
|
||||
$packageType = trim($gSArray['packageType']); // 1 => Pallet , 0 => Carton
|
||||
$packageTypeDesc = $packageType == 1 ? 'Pallet' : 'Carton';
|
||||
$manufactID = '0826528'; // MAK : get ID from Nvent and save to Config File
|
||||
$total_length = 9;
|
||||
|
||||
$html = '
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.border_btm {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
.border_rght {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
|
||||
.margin_t {
|
||||
padding-top : 10px;
|
||||
}
|
||||
|
||||
.align_lft {
|
||||
text-align: left;
|
||||
}
|
||||
.align_center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@page { margin: 5px; }
|
||||
body { margin: 0px; }
|
||||
</style>
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif;">';
|
||||
|
||||
// Get number of Pallets
|
||||
$packageCount = count($gSArray['PackagesArray']);
|
||||
$packageNum = 1;
|
||||
|
||||
// Get GS1 Label MAX ID from ICM695M3 :
|
||||
$gS1SEQUENCESel = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m3')->max('ID');
|
||||
$gS1SEQUENCE = isset($gS1SEQUENCESel) ? $gS1SEQUENCESel : 0;
|
||||
|
||||
// Loop PackagesArray : Build Table for PDF and Insert to ICM695m3
|
||||
foreach ($gSArray['PackagesArray'] as $value) {
|
||||
$table_style = $packageNum < $packageCount ? ' style="page-break-after: always;" ' : '';
|
||||
|
||||
$a2INTBOX = trim($value);
|
||||
|
||||
$gS1SEQUENCE++;
|
||||
$gS1SEQUENCEID = str_pad($gS1SEQUENCE, $total_length, '0', STR_PAD_LEFT);
|
||||
// Build GS1 18 Digits Code
|
||||
$gs1_128_bc_1 = '00' . $packageType . $manufactID . $gS1SEQUENCEID;
|
||||
|
||||
// Calculate Check Digit
|
||||
$digits = str_split($gs1_128_bc_1);
|
||||
$sum = 0;
|
||||
$length = count($digits);
|
||||
|
||||
// Loop through each digit starting from the right
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$digit = $digits[$length - $i - 1];
|
||||
// Assign a weight of 3 or 1 alternately
|
||||
$weight = ($i % 2 == 0) ? 3 : 1;
|
||||
// Add the product of the digit and its weight to the sum
|
||||
$sum += $digit * $weight;
|
||||
}
|
||||
// Calculate the remainder when sum is divided by 10
|
||||
$remainder = $sum % 10;
|
||||
// If remainder is 0, check digit is 0; otherwise, subtract remainder from 10
|
||||
$checkDigit = ($remainder == 0) ? 0 : 10 - $remainder;
|
||||
// End Check Digit Calculation
|
||||
|
||||
// SSCC 18 Digits Code
|
||||
$gs1_128_bc = $gs1_128_bc_1 . $checkDigit;
|
||||
|
||||
$gs1_128_bc_desc = '(00)' . $packageType . $manufactID . $gS1SEQUENCEID . $checkDigit;
|
||||
|
||||
$data = [
|
||||
'ship_to' => $gSArray['Recipient_CompanyName'] . '<br>' . $gSArray['Recipient_Address1'] . '<br>' .
|
||||
$gSArray['Recipient_City'] . ',' . $gSArray['Recipient_State']
|
||||
. '<br>' . $gSArray['Recipient_PostalCode'],
|
||||
'from' => $gSArray['Sender_CompanyName'] . '<br>' . $gSArray['Sender_Address1'] . '<br>' .
|
||||
$gSArray['Sender_City'] . ',' . $gSArray['Sender_State']
|
||||
. '<br>' . $gSArray['Sender_PostalCode'],
|
||||
'ship_to_lbl' => '420' . $gSArray['Recipient_PostalCode'],
|
||||
'ship_to_desc' => '(420)' . $gSArray['Recipient_PostalCode'],
|
||||
'pro' => '190071217845706', // MAK : Check missing info with Brad
|
||||
'item_number' => '10000B',
|
||||
'upc' => '098506095310',
|
||||
'quantity' => '1',
|
||||
'serial_shipping_container' => $gs1_128_bc_desc,
|
||||
];
|
||||
|
||||
// Initialize barcode generator
|
||||
$generator = new BarcodeGeneratorPNG;
|
||||
|
||||
// Generate barcodes
|
||||
$shipToPostalCodeBarcode = $generator->getBarcode($data['ship_to_lbl'], $generator::TYPE_CODE_128);
|
||||
$serialShippingContainerBarcode = $generator->getBarcode($data['serial_shipping_container'], $generator::TYPE_CODE_128, 2, 50);
|
||||
|
||||
// HTML content for the label
|
||||
$html .= '
|
||||
<table ' . $table_style . '>
|
||||
<tr>
|
||||
<td colspan="2" class="border_btm border_rght align_lft">
|
||||
FROM:<br>' . $data['from'] . '
|
||||
</td>
|
||||
<td colspan="2" class="border_btm align_lft">
|
||||
SHIP TO:<br>' . $data['ship_to'] . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" class="border_btm border_rght margin_t align_center">
|
||||
<img src="data:image/png;base64,' . base64_encode($shipToPostalCodeBarcode) . '"> <br>
|
||||
' . $data['ship_to_desc'] . '
|
||||
</td>
|
||||
<td class="border_btm margin_t align_lft">
|
||||
Carrier: ' . $gSArray['CarrierName'] . ' <br>
|
||||
PRO #: ' . $gSArray['trackingno'] . ' <br>
|
||||
B/L #: ' . $gSArray['BOLnumber'] . ' <br>
|
||||
Ref : ' . $a2INTBOX . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4" class="border_btm margin_t align_lft">
|
||||
PURCHASE ORDER: ' . $gSArray['ShipmentPONumber'] . ' <br>
|
||||
Vendor: ' . $manufactID . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4" class="border_btm margin_t align_center">
|
||||
' . $packageTypeDesc . ' # : ' . $packageNum . ' of ' . $packageCount . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4" style="text-align: center;" class="margin_t">
|
||||
<img src="data:image/png;base64,' . base64_encode($serialShippingContainerBarcode) . '"><br>
|
||||
' . $data['serial_shipping_container'] . '
|
||||
</td>
|
||||
</tr>
|
||||
</table>';
|
||||
|
||||
$packageNum++;
|
||||
|
||||
// Insert new Record to ICM695M3 $gs1_128_bc
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('icm695m3')
|
||||
->insert(['A2CO' => $cOMPANY, 'A2WHS' => $wHS, 'A2PLANT' => $pLANT, 'A2MACPKR' => $macpkr, 'A2GS1LABEL' => $gs1_128_bc, 'A2INTBOX' => $a2INTBOX]);
|
||||
|
||||
Log::channel('LabelCron')->info('<<< GS1-128...End of Label Creation for Mackpkr: ' . $macpkr);
|
||||
}
|
||||
|
||||
$html .= '</body> </html>';
|
||||
|
||||
ob_start();
|
||||
|
||||
// Initialize Dompdf
|
||||
$dompdf = new Dompdf;
|
||||
$dompdf->loadHtml($html);
|
||||
$dompdf->setPaper('a6', 'portrait');
|
||||
// Render the HTML as PDF
|
||||
$dompdf->render();
|
||||
|
||||
// Output the generated PDF to Browser
|
||||
// $dompdf->stream();
|
||||
|
||||
$pdfContent = $dompdf->output();
|
||||
|
||||
$labelsPath = Config::get('arrays.PdfPath'); // '/www/sentm3live/htdocs/labels/';
|
||||
// Put the PDF in labels/CarrierLabel
|
||||
$gSFolder = 'GSLabel';
|
||||
|
||||
$carrierFileName = $gSFolder . '_' . $macpkr . '_' . $cOMPANY . '_' . $wHS . '_' . $a2INTBOX;
|
||||
// LTL
|
||||
// if ($packageType=='1') {
|
||||
// $carrierFileName = $gSFolder.'_'.$macpkr.'_'.$cOMPANY.'_'.$wHS;
|
||||
// }
|
||||
// # small Packs
|
||||
// else{
|
||||
// $carrierFileName = $gSFolder.'_'.$macpkr.'_'.$cOMPANY.'_'.$wHS.'_'.$a2INTBOX;
|
||||
// }
|
||||
|
||||
$gS1FileName = $labelsPath . $gSFolder . '/' . $carrierFileName . '.pdf';
|
||||
$gS1FileNameNoRoot = $gSFolder . '/' . $carrierFileName;
|
||||
file_put_contents($gS1FileName, $pdfContent);
|
||||
ob_end_clean();
|
||||
if ($sHUSER !== '') {
|
||||
$gS1FileNameNoRoot = self::generateGS128ForUser($gSArray, $sHUSER);
|
||||
}
|
||||
|
||||
// # Insert new Record to ICM695M3 $gs1_128_bc
|
||||
// DB::connection(config('m3.connection', 'pgsql'))->table('icm695m3')
|
||||
// ->insert(['A2CO'=> $cOMPANY,'A2WHS'=> $wHS,'A2MACPKR'=> $macpkr,'A2GS1LABEL'=> $gs1_128_bc]);
|
||||
|
||||
return json_encode(['result' => 'success', 'GS1File' => $gS1FileNameNoRoot]);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
Log::channel('LabelCron')->error($th);
|
||||
|
||||
return json_encode(['result' => 'error', 'GS1File' => $th]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static function generateGS128ForUser(array $gSArray, string $sHUSER): string
|
||||
{
|
||||
// Get User CO & WH from Table ICM428M
|
||||
$iCM428M = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')
|
||||
->select('R428US', 'R428CO', 'R428WH', 'R428PL')
|
||||
->where('R428US', '=', $sHUSER)
|
||||
->first();
|
||||
|
||||
$cOMPANY = isset($iCM428M->R428CO) ? $iCM428M->R428CO : ''; // Company
|
||||
$pLANT = isset($iCM428M->R428PL) ? $iCM428M->R428PL : ''; // Plant
|
||||
$wHS = isset($iCM428M->R428WH) ? $iCM428M->R428WH : ''; // WareHouse
|
||||
|
||||
$macpkr = $gSArray['Macpkr'];
|
||||
$packageType = trim($gSArray['packageType']); // 1 => Pallet , 0 => Carton
|
||||
$packageTypeDesc = $packageType == 1 ? 'Pallet' : 'Carton';
|
||||
$manufactID = '0826528'; // MAK : get ID from Nvent and save to Config File
|
||||
$total_length = 9;
|
||||
|
||||
$html = '
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.border_btm {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
.border_rght {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
|
||||
.margin_t {
|
||||
padding-top : 10px;
|
||||
}
|
||||
|
||||
.align_lft {
|
||||
text-align: left;
|
||||
}
|
||||
.align_center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@page { margin: 5px; }
|
||||
body { margin: 0px; }
|
||||
</style>
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif;">';
|
||||
|
||||
// Get number of Pallets
|
||||
$packageCount = count($gSArray['PackagesArray']);
|
||||
$packageNum = 1;
|
||||
|
||||
// Get GS1 Label MAX ID from ICM695M3 :
|
||||
$gS1SEQUENCESel = DB::connection(config('m3.connection', 'pgsql'))->table('icm695m3')->max('ID');
|
||||
$gS1SEQUENCE = isset($gS1SEQUENCESel) ? $gS1SEQUENCESel : 0;
|
||||
|
||||
// Loop PackagesArray : Build Table for PDF and Insert to ICM695m3
|
||||
foreach ($gSArray['PackagesArray'] as $value) {
|
||||
$table_style = $packageNum < $packageCount ? ' style="page-break-after: always;" ' : '';
|
||||
|
||||
$a2INTBOX = trim($value);
|
||||
|
||||
$gS1SEQUENCE++;
|
||||
$gS1SEQUENCEID = str_pad($gS1SEQUENCE, $total_length, '0', STR_PAD_LEFT);
|
||||
// Build GS1 18 Digits Code
|
||||
$gs1_128_bc_1 = '00' . $packageType . $manufactID . $gS1SEQUENCEID;
|
||||
|
||||
$checkDigit = self::gs1CheckDigit($gs1_128_bc_1);
|
||||
|
||||
// SSCC 18 Digits Code
|
||||
$gs1_128_bc = $gs1_128_bc_1 . $checkDigit;
|
||||
|
||||
$gs1_128_bc_desc = '(00)' . $packageType . $manufactID . $gS1SEQUENCEID . $checkDigit;
|
||||
|
||||
$data = [
|
||||
'ship_to' => $gSArray['Recipient_CompanyName'] . '<br>' . $gSArray['Recipient_Address1'] . '<br>' .
|
||||
$gSArray['Recipient_City'] . ',' . $gSArray['Recipient_State']
|
||||
. '<br>' . $gSArray['Recipient_PostalCode'],
|
||||
'from' => $gSArray['Sender_CompanyName'] . '<br>' . $gSArray['Sender_Address1'] . '<br>' .
|
||||
$gSArray['Sender_City'] . ',' . $gSArray['Sender_State']
|
||||
. '<br>' . $gSArray['Sender_PostalCode'],
|
||||
'ship_to_lbl' => '420' . $gSArray['Recipient_PostalCode'],
|
||||
'ship_to_desc' => '(420)' . $gSArray['Recipient_PostalCode'],
|
||||
'pro' => '190071217845706', // MAK : Check missing info with Brad
|
||||
'item_number' => '10000B',
|
||||
'upc' => '098506095310',
|
||||
'quantity' => '1',
|
||||
'serial_shipping_container' => $gs1_128_bc_desc,
|
||||
];
|
||||
|
||||
// Initialize barcode generator
|
||||
$generator = new BarcodeGeneratorPNG;
|
||||
|
||||
// Generate barcodes
|
||||
$shipToPostalCodeBarcode = $generator->getBarcode($data['ship_to_lbl'], $generator::TYPE_CODE_128);
|
||||
$serialShippingContainerBarcode = $generator->getBarcode($data['serial_shipping_container'], $generator::TYPE_CODE_128, 2, 50);
|
||||
|
||||
// HTML content for the label
|
||||
$html .= self::gs128LabelHtml([
|
||||
'data' => $data,
|
||||
'gs' => $gSArray,
|
||||
'internal_box' => $a2INTBOX,
|
||||
'manufacturer_id' => $manufactID,
|
||||
'package_type' => $packageTypeDesc,
|
||||
'package_number' => $packageNum,
|
||||
'package_count' => $packageCount,
|
||||
'table_style' => $table_style,
|
||||
'postal_barcode' => $shipToPostalCodeBarcode,
|
||||
'container_barcode' => $serialShippingContainerBarcode,
|
||||
]);
|
||||
|
||||
$packageNum++;
|
||||
|
||||
// Insert new Record to ICM695M3 $gs1_128_bc
|
||||
DB::connection(config('m3.connection', 'pgsql'))->table('icm695m3')
|
||||
->insert(['A2CO' => $cOMPANY, 'A2WHS' => $wHS, 'A2PLANT' => $pLANT, 'A2MACPKR' => $macpkr, 'A2GS1LABEL' => $gs1_128_bc, 'A2INTBOX' => $a2INTBOX]);
|
||||
|
||||
Log::channel('LabelCron')->info('<<< GS1-128...End of Label Creation for Mackpkr: ' . $macpkr);
|
||||
}
|
||||
|
||||
$html .= '</body> </html>';
|
||||
|
||||
ob_start();
|
||||
|
||||
// Initialize Dompdf
|
||||
$dompdf = new Dompdf;
|
||||
$dompdf->loadHtml($html);
|
||||
$dompdf->setPaper('a6', 'portrait');
|
||||
// Render the HTML as PDF
|
||||
$dompdf->render();
|
||||
|
||||
// Output the generated PDF to Browser
|
||||
// $dompdf->stream();
|
||||
|
||||
$pdfContent = $dompdf->output();
|
||||
|
||||
$labelsPath = Config::get('arrays.PdfPath'); // '/www/sentm3live/htdocs/labels/';
|
||||
// Put the PDF in labels/CarrierLabel
|
||||
$gSFolder = 'GSLabel';
|
||||
|
||||
$carrierFileName = $gSFolder . '_' . $macpkr . '_' . $cOMPANY . '_' . $wHS . '_' . $a2INTBOX;
|
||||
// LTL
|
||||
// if ($packageType=='1') {
|
||||
// $carrierFileName = $gSFolder.'_'.$macpkr.'_'.$cOMPANY.'_'.$wHS;
|
||||
// }
|
||||
// # small Packs
|
||||
// else{
|
||||
// $carrierFileName = $gSFolder.'_'.$macpkr.'_'.$cOMPANY.'_'.$wHS.'_'.$a2INTBOX;
|
||||
// }
|
||||
|
||||
$gS1FileName = $labelsPath . $gSFolder . '/' . $carrierFileName . '.pdf';
|
||||
$gS1FileNameNoRoot = $gSFolder . '/' . $carrierFileName;
|
||||
file_put_contents($gS1FileName, $pdfContent);
|
||||
ob_end_clean();
|
||||
|
||||
return $gS1FileNameNoRoot;
|
||||
}
|
||||
|
||||
private static function gs128LabelHtml(array $context): string
|
||||
{
|
||||
$data = $context['data'];
|
||||
$gSArray = $context['gs'];
|
||||
$a2INTBOX = (string) $context['internal_box'];
|
||||
$manufactID = (string) $context['manufacturer_id'];
|
||||
$packageTypeDesc = (string) $context['package_type'];
|
||||
$packageNum = (int) $context['package_number'];
|
||||
$packageCount = (int) $context['package_count'];
|
||||
$table_style = (string) $context['table_style'];
|
||||
$shipToPostalCodeBarcode = (string) $context['postal_barcode'];
|
||||
$serialShippingContainerBarcode = (string) $context['container_barcode'];
|
||||
|
||||
return '
|
||||
<table ' . $table_style . '>
|
||||
<tr>
|
||||
<td colspan="2" class="border_btm border_rght align_lft">
|
||||
FROM:<br>' . $data['from'] . '
|
||||
</td>
|
||||
<td colspan="2" class="border_btm align_lft">
|
||||
SHIP TO:<br>' . $data['ship_to'] . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" class="border_btm border_rght margin_t align_center">
|
||||
<img src="data:image/png;base64,' . base64_encode($shipToPostalCodeBarcode) . '"> <br>
|
||||
' . $data['ship_to_desc'] . '
|
||||
</td>
|
||||
<td class="border_btm margin_t align_lft">
|
||||
Carrier: ' . $gSArray['CarrierName'] . ' <br>
|
||||
PRO #: ' . $gSArray['trackingno'] . ' <br>
|
||||
B/L #: ' . $gSArray['BOLnumber'] . ' <br>
|
||||
Ref : ' . $a2INTBOX . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4" class="border_btm margin_t align_lft">
|
||||
PURCHASE ORDER: ' . $gSArray['ShipmentPONumber'] . ' <br>
|
||||
Vendor: ' . $manufactID . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4" class="border_btm margin_t align_center">
|
||||
' . $packageTypeDesc . ' # : ' . $packageNum . ' of ' . $packageCount . '
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4" style="text-align: center;" class="margin_t">
|
||||
<img src="data:image/png;base64,' . base64_encode($serialShippingContainerBarcode) . '"><br>
|
||||
' . $data['serial_shipping_container'] . '
|
||||
</td>
|
||||
</tr>
|
||||
</table>';
|
||||
}
|
||||
|
||||
private static function gs1CheckDigit(string $value): int
|
||||
{
|
||||
$digits = str_split($value);
|
||||
$sum = 0;
|
||||
$length = count($digits);
|
||||
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$digit = (int) $digits[$length - $i - 1];
|
||||
$weight = $i % 2 === 0 ? 3 : 1;
|
||||
$sum += $digit * $weight;
|
||||
}
|
||||
|
||||
$remainder = $sum % 10;
|
||||
|
||||
return $remainder === 0 ? 0 : 10 - $remainder;
|
||||
}
|
||||
|
||||
public static function generateGS128Tst(Request $request)
|
||||
{
|
||||
print_r('>>> Generate PDF');
|
||||
|
||||
@@ -60,7 +60,7 @@ class WhsPerfMetrics extends Controller
|
||||
private static function loadUserContext(): array
|
||||
{
|
||||
$connection = config('m3.connection', 'pgsql');
|
||||
$user = Str::upper(trim((string) m3_user()));
|
||||
$user = Str::upper(trim((string) m3User()));
|
||||
|
||||
if ($user === '' || ! Schema::connection($connection)->hasTable('icm428m')) {
|
||||
return ['COMPANY' => '', 'PLANT' => '', 'WHS' => ''];
|
||||
|
||||
@@ -35,7 +35,7 @@ class WhsePerfController extends Controller
|
||||
|
||||
$iCM711M = DB::connection(config('m3.connection', 'pgsql'))->select($sqlstmt);
|
||||
$uSER_INFO = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')->selectRaw('R428US as USERPRF, R428STS as STATUS, NULL as DATE_EXPIRED, NULL as EXPIRED')->get()->all();
|
||||
$power_user = DB::connection(config('m3.connection', 'pgsql'))->select("select R428PWRUSR, R428CO, R428PL, R428WH from ICM428M where R428US='" . strtoupper(m3_user()) . "'");
|
||||
$power_user = DB::connection(config('m3.connection', 'pgsql'))->select("select R428PWRUSR, R428CO, R428PL, R428WH from ICM428M where R428US='" . strtoupper(m3User()) . "'");
|
||||
|
||||
$pct_array = Config::get('arrays.whsePerf_targets');
|
||||
|
||||
@@ -58,7 +58,7 @@ class WhsePerfController extends Controller
|
||||
|
||||
$iCM711M = DB::connection(config('m3.connection', 'pgsql'))->select($sqlstmt);
|
||||
$uSER_INFO = DB::connection(config('m3.connection', 'pgsql'))->table('icm428m')->selectRaw('R428US as USERPRF, R428STS as STATUS, NULL as DATE_EXPIRED, NULL as EXPIRED')->get()->all();
|
||||
$power_user = DB::connection(config('m3.connection', 'pgsql'))->select("select R428PWRUSR, R428CO, R428PL, R428WH from ICM428M where R428US='" . strtoupper(m3_user()) . "'");
|
||||
$power_user = DB::connection(config('m3.connection', 'pgsql'))->select("select R428PWRUSR, R428CO, R428PL, R428WH from ICM428M where R428US='" . strtoupper(m3User()) . "'");
|
||||
|
||||
$pct_array = Config::get('arrays.whsePerf_targets');
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ class BasicAuth
|
||||
{
|
||||
public function handle(Request $request, Closure $next): mixed
|
||||
{
|
||||
$login = trim((string) m3_user());
|
||||
$password = (string) m3_legacy_password();
|
||||
$login = trim((string) m3User());
|
||||
$password = (string) m3LegacyPassword();
|
||||
|
||||
if ($login !== '' && $this->checkPassword($login, $password, '%%SYSTEM%%')) {
|
||||
return $next($request);
|
||||
@@ -27,26 +27,26 @@ class BasicAuth
|
||||
}
|
||||
|
||||
$handle = fopen($passwordFile, 'rb');
|
||||
if ($handle === false) {
|
||||
return false;
|
||||
}
|
||||
$valid = false;
|
||||
|
||||
try {
|
||||
while (($line = fgets($handle)) !== false) {
|
||||
$parts = explode(':', trim($line), 2);
|
||||
if (count($parts) !== 2 || ! hash_equals($parts[0], $login)) {
|
||||
continue;
|
||||
if ($handle !== false) {
|
||||
try {
|
||||
while (($line = fgets($handle)) !== false) {
|
||||
$parts = explode(':', trim($line), 2);
|
||||
if (count($parts) !== 2 || ! hash_equals($parts[0], $login)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$storedHash = trim($parts[1]);
|
||||
$valid = $storedHash !== '' && password_verify($password, $storedHash);
|
||||
break;
|
||||
}
|
||||
|
||||
$storedHash = trim($parts[1]);
|
||||
|
||||
return $storedHash !== '' && password_verify($password, $storedHash);
|
||||
} finally {
|
||||
fclose($handle);
|
||||
}
|
||||
} finally {
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
return false;
|
||||
return $valid;
|
||||
}
|
||||
|
||||
private function unauthorized(): Response
|
||||
|
||||
@@ -52,11 +52,6 @@ class ShipTo extends Model
|
||||
$existingRecord->where($this->getKeyName(), '!=', $this->getKey());
|
||||
}
|
||||
|
||||
if ($existingRecord->count() > 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
|
||||
}
|
||||
return $existingRecord->count() === 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,17 +14,6 @@ class RouteServiceProvider extends ServiceProvider
|
||||
*/
|
||||
protected $moduleNamespace = 'Modules\M3\Http\Controllers';
|
||||
|
||||
/**
|
||||
* Called before routes are registered.
|
||||
*
|
||||
* Register any model bindings or pattern based filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
parent::boot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the routes for the application.
|
||||
|
||||
@@ -444,18 +444,11 @@ legend + * {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
@@ -2230,24 +2223,7 @@ div.table-responsive > table > tbody > tr:last-child > td{
|
||||
background-color: #e9ecef;
|
||||
opacity: 1;
|
||||
}
|
||||
.form-control::-webkit-file-upload-button, .dataTable-input::-webkit-file-upload-button {
|
||||
padding: 0.375rem 0.75rem;
|
||||
margin: -0.375rem -0.75rem;
|
||||
-webkit-margin-end: 0.75rem;
|
||||
margin-inline-end: 0.75rem;
|
||||
color: #212529;
|
||||
background-color: #e9ecef;
|
||||
pointer-events: none;
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
border-inline-end-width: 1px;
|
||||
border-radius: 0;
|
||||
-webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
}
|
||||
.form-control::file-selector-button, .dataTable-input::file-selector-button {
|
||||
padding: 0.375rem 0.75rem;
|
||||
margin: -0.375rem -0.75rem;
|
||||
-webkit-margin-end: 0.75rem;
|
||||
margin-inline-end: 0.75rem;
|
||||
@@ -2260,48 +2236,16 @@ div.table-responsive > table > tbody > tr:last-child > td{
|
||||
border-inline-end-width: 1px;
|
||||
border-radius: 0;
|
||||
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
padding: 0.375rem 0.75rem;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.form-control::-webkit-file-upload-button, .dataTable-input::-webkit-file-upload-button {
|
||||
-webkit-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
.form-control::file-selector-button, .dataTable-input::file-selector-button {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button, .dataTable-input:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {
|
||||
background-color: #dde0e3;
|
||||
}
|
||||
.form-control:hover:not(:disabled):not([readonly])::file-selector-button, .dataTable-input:hover:not(:disabled):not([readonly])::file-selector-button {
|
||||
background-color: #dde0e3;
|
||||
}
|
||||
.form-control::-webkit-file-upload-button, .dataTable-input::-webkit-file-upload-button {
|
||||
padding: 0.375rem 0.75rem;
|
||||
margin: -0.375rem -0.75rem;
|
||||
-webkit-margin-end: 0.75rem;
|
||||
margin-inline-end: 0.75rem;
|
||||
color: #212529;
|
||||
background-color: #e9ecef;
|
||||
pointer-events: none;
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
border-inline-end-width: 1px;
|
||||
border-radius: 0;
|
||||
-webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.form-control::-webkit-file-upload-button, .dataTable-input::-webkit-file-upload-button {
|
||||
-webkit-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button, .dataTable-input:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {
|
||||
background-color: #dde0e3;
|
||||
}
|
||||
|
||||
.form-control-plaintext {
|
||||
display: block;
|
||||
width: 100%;
|
||||
@@ -2324,24 +2268,12 @@ div.table-responsive > table > tbody > tr:last-child > td{
|
||||
font-size: 0.875rem;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
.form-control-sm::-webkit-file-upload-button {
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin: -0.25rem -0.5rem;
|
||||
-webkit-margin-end: 0.5rem;
|
||||
margin-inline-end: 0.5rem;
|
||||
}
|
||||
.form-control-sm::file-selector-button {
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin: -0.25rem -0.5rem;
|
||||
-webkit-margin-end: 0.5rem;
|
||||
margin-inline-end: 0.5rem;
|
||||
}
|
||||
.form-control-sm::-webkit-file-upload-button {
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin: -0.25rem -0.5rem;
|
||||
-webkit-margin-end: 0.5rem;
|
||||
margin-inline-end: 0.5rem;
|
||||
}
|
||||
|
||||
.form-control-lg {
|
||||
min-height: calc(1.5em + 1rem + 2px);
|
||||
@@ -2349,24 +2281,12 @@ div.table-responsive > table > tbody > tr:last-child > td{
|
||||
font-size: 1.25rem;
|
||||
border-radius: 0.3rem;
|
||||
}
|
||||
.form-control-lg::-webkit-file-upload-button {
|
||||
padding: 0.5rem 1rem;
|
||||
margin: -0.5rem -1rem;
|
||||
-webkit-margin-end: 1rem;
|
||||
margin-inline-end: 1rem;
|
||||
}
|
||||
.form-control-lg::file-selector-button {
|
||||
padding: 0.5rem 1rem;
|
||||
margin: -0.5rem -1rem;
|
||||
-webkit-margin-end: 1rem;
|
||||
margin-inline-end: 1rem;
|
||||
}
|
||||
.form-control-lg::-webkit-file-upload-button {
|
||||
padding: 0.5rem 1rem;
|
||||
margin: -0.5rem -1rem;
|
||||
-webkit-margin-end: 1rem;
|
||||
margin-inline-end: 1rem;
|
||||
}
|
||||
|
||||
textarea.form-control, textarea.dataTable-input {
|
||||
min-height: calc(1.5em + 0.75rem + 2px);
|
||||
@@ -3711,19 +3631,16 @@ textarea.form-control-lg {
|
||||
.dropend .dropdown-toggle::after {
|
||||
display: inline-block;
|
||||
margin-left: 0.255em;
|
||||
vertical-align: 0.255em;
|
||||
content: "";
|
||||
border-top: 0.3em solid transparent;
|
||||
border-right: 0;
|
||||
border-bottom: 0.3em solid transparent;
|
||||
border-left: 0.3em solid;
|
||||
vertical-align: 0;
|
||||
}
|
||||
.dropend .dropdown-toggle:empty::after {
|
||||
margin-left: 0;
|
||||
}
|
||||
.dropend .dropdown-toggle::after {
|
||||
vertical-align: 0;
|
||||
}
|
||||
|
||||
.dropstart .dropdown-menu[data-bs-popper] {
|
||||
top: 0;
|
||||
@@ -3733,29 +3650,23 @@ textarea.form-control-lg {
|
||||
margin-right: 0.125rem;
|
||||
}
|
||||
.dropstart .dropdown-toggle::after {
|
||||
display: inline-block;
|
||||
margin-left: 0.255em;
|
||||
vertical-align: 0.255em;
|
||||
content: "";
|
||||
}
|
||||
.dropstart .dropdown-toggle::after {
|
||||
display: none;
|
||||
}
|
||||
.dropstart .dropdown-toggle::before {
|
||||
display: inline-block;
|
||||
margin-right: 0.255em;
|
||||
vertical-align: 0.255em;
|
||||
content: "";
|
||||
border-top: 0.3em solid transparent;
|
||||
border-right: 0.3em solid;
|
||||
border-bottom: 0.3em solid transparent;
|
||||
vertical-align: 0;
|
||||
}
|
||||
.dropstart .dropdown-toggle:empty::after {
|
||||
margin-left: 0;
|
||||
}
|
||||
.dropstart .dropdown-toggle::before {
|
||||
vertical-align: 0;
|
||||
}
|
||||
|
||||
.dropdown-divider {
|
||||
height: 0;
|
||||
@@ -3821,7 +3732,7 @@ textarea.form-control-lg {
|
||||
}
|
||||
.dropdown-menu-dark .dropdown-item:hover, .dropdown-menu-dark .dropdown-item:focus {
|
||||
color: #fff;
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
background-color: #495057;
|
||||
}
|
||||
.dropdown-menu-dark .dropdown-item.active, .dropdown-menu-dark .dropdown-item:active {
|
||||
color: #fff;
|
||||
@@ -4784,6 +4695,9 @@ textarea.form-control-lg {
|
||||
padding: 0 0;
|
||||
margin-bottom: 1rem;
|
||||
list-style: none;
|
||||
border: 1px solid #f3f3f3;
|
||||
background-color: transparent;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.breadcrumb-item + .breadcrumb-item {
|
||||
@@ -4849,9 +4763,6 @@ textarea.form-control-lg {
|
||||
border-color: #dee2e6;
|
||||
}
|
||||
|
||||
.page-link, .dataTable-pagination a {
|
||||
padding: 0.375rem 0.75rem;
|
||||
}
|
||||
|
||||
.page-item:first-child .page-link, .page-item:first-child .dataTable-pagination a, .dataTable-pagination .page-item:first-child a, .dataTable-pagination li:first-child .page-link, .dataTable-pagination li:first-child a {
|
||||
border-top-left-radius: 0.25rem;
|
||||
@@ -5008,11 +4919,7 @@ textarea.form-control-lg {
|
||||
color: #101214;
|
||||
}
|
||||
|
||||
@-webkit-keyframes progress-bar-stripes {
|
||||
0% {
|
||||
background-position-x: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes progress-bar-stripes {
|
||||
0% {
|
||||
@@ -6198,11 +6105,7 @@ textarea.form-control-lg {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
@-webkit-keyframes spinner-border {
|
||||
to {
|
||||
transform: rotate(360deg) /* rtl:ignore */;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes spinner-border {
|
||||
to {
|
||||
@@ -6227,15 +6130,7 @@ textarea.form-control-lg {
|
||||
border-width: 0.2em;
|
||||
}
|
||||
|
||||
@-webkit-keyframes spinner-grow {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes spinner-grow {
|
||||
0% {
|
||||
@@ -6398,11 +6293,7 @@ textarea.form-control-lg {
|
||||
animation: placeholder-glow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes placeholder-glow {
|
||||
50% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes placeholder-glow {
|
||||
50% {
|
||||
@@ -6418,12 +6309,7 @@ textarea.form-control-lg {
|
||||
animation: placeholder-wave 2s linear infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes placeholder-wave {
|
||||
100% {
|
||||
-webkit-mask-position: -200% 0%;
|
||||
mask-position: -200% 0%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes placeholder-wave {
|
||||
100% {
|
||||
@@ -7708,7 +7594,7 @@ textarea.form-control-lg {
|
||||
/* rtl:begin:remove */
|
||||
.text-break {
|
||||
word-wrap: break-word !important;
|
||||
word-break: break-word !important;
|
||||
overflow-wrap: break-word !important;
|
||||
}
|
||||
|
||||
/* rtl:end:remove */
|
||||
@@ -11687,19 +11573,6 @@ body {
|
||||
border-color: #dbe3e6
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
border: 1px solid #f3f3f3
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 0.56rem 1.13rem;
|
||||
margin-bottom: 1rem;
|
||||
list-style: none;
|
||||
background-color: transparent;
|
||||
border-radius: 0.25rem
|
||||
}
|
||||
|
||||
nav {
|
||||
display: block
|
||||
@@ -11752,10 +11625,6 @@ nav {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.breadcrumb.breadcrumb-custom .breadcrumb-item:before {
|
||||
content: ""
|
||||
}
|
||||
|
||||
.breadcrumb.breadcrumb-custom .breadcrumb-item a:before,
|
||||
.breadcrumb.breadcrumb-custom .breadcrumb-item a:after {
|
||||
position: absolute;
|
||||
@@ -11771,12 +11640,6 @@ a:link {
|
||||
text-decoration: none
|
||||
}
|
||||
|
||||
.breadcrumb-item+.breadcrumb-item::before {
|
||||
display: inline-block;
|
||||
padding-right: 0.5rem;
|
||||
color: #6c757d;
|
||||
content: "/"
|
||||
}
|
||||
|
||||
|
||||
.highcharts-figure, .highcharts-data-table table {
|
||||
|
||||
@@ -102,8 +102,7 @@ $(function() {
|
||||
customize: function(xlsx,btnObj, tableInst) {
|
||||
let sheet = xlsx.xl.worksheets['sheet1.xml'];
|
||||
let cellIndexes = tableInst.cells(".bg-danger").indexes();
|
||||
for (let i = 0; i < cellIndexes.length; i++) {
|
||||
let cellIndex = cellIndexes[i];
|
||||
for (const cellIndex of cellIndexes) {
|
||||
let tblRow = cellIndex['row']+3; // adjusted from 0 indexed
|
||||
let tblCol = cellIndex['column']; // adjusted from 0 indexed
|
||||
let xlCol = numberToLetters(tblCol);
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+5
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}div.dt-button-collection{position:absolute;z-index:2001;width:100%}div.dt-button-collection div.dropdown-menu{display:block;z-index:2002;min-width:100%;padding-left:2px;padding-right:2px}div.dt-button-collection div.dt-button-collection-title{background-color:white;border:1px solid rgba(0, 0, 0, 0.15)}div.dt-button-collection.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.fixed{max-width:none}div.dt-button-collection.fixed:before,div.dt-button-collection.fixed:after{display:none}div.dt-button-collection div.dt-btn-split-wrapper{width:100%}div.dt-button-collection button.dt-btn-split-drop-button{width:100%;color:#212529;border:none;background-color:white;border-radius:0px;margin-left:0px !important}div.dt-button-collection button.dt-btn-split-drop-button:focus{border:none;border-radius:0px;outline:none}div.dt-button-collection button.dt-btn-split-drop-button:hover{background-color:#e9ecef}div.dt-button-collection button.dt-btn-split-drop-button:active{background-color:#007bff !important}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:999}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5em}div.dt-buttons a.btn{float:none}}div.dt-buttons button.btn.processing,div.dt-buttons div.btn.processing,div.dt-buttons a.btn.processing{color:rgba(0, 0, 0, 0.2)}div.dt-buttons button.btn.processing:after,div.dt-buttons div.btn.processing:after,div.dt-buttons a.btn.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-btn-split-wrapper button.dt-btn-split-drop{border-top-right-radius:.25rem !important;border-bottom-right-radius:.25rem !important}
|
||||
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+4
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty{cursor:default !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty:before{display:none !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control,table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before{top:50%;left:5px;height:1em;width:1em;margin-top:-9px;display:block;position:absolute;color:white;border:.15em solid white;border-radius:1em;box-shadow:0 0 .2em #444;box-sizing:content-box;text-align:center;text-indent:0 !important;font-family:"Courier New",Courier,monospace;line-height:1em;content:"+";background-color:#337ab7}table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before{content:"-";background-color:#d33333}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td.dtr-control,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th.dtr-control{padding-left:27px}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td.dtr-control:before,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th.dtr-control:before{left:4px;height:14px;width:14px;border-radius:14px;line-height:14px;text-indent:3px}table.dataTable.dtr-column>tbody>tr>td.dtr-control,table.dataTable.dtr-column>tbody>tr>th.dtr-control,table.dataTable.dtr-column>tbody>tr>td.control,table.dataTable.dtr-column>tbody>tr>th.control{position:relative;cursor:pointer}table.dataTable.dtr-column>tbody>tr>td.dtr-control:before,table.dataTable.dtr-column>tbody>tr>th.dtr-control:before,table.dataTable.dtr-column>tbody>tr>td.control:before,table.dataTable.dtr-column>tbody>tr>th.control:before{top:50%;left:50%;height:.8em;width:.8em;margin-top:-0.5em;margin-left:-0.5em;display:block;position:absolute;color:white;border:.15em solid white;border-radius:1em;box-shadow:0 0 .2em #444;box-sizing:content-box;text-align:center;text-indent:0 !important;font-family:"Courier New",Courier,monospace;line-height:1em;content:"+";background-color:#337ab7}table.dataTable.dtr-column>tbody>tr.parent td.dtr-control:before,table.dataTable.dtr-column>tbody>tr.parent th.dtr-control:before,table.dataTable.dtr-column>tbody>tr.parent td.control:before,table.dataTable.dtr-column>tbody>tr.parent th.control:before{content:"-";background-color:#d33333}table.dataTable>tbody>tr.child{padding:.5em 1em}table.dataTable>tbody>tr.child:hover{background:transparent !important}table.dataTable>tbody>tr.child ul.dtr-details{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable>tbody>tr.child ul.dtr-details>li{border-bottom:1px solid #efefef;padding:.5em 0}table.dataTable>tbody>tr.child ul.dtr-details>li:first-child{padding-top:0}table.dataTable>tbody>tr.child ul.dtr-details>li:last-child{border-bottom:none}table.dataTable>tbody>tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:bold}div.dtr-modal{position:fixed;box-sizing:border-box;top:0;left:0;height:100%;width:100%;z-index:100;padding:10em 1em}div.dtr-modal div.dtr-modal-display{position:absolute;top:0;left:0;bottom:0;right:0;width:50%;height:50%;overflow:auto;margin:auto;z-index:102;overflow:auto;background-color:#f5f5f7;border:1px solid black;border-radius:.5em;box-shadow:0 12px 30px rgba(0, 0, 0, 0.6)}div.dtr-modal div.dtr-modal-content{position:relative;padding:1em}div.dtr-modal div.dtr-modal-close{position:absolute;top:6px;right:6px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}div.dtr-modal div.dtr-modal-close:hover{background-color:#eaeaea}div.dtr-modal div.dtr-modal-background{position:fixed;top:0;left:0;right:0;bottom:0;z-index:101;background:rgba(0, 0, 0, 0.6)}@media screen and (max-width: 767px){div.dtr-modal div.dtr-modal-display{width:95%}}div.dtr-bs-modal table.table tr:first-child td{border-top:none}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
/*! Bootstrap integration for DataTables' Responsive
|
||||
* © SpryMedia Ltd - datatables.net/license
|
||||
*/
|
||||
!function(a){var n,o;"function"==typeof define&&define.amd?define(["jquery","datatables.net-bs","datatables.net-responsive"],function(e){return a(e,window,document)}):"object"==typeof exports?(n=require("jquery"),o=function(e,d){d.fn.dataTable||require("datatables.net-bs")(e,d),d.fn.dataTable.Responsive||require("datatables.net-responsive")(e,d)},"undefined"!=typeof window?module.exports=function(e,d){return e=e||window,d=d||n(e),o(e,d),a(d,0,e.document)}:(o(window,n),module.exports=a(n,window,window.document))):a(jQuery,window,document)}(function(i,e,d,a){"use strict";var n=i.fn.dataTable,o=n.Responsive.display,s=o.modal,l=i('<div class="modal fade dtr-bs-modal" role="dialog"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button></div><div class="modal-body"/></div></div></div>');return o.modal=function(t){return function(e,d,a){var n,o;i.fn.modal?d||(t&&t.header&&(o=(n=l.find("div.modal-header")).find("button").detach(),n.empty().append('<h4 class="modal-title">'+t.header(e)+"</h4>").prepend(o)),l.find("div.modal-body").empty().append(a()),l.appendTo("body").modal()):s(e,d,a)}},n});
|
||||
+1
@@ -0,0 +1 @@
|
||||
table.dataTable tbody>tr.selected,table.dataTable tbody>tr>.selected{background-color:#0d6efd}table.dataTable.stripe tbody>tr.odd.selected,table.dataTable.stripe tbody>tr.odd>.selected,table.dataTable.display tbody>tr.odd.selected,table.dataTable.display tbody>tr.odd>.selected{background-color:#0d6bf7}table.dataTable.hover tbody>tr.selected:hover,table.dataTable.hover tbody>tr>.selected:hover,table.dataTable.display tbody>tr.selected:hover,table.dataTable.display tbody>tr>.selected:hover{background-color:#0d6af4}table.dataTable.order-column tbody>tr.selected>.sorting_1,table.dataTable.order-column tbody>tr.selected>.sorting_2,table.dataTable.order-column tbody>tr.selected>.sorting_3,table.dataTable.order-column tbody>tr>.selected,table.dataTable.display tbody>tr.selected>.sorting_1,table.dataTable.display tbody>tr.selected>.sorting_2,table.dataTable.display tbody>tr.selected>.sorting_3,table.dataTable.display tbody>tr>.selected{background-color:#0d6cf8}table.dataTable.display tbody>tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_1{background-color:#0c68ef}table.dataTable.display tbody>tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_2{background-color:#0c69f1}table.dataTable.display tbody>tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_3{background-color:#0c6af3}table.dataTable.display tbody>tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_1{background-color:#0d6cf8}table.dataTable.display tbody>tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_2{background-color:#0d6dfa}table.dataTable.display tbody>tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_3{background-color:#0d6efc}table.dataTable.display tbody>tr.odd>.selected,table.dataTable.order-column.stripe tbody>tr.odd>.selected{background-color:#0c68ef}table.dataTable.display tbody>tr.even>.selected,table.dataTable.order-column.stripe tbody>tr.even>.selected{background-color:#0d6cf8}table.dataTable.display tbody>tr.selected:hover>.sorting_1,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_1{background-color:#0c65e8}table.dataTable.display tbody>tr.selected:hover>.sorting_2,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_2{background-color:#0c66ea}table.dataTable.display tbody>tr.selected:hover>.sorting_3,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_3{background-color:#0c67ed}table.dataTable.display tbody>tr:hover>.selected,table.dataTable.display tbody>tr>.selected:hover,table.dataTable.order-column.hover tbody>tr:hover>.selected,table.dataTable.order-column.hover tbody>tr>.selected:hover{background-color:#0c65e8}table.dataTable tbody td.select-checkbox,table.dataTable tbody th.select-checkbox{position:relative}table.dataTable tbody td.select-checkbox:before,table.dataTable tbody td.select-checkbox:after,table.dataTable tbody th.select-checkbox:before,table.dataTable tbody th.select-checkbox:after{display:block;position:absolute;top:1.2em;left:50%;width:12px;height:12px;box-sizing:border-box}table.dataTable tbody td.select-checkbox:before,table.dataTable tbody th.select-checkbox:before{content:" ";margin-top:-2px;margin-left:-6px;border:1px solid black;border-radius:3px}table.dataTable tr.selected td.select-checkbox:after,table.dataTable tr.selected th.select-checkbox:after{content:"✓";font-size:20px;margin-top:-19px;margin-left:-6px;text-align:center;text-shadow:1px 1px #b0bed9,-1px -1px #b0bed9,1px -1px #b0bed9,-1px 1px #b0bed9}table.dataTable.compact tbody td.select-checkbox:before,table.dataTable.compact tbody th.select-checkbox:before{margin-top:-12px}table.dataTable.compact tr.selected td.select-checkbox:after,table.dataTable.compact tr.selected th.select-checkbox:after{margin-top:-16px}div.dataTables_wrapper span.select-info,div.dataTables_wrapper span.select-item{margin-left:.5em}@media screen and (max-width: 640px){div.dataTables_wrapper span.select-info,div.dataTables_wrapper span.select-item{margin-left:0;display:block}}table.dataTable tbody tr.selected,table.dataTable tbody th.selected,table.dataTable tbody td.selected{color:white}table.dataTable tbody tr.selected a,table.dataTable tbody th.selected a,table.dataTable tbody td.selected a{color:#a2d4ed}
|
||||
@@ -0,0 +1,410 @@
|
||||
.daterangepicker {
|
||||
position: absolute;
|
||||
color: inherit;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
width: 278px;
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
margin-top: 7px;
|
||||
top: 100px;
|
||||
left: 20px;
|
||||
z-index: 3001;
|
||||
display: none;
|
||||
font-family: arial;
|
||||
font-size: 15px;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.daterangepicker:before, .daterangepicker:after {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
border-bottom-color: rgba(0, 0, 0, 0.2);
|
||||
content: '';
|
||||
}
|
||||
|
||||
.daterangepicker:before {
|
||||
top: -7px;
|
||||
border-right: 7px solid transparent;
|
||||
border-left: 7px solid transparent;
|
||||
border-bottom: 7px solid #ccc;
|
||||
}
|
||||
|
||||
.daterangepicker:after {
|
||||
top: -6px;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid #fff;
|
||||
border-left: 6px solid transparent;
|
||||
}
|
||||
|
||||
.daterangepicker.opensleft:before {
|
||||
right: 9px;
|
||||
}
|
||||
|
||||
.daterangepicker.opensleft:after {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.daterangepicker.openscenter:before {
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.daterangepicker.openscenter:after {
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.daterangepicker.opensright:before {
|
||||
left: 9px;
|
||||
}
|
||||
|
||||
.daterangepicker.opensright:after {
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.daterangepicker.drop-up {
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
||||
.daterangepicker.drop-up:before {
|
||||
top: initial;
|
||||
bottom: -7px;
|
||||
border-bottom: initial;
|
||||
border-top: 7px solid #ccc;
|
||||
}
|
||||
|
||||
.daterangepicker.drop-up:after {
|
||||
top: initial;
|
||||
bottom: -6px;
|
||||
border-bottom: initial;
|
||||
border-top: 6px solid #fff;
|
||||
}
|
||||
|
||||
.daterangepicker.single .daterangepicker .ranges, .daterangepicker.single .drp-calendar {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.daterangepicker.single .drp-selected {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.daterangepicker.show-calendar .drp-calendar {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.daterangepicker.show-calendar .drp-buttons {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.daterangepicker.auto-apply .drp-buttons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar {
|
||||
display: none;
|
||||
max-width: 270px;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left {
|
||||
padding: 8px 0 8px 8px;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.right {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.single .calendar-table {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table .next span, .daterangepicker .calendar-table .prev span {
|
||||
color: #fff;
|
||||
border: solid black;
|
||||
border-width: 0 2px 2px 0;
|
||||
border-radius: 0;
|
||||
display: inline-block;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table .next span {
|
||||
transform: rotate(-45deg);
|
||||
-webkit-transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table .prev span {
|
||||
transform: rotate(135deg);
|
||||
-webkit-transform: rotate(135deg);
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table th, .daterangepicker .calendar-table td {
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
min-width: 32px;
|
||||
width: 32px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table {
|
||||
border: 1px solid #fff;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table table {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.daterangepicker td.available:hover, .daterangepicker th.available:hover {
|
||||
background-color: #eee;
|
||||
border-color: transparent;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.daterangepicker td.week, .daterangepicker th.week {
|
||||
font-size: 80%;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.daterangepicker td.off, .daterangepicker td.off.in-range, .daterangepicker td.off.start-date, .daterangepicker td.off.end-date {
|
||||
background-color: #fff;
|
||||
border-color: transparent;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.daterangepicker td.in-range {
|
||||
background-color: #ebf4f8;
|
||||
border-color: transparent;
|
||||
color: #000;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.daterangepicker td.start-date {
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
.daterangepicker td.end-date {
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
.daterangepicker td.start-date.end-date {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.daterangepicker td.active, .daterangepicker td.active:hover {
|
||||
background-color: #357ebd;
|
||||
border-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.daterangepicker th.month {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.daterangepicker td.disabled, .daterangepicker option.disabled {
|
||||
color: #999;
|
||||
cursor: not-allowed;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.daterangepicker select.monthselect, .daterangepicker select.yearselect {
|
||||
font-size: 12px;
|
||||
padding: 1px;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.daterangepicker select.monthselect {
|
||||
margin-right: 2%;
|
||||
width: 56%;
|
||||
}
|
||||
|
||||
.daterangepicker select.yearselect {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect {
|
||||
width: 50px;
|
||||
margin: 0 auto;
|
||||
background: #eee;
|
||||
border: 1px solid #eee;
|
||||
padding: 2px;
|
||||
outline: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-time {
|
||||
text-align: center;
|
||||
margin: 4px auto 0 auto;
|
||||
line-height: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-time select.disabled {
|
||||
color: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-buttons {
|
||||
clear: both;
|
||||
text-align: right;
|
||||
padding: 8px;
|
||||
border-top: 1px solid #ddd;
|
||||
display: none;
|
||||
line-height: 12px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-selected {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-buttons .btn {
|
||||
margin-left: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.daterangepicker.show-ranges.single.rtl .drp-calendar.left {
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.daterangepicker.show-ranges.single.ltr .drp-calendar.left {
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.daterangepicker.show-ranges.rtl .drp-calendar.right {
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.daterangepicker.show-ranges.ltr .drp-calendar.left {
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges {
|
||||
float: none;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.daterangepicker.show-calendar .ranges {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges ul {
|
||||
list-style: none;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges li {
|
||||
font-size: 12px;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges li:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges li.active {
|
||||
background-color: #08c;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Larger Screen Styling */
|
||||
@media (min-width: 564px) {
|
||||
.daterangepicker {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges ul {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.daterangepicker.single .ranges ul {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.daterangepicker.single .drp-calendar.left {
|
||||
clear: none;
|
||||
}
|
||||
|
||||
.daterangepicker.single .ranges, .daterangepicker.single .drp-calendar {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.daterangepicker {
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left {
|
||||
clear: left;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left .calendar-table {
|
||||
border-right: none;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.right {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.right .calendar-table {
|
||||
border-left: none;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left .calendar-table {
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges, .daterangepicker .drp-calendar {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 730px) {
|
||||
.daterangepicker .ranges {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.daterangepicker.rtl .ranges {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left {
|
||||
clear: none !important;
|
||||
}
|
||||
}
|
||||
+15
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+117
@@ -0,0 +1,117 @@
|
||||
.flatpickr-monthSelect-months {
|
||||
margin: 10px 1px 3px 1px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-month {
|
||||
background: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
color: #393939;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: 400;
|
||||
margin: 0.5px;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
position: relative;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
-ms-flex-pack: center;
|
||||
text-align: center;
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-month.flatpickr-disabled {
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-month.flatpickr-disabled:hover,
|
||||
.flatpickr-monthSelect-month.flatpickr-disabled:focus {
|
||||
cursor: not-allowed;
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-theme-dark {
|
||||
background: #3f4458;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-theme-dark .flatpickr-current-month input.cur-year {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-theme-dark .flatpickr-months .flatpickr-prev-month,
|
||||
.flatpickr-monthSelect-theme-dark .flatpickr-months .flatpickr-next-month {
|
||||
color: #fff;
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month {
|
||||
color: rgba(255, 255, 255, 0.95);
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-month.today {
|
||||
border-color: #959ea9;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-month.inRange,
|
||||
.flatpickr-monthSelect-month.inRange.today,
|
||||
.flatpickr-monthSelect-month:hover,
|
||||
.flatpickr-monthSelect-month:focus {
|
||||
background: #e6e6e6;
|
||||
cursor: pointer;
|
||||
outline: 0;
|
||||
border-color: #e6e6e6;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month.inRange,
|
||||
.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month:hover,
|
||||
.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month:focus {
|
||||
background: #646c8c;
|
||||
border-color: #646c8c;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-month.today:hover,
|
||||
.flatpickr-monthSelect-month.today:focus {
|
||||
background: #959ea9;
|
||||
border-color: #959ea9;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-month.selected,
|
||||
.flatpickr-monthSelect-month.startRange,
|
||||
.flatpickr-monthSelect-month.endRange {
|
||||
background-color: #569ff7;
|
||||
box-shadow: none;
|
||||
color: #fff;
|
||||
border-color: #569ff7;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-month.startRange {
|
||||
border-radius: 50px 0 0 50px;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-month.endRange {
|
||||
border-radius: 0 50px 50px 0;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-month.startRange.endRange {
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-month.inRange {
|
||||
border-radius: 0;
|
||||
box-shadow: -5px 0 0 #e6e6e6, 5px 0 0 #e6e6e6;
|
||||
}
|
||||
|
||||
.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month.selected,
|
||||
.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month.startRange,
|
||||
.flatpickr-monthSelect-theme-dark .flatpickr-monthSelect-month.endRange {
|
||||
background: #80cbc4;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
color: #fff;
|
||||
border-color: #80cbc4;
|
||||
}
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.monthSelectPlugin = factory());
|
||||
}(this, (function () { 'use strict';
|
||||
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
***************************************************************************** */
|
||||
|
||||
var __assign = function() {
|
||||
__assign = Object.assign || function __assign(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
|
||||
var monthToStr = function (monthNumber, shorthand, locale) { return locale.months[shorthand ? "shorthand" : "longhand"][monthNumber]; };
|
||||
|
||||
function clearNode(node) {
|
||||
while (node.firstChild)
|
||||
node.removeChild(node.firstChild);
|
||||
}
|
||||
function getEventTarget(event) {
|
||||
try {
|
||||
if (typeof event.composedPath === "function") {
|
||||
var path = event.composedPath();
|
||||
return path[0];
|
||||
}
|
||||
return event.target;
|
||||
}
|
||||
catch (error) {
|
||||
return event.target;
|
||||
}
|
||||
}
|
||||
|
||||
var defaultConfig = {
|
||||
shorthand: false,
|
||||
dateFormat: "F Y",
|
||||
altFormat: "F Y",
|
||||
theme: "light",
|
||||
};
|
||||
function monthSelectPlugin(pluginConfig) {
|
||||
var config = __assign(__assign({}, defaultConfig), pluginConfig);
|
||||
return function (fp) {
|
||||
fp.config.dateFormat = config.dateFormat;
|
||||
fp.config.altFormat = config.altFormat;
|
||||
var self = { monthsContainer: null };
|
||||
function clearUnnecessaryDOMElements() {
|
||||
if (!fp.rContainer)
|
||||
return;
|
||||
clearNode(fp.rContainer);
|
||||
for (var index = 0; index < fp.monthElements.length; index++) {
|
||||
var element = fp.monthElements[index];
|
||||
if (!element.parentNode)
|
||||
continue;
|
||||
element.parentNode.removeChild(element);
|
||||
}
|
||||
}
|
||||
function build() {
|
||||
if (!fp.rContainer)
|
||||
return;
|
||||
self.monthsContainer = fp._createElement("div", "flatpickr-monthSelect-months");
|
||||
self.monthsContainer.tabIndex = -1;
|
||||
buildMonths();
|
||||
fp.rContainer.appendChild(self.monthsContainer);
|
||||
fp.calendarContainer.classList.add("flatpickr-monthSelect-theme-" + config.theme);
|
||||
}
|
||||
function buildMonths() {
|
||||
if (!self.monthsContainer)
|
||||
return;
|
||||
clearNode(self.monthsContainer);
|
||||
var frag = document.createDocumentFragment();
|
||||
for (var i = 0; i < 12; i++) {
|
||||
var month = fp.createDay("flatpickr-monthSelect-month", new Date(fp.currentYear, i), 0, i);
|
||||
if (month.dateObj.getMonth() === new Date().getMonth() &&
|
||||
month.dateObj.getFullYear() === new Date().getFullYear())
|
||||
month.classList.add("today");
|
||||
month.textContent = monthToStr(i, config.shorthand, fp.l10n);
|
||||
month.addEventListener("click", selectMonth);
|
||||
frag.appendChild(month);
|
||||
}
|
||||
self.monthsContainer.appendChild(frag);
|
||||
if (fp.config.minDate &&
|
||||
fp.currentYear === fp.config.minDate.getFullYear())
|
||||
fp.prevMonthNav.classList.add("flatpickr-disabled");
|
||||
else
|
||||
fp.prevMonthNav.classList.remove("flatpickr-disabled");
|
||||
if (fp.config.maxDate &&
|
||||
fp.currentYear === fp.config.maxDate.getFullYear())
|
||||
fp.nextMonthNav.classList.add("flatpickr-disabled");
|
||||
else
|
||||
fp.nextMonthNav.classList.remove("flatpickr-disabled");
|
||||
}
|
||||
function bindEvents() {
|
||||
fp._bind(fp.prevMonthNav, "click", function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
fp.changeYear(fp.currentYear - 1);
|
||||
selectYear();
|
||||
buildMonths();
|
||||
});
|
||||
fp._bind(fp.nextMonthNav, "click", function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
fp.changeYear(fp.currentYear + 1);
|
||||
selectYear();
|
||||
buildMonths();
|
||||
});
|
||||
fp._bind(self.monthsContainer, "mouseover", function (e) {
|
||||
if (fp.config.mode === "range")
|
||||
fp.onMouseOver(getEventTarget(e), "flatpickr-monthSelect-month");
|
||||
});
|
||||
}
|
||||
function setCurrentlySelected() {
|
||||
if (!fp.rContainer)
|
||||
return;
|
||||
if (!fp.selectedDates.length)
|
||||
return;
|
||||
var currentlySelected = fp.rContainer.querySelectorAll(".flatpickr-monthSelect-month.selected");
|
||||
for (var index = 0; index < currentlySelected.length; index++) {
|
||||
currentlySelected[index].classList.remove("selected");
|
||||
}
|
||||
var targetMonth = fp.selectedDates[0].getMonth();
|
||||
var month = fp.rContainer.querySelector(".flatpickr-monthSelect-month:nth-child(" + (targetMonth + 1) + ")");
|
||||
if (month) {
|
||||
month.classList.add("selected");
|
||||
}
|
||||
}
|
||||
function selectYear() {
|
||||
var selectedDate = fp.selectedDates[0];
|
||||
if (selectedDate) {
|
||||
selectedDate = new Date(selectedDate);
|
||||
selectedDate.setFullYear(fp.currentYear);
|
||||
if (fp.config.minDate && selectedDate < fp.config.minDate) {
|
||||
selectedDate = fp.config.minDate;
|
||||
}
|
||||
if (fp.config.maxDate && selectedDate > fp.config.maxDate) {
|
||||
selectedDate = fp.config.maxDate;
|
||||
}
|
||||
fp.currentYear = selectedDate.getFullYear();
|
||||
}
|
||||
fp.currentYearElement.value = String(fp.currentYear);
|
||||
if (fp.rContainer) {
|
||||
var months = fp.rContainer.querySelectorAll(".flatpickr-monthSelect-month");
|
||||
months.forEach(function (month) {
|
||||
month.dateObj.setFullYear(fp.currentYear);
|
||||
if ((fp.config.minDate && month.dateObj < fp.config.minDate) ||
|
||||
(fp.config.maxDate && month.dateObj > fp.config.maxDate)) {
|
||||
month.classList.add("flatpickr-disabled");
|
||||
}
|
||||
else {
|
||||
month.classList.remove("flatpickr-disabled");
|
||||
}
|
||||
});
|
||||
}
|
||||
setCurrentlySelected();
|
||||
}
|
||||
function selectMonth(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var eventTarget = getEventTarget(e);
|
||||
if (!(eventTarget instanceof Element))
|
||||
return;
|
||||
if (eventTarget.classList.contains("flatpickr-disabled"))
|
||||
return;
|
||||
if (eventTarget.classList.contains("notAllowed"))
|
||||
return; // necessary??
|
||||
setMonth(eventTarget.dateObj);
|
||||
if (fp.config.closeOnSelect) {
|
||||
var single = fp.config.mode === "single";
|
||||
var range = fp.config.mode === "range" && fp.selectedDates.length === 2;
|
||||
if (single || range)
|
||||
fp.close();
|
||||
}
|
||||
}
|
||||
function setMonth(date) {
|
||||
var selectedDate = new Date(fp.currentYear, date.getMonth(), date.getDate());
|
||||
var selectedDates = [];
|
||||
switch (fp.config.mode) {
|
||||
case "single":
|
||||
selectedDates = [selectedDate];
|
||||
break;
|
||||
case "multiple":
|
||||
selectedDates.push(selectedDate);
|
||||
break;
|
||||
case "range":
|
||||
if (fp.selectedDates.length === 2) {
|
||||
selectedDates = [selectedDate];
|
||||
}
|
||||
else {
|
||||
selectedDates = fp.selectedDates.concat([selectedDate]);
|
||||
selectedDates.sort(function (a, b) { return a.getTime() - b.getTime(); });
|
||||
}
|
||||
break;
|
||||
}
|
||||
fp.setDate(selectedDates, true);
|
||||
setCurrentlySelected();
|
||||
}
|
||||
var shifts = {
|
||||
37: -1,
|
||||
39: 1,
|
||||
40: 3,
|
||||
38: -3,
|
||||
};
|
||||
function onKeyDown(_, __, ___, e) {
|
||||
var shouldMove = shifts[e.keyCode] !== undefined;
|
||||
if (!shouldMove && e.keyCode !== 13) {
|
||||
return;
|
||||
}
|
||||
if (!fp.rContainer || !self.monthsContainer)
|
||||
return;
|
||||
var currentlySelected = fp.rContainer.querySelector(".flatpickr-monthSelect-month.selected");
|
||||
var index = Array.prototype.indexOf.call(self.monthsContainer.children, document.activeElement);
|
||||
if (index === -1) {
|
||||
var target = currentlySelected || self.monthsContainer.firstElementChild;
|
||||
target.focus();
|
||||
index = target.$i;
|
||||
}
|
||||
if (shouldMove) {
|
||||
self.monthsContainer.children[(12 + index + shifts[e.keyCode]) % 12].focus();
|
||||
}
|
||||
else if (e.keyCode === 13 &&
|
||||
self.monthsContainer.contains(document.activeElement)) {
|
||||
setMonth(document.activeElement.dateObj);
|
||||
}
|
||||
}
|
||||
function closeHook() {
|
||||
var _a;
|
||||
if (((_a = fp.config) === null || _a === void 0 ? void 0 : _a.mode) === "range" && fp.selectedDates.length === 1)
|
||||
fp.clear(false);
|
||||
if (!fp.selectedDates.length)
|
||||
buildMonths();
|
||||
}
|
||||
// Help the prev/next year nav honor config.minDate (see 3fa5a69)
|
||||
function stubCurrentMonth() {
|
||||
config._stubbedCurrentMonth = fp._initialDate.getMonth();
|
||||
fp._initialDate.setMonth(config._stubbedCurrentMonth);
|
||||
fp.currentMonth = config._stubbedCurrentMonth;
|
||||
}
|
||||
function unstubCurrentMonth() {
|
||||
if (!config._stubbedCurrentMonth)
|
||||
return;
|
||||
fp._initialDate.setMonth(config._stubbedCurrentMonth);
|
||||
fp.currentMonth = config._stubbedCurrentMonth;
|
||||
delete config._stubbedCurrentMonth;
|
||||
}
|
||||
function destroyPluginInstance() {
|
||||
if (self.monthsContainer !== null) {
|
||||
var months = self.monthsContainer.querySelectorAll(".flatpickr-monthSelect-month");
|
||||
for (var index = 0; index < months.length; index++) {
|
||||
months[index].removeEventListener("click", selectMonth);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
onParseConfig: function () {
|
||||
fp.config.enableTime = false;
|
||||
},
|
||||
onValueUpdate: setCurrentlySelected,
|
||||
onKeyDown: onKeyDown,
|
||||
onReady: [
|
||||
stubCurrentMonth,
|
||||
clearUnnecessaryDOMElements,
|
||||
build,
|
||||
bindEvents,
|
||||
setCurrentlySelected,
|
||||
function () {
|
||||
fp.config.onClose.push(closeHook);
|
||||
fp.loadedPlugins.push("monthSelect");
|
||||
},
|
||||
],
|
||||
onDestroy: [
|
||||
unstubCurrentMonth,
|
||||
destroyPluginInstance,
|
||||
function () {
|
||||
fp.config.onClose = fp.config.onClose.filter(function (hook) { return hook !== closeHook; });
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
return monthSelectPlugin;
|
||||
|
||||
})));
|
||||
+5
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+234
@@ -0,0 +1,234 @@
|
||||
.datatable-wrapper.no-header .datatable-container {
|
||||
border-top: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.datatable-wrapper.no-footer .datatable-container {
|
||||
border-bottom: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.datatable-top,
|
||||
.datatable-bottom {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
.datatable-top > nav:first-child,
|
||||
.datatable-top > div:first-child,
|
||||
.datatable-bottom > nav:first-child,
|
||||
.datatable-bottom > div:first-child {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.datatable-top > nav:last-child,
|
||||
.datatable-top > div:not(first-child),
|
||||
.datatable-bottom > nav:last-child,
|
||||
.datatable-bottom > div:last-child {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.datatable-selector {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.datatable-input {
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
.datatable-info {
|
||||
margin: 7px 0;
|
||||
}
|
||||
|
||||
/* PAGER */
|
||||
.datatable-pagination ul {
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.datatable-pagination li {
|
||||
list-style: none;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.datatable-pagination li.datatable-hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.datatable-pagination a,
|
||||
.datatable-pagination button {
|
||||
border: 1px solid transparent;
|
||||
float: left;
|
||||
margin-left: 2px;
|
||||
padding: 6px 12px;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.datatable-pagination a:hover,
|
||||
.datatable-pagination button:hover {
|
||||
background-color: #d9d9d9;
|
||||
}
|
||||
|
||||
.datatable-pagination .datatable-active a,
|
||||
.datatable-pagination .datatable-active a:focus,
|
||||
.datatable-pagination .datatable-active a:hover,
|
||||
.datatable-pagination .datatable-active button,
|
||||
.datatable-pagination .datatable-active button:focus,
|
||||
.datatable-pagination .datatable-active button:hover {
|
||||
background-color: #d9d9d9;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.datatable-pagination .datatable-ellipsis a,
|
||||
.datatable-pagination .datatable-disabled a,
|
||||
.datatable-pagination .datatable-disabled a:focus,
|
||||
.datatable-pagination .datatable-disabled a:hover,
|
||||
.datatable-pagination .datatable-ellipsis button,
|
||||
.datatable-pagination .datatable-disabled button,
|
||||
.datatable-pagination .datatable-disabled button:focus,
|
||||
.datatable-pagination .datatable-disabled button:hover {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.datatable-pagination .datatable-disabled a,
|
||||
.datatable-pagination .datatable-disabled a:focus,
|
||||
.datatable-pagination .datatable-disabled a:hover,
|
||||
.datatable-pagination .datatable-disabled button,
|
||||
.datatable-pagination .datatable-disabled button:focus,
|
||||
.datatable-pagination .datatable-disabled button:hover {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.datatable-pagination .datatable-pagination a,
|
||||
.datatable-pagination .datatable-pagination button {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* TABLE */
|
||||
.datatable-table {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: separate;
|
||||
}
|
||||
|
||||
.datatable-table > tbody > tr > td,
|
||||
.datatable-table > tbody > tr > th,
|
||||
.datatable-table > tfoot > tr > td,
|
||||
.datatable-table > tfoot > tr > th,
|
||||
.datatable-table > thead > tr > td,
|
||||
.datatable-table > thead > tr > th {
|
||||
vertical-align: top;
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
.datatable-table > thead > tr > th {
|
||||
vertical-align: bottom;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.datatable-table > tfoot > tr > th {
|
||||
vertical-align: bottom;
|
||||
text-align: left;
|
||||
border-top: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.datatable-table th {
|
||||
vertical-align: bottom;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.datatable-table th a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.datatable-table th button,
|
||||
.datatable-pagination-list button {
|
||||
color: inherit;
|
||||
border: 0;
|
||||
background-color: inherit;
|
||||
cursor: pointer;
|
||||
text-align: inherit;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.datatable-sorter, .datatable-filter {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.datatable-sorter::before,
|
||||
.datatable-sorter::after {
|
||||
content: "";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
|
||||
.datatable-sorter::before {
|
||||
border-top: 4px solid #000;
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
.datatable-sorter::after {
|
||||
border-bottom: 4px solid #000;
|
||||
border-top: 4px solid transparent;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.datatable-ascending .datatable-sorter::after,
|
||||
.datatable-descending .datatable-sorter::before,
|
||||
.datatable-ascending .datatable-filter::after,
|
||||
.datatable-descending .datatable-filter::before {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.datatable-filter::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
opacity: 0.2;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 7px solid transparent;
|
||||
border-right: 7px solid transparent;
|
||||
border-radius: 50%;
|
||||
border-top: 10px solid #000;
|
||||
top: 25%;
|
||||
}
|
||||
|
||||
.datatable-filter-active .datatable-filter::before {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.datatable-empty {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.datatable-top::after, .datatable-bottom::after {
|
||||
clear: both;
|
||||
content: " ";
|
||||
display: table;
|
||||
}
|
||||
|
||||
table.datatable-table:focus tr.datatable-cursor > td:first-child {
|
||||
border-left: 3px blue solid;
|
||||
}
|
||||
|
||||
table.datatable-table:focus {
|
||||
outline: solid 1px black;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
@php
|
||||
# Get Current USER
|
||||
$loggedUser = strtoUpper(m3_user());
|
||||
$loggedUser = strtoUpper(m3User());
|
||||
|
||||
$admin_users = $power_users = $csr = $execUser = "";
|
||||
$UserCO = $UserWHS = $UserPL = '';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user