fix(helpdesk): resolve contactNo from ticket for SOAP file authorization

BC's GetTicketFile requires a valid contactNo for authorization.
The endpoint now accepts ticketNo, loads the ticket via OData to get
Current_Contact_Name, looks up the contact's No, and passes it to
the SOAP call. Frontend includes ticketNo in the file download URL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-05 22:56:11 +02:00
parent 2b2f41ebab
commit f1c9c414a6
2 changed files with 27 additions and 2 deletions

View File

@@ -17,6 +17,7 @@ if ($request->method() !== 'GET') {
}
$entryNo = (int) $request->query('entryNo', '0');
$ticketNo = trim((string) $request->query('ticketNo', ''));
$filename = trim((string) $request->query('filename', ''));
if ($entryNo <= 0) {
@@ -27,9 +28,33 @@ if ($entryNo <= 0) {
}
$soapGateway = app(BcSoapGateway::class);
$odataGateway = app(\MintyPHP\Module\Helpdesk\Service\BcODataGateway::class);
// Resolve contactNo from ticket's Current_Contact_Name for SOAP authorization
$contactNo = '';
if ($ticketNo !== '') {
try {
$ticket = $odataGateway->getTicket($ticketNo);
if (is_array($ticket)) {
$contactName = trim((string) ($ticket['Current_Contact_Name'] ?? ''));
$customerName = trim((string) ($ticket['Company_Contact_Name'] ?? ''));
if ($contactName !== '' && $customerName !== '') {
$contacts = $odataGateway->getContactsForCustomer('', $customerName);
foreach ($contacts as $contact) {
if (trim((string) ($contact['Name'] ?? '')) === $contactName) {
$contactNo = trim((string) ($contact['No'] ?? ''));
break;
}
}
}
}
} catch (\Throwable) {
// Continue without contactNo — SOAP may still work
}
}
try {
$result = $soapGateway->getTicketFile($entryNo);
$result = $soapGateway->getTicketFile($entryNo, $contactNo);
} catch (\Throwable) {
http_response_code(502);
Router::json(['ok' => false, 'error' => 'Failed to load file']);

View File

@@ -118,7 +118,7 @@ export function renderCommunicationFeed(entries, options = {}) {
// File attachment: render download link and inline image for images
if (typeVariant === 'file' && fileDownloadUrl && entry.file_entry_no) {
const fileName = entry.file_name || 'attachment';
const fileUrl = fileDownloadUrl + '?entryNo=' + encodeURIComponent(entry.file_entry_no) + '&filename=' + encodeURIComponent(fileName);
const fileUrl = fileDownloadUrl + '?entryNo=' + encodeURIComponent(entry.file_entry_no) + '&ticketNo=' + encodeURIComponent(ticketNo) + '&filename=' + encodeURIComponent(fileName);
const ext = fileName.includes('.') ? fileName.split('.').pop().toLowerCase() : '';
const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'bmp'];
const isImage = imageExts.includes(ext);