M3 Integration fixes
This commit is contained in:
Executable
+99
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\M3\Services;
|
||||
|
||||
use setasign\Fpdi\Fpdi;
|
||||
use Storage;
|
||||
|
||||
class BillOfLadingService
|
||||
{
|
||||
public function fillBillOfLading(array $data, ?string $outputPath = null): string
|
||||
{
|
||||
$templatePath = Storage::disk('public')->path('ETN-BOL2.pdf');
|
||||
$newFile = 'BOL_' . ($data['bol_number'] ?? 'unknown') . '.pdf';
|
||||
$outputPath ??= Storage::disk('public')->path($newFile);
|
||||
|
||||
$pdf = new Fpdi;
|
||||
$pdf->setSourceFile($templatePath);
|
||||
|
||||
$this->renderPage($pdf, $data, 1, true);
|
||||
$this->renderPage($pdf, $data, 2, false);
|
||||
$pdf->Output('F', $outputPath);
|
||||
|
||||
return $outputPath;
|
||||
}
|
||||
|
||||
private function renderPage(Fpdi $pdf, array $data, int $pageNumber, bool $includeLineDetails): void
|
||||
{
|
||||
$template = $pdf->importPage($pageNumber);
|
||||
$pdf->AddPage();
|
||||
$pdf->useTemplate($template);
|
||||
$pdf->SetFont('Helvetica', '', 10);
|
||||
$pdf->SetTextColor(0, 0, 0);
|
||||
|
||||
foreach ($this->headerFields() as $field => [$x, $y]) {
|
||||
$this->writeField($pdf, $data, $field, $x, $y);
|
||||
}
|
||||
|
||||
if ($includeLineDetails) {
|
||||
foreach ($this->lineFields() as $field => [$x, $y]) {
|
||||
$this->writeField($pdf, $data, $field, $x, $y);
|
||||
}
|
||||
$this->writeDescription($pdf, $data);
|
||||
}
|
||||
}
|
||||
|
||||
private function writeField(Fpdi $pdf, array $data, string $field, float $x, float $y): void
|
||||
{
|
||||
if (! array_key_exists($field, $data) || $data[$field] === null || $data[$field] === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$pdf->SetXY($x, $y);
|
||||
$pdf->Write(0, (string) $data[$field]);
|
||||
}
|
||||
|
||||
private function writeDescription(Fpdi $pdf, array $data): void
|
||||
{
|
||||
$description = $data['description'] ?? null;
|
||||
if ($description === null || $description === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$pdf->SetXY(28, 140);
|
||||
$pdf->MultiCell(67, 4.5, (string) $description, 0, 'L');
|
||||
}
|
||||
|
||||
private function headerFields(): array
|
||||
{
|
||||
return [
|
||||
'bol_number' => [126, 44],
|
||||
'date' => [171, 44],
|
||||
'shipper_no' => [126, 53],
|
||||
'master_bill_no' => [172, 54],
|
||||
'master_bill_yes' => [183, 54],
|
||||
'master_bill_drops' => [194, 55],
|
||||
'consignor_name' => [21, 44],
|
||||
'consignor_address1' => [21, 48],
|
||||
'consignor_address2' => [21, 52],
|
||||
'consignor_address3' => [21, 56],
|
||||
'consignee_name' => [21, 72],
|
||||
'consignee_address1' => [21, 76],
|
||||
'consignee_address2' => [21, 80],
|
||||
'consignee_address3' => [21, 84],
|
||||
'freight_collect' => [127, 90],
|
||||
'carrier_name' => [10, 100],
|
||||
];
|
||||
}
|
||||
|
||||
private function lineFields(): array
|
||||
{
|
||||
return [
|
||||
'pieces' => [6, 142],
|
||||
'line_class' => [145, 142],
|
||||
'line_weight' => [177, 142],
|
||||
'total_pieces' => [6, 244],
|
||||
'total_line_weight' => [177, 244],
|
||||
];
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\M3\Services;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* PostgreSQL replacement for the old IBM i Toolkit program-call transport.
|
||||
*
|
||||
* The legacy M3 code invokes IBM i programs after writing PostgreSQL-backed
|
||||
* staging data. Core no longer connects to DB2. These requests are persisted
|
||||
* so a PostgreSQL-native worker/integration can process them without making
|
||||
* the web request depend on IBM i drivers.
|
||||
*/
|
||||
class PostgresProgramBridge
|
||||
{
|
||||
private string $errorCode = '';
|
||||
|
||||
private string $errorMessage = '';
|
||||
|
||||
public function setOptions(array $options): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function AddParameterChar(string $io, int $size, string $comment = '', string $name = '', mixed $value = null, mixed ...$rest): array
|
||||
{
|
||||
return compact('io', 'size', 'comment', 'name', 'value');
|
||||
}
|
||||
|
||||
public function AddParameterPackDec(string $io, int $length, int $scale, string $comment = '', string $name = '', mixed $value = null, mixed ...$rest): array
|
||||
{
|
||||
return compact('io', 'length', 'scale', 'comment', 'name', 'value');
|
||||
}
|
||||
|
||||
public function AddParameterZoned(string $io, int $length, int $scale, string $comment = '', string $name = '', mixed $value = null, mixed ...$rest): array
|
||||
{
|
||||
return compact('io', 'length', 'scale', 'comment', 'name', 'value');
|
||||
}
|
||||
|
||||
public function PgmCall(string $program, ?string $library = null, array $parameters = [], array $returnParameters = [], array $options = []): array|false
|
||||
{
|
||||
return $this->queue('program', $program, $library, [
|
||||
'parameters' => $parameters,
|
||||
'return_parameters' => $returnParameters,
|
||||
'options' => $options,
|
||||
]);
|
||||
}
|
||||
|
||||
public function CLCommand(string $command): array|false
|
||||
{
|
||||
return $this->queue('command', $command, null, []);
|
||||
}
|
||||
|
||||
public function getErrorCode(): string
|
||||
{
|
||||
return $this->errorCode;
|
||||
}
|
||||
|
||||
public function getErrorMsg(): string
|
||||
{
|
||||
return $this->errorMessage;
|
||||
}
|
||||
|
||||
private function queue(string $type, string $operation, ?string $library, array $payload): array|false
|
||||
{
|
||||
try {
|
||||
$record = [
|
||||
'type' => $type,
|
||||
'operation' => $operation,
|
||||
'library' => $library,
|
||||
'payload' => json_encode($payload, JSON_THROW_ON_ERROR),
|
||||
'requested_by' => function_exists('m3_user') ? m3_user() : null,
|
||||
'status' => 'pending',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
];
|
||||
|
||||
if (Schema::connection(config('m3.connection', 'pgsql'))->hasTable('m3_program_requests')) {
|
||||
$id = DB::connection(config('m3.connection', 'pgsql'))
|
||||
->table('m3_program_requests')
|
||||
->insertGetId($record);
|
||||
} else {
|
||||
Log::warning('M3 PostgreSQL program bridge table is not migrated; request logged only.', $record);
|
||||
$id = null;
|
||||
}
|
||||
|
||||
return ['success' => true, 'queued' => true, 'request_id' => $id, 'io_param' => []];
|
||||
} catch (\Throwable $e) {
|
||||
$this->errorCode = (string) $e->getCode();
|
||||
$this->errorMessage = $e->getMessage();
|
||||
Log::error('Unable to queue M3 program request.', ['exception' => $e]);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\M3\Services;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
class SpreadsheetExport
|
||||
{
|
||||
private const EXPORT_DIRECTORY = 'app/m3-exports/';
|
||||
|
||||
public function download(Collection $rows, string $filename): BinaryFileResponse
|
||||
{
|
||||
$path = storage_path(self::EXPORT_DIRECTORY . uniqid('', true) . '-' . basename($filename));
|
||||
$this->write($rows, $path);
|
||||
|
||||
return response()->download($path, basename($filename))->deleteFileAfterSend(true);
|
||||
}
|
||||
|
||||
public function store(Collection $rows, string $filename, ?string $disk = null): string
|
||||
{
|
||||
$tmp = storage_path(self::EXPORT_DIRECTORY . uniqid('', true) . '-' . basename($filename));
|
||||
$this->write($rows, $tmp);
|
||||
|
||||
if ($disk && config("filesystems.disks.$disk")) {
|
||||
Storage::disk($disk)->put($filename, file_get_contents($tmp));
|
||||
@unlink($tmp);
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
public function storeSheets(array $sheets, string $filename, ?string $disk = null): string
|
||||
{
|
||||
$book = new Spreadsheet;
|
||||
$book->removeSheetByIndex(0);
|
||||
foreach ($sheets as $title => $rows) {
|
||||
$sheet = $book->createSheet();
|
||||
$sheet->setTitle(substr((string) $title, 0, 31));
|
||||
$array = collect($rows)->map(fn ($row) => (array) $row)->values();
|
||||
if ($array->isNotEmpty()) {
|
||||
$sheet->fromArray($array->map(fn ($row) => array_values($row))->all(), null, 'A1');
|
||||
}
|
||||
}
|
||||
$tmp = storage_path(self::EXPORT_DIRECTORY . uniqid('', true) . '-' . basename($filename));
|
||||
if (! is_dir(dirname($tmp))) {
|
||||
mkdir(dirname($tmp), 0775, true);
|
||||
}
|
||||
(new Xlsx($book))->save($tmp);
|
||||
if ($disk && config("filesystems.disks.$disk")) {
|
||||
Storage::disk($disk)->put($filename, file_get_contents($tmp));
|
||||
@unlink($tmp);
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
private function write(Collection $rows, string $path): void
|
||||
{
|
||||
if (! is_dir(dirname($path))) {
|
||||
mkdir(dirname($path), 0775, true);
|
||||
}
|
||||
|
||||
$sheet = (new Spreadsheet)->getActiveSheet();
|
||||
$array = $rows->map(fn ($row) => (array) $row)->values();
|
||||
$headers = $array->first() ? array_keys($array->first()) : [];
|
||||
if ($headers) {
|
||||
$sheet->fromArray($headers, null, 'A1');
|
||||
$sheet->fromArray($array->map(fn ($row) => array_values($row))->all(), null, 'A2');
|
||||
}
|
||||
(new Xlsx($sheet->getParent()))->save($path);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user