diff --git a/backend/migrations/20260421_add_budget_to_member_orders.sql b/backend/migrations/20260421_add_budget_to_member_orders.sql new file mode 100644 index 00000000..1107b566 --- /dev/null +++ b/backend/migrations/20260421_add_budget_to_member_orders.sql @@ -0,0 +1,5 @@ +ALTER TABLE `member_orders` + ADD COLUMN `budget` DECIMAL(10,2) NOT NULL DEFAULT 0.00 AFTER `paid_amount`; + +ALTER TABLE `member_order_history` + ADD COLUMN `budget` DECIMAL(10,2) NOT NULL DEFAULT 0.00 AFTER `paid_amount`; diff --git a/backend/models/MemberOrder.js b/backend/models/MemberOrder.js index d3d892ea..bff2c2bd 100644 --- a/backend/models/MemberOrder.js +++ b/backend/models/MemberOrder.js @@ -49,6 +49,11 @@ const MemberOrder = sequelize.define('MemberOrder', { allowNull: false, defaultValue: 0, field: 'paid_amount' + }, + budget: { + type: DataTypes.DECIMAL(10, 2), + allowNull: false, + defaultValue: 0 } }, { underscored: true, diff --git a/backend/models/MemberOrderHistory.js b/backend/models/MemberOrderHistory.js index f8445a42..feba6d94 100644 --- a/backend/models/MemberOrderHistory.js +++ b/backend/models/MemberOrderHistory.js @@ -47,6 +47,11 @@ const MemberOrderHistory = sequelize.define('MemberOrderHistory', { allowNull: false, defaultValue: 0, field: 'paid_amount' + }, + budget: { + type: DataTypes.DECIMAL(10, 2), + allowNull: false, + defaultValue: 0 } }, { underscored: true, diff --git a/backend/services/memberOrderService.js b/backend/services/memberOrderService.js index c9e717cd..d78eb08a 100644 --- a/backend/services/memberOrderService.js +++ b/backend/services/memberOrderService.js @@ -20,10 +20,12 @@ const serializeOrder = (order) => { const plain = typeof order.toJSON === 'function' ? order.toJSON() : { ...order }; const cost = normalizeAmount(plain.cost); const paidAmount = normalizeAmount(plain.paidAmount); + const budget = normalizeAmount(plain.budget); return { ...plain, cost, paidAmount, + budget, openAmount: Math.max(0, Number((cost - paidAmount).toFixed(2))) }; }; @@ -32,10 +34,12 @@ const serializeHistoryEntry = (entry) => { const plain = typeof entry.toJSON === 'function' ? entry.toJSON() : { ...entry }; const cost = normalizeAmount(plain.cost); const paidAmount = normalizeAmount(plain.paidAmount); + const budget = normalizeAmount(plain.budget); return { ...plain, cost, paidAmount, + budget, openAmount: Math.max(0, Number((cost - paidAmount).toFixed(2))) }; }; @@ -64,7 +68,8 @@ class MemberOrderService { status: order.status, changedAt: new Date(), cost: normalizeAmount(order.cost), - paidAmount: normalizeAmount(order.paidAmount) + paidAmount: normalizeAmount(order.paidAmount), + budget: normalizeAmount(order.budget) }, transaction ? { transaction } : undefined); } @@ -105,6 +110,7 @@ class MemberOrderService { const status = ORDER_STATUSES.includes(payload?.status) ? payload.status : 'requested'; const cost = normalizeAmount(payload?.cost); const paidAmount = normalizeAmount(payload?.paidAmount); + const budget = normalizeAmount(payload?.budget); if (!item) { return { @@ -121,7 +127,8 @@ class MemberOrderService { orderDate: new Date(), statusDate: new Date(), cost, - paidAmount + paidAmount, + budget }); await this._createHistorySnapshot(order); @@ -171,6 +178,7 @@ class MemberOrderService { const nextStatus = payload?.status && ORDER_STATUSES.includes(payload.status) ? payload.status : order.status; 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); if (nextItem && nextItem !== order.item) { order.item = nextItem; @@ -189,6 +197,10 @@ class MemberOrderService { order.paidAmount = nextPaidAmount; changed = true; } + if (nextBudget !== normalizeAmount(order.budget)) { + order.budget = nextBudget; + 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 140c7d9f..e42404dd 100644 --- a/frontend/src/components/OrdersPanel.vue +++ b/frontend/src/components/OrdersPanel.vue @@ -40,6 +40,10 @@ {{ $t('orders.paid') }} +