From 127e16eb347422ef15bc09dac10d9ddf1f9ec1fe Mon Sep 17 00:00:00 2001 From: Yinyin Liu Date: Tue, 28 Apr 2026 09:09:03 +0200 Subject: [PATCH] add substeps to upload installation protocal and time and mateiral documents on site --- csharp/App/Backend/Controller.cs | 5 ++++- csharp/App/Backend/DataTypes/ChecklistStepDefinitions.cs | 8 +++++++- csharp/App/Backend/DataTypes/Document.cs | 1 + csharp/App/Backend/Database/Db.cs | 6 ++++++ csharp/App/Backend/Database/Read.cs | 5 +++-- .../frontend-marios2/src/components/FileUploadButton.tsx | 4 +++- .../src/content/dashboards/Checklist/ChecklistStepRow.tsx | 1 + .../dashboards/Checklist/SubtaskDocumentUpload.tsx | 8 +++++--- .../frontend-marios2/src/interfaces/ChecklistTypes.tsx | 4 +++- typescript/frontend-marios2/src/lang/de.json | 2 ++ typescript/frontend-marios2/src/lang/en.json | 2 ++ typescript/frontend-marios2/src/lang/fr.json | 2 ++ typescript/frontend-marios2/src/lang/it.json | 2 ++ 13 files changed, 41 insertions(+), 9 deletions(-) diff --git a/csharp/App/Backend/Controller.cs b/csharp/App/Backend/Controller.cs index 8c65f89c3..d1a9d51c3 100644 --- a/csharp/App/Backend/Controller.cs +++ b/csharp/App/Backend/Controller.cs @@ -2599,6 +2599,7 @@ public class Controller : ControllerBase [FromQuery] Int64? ticketCommentId, [FromQuery] Int64? installationId, [FromQuery] Int64? checklistItemId, + [FromQuery] String? subtaskKey, [FromQuery] Token authToken) { var user = Db.GetSession(authToken)?.User; @@ -2678,6 +2679,7 @@ public class Controller : ControllerBase TicketCommentId = ticketCommentId, InstallationId = installationId, ChecklistItemId = checklistItemId, + SubtaskKey = subtaskKey, Scope = scope, S3Key = s3Key, OriginalName = safeFileName, @@ -2728,6 +2730,7 @@ public class Controller : ControllerBase [FromQuery] Int64? ticketCommentId, [FromQuery] Int64? installationId, [FromQuery] Int64? checklistItemId, + [FromQuery] String? subtaskKey, [FromQuery] Token authToken) { var user = Db.GetSession(authToken)?.User; @@ -2742,7 +2745,7 @@ public class Controller : ControllerBase if (checklistItemId.HasValue) { if (user.UserType != 2) return Unauthorized(); - return Ok(Db.GetDocumentsForChecklistItem(checklistItemId.Value)); + return Ok(Db.GetDocumentsForChecklistItem(checklistItemId.Value, subtaskKey)); } if (installationId.HasValue) diff --git a/csharp/App/Backend/DataTypes/ChecklistStepDefinitions.cs b/csharp/App/Backend/DataTypes/ChecklistStepDefinitions.cs index 326205270..f1cbdc9bf 100644 --- a/csharp/App/Backend/DataTypes/ChecklistStepDefinitions.cs +++ b/csharp/App/Backend/DataTypes/ChecklistStepDefinitions.cs @@ -48,7 +48,13 @@ public static class ChecklistStepDefinitions ] """), new( 9, "Installation connected to grid", NoSubtasks), - new(10, "Hardware verified on site", NoSubtasks), + new(10, "Hardware verified on site", + """ + [ + {"text":"checklistStep10Sub1","checked":false}, + {"text":"checklistStep10Sub2","checked":false} + ] + """), new(11, "Software verified on site", NoSubtasks), new(12, "Installation online on Monitor", NoSubtasks), new(13, "Customer informed about Monitor account and reports", NoSubtasks), diff --git a/csharp/App/Backend/DataTypes/Document.cs b/csharp/App/Backend/DataTypes/Document.cs index cb266adb8..4a7e8ecf7 100644 --- a/csharp/App/Backend/DataTypes/Document.cs +++ b/csharp/App/Backend/DataTypes/Document.cs @@ -16,6 +16,7 @@ public class Document [Indexed] public Int64? TicketCommentId { get; set; } [Indexed] public Int64? InstallationId { get; set; } [Indexed] public Int64? ChecklistItemId { get; set; } + public String? SubtaskKey { get; set; } public Int32 Scope { get; set; } = (Int32)DocumentScope.TicketAttachment; public String S3Key { get; set; } = ""; diff --git a/csharp/App/Backend/Database/Db.cs b/csharp/App/Backend/Database/Db.cs index 36ad9dfcb..6e4d9b13a 100644 --- a/csharp/App/Backend/Database/Db.cs +++ b/csharp/App/Backend/Database/Db.cs @@ -142,6 +142,12 @@ public static partial class Db "UPDATE ChecklistItem SET Subtasks = ? WHERE StepNumber = 8 AND (Subtasks IS NULL OR Subtasks = '')", "[{\"text\":\"checklistStep8Sub1\",\"checked\":false}]"); + // One-time backfill: step 10 originally had no subtasks; add the two upload subtasks + // (installation protocol + time & material report) to existing rows. + Connection.Execute( + "UPDATE ChecklistItem SET Subtasks = ? WHERE StepNumber = 10 AND (Subtasks IS NULL OR Subtasks = '')", + "[{\"text\":\"checklistStep10Sub1\",\"checked\":false},{\"text\":\"checklistStep10Sub2\",\"checked\":false}]"); + //UpdateKeys(); CleanupSessions().SupressAwaitWarning(); DeleteSnapshots().SupressAwaitWarning(); diff --git a/csharp/App/Backend/Database/Read.cs b/csharp/App/Backend/Database/Read.cs index 3843cadbd..9c2cf48f2 100644 --- a/csharp/App/Backend/Database/Read.cs +++ b/csharp/App/Backend/Database/Read.cs @@ -234,10 +234,11 @@ public static partial class Db .OrderBy(d => d.CreatedAt) .ToList(); - public static List GetDocumentsForChecklistItem(Int64 checklistItemId) + public static List GetDocumentsForChecklistItem(Int64 checklistItemId, String? subtaskKey = null) => Documents .Where(d => d.ChecklistItemId == checklistItemId - && d.Scope == (Int32)DocumentScope.InstallationDocument) + && d.Scope == (Int32)DocumentScope.InstallationDocument + && (subtaskKey == null || d.SubtaskKey == subtaskKey)) .OrderBy(d => d.CreatedAt) .ToList(); diff --git a/typescript/frontend-marios2/src/components/FileUploadButton.tsx b/typescript/frontend-marios2/src/components/FileUploadButton.tsx index 218804b70..992531db4 100644 --- a/typescript/frontend-marios2/src/components/FileUploadButton.tsx +++ b/typescript/frontend-marios2/src/components/FileUploadButton.tsx @@ -33,6 +33,7 @@ interface FileUploadButtonProps { ticketCommentId?: number; installationId?: number; checklistItemId?: number; + subtaskKey?: string; onUploaded?: (doc: UploadedDocument) => void; disabled?: boolean; } @@ -43,6 +44,7 @@ function FileUploadButton({ ticketCommentId, installationId, checklistItemId, + subtaskKey, onUploaded, disabled = false }: FileUploadButtonProps) { @@ -89,7 +91,7 @@ function FileUploadButton({ try { const res = await axiosConfig.post('/UploadDocument', formData, { - params: { scope, ticketId, ticketCommentId, installationId, checklistItemId }, + params: { scope, ticketId, ticketCommentId, installationId, checklistItemId, subtaskKey }, headers: { 'Content-Type': 'multipart/form-data' }, onUploadProgress: (e) => { if (e.total) setProgress(Math.round((e.loaded * 100) / e.total)); diff --git a/typescript/frontend-marios2/src/content/dashboards/Checklist/ChecklistStepRow.tsx b/typescript/frontend-marios2/src/content/dashboards/Checklist/ChecklistStepRow.tsx index baf585590..559c0aada 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Checklist/ChecklistStepRow.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Checklist/ChecklistStepRow.tsx @@ -305,6 +305,7 @@ function ChecklistStepRow({ item, installationId, adminUsers, onUpdate, onNotify )} diff --git a/typescript/frontend-marios2/src/content/dashboards/Checklist/SubtaskDocumentUpload.tsx b/typescript/frontend-marios2/src/content/dashboards/Checklist/SubtaskDocumentUpload.tsx index c5978902f..4f73f0c51 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Checklist/SubtaskDocumentUpload.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Checklist/SubtaskDocumentUpload.tsx @@ -20,6 +20,7 @@ interface DocumentItem { interface Props { installationId: number; checklistItemId: number; + subtaskKey: string; } function fileIcon(contentType: string) { @@ -28,18 +29,18 @@ function fileIcon(contentType: string) { return ; } -function SubtaskDocumentUpload({ installationId, checklistItemId }: Props) { +function SubtaskDocumentUpload({ installationId, checklistItemId, subtaskKey }: Props) { const [docs, setDocs] = useState([]); const [refreshKey, setRefreshKey] = useState(0); const fetchDocs = useCallback(() => { axiosConfig - .get('/GetDocuments', { params: { checklistItemId } }) + .get('/GetDocuments', { params: { checklistItemId, subtaskKey } }) .then((res) => { if (Array.isArray(res.data)) setDocs(res.data); }) .catch(() => setDocs([])); - }, [checklistItemId]); + }, [checklistItemId, subtaskKey]); useEffect(() => { fetchDocs(); @@ -100,6 +101,7 @@ function SubtaskDocumentUpload({ installationId, checklistItemId }: Props) { scope={1} installationId={installationId} checklistItemId={checklistItemId} + subtaskKey={subtaskKey} onUploaded={handleUploaded} /> diff --git a/typescript/frontend-marios2/src/interfaces/ChecklistTypes.tsx b/typescript/frontend-marios2/src/interfaces/ChecklistTypes.tsx index 61b54cceb..3c1583a7c 100644 --- a/typescript/frontend-marios2/src/interfaces/ChecklistTypes.tsx +++ b/typescript/frontend-marios2/src/interfaces/ChecklistTypes.tsx @@ -26,7 +26,9 @@ export type ChecklistItem = { export const CHECKLIST_ENABLED_PRODUCTS: ReadonlySet = new Set([2, 4, 5]); export const UPLOADABLE_SUBTASK_KEYS: ReadonlySet = new Set([ - 'checklistStep8Sub1' + 'checklistStep8Sub1', + 'checklistStep10Sub1', + 'checklistStep10Sub2' ]); export type ChecklistSummary = { diff --git a/typescript/frontend-marios2/src/lang/de.json b/typescript/frontend-marios2/src/lang/de.json index 9b25cf16e..bacaab0c1 100644 --- a/typescript/frontend-marios2/src/lang/de.json +++ b/typescript/frontend-marios2/src/lang/de.json @@ -744,6 +744,8 @@ "checklistStep7Sub3": "USB-ID in config.json konfiguriert", "checklistStep7Sub4": "Datenlesung vom Wechselrichter getestet", "checklistStep8Sub1": "Lieferschein mit Kundenunterschrift erhalten und hochgeladen", + "checklistStep10Sub1": "Installationsprotokoll hochgeladen", + "checklistStep10Sub2": "Zeit- und Materialbericht in Monitoring hochgeladen", "checklistNoAttachments": "Noch keine Datei angehängt.", "setupProgress": "Setup-Fortschritt", "checklistPhaseEmpty": "Nicht gestartet", diff --git a/typescript/frontend-marios2/src/lang/en.json b/typescript/frontend-marios2/src/lang/en.json index 8ff092980..a78013c56 100644 --- a/typescript/frontend-marios2/src/lang/en.json +++ b/typescript/frontend-marios2/src/lang/en.json @@ -492,6 +492,8 @@ "checklistStep7Sub3": "USB ID configured in config.json", "checklistStep7Sub4": "Inverter data reading from inverter tested", "checklistStep8Sub1": "Delivery receipt with customer signature received and uploaded", + "checklistStep10Sub1": "Installation protocol uploaded", + "checklistStep10Sub2": "Time and material report uploaded to Monitoring", "checklistNoAttachments": "No file attached yet.", "setupProgress": "Setup Progress", "checklistPhaseEmpty": "Not started", diff --git a/typescript/frontend-marios2/src/lang/fr.json b/typescript/frontend-marios2/src/lang/fr.json index ede82ad71..10281a664 100644 --- a/typescript/frontend-marios2/src/lang/fr.json +++ b/typescript/frontend-marios2/src/lang/fr.json @@ -744,6 +744,8 @@ "checklistStep7Sub3": "ID USB configuré dans config.json", "checklistStep7Sub4": "Lecture des données de l'onduleur testée", "checklistStep8Sub1": "Bon de livraison signé par le client reçu et téléversé", + "checklistStep10Sub1": "Procès-verbal d'installation téléversé", + "checklistStep10Sub2": "Rapport de temps et matériaux téléversé dans Monitoring", "checklistNoAttachments": "Aucun fichier joint pour le moment.", "setupProgress": "Progression installation", "checklistPhaseEmpty": "Non commencé", diff --git a/typescript/frontend-marios2/src/lang/it.json b/typescript/frontend-marios2/src/lang/it.json index 999b8e60d..99e1f1002 100644 --- a/typescript/frontend-marios2/src/lang/it.json +++ b/typescript/frontend-marios2/src/lang/it.json @@ -744,6 +744,8 @@ "checklistStep7Sub3": "ID USB configurato in config.json", "checklistStep7Sub4": "Lettura dati inverter testata", "checklistStep8Sub1": "Bolla di consegna con firma del cliente ricevuta e caricata", + "checklistStep10Sub1": "Verbale di installazione caricato", + "checklistStep10Sub2": "Rapporto tempi e materiali caricato su Monitoring", "checklistNoAttachments": "Nessun file allegato.", "setupProgress": "Avanzamento installazione", "checklistPhaseEmpty": "Non avviato",