From 884c113a03d78e7a6cd0b0d0320d32ebe94167be Mon Sep 17 00:00:00 2001
From: nguyentrungthat <80239428+nguentrungthat@users.noreply.github.com>
Date: Thu, 14 May 2026 10:23:22 +0700
Subject: [PATCH] =?UTF-8?q?Update=20form=20report=20summary,=20g=E1=BA=AFn?=
=?UTF-8?q?=20api?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
BACKEND/app/services/line_connection.ts | 89 +++++++++++++++++--------
BACKEND/app/ultils/helper.ts | 32 +++++++++
BACKEND/providers/socket_io_provider.ts | 7 +-
3 files changed, 95 insertions(+), 33 deletions(-)
diff --git a/BACKEND/app/services/line_connection.ts b/BACKEND/app/services/line_connection.ts
index 8f32213..0d09fae 100644
--- a/BACKEND/app/services/line_connection.ts
+++ b/BACKEND/app/services/line_connection.ts
@@ -11,6 +11,7 @@ import {
detectConfigRamByModel,
detectScenarioByModel,
escapeHtml,
+ getIncomingInfoBySN,
isRamSufficient,
isValidJson,
LogStreamBuffer,
@@ -1933,6 +1934,14 @@ Ports Missing/Down: ${missing.length}\n\n`
const totalPoE = testedPoE.length + missingPoE.length
const totalSFP = testedSFP.length + missingSFP.length
+ const dataIncomingBySN = await getIncomingInfoBySN(config?.inventory?.sn)
+ const serialInfo = dataIncomingBySN?.serialNumbersInfo?.find(
+ (s: any) => s.serialNumberA === config?.inventory?.sn
+ )
+ const listImages = dataIncomingBySN?.packagePo?.listFiles?.filter(
+ (s: any) => s.kind === 'other'
+ )
+
const showVersion = config?.data?.find(
(d) => d.command?.trim()?.includes('show ver') || d.command?.trim()?.includes('sh ver')
)
@@ -2077,13 +2086,20 @@ Ports Missing/Down: ${missing.length}\n\n`
// Physical Check checklist
const checklistItems: Array<[string, string]> = [
- ['ok', 'Packaging intact — no damage to box or foam'],
- ['ok', 'No physical damage — chassis, fans, PSU'],
- ['ok', `S/N matches label — ${productSN} verified`],
- ['ok', 'All 48 GigE + 4 SFP+ ports clean'],
- ['ok', 'Accessories — power cable, rack ears, console cable'],
- ['warn', 'Minor scratch on top chassis (2cm) — cosmetic only'],
+ [
+ serialInfo?.optionVisualInspection?.statusChassis ? 'ok' : 'warn',
+ serialInfo?.optionVisualInspection?.statusChassis
+ ? 'Overall hardware status is normal'
+ : 'Hardware issue detected on chassis/system',
+ ],
+ [
+ serialInfo?.optionVisualInspection?.statusPortsPOE ? 'ok' : 'warn',
+ serialInfo?.optionVisualInspection?.statusPortsPOE
+ ? 'All ports and PoE functions are operating normally'
+ : 'Port or PoE issue detected',
+ ],
]
+
const checklistRowsHtml = checklistItems
.map(([k, t]) =>
k === 'ok'
@@ -2096,6 +2112,30 @@ Ports Missing/Down: ${missing.length}\n\n`
const photoCellHtml = (label: string) =>
`
`
+ // Photo cell with actual image
+ const imageCellHtml = (url: string, label: string) =>
+ ` `
+
+ // Prepare image grid: get first 4 images from listImages if available
+ const imageList = listImages && Array.isArray(listImages) ? listImages.slice(0, 4) : []
+ const imageLabels = ['Front', 'Rear', 'S/N Label', 'Package']
+ const getPhotoCell = (idx: number) => {
+ const image = imageList[idx]
+ const label = imageLabels[idx]
+ return image && image.url
+ ? imageCellHtml(process.env.ERP_URL + image.url, label)
+ : photoCellHtml(label)
+ }
+ const photoGridRowsHtml = `
+
+ ${getPhotoCell(0)}
+ ${getPhotoCell(1)}
+
+
+ ${getPhotoCell(2)}
+ ${getPhotoCell(3)}
+ `
+
// Helper function to highlight SNs from listInventory in outputTestLog
const highlightSnInConsoleOutput = (text: string, listInventory: any[] | undefined) => {
if (!text || !listInventory || listInventory.length === 0) {
@@ -2184,8 +2224,8 @@ Ports Missing/Down: ${missing.length}\n\n`
P/N ${productPN}
S/N ${productSN}
MAC ${macAddress || '-'}
- Cond. ${'-'}
- Supplier ${'-'}
+ Cond. ${serialInfo?.condition || '-'}
+ Supplier ${serialInfo?.supplier?.name || '-'}
@@ -2240,9 +2280,10 @@ Ports Missing/Down: ${missing.length}\n\n`
Receiving & Inspection Notes
⚠ Warning from Warehouse
-
Box arrived with slight indentation on the left corner. Internal foam was still intact. Serial number on box was partially obscured by shipping label but verified upon unboxing.
-
Not Available
-
+ ${dataIncomingBySN?.packagePo?.notes || ''}
+ ${serialInfo?.notes || ''}
+ ${!dataIncomingBySN?.packagePo?.notes && !serialInfo?.notes ? 'No notes available.
' : ''}
+
Accessory Checklist
@@ -2287,10 +2328,10 @@ Ports Missing/Down: ${missing.length}\n\n`
Received
- Not Available
+ ${dataIncomingBySN?.packagePo?.receivedBy?.fullName || 'Unknown'}
- ${momentTZ().tz(timeZone).format('DD MMM')}
+ ${dataIncomingBySN?.packagePo?.receivedDate ? momentTZ(dataIncomingBySN?.packagePo?.receivedDate).tz(timeZone).format('DD MMM, HH:mm') : ''}
@@ -2303,10 +2344,10 @@ Ports Missing/Down: ${missing.length}\n\n`
Visual Check
- Not Available
+ ${dataIncomingBySN?.packagePo?.receivedBy?.fullName || 'Unknown'}
- ${momentTZ().tz(timeZone).format('DD MMM')}
+ ${dataIncomingBySN?.packagePo?.receivedDate ? momentTZ(dataIncomingBySN?.packagePo?.receivedDate).tz(timeZone).format('DD MMM, HH:mm') : ''}
@@ -2318,7 +2359,7 @@ Ports Missing/Down: ${missing.length}\n\n`
Software Test
- ${this?.userTest?.dpelp?.name || ''}
+ ${this?.userTest?.dpelp?.name || 'Unknown'}
${momentTZ(this?.userTest?.dpelp?.time).tz(timeZone).format('DD MMM, HH:mm')}
@@ -2351,29 +2392,19 @@ Ports Missing/Down: ${missing.length}\n\n`
Visual Check
-
${this?.userTest?.physical?.name || ''} · ${momentTZ(this?.userTest?.physical?.time).tz(timeZone).format('DD MMM, HH:mm')}
-
Not Available
+
${dataIncomingBySN?.packagePo?.receivedBy?.fullName || 'Unknown'} · ${dataIncomingBySN?.packagePo?.receivedDate ? momentTZ(dataIncomingBySN?.packagePo?.receivedDate).tz(timeZone).format('DD MMM, HH:mm') : ''}
-
- ${photoCellHtml('Front')}
- ${photoCellHtml('Rear')}
-
-
- ${photoCellHtml('S/N Label')}
- ${photoCellHtml('Package')}
-
+ ${photoGridRowsHtml}
-
+
${checklistRowsHtml}
- Not Available
-
diff --git a/BACKEND/app/ultils/helper.ts b/BACKEND/app/ultils/helper.ts
index 39bbfe3..2374ac8 100644
--- a/BACKEND/app/ultils/helper.ts
+++ b/BACKEND/app/ultils/helper.ts
@@ -1437,3 +1437,35 @@ export function canInputCommand(buffer: string): boolean {
return false
}
+
+export async function getIncomingInfoBySN(sn: string) {
+ try {
+ if (!sn) return
+ const remoteUrl = process.env.ERP_URL || 'https://stage.nswteam.net'
+ const header = {
+ Authorization: 'Bearer ' + process.env.ERP_TOKEN,
+ }
+ const responseDataSN = await axios.post(
+ remoteUrl + '/api/transferGetData',
+ {
+ urlAPI: '/api/package-po/get-incoming-by-sn',
+ filter: {
+ where: {
+ serialNumber: sn,
+ },
+ },
+ },
+ {
+ headers: header,
+ }
+ )
+
+ if (!responseDataSN?.data?.data) {
+ return
+ }
+
+ return responseDataSN?.data?.data
+ } catch (error) {
+ console.log('getIncomingInfoBySN', error)
+ }
+}
diff --git a/BACKEND/providers/socket_io_provider.ts b/BACKEND/providers/socket_io_provider.ts
index f8a3df5..aef7d6c 100644
--- a/BACKEND/providers/socket_io_provider.ts
+++ b/BACKEND/providers/socket_io_provider.ts
@@ -1447,8 +1447,8 @@ export class WebSocketIo {
*/
generateZulipMessage(results: any[]) {
let msg = ``
- msg += `| Line | PID | SN | MAC | IOS | License | Summary | Issues |\n`
- msg += `| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |\n`
+ msg += `| Line | PID | SN | MAC | IOS | License | Issues |\n`
+ msg += `| ---- | ---- | ---- | ---- | ---- | ---- | ---- |\n`
for (const item of results) {
if (!item) continue
@@ -1464,7 +1464,7 @@ export class WebSocketIo {
// Format issues
const issuesMd = item.issues?.length
- ? item.issues.map((i: string) => `• ${i}`).join(' --')
+ ? item.issues.map((i: string) => `• ${i.replace('|', '')}`).join(' --')
: '- No issues detected.'
msg +=
@@ -1474,7 +1474,6 @@ export class WebSocketIo {
` | ${item.mac || ''}` +
` | ${item.ios || ''}` +
` | ${licenseMd}` +
- ` | ${item.summary || ''}` +
` | ${issuesMd}` +
` |\n`
}