mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git
synced 2026-08-19 04:23:55 +00:00
199 lines
7.4 KiB
PHP
199 lines
7.4 KiB
PHP
<?php
|
|
|
|
namespace App\Classes\Modules\Transactions\Processors;
|
|
|
|
use App\Classes\Modules\OpenAI\Services\UploadsOpenAIFiles;
|
|
use App\Classes\Modules\OpenAI\Services\CreatesChatGPTResponseWithFiles;
|
|
use App\Classes\Exceptions\ResourceNotFoundException;
|
|
use App\Classes\Modules\Bookings\Services\FetchesBooking;
|
|
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
|
|
use App\Classes\Modules\Transactions\Processors\CreatePurchaseOrderTransactionProcessor;
|
|
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
|
|
use App\Classes\ValueObjects\Constants\KVPKey;
|
|
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
|
use App\Classes\ValueObjects\Constants\PaymentMethodType;
|
|
use App\Classes\ValueObjects\Constants\TransactionType;
|
|
use App\Models\KeyValuePair;
|
|
use App\Models\Booking;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class ETLPDFPurchaseOrderTransactionProcessor
|
|
{
|
|
/** @var FetchesBooking */
|
|
private $fetchesBooking;
|
|
|
|
/** @var GeneratesTransactionBillNumber */
|
|
private $generatesTransactionBillNumber;
|
|
|
|
/** @var CreatePurchaseOrderTransactionProcessor */
|
|
private $createPurchaseOrderTransactionProcessor;
|
|
|
|
/** @var UploadsOpenAIFiles */
|
|
private $uploadsOpenAIFiles;
|
|
|
|
/** @var CreatesChatGPTResponseWithFiles */
|
|
private $createsChatGPTResponseWithFiles;
|
|
|
|
/**
|
|
* ETLPDFPurchaseOrderTransactionProcessor constructor.
|
|
* @param FetchesBooking $fetchesBooking
|
|
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
|
|
* @param CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor
|
|
* @param UploadsOpenAIFiles $uploadsOpenAIFiles
|
|
* @param CreatesChatGPTResponseWithFiles $createsChatGPTResponseWithFiles
|
|
*/
|
|
public function __construct(FetchesBooking $fetchesBooking, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor, UploadsOpenAIFiles $uploadsOpenAIFiles,
|
|
CreatesChatGPTResponseWithFiles $createsChatGPTResponseWithFiles)
|
|
{
|
|
$this->fetchesBooking = $fetchesBooking;
|
|
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
|
|
$this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor;
|
|
$this->uploadsOpenAIFiles = $uploadsOpenAIFiles;
|
|
$this->createsChatGPTResponseWithFiles = $createsChatGPTResponseWithFiles;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param UploadedFile[] $files
|
|
* @param int $bookingId
|
|
* @return array|null
|
|
*/
|
|
public function execute(array $files, ?int $bookingId = null): ?array
|
|
{
|
|
// Ensure temp directory exists
|
|
$tempDir = storage_path('app/documents');
|
|
if (!file_exists($tempDir)) {
|
|
mkdir($tempDir, 0755, true);
|
|
}
|
|
|
|
$tempPaths = [];
|
|
|
|
try {
|
|
foreach ($files as $index => $fileBase64) {
|
|
// Strip prefix if present
|
|
if (preg_match('/^data:application\/pdf;base64,/', $fileBase64)) {
|
|
$fileBase64 = preg_replace('/^data:application\/pdf;base64,/', '', $fileBase64);
|
|
}
|
|
|
|
// Decode Base64
|
|
$fileContent = base64_decode($fileBase64);
|
|
if ($fileContent === false) {
|
|
Log::warning("Invalid Base64 for file index $index");
|
|
continue;
|
|
}
|
|
|
|
// Ensure temp directory exists
|
|
$tempDir = storage_path('app/documents');
|
|
if (!file_exists($tempDir)) {
|
|
mkdir($tempDir, 0755, true);
|
|
}
|
|
|
|
// Generate unique temp file path
|
|
$fileName = uniqid("file_{$index}_") . '.pdf';
|
|
$filePath = $tempDir . '/' . $fileName;
|
|
|
|
// Save file to disk
|
|
file_put_contents($filePath, $fileContent);
|
|
|
|
// Track temp path
|
|
$tempPaths[] = $filePath;
|
|
}
|
|
|
|
Log::info('tempPaths: ' . json_encode($tempPaths));
|
|
|
|
// Upload to OpenAI
|
|
$fileIds = $this->uploadsOpenAIFiles->execute($tempPaths);
|
|
|
|
$kvp = KeyValuePair::where(
|
|
'key',
|
|
KVPKey::CHATGPT_PROMPT_PREFIX . 'EXTRACT_1'
|
|
)->first();
|
|
|
|
if (! $kvp) {
|
|
throw new ResourceNotFoundException('AI Setup incomplete!');
|
|
}
|
|
|
|
$userPrompt = $kvp->value;
|
|
$response = $this->createsChatGPTResponseWithFiles->execute($userPrompt, $fileIds);
|
|
|
|
// Extract the text content from the first output message
|
|
$textContent = $response['output'][0]['content'][0]['text'] ?? '[]';
|
|
|
|
// Remove ```json fences if present
|
|
if (preg_match('/```json\s*(.*?)\s*```/s', $textContent, $matches)) {
|
|
$jsonString = $matches[1];
|
|
} else {
|
|
$jsonString = $textContent;
|
|
}
|
|
|
|
// Decode JSON
|
|
$data = json_decode($jsonString, true);
|
|
|
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
Log::error('Failed to decode OpenAI JSON response', [
|
|
'error' => json_last_error_msg(),
|
|
'textContent' => $textContent
|
|
]);
|
|
$data = [];
|
|
}
|
|
|
|
// Optional: convert keys to snake_case
|
|
$data = array_map(function($item) {
|
|
$newItem = [];
|
|
foreach ($item as $key => $value) {
|
|
$newKey = strtolower(str_replace(' ', '_', $key));
|
|
$newItem[$newKey] = $value;
|
|
}
|
|
return $newItem;
|
|
}, $data);
|
|
|
|
if($bookingId){
|
|
/** @var Booking $booking */
|
|
$booking = $this->fetchesBooking->execute(['id' => $bookingId]);
|
|
|
|
$billNumber = $this->generatesTransactionBillNumber->execute('PO-');
|
|
|
|
$total = collect($data)->sum(function($product){
|
|
return $product['quantity'] * floatval(str_replace(',', '', $product['unit_price']));
|
|
});
|
|
|
|
$object = new TransactionObject($billNumber, TransactionType::PURCHASE_ORDER, $booking->company->id, 1,
|
|
1, PaymentMethodType::CASH,
|
|
$total, $total, $booking->fix_currency_id, $booking->fix_currency_id,
|
|
1, 0, 0, null, ApprovalStatus::PENDING_SUBMISSION, $data);
|
|
|
|
|
|
$transaction = $this->createPurchaseOrderTransactionProcessor->execute($booking, $object);
|
|
}
|
|
return $data;
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error('Error processing PDF files with ChatGPT', [
|
|
'message' => $e->getMessage(),
|
|
'trace' => $e->getTraceAsString(),
|
|
]);
|
|
throw $e;
|
|
} finally {
|
|
// Clean up
|
|
foreach ($tempPaths as $path) {
|
|
if (file_exists($path)) {
|
|
unlink($path);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function convertKeysToSnakeCase(array $items): array {
|
|
return array_map(function($item) {
|
|
$newItem = [];
|
|
foreach ($item as $key => $value) {
|
|
$newKey = strtolower(str_replace(' ', '_', $key));
|
|
$newItem[$newKey] = $value;
|
|
}
|
|
return $newItem;
|
|
}, $items);
|
|
}
|
|
}
|