From 95bfbf86a4ff0cef79d126ee8512dceed0101d5b Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Wed, 6 May 2026 09:05:28 +0200 Subject: [PATCH] feat(MemberOrder, MemberOrderHistory, MemberOrderService, OrdersPanel): add paidConfirmed field and update related logic - Introduced a new boolean field `paidConfirmed` in MemberOrder and MemberOrderHistory models to track payment confirmation status. - Updated serialization functions in MemberOrderService to include `paidConfirmed` in order and history entries. - Enhanced OrdersPanel component to allow users to set and display the `paidConfirmed` status for orders. - Added localization support for the new `paidConfirmed` label in German. - Adjusted related logic to ensure proper handling of the `paidConfirmed` state throughout the application. --- ...06_add_paid_confirmed_to_member_orders.sql | 5 ++ backend/models/MemberOrder.js | 6 +++ backend/models/MemberOrderHistory.js | 6 +++ backend/services/memberOrderService.js | 16 ++++++- frontend/src/components/OrdersPanel.vue | 48 +++++++++++++++---- frontend/src/i18n/locales/de.json | 1 + 6 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 backend/migrations/20260506_add_paid_confirmed_to_member_orders.sql diff --git a/backend/migrations/20260506_add_paid_confirmed_to_member_orders.sql b/backend/migrations/20260506_add_paid_confirmed_to_member_orders.sql new file mode 100644 index 00000000..47ef07c1 --- /dev/null +++ b/backend/migrations/20260506_add_paid_confirmed_to_member_orders.sql @@ -0,0 +1,5 @@ +ALTER TABLE `member_orders` + ADD COLUMN `paid_confirmed` TINYINT(1) NOT NULL DEFAULT 0 AFTER `budget`; + +ALTER TABLE `member_order_history` + ADD COLUMN `paid_confirmed` TINYINT(1) NOT NULL DEFAULT 0 AFTER `budget`; diff --git a/backend/models/MemberOrder.js b/backend/models/MemberOrder.js index bff2c2bd..d5f3c676 100644 --- a/backend/models/MemberOrder.js +++ b/backend/models/MemberOrder.js @@ -54,6 +54,12 @@ const MemberOrder = sequelize.define('MemberOrder', { type: DataTypes.DECIMAL(10, 2), allowNull: false, defaultValue: 0 + }, + paidConfirmed: { + type: DataTypes.BOOLEAN, + allowNull: false, + defaultValue: false, + field: 'paid_confirmed' } }, { underscored: true, diff --git a/backend/models/MemberOrderHistory.js b/backend/models/MemberOrderHistory.js index feba6d94..3b0bacf0 100644 --- a/backend/models/MemberOrderHistory.js +++ b/backend/models/MemberOrderHistory.js @@ -52,6 +52,12 @@ const MemberOrderHistory = sequelize.define('MemberOrderHistory', { type: DataTypes.DECIMAL(10, 2), allowNull: false, defaultValue: 0 + }, + paidConfirmed: { + type: DataTypes.BOOLEAN, + allowNull: false, + defaultValue: false, + field: 'paid_confirmed' } }, { underscored: true, diff --git a/backend/services/memberOrderService.js b/backend/services/memberOrderService.js index d78eb08a..5aac04b9 100644 --- a/backend/services/memberOrderService.js +++ b/backend/services/memberOrderService.js @@ -21,11 +21,13 @@ const serializeOrder = (order) => { const cost = normalizeAmount(plain.cost); const paidAmount = normalizeAmount(plain.paidAmount); const budget = normalizeAmount(plain.budget); + const paidConfirmed = Boolean(plain.paidConfirmed); return { ...plain, cost, paidAmount, budget, + paidConfirmed, openAmount: Math.max(0, Number((cost - paidAmount).toFixed(2))) }; }; @@ -35,11 +37,13 @@ const serializeHistoryEntry = (entry) => { const cost = normalizeAmount(plain.cost); const paidAmount = normalizeAmount(plain.paidAmount); const budget = normalizeAmount(plain.budget); + const paidConfirmed = Boolean(plain.paidConfirmed); return { ...plain, cost, paidAmount, budget, + paidConfirmed, openAmount: Math.max(0, Number((cost - paidAmount).toFixed(2))) }; }; @@ -69,7 +73,8 @@ class MemberOrderService { changedAt: new Date(), cost: normalizeAmount(order.cost), paidAmount: normalizeAmount(order.paidAmount), - budget: normalizeAmount(order.budget) + budget: normalizeAmount(order.budget), + paidConfirmed: Boolean(order.paidConfirmed) }, transaction ? { transaction } : undefined); } @@ -111,6 +116,7 @@ class MemberOrderService { const cost = normalizeAmount(payload?.cost); const paidAmount = normalizeAmount(payload?.paidAmount); const budget = normalizeAmount(payload?.budget); + const paidConfirmed = Boolean(payload?.paidConfirmed); if (!item) { return { @@ -128,7 +134,8 @@ class MemberOrderService { statusDate: new Date(), cost, paidAmount, - budget + budget, + paidConfirmed }); await this._createHistorySnapshot(order); @@ -179,6 +186,7 @@ class MemberOrderService { const nextCost = payload?.cost != null ? normalizeAmount(payload.cost) : normalizeAmount(order.cost); const nextPaidAmount = payload?.paidAmount != null ? normalizeAmount(payload.paidAmount) : normalizeAmount(order.paidAmount); const nextBudget = payload?.budget != null ? normalizeAmount(payload.budget) : normalizeAmount(order.budget); + const nextPaidConfirmed = payload?.paidConfirmed != null ? Boolean(payload.paidConfirmed) : Boolean(order.paidConfirmed); if (nextItem && nextItem !== order.item) { order.item = nextItem; @@ -201,6 +209,10 @@ class MemberOrderService { order.budget = nextBudget; changed = true; } + if (nextPaidConfirmed !== Boolean(order.paidConfirmed)) { + order.paidConfirmed = nextPaidConfirmed; + changed = true; + } if (!changed) { const existing = await this.getMemberOrders(userToken, clubId, memberId); diff --git a/frontend/src/components/OrdersPanel.vue b/frontend/src/components/OrdersPanel.vue index 990def34..6d8baae6 100644 --- a/frontend/src/components/OrdersPanel.vue +++ b/frontend/src/components/OrdersPanel.vue @@ -53,6 +53,10 @@ {{ $t('orders.budget') }} +