Abo-Status eines Kunden fuer alle Mitarbeiter im Team-Eingang
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0fdd13246c
commit
45203284ee
3 files changed
+45
-1
No files matched your search
@@ -2,6 +2,9 @@ import { Router } from 'express'
|
|||||||
import { config } from '../../config.js'
|
import { config } from '../../config.js'
|
||||||
import { listViewLog } from '../../services/customerViewLog.js'
|
import { listViewLog } from '../../services/customerViewLog.js'
|
||||||
import { getPortalAccessStatus } from '../../services/portalAccessStatus.js'
|
import { getPortalAccessStatus } from '../../services/portalAccessStatus.js'
|
||||||
|
import { PRODUCT_KEYS } from '../../services/products.js'
|
||||||
|
import { ACTIVE_STATUSES, getCurrentSubscription } from '../../services/stripeBilling.js'
|
||||||
|
import { serviceStartOf } from '../../services/takeoverCredits.js'
|
||||||
import { createStaffPreviewToken } from '../../services/staffPreviewTokens.js'
|
import { createStaffPreviewToken } from '../../services/staffPreviewTokens.js'
|
||||||
|
|
||||||
// Kunden im Team-Eingang (/api/team/customers), requireStaffJwt sitzt in routes/team/index.js
|
// Kunden im Team-Eingang (/api/team/customers), requireStaffJwt sitzt in routes/team/index.js
|
||||||
@@ -27,6 +30,29 @@ router.get('/:id/protokoll', async (req, res) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Abo-Status (Kunden-Reiter "Abo & Angebote", Stunden-Pruefung am Ticket): productKey/active wie die Admin-Route
|
||||||
|
// /api/admin/customers/:id/abo, dazu Laufzeit und Speicher; nur der Appwrite-Spiegel, kein Stripe
|
||||||
|
router.get('/:id/abo', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const sub = await getCurrentSubscription(req.params.id)
|
||||||
|
if (!sub) {
|
||||||
|
return res.json({ productKey: null, active: false, status: null, storageUnits: 0, startedAt: null, serviceStart: null, currentPeriodEnd: null, cancelAt: null })
|
||||||
|
}
|
||||||
|
return res.json({
|
||||||
|
productKey: PRODUCT_KEYS.includes(sub.productKey) ? sub.productKey : 'wartung',
|
||||||
|
active: ACTIVE_STATUSES.has(sub.status),
|
||||||
|
status: sub.status || null,
|
||||||
|
storageUnits: Number(sub.storageUnits) || 0,
|
||||||
|
startedAt: sub.startedAt || null,
|
||||||
|
serviceStart: serviceStartOf(sub),
|
||||||
|
currentPeriodEnd: sub.currentPeriodEnd || null,
|
||||||
|
cancelAt: sub.cancelAt || null,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
return res.status(err.status || 500).json({ error: err.message || 'Abo konnte nicht geladen werden' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Kundenansicht oeffnen: Einmal-Link (60 s), den das Ticketsystem in einem neuen Tab aufruft
|
// Kundenansicht oeffnen: Einmal-Link (60 s), den das Ticketsystem in einem neuen Tab aufruft
|
||||||
router.post('/:id/kundenansicht', async (req, res) => {
|
router.post('/:id/kundenansicht', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ function withHistory(doc, entry) {
|
|||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
|
|
||||||
const serviceStartOf = (sub) => sub?.trialEnd || sub?.startedAt || null
|
export const serviceStartOf = (sub) => sub?.trialEnd || sub?.startedAt || null
|
||||||
const isActiveSub = (sub) => Boolean(sub && ACTIVE_STATUSES.has(sub.status))
|
const isActiveSub = (sub) => Boolean(sub && ACTIVE_STATUSES.has(sub.status))
|
||||||
// Produkt des Abos: Altbestand ohne productKey und unbekannte Schluessel gelten als Wartungs-Abo
|
// Produkt des Abos: Altbestand ohne productKey und unbekannte Schluessel gelten als Wartungs-Abo
|
||||||
const productKeyOf = (sub) => (PRODUCT_KEYS.includes(sub?.productKey) ? sub.productKey : 'wartung')
|
const productKeyOf = (sub) => (PRODUCT_KEYS.includes(sub?.productKey) ? sub.productKey : 'wartung')
|
||||||
|
|||||||
@@ -67,3 +67,21 @@ test('alle Team-Routen ohne JWT -> 401', async () => {
|
|||||||
assert.equal(res.status, 401, `${method} ${p}`)
|
assert.equal(res.status, 401, `${method} ${p}`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Etappe 3: Abo-Status fuer alle Mitarbeiter (Kunden-Reiter "Abo & Angebote", Stunden-Pruefung am Ticket)
|
||||||
|
test('abo: Mitarbeiter ohne Admin-Label sieht den Abo-Status', async () => {
|
||||||
|
aw.seed('subscriptions', {
|
||||||
|
$id: 'sub_t', customerId: 'c3', status: 'active', productKey: 'wartung', storageUnits: 1,
|
||||||
|
startedAt: '2026-09-01T10:00:00.000Z', trialEnd: '2026-09-15T00:00:00.000Z', currentPeriodEnd: '2026-11-01T00:00:00.000Z', cancelAt: null,
|
||||||
|
})
|
||||||
|
const res = await rawGet('/api/team/customers/c3/abo', auth)
|
||||||
|
assert.equal(res.status, 200)
|
||||||
|
assert.deepEqual(res.body, {
|
||||||
|
productKey: 'wartung', active: true, status: 'active', storageUnits: 1, startedAt: '2026-09-01T10:00:00.000Z',
|
||||||
|
serviceStart: '2026-09-15T00:00:00.000Z', currentPeriodEnd: '2026-11-01T00:00:00.000Z', cancelAt: null,
|
||||||
|
})
|
||||||
|
assert.deepEqual((await rawGet('/api/team/customers/c4/abo', auth)).body, {
|
||||||
|
productKey: null, active: false, status: null, storageUnits: 0, startedAt: null, serviceStart: null, currentPeriodEnd: null, cancelAt: null,
|
||||||
|
})
|
||||||
|
assert.equal((await rawGet('/api/team/customers/c3/abo')).status, 401)
|
||||||
|
})
|
||||||
Reference in new issue
Block a user