From 2e5b345daaccfc4ffc73d031a8b2ccb87ede916b Mon Sep 17 00:00:00 2001
From: Julian Krauser <jkrauser209@gmail.com>
Date: Fri, 21 Mar 2025 09:46:29 +0100
Subject: [PATCH] add sorting to protocol agenda, decision and votings

---
 .../club/protocol/protocolAgendaCommand.ts    |  1 +
 .../protocol/protocolAgendaCommandHandler.ts  |  5 +++-
 .../club/protocol/protocolDecisionCommand.ts  |  1 +
 .../protocolDecisionCommandHandler.ts         |  5 +++-
 .../club/protocol/protocolVotingCommand.ts    |  1 +
 .../protocol/protocolVotingCommandHandler.ts  |  5 +++-
 .../admin/club/protocolController.ts          | 23 ++++++++-------
 src/data-source.ts                            |  2 ++
 src/entity/club/protocol/protocolAgenda.ts    |  3 ++
 src/entity/club/protocol/protocolDecision.ts  |  3 ++
 src/entity/club/protocol/protocolVoting.ts    |  3 ++
 .../admin/club/protocol/protocolAgenda.ts     |  1 +
 .../admin/club/protocol/protocolDecision.ts   |  1 +
 .../admin/club/protocol/protocolVoting.ts     |  1 +
 src/helpers/backupHelper.ts                   | 13 +++++++--
 src/migrations/1742544887410-protocolSort.ts  | 29 +++++++++++++++++++
 .../club/protocol/protocolAgendaService.ts    | 18 ++++++++++++
 .../club/protocol/protocolDecisionService.ts  | 18 ++++++++++++
 .../club/protocol/protocolVotingService.ts    | 18 ++++++++++++
 .../club/protocol/protocolAgenda.models.ts    |  1 +
 .../club/protocol/protocolDecision.models.ts  |  1 +
 .../club/protocol/protocolVoting.models.ts    |  1 +
 22 files changed, 138 insertions(+), 16 deletions(-)
 create mode 100644 src/migrations/1742544887410-protocolSort.ts

diff --git a/src/command/club/protocol/protocolAgendaCommand.ts b/src/command/club/protocol/protocolAgendaCommand.ts
index 749390d..2889122 100644
--- a/src/command/club/protocol/protocolAgendaCommand.ts
+++ b/src/command/club/protocol/protocolAgendaCommand.ts
@@ -2,5 +2,6 @@ export interface SynchronizeProtocolAgendaCommand {
   id?: number;
   topic: string;
   context: string;
+  sort?: number;
   protocolId: number;
 }
diff --git a/src/command/club/protocol/protocolAgendaCommandHandler.ts b/src/command/club/protocol/protocolAgendaCommandHandler.ts
index 02fe4f2..96dbc08 100644
--- a/src/command/club/protocol/protocolAgendaCommandHandler.ts
+++ b/src/command/club/protocol/protocolAgendaCommandHandler.ts
@@ -2,6 +2,7 @@ import { dataSource } from "../../../data-source";
 import { protocolAgenda } from "../../../entity/club/protocol/protocolAgenda";
 import DatabaseActionException from "../../../exceptions/databaseActionException";
 import InternalException from "../../../exceptions/internalException";
+import ProtocolAgendaService from "../../../service/club/protocol/protocolAgendaService";
 import { SynchronizeProtocolAgendaCommand } from "./protocolAgendaCommand";
 
 export default abstract class ProtocolAgendaCommandHandler {
@@ -11,6 +12,7 @@ export default abstract class ProtocolAgendaCommandHandler {
    * @returns {Promise<number>}
    */
   static async create(protocolId: number): Promise<number> {
+    let count = await ProtocolAgendaService.getInstanceCount(protocolId);
     return await dataSource
       .createQueryBuilder()
       .insert()
@@ -18,6 +20,7 @@ export default abstract class ProtocolAgendaCommandHandler {
       .values({
         topic: "",
         context: "",
+        sort: count,
         protocolId,
       })
       .execute()
@@ -40,7 +43,7 @@ export default abstract class ProtocolAgendaCommandHandler {
       .insert()
       .into(protocolAgenda)
       .values(syncProtocolAgenda)
-      .orUpdate(["topic", "context"], ["id"])
+      .orUpdate(["topic", "context", "sort"], ["id"])
       .execute()
       .then(() => {})
       .catch((err) => {
diff --git a/src/command/club/protocol/protocolDecisionCommand.ts b/src/command/club/protocol/protocolDecisionCommand.ts
index 61eb6f0..aeb2f24 100644
--- a/src/command/club/protocol/protocolDecisionCommand.ts
+++ b/src/command/club/protocol/protocolDecisionCommand.ts
@@ -2,5 +2,6 @@ export interface SynchronizeProtocolDecisionCommand {
   id?: number;
   topic: string;
   context: string;
+  sort?: number;
   protocolId: number;
 }
diff --git a/src/command/club/protocol/protocolDecisionCommandHandler.ts b/src/command/club/protocol/protocolDecisionCommandHandler.ts
index 585abf1..9425d38 100644
--- a/src/command/club/protocol/protocolDecisionCommandHandler.ts
+++ b/src/command/club/protocol/protocolDecisionCommandHandler.ts
@@ -2,6 +2,7 @@ import { dataSource } from "../../../data-source";
 import { protocolDecision } from "../../../entity/club/protocol/protocolDecision";
 import DatabaseActionException from "../../../exceptions/databaseActionException";
 import InternalException from "../../../exceptions/internalException";
+import ProtocolDecisionService from "../../../service/club/protocol/protocolDecisionService";
 import { SynchronizeProtocolDecisionCommand } from "./protocolDecisionCommand";
 
 export default abstract class ProtocolDecisionCommandHandler {
@@ -11,6 +12,7 @@ export default abstract class ProtocolDecisionCommandHandler {
    * @returns {Promise<number>}
    */
   static async create(protocolId: number): Promise<number> {
+    let count = await ProtocolDecisionService.getInstanceCount(protocolId);
     return await dataSource
       .createQueryBuilder()
       .insert()
@@ -18,6 +20,7 @@ export default abstract class ProtocolDecisionCommandHandler {
       .values({
         topic: "",
         context: "",
+        sort: count,
         protocolId,
       })
       .execute()
@@ -39,7 +42,7 @@ export default abstract class ProtocolDecisionCommandHandler {
       .insert()
       .into(protocolDecision)
       .values(syncProtocolDecisions)
-      .orUpdate(["topic", "context"], ["id"])
+      .orUpdate(["topic", "context", "sort"], ["id"])
       .execute()
       .then(() => {})
       .catch((err) => {
diff --git a/src/command/club/protocol/protocolVotingCommand.ts b/src/command/club/protocol/protocolVotingCommand.ts
index a707b64..617a560 100644
--- a/src/command/club/protocol/protocolVotingCommand.ts
+++ b/src/command/club/protocol/protocolVotingCommand.ts
@@ -5,5 +5,6 @@ export interface SynchronizeProtocolVotingCommand {
   favour: number;
   abstain: number;
   against: number;
+  sort?: number;
   protocolId: number;
 }
diff --git a/src/command/club/protocol/protocolVotingCommandHandler.ts b/src/command/club/protocol/protocolVotingCommandHandler.ts
index 45a4642..741c0da 100644
--- a/src/command/club/protocol/protocolVotingCommandHandler.ts
+++ b/src/command/club/protocol/protocolVotingCommandHandler.ts
@@ -2,6 +2,7 @@ import { dataSource } from "../../../data-source";
 import { protocolVoting } from "../../../entity/club/protocol/protocolVoting";
 import DatabaseActionException from "../../../exceptions/databaseActionException";
 import InternalException from "../../../exceptions/internalException";
+import ProtocolVotingService from "../../../service/club/protocol/protocolVotingService";
 import { SynchronizeProtocolVotingCommand } from "./protocolVotingCommand";
 
 export default abstract class ProtocolVotingCommandHandler {
@@ -11,6 +12,7 @@ export default abstract class ProtocolVotingCommandHandler {
    * @returns {Promise<number>}
    */
   static async create(protocolId: number): Promise<number> {
+    let count = await ProtocolVotingService.getInstanceCount(protocolId);
     return await dataSource
       .createQueryBuilder()
       .insert()
@@ -18,6 +20,7 @@ export default abstract class ProtocolVotingCommandHandler {
       .values({
         topic: "",
         context: "",
+        sort: count,
         protocolId,
       })
       .execute()
@@ -39,7 +42,7 @@ export default abstract class ProtocolVotingCommandHandler {
       .insert()
       .into(protocolVoting)
       .values(syncProtocolVotings)
-      .orUpdate(["topic", "context", "favour", "abstain", "against"], ["id"])
+      .orUpdate(["topic", "context", "favour", "abstain", "against", "sort"], ["id"])
       .execute()
       .then(() => {})
       .catch((err) => {
diff --git a/src/controller/admin/club/protocolController.ts b/src/controller/admin/club/protocolController.ts
index 868715f..2a6f5fb 100644
--- a/src/controller/admin/club/protocolController.ts
+++ b/src/controller/admin/club/protocolController.ts
@@ -257,13 +257,13 @@ export async function createProtocolPrintoutById(req: Request, res: Response): P
       }),
       start: protocol.starttime,
       end: protocol.endtime,
-      agenda,
-      decisions,
+      agenda: agenda.sort((a, b) => a.sort - b.sort),
+      decisions: decisions.sort((a, b) => a.sort - b.sort),
       presence: presence.filter((p) => !p.absent).map((p) => p.member),
       absent: presence.filter((p) => p.absent).map((p) => ({ ...p.member, excused: p.excused })),
       excused_absent: presence.filter((p) => p.absent && p.excused).map((p) => p.member),
       unexcused_absent: presence.filter((p) => p.absent && !p.excused).map((p) => p.member),
-      votings,
+      votings: votings.sort((a, b) => a.sort - b.sort),
     },
   });
 
@@ -320,6 +320,7 @@ export async function synchronizeProtocolAgendaById(req: Request, res: Response)
       id: a.id ?? null,
       topic: a.topic,
       context: a.context,
+      sort: a.sort,
       protocolId,
     })
   );
@@ -343,6 +344,7 @@ export async function synchronizeProtocolDecisonsById(req: Request, res: Respons
       id: d.id ?? null,
       topic: d.topic,
       context: d.context,
+      sort: d.sort,
       protocolId,
     })
   );
@@ -362,13 +364,14 @@ export async function synchronizeProtocolVotingsById(req: Request, res: Response
   let votings = req.body.votings as Array<ProtocolVotingViewModel>;
 
   let syncVoting: Array<SynchronizeProtocolVotingCommand> = votings.map(
-    (d: ProtocolVotingViewModel): SynchronizeProtocolVotingCommand => ({
-      id: d.id ?? null,
-      topic: d.topic,
-      context: d.context,
-      favour: d.favour,
-      abstain: d.abstain,
-      against: d.abstain,
+    (v: ProtocolVotingViewModel): SynchronizeProtocolVotingCommand => ({
+      id: v.id ?? null,
+      topic: v.topic,
+      context: v.context,
+      favour: v.favour,
+      abstain: v.abstain,
+      against: v.abstain,
+      sort: v.sort,
       protocolId,
     })
   );
diff --git a/src/data-source.ts b/src/data-source.ts
index ea45dc3..37aebfd 100644
--- a/src/data-source.ts
+++ b/src/data-source.ts
@@ -49,6 +49,7 @@ import { BackupAndResetDatabase1738166124200 } from "./migrations/1738166124200-
 import { CreateSchema1738166167472 } from "./migrations/1738166167472-CreateSchema";
 import { MemberPrintoutTemplates1742207245862 } from "./migrations/1742207245862-memberPrintoutTemplates";
 import { Listprinting1742311486232 } from "./migrations/1742311486232-listprinting";
+import { ProtocolSort1742544887410 } from "./migrations/1742544887410-protocolSort";
 
 const dataSource = new DataSource({
   type: DB_TYPE as any,
@@ -107,6 +108,7 @@ const dataSource = new DataSource({
     CreateSchema1738166167472,
     MemberPrintoutTemplates1742207245862,
     Listprinting1742311486232,
+    ProtocolSort1742544887410,
   ],
   migrationsRun: true,
   migrationsTransactionMode: "each",
diff --git a/src/entity/club/protocol/protocolAgenda.ts b/src/entity/club/protocol/protocolAgenda.ts
index 7ce7556..a64bf9a 100644
--- a/src/entity/club/protocol/protocolAgenda.ts
+++ b/src/entity/club/protocol/protocolAgenda.ts
@@ -12,6 +12,9 @@ export class protocolAgenda {
   @Column({ type: "text", default: "" })
   context: string;
 
+  @Column({ type: "int", default: 0 })
+  sort: number;
+
   @Column()
   protocolId: number;
 
diff --git a/src/entity/club/protocol/protocolDecision.ts b/src/entity/club/protocol/protocolDecision.ts
index 4978d17..e2cc4c1 100644
--- a/src/entity/club/protocol/protocolDecision.ts
+++ b/src/entity/club/protocol/protocolDecision.ts
@@ -12,6 +12,9 @@ export class protocolDecision {
   @Column({ type: "text", default: "" })
   context: string;
 
+  @Column({ type: "int", default: 0 })
+  sort: number;
+
   @Column()
   protocolId: number;
 
diff --git a/src/entity/club/protocol/protocolVoting.ts b/src/entity/club/protocol/protocolVoting.ts
index 8e8f7a1..438e8fc 100644
--- a/src/entity/club/protocol/protocolVoting.ts
+++ b/src/entity/club/protocol/protocolVoting.ts
@@ -21,6 +21,9 @@ export class protocolVoting {
   @Column({ type: "int", default: 0 })
   against: number;
 
+  @Column({ type: "int", default: 0 })
+  sort: number;
+
   @Column()
   protocolId: number;
 
diff --git a/src/factory/admin/club/protocol/protocolAgenda.ts b/src/factory/admin/club/protocol/protocolAgenda.ts
index aa15b75..65d2334 100644
--- a/src/factory/admin/club/protocol/protocolAgenda.ts
+++ b/src/factory/admin/club/protocol/protocolAgenda.ts
@@ -12,6 +12,7 @@ export default abstract class ProtocolAgendaFactory {
       id: record.id,
       topic: record.topic,
       context: record.context,
+      sort: record.sort,
       protocolId: record.protocolId,
     };
   }
diff --git a/src/factory/admin/club/protocol/protocolDecision.ts b/src/factory/admin/club/protocol/protocolDecision.ts
index 0fbfff5..608bc2a 100644
--- a/src/factory/admin/club/protocol/protocolDecision.ts
+++ b/src/factory/admin/club/protocol/protocolDecision.ts
@@ -12,6 +12,7 @@ export default abstract class ProtocolDecisionFactory {
       id: record.id,
       topic: record.topic,
       context: record.context,
+      sort: record.sort,
       protocolId: record.protocolId,
     };
   }
diff --git a/src/factory/admin/club/protocol/protocolVoting.ts b/src/factory/admin/club/protocol/protocolVoting.ts
index 2f4fa4e..49f954c 100644
--- a/src/factory/admin/club/protocol/protocolVoting.ts
+++ b/src/factory/admin/club/protocol/protocolVoting.ts
@@ -15,6 +15,7 @@ export default abstract class ProtocolVotingFactory {
       favour: record.favour,
       abstain: record.abstain,
       against: record.against,
+      sort: record.sort,
       protocolId: record.protocolId,
     };
   }
diff --git a/src/helpers/backupHelper.ts b/src/helpers/backupHelper.ts
index a60e963..7727527 100644
--- a/src/helpers/backupHelper.ts
+++ b/src/helpers/backupHelper.ts
@@ -300,8 +300,8 @@ export default abstract class BackupHelper {
       .leftJoin("protocol.printouts", "printouts")
       .leftJoin("protocol.votings", "votings")
       .select(["protocol.title", "protocol.date", "protocol.starttime", "protocol.endtime", "protocol.summary"])
-      .addSelect(["agendas.topic", "agendas.context"])
-      .addSelect(["decisions.topic", "decisions.context"])
+      .addSelect(["agendas.topic", "agendas.context", "agendas.sort"])
+      .addSelect(["decisions.topic", "decisions.context", "decisions.sort"])
       .addSelect(["presences.absent", "presences.excused"])
       .addSelect([
         ...(collectIds ? ["member.id"] : []),
@@ -312,7 +312,14 @@ export default abstract class BackupHelper {
         "member.internalId",
       ])
       .addSelect(["printouts.title", "printouts.iteration", "printouts.filename", "printouts.createdAt"])
-      .addSelect(["votings.topic", "votings.context", "votings.favour", "votings.abstain", "votings.against"])
+      .addSelect([
+        "votings.topic",
+        "votings.context",
+        "votings.favour",
+        "votings.abstain",
+        "votings.against",
+        "votings.sort",
+      ])
       .getMany();
   }
   private static async getNewsletter(collectIds: boolean): Promise<Array<any>> {
diff --git a/src/migrations/1742544887410-protocolSort.ts b/src/migrations/1742544887410-protocolSort.ts
new file mode 100644
index 0000000..77f6011
--- /dev/null
+++ b/src/migrations/1742544887410-protocolSort.ts
@@ -0,0 +1,29 @@
+import { MigrationInterface, QueryRunner, TableColumn } from "typeorm";
+import { getDefaultByORM, getTypeByORM } from "./ormHelper";
+
+export class ProtocolSort1742544887410 implements MigrationInterface {
+  name = "ProtocolSort1742544887410";
+
+  public async up(queryRunner: QueryRunner): Promise<void> {
+    await queryRunner.addColumn(
+      "protocol_agenda",
+      new TableColumn({ name: "sort", ...getTypeByORM("int"), default: getDefaultByORM("number", 0) })
+    );
+
+    await queryRunner.addColumn(
+      "protocol_decision",
+      new TableColumn({ name: "sort", ...getTypeByORM("int"), default: getDefaultByORM("number", 0) })
+    );
+
+    await queryRunner.addColumn(
+      "protocol_voting",
+      new TableColumn({ name: "sort", ...getTypeByORM("int"), default: getDefaultByORM("number", 0) })
+    );
+  }
+
+  public async down(queryRunner: QueryRunner): Promise<void> {
+    await queryRunner.dropColumn("protocol_agenda", "sort");
+    await queryRunner.dropColumn("protocol_decision", "sort");
+    await queryRunner.dropColumn("protocol_voting", "sort");
+  }
+}
diff --git a/src/service/club/protocol/protocolAgendaService.ts b/src/service/club/protocol/protocolAgendaService.ts
index fb8ead8..7d54168 100644
--- a/src/service/club/protocol/protocolAgendaService.ts
+++ b/src/service/club/protocol/protocolAgendaService.ts
@@ -39,4 +39,22 @@ export default abstract class ProtocolAgendaService {
         throw new DatabaseActionException("SELECT", "protocolAgenda", err);
       });
   }
+
+  /**
+   * @description get count of exisiting protocolAgenda by protocolId
+   * @returns {Promise<number>}
+   */
+  static async getInstanceCount(protocolId: number): Promise<number> {
+    return await dataSource
+      .getRepository(protocolAgenda)
+      .createQueryBuilder("protocolAgenda")
+      .where({ protocolId })
+      .getCount()
+      .then((res) => {
+        return res;
+      })
+      .catch((err) => {
+        throw new DatabaseActionException("COUNT", "protocolAgenda", err);
+      });
+  }
 }
diff --git a/src/service/club/protocol/protocolDecisionService.ts b/src/service/club/protocol/protocolDecisionService.ts
index 56ac4c6..241dba2 100644
--- a/src/service/club/protocol/protocolDecisionService.ts
+++ b/src/service/club/protocol/protocolDecisionService.ts
@@ -39,4 +39,22 @@ export default abstract class ProtocolDecisionService {
         throw new DatabaseActionException("SELECT", "protocolDecision", err);
       });
   }
+
+  /**
+   * @description get count of exisiting protocolDecision by protocolId
+   * @returns {Promise<number>}
+   */
+  static async getInstanceCount(protocolId: number): Promise<number> {
+    return await dataSource
+      .getRepository(protocolDecision)
+      .createQueryBuilder("protocolDecisions")
+      .where({ protocolId })
+      .getCount()
+      .then((res) => {
+        return res;
+      })
+      .catch((err) => {
+        throw new DatabaseActionException("COUNT", "protocolDecision", err);
+      });
+  }
 }
diff --git a/src/service/club/protocol/protocolVotingService.ts b/src/service/club/protocol/protocolVotingService.ts
index 2000cce..220d29e 100644
--- a/src/service/club/protocol/protocolVotingService.ts
+++ b/src/service/club/protocol/protocolVotingService.ts
@@ -39,4 +39,22 @@ export default abstract class ProtocolVotingService {
         throw new DatabaseActionException("SELECT", "protocolVoting", err);
       });
   }
+
+  /**
+   * @description get count of exisiting protocolVoting by protocolId
+   * @returns {Promise<number>}
+   */
+  static async getInstanceCount(protocolId: number): Promise<number> {
+    return await dataSource
+      .getRepository(protocolVoting)
+      .createQueryBuilder("protocolVotings")
+      .where({ protocolId })
+      .getCount()
+      .then((res) => {
+        return res;
+      })
+      .catch((err) => {
+        throw new DatabaseActionException("COUNT", "protocolVoting", err);
+      });
+  }
 }
diff --git a/src/viewmodel/admin/club/protocol/protocolAgenda.models.ts b/src/viewmodel/admin/club/protocol/protocolAgenda.models.ts
index 3a59327..eed423d 100644
--- a/src/viewmodel/admin/club/protocol/protocolAgenda.models.ts
+++ b/src/viewmodel/admin/club/protocol/protocolAgenda.models.ts
@@ -2,5 +2,6 @@ export interface ProtocolAgendaViewModel {
   id: number;
   topic: string;
   context: string;
+  sort: number;
   protocolId: number;
 }
diff --git a/src/viewmodel/admin/club/protocol/protocolDecision.models.ts b/src/viewmodel/admin/club/protocol/protocolDecision.models.ts
index 4a7212c..7de33c4 100644
--- a/src/viewmodel/admin/club/protocol/protocolDecision.models.ts
+++ b/src/viewmodel/admin/club/protocol/protocolDecision.models.ts
@@ -2,5 +2,6 @@ export interface ProtocolDecisionViewModel {
   id: number;
   topic: string;
   context: string;
+  sort: number;
   protocolId: number;
 }
diff --git a/src/viewmodel/admin/club/protocol/protocolVoting.models.ts b/src/viewmodel/admin/club/protocol/protocolVoting.models.ts
index 686f423..a5bd723 100644
--- a/src/viewmodel/admin/club/protocol/protocolVoting.models.ts
+++ b/src/viewmodel/admin/club/protocol/protocolVoting.models.ts
@@ -5,5 +5,6 @@ export interface ProtocolVotingViewModel {
   favour: number;
   abstain: number;
   against: number;
+  sort: number;
   protocolId: number;
 }