pénzügyi modul továbbfejlesztése (csomagkezelés)

This commit is contained in:
Roo
2026-07-29 09:46:10 +00:00
parent 6f28d3e70d
commit 75904cd2f8
50 changed files with 5851 additions and 312 deletions

View File

@@ -0,0 +1,161 @@
# 🏗️ Végrehajtási Terv: Csomagváltási és Fizetési Anomáliák Javítása (4 fázis)
**Dátum:** 2026-07-28
**Szerző:** Technical Lead & System Architect
**Státusz:** 🔵 Tervezés kész — Gitea Issue-k létrehozva
**Kapcsolódó kártyák:** #429, #430, #431, #432
---
## 📋 Áttekintés
A felhasználó csomagot váltott (Ingyenesre), de a tranzakció adatbázis szinten nem ment végbe a `net_amount > 0` validációs hiba miatt. A javítást szigorú sorrendben, a mélyebb rétegektől (Backend/Adatbázis) a felület (Vue.js frontend) felé haladva kell végezni.
---
## 🔴 Fázis 1: Ingyenes csomag (0 Ft) bypass és Adatbázis szinkronizáció
**Gitea kártya:** [#429 - Issue #1: Ingyenes csomag (0 Ft) bypass és Adatbázis szinkronizáció javítása](https://gitea.profibot.hu/kincses/service-finder/issues/429)
### Root Cause
A [`FinancialManager.purchase_package()`](backend/app/services/financial_manager.py:176) mindig létrehoz egy PaymentIntent-et, még ingyenes (0 Ft) csomagok esetén is. A [`PaymentRouter.create_payment_intent()`](backend/app/services/payment_router.py:34) a 62. sorban elvégzi a `net_amount <= 0` validációt, ami ValueError-t dob.
### Megoldás
1. **Adatbázis modell bővítés:** `pending_tier_id` (FK) és `pending_activated_at` (DateTime) mezők hozzáadása a [`UserSubscription`](backend/app/models/core_logic.py:200) és [`OrganizationSubscription`](backend/app/models/core_logic.py:143) modellekhez.
2. **`is_downgrade()` metódus:** Új statikus metódus a [`SubscriptionService`](backend/app/services/subscription_service.py:74) osztályban, amely összehasonlítja a jelenlegi és a cél tier_level értékeket.
3. **Free tier bypass:** Ha `price <= 0`, a [`FinancialManager.purchase_package()`](backend/app/services/financial_manager.py:176) közvetlenül aktiválja a subscription-t, megkerülve a PaymentRouter-t.
4. **Downgrade logika:** Ha a cél tier_level < current tier_level → `pending_tier_id` beállítása, nem azonnali aktiválás. Upgrade esetén a pending flag törlése.
5. **Downgrade Executor:** Új szolgáltatás [`backend/app/services/downgrade_executor.py`](backend/app/services/downgrade_executor.py) a pending downgrade-ek aktiválására a `valid_until` lejárta után.
### Érintett fájlok
| Fájl | Módosítás |
|------|-----------|
| [`backend/app/models/core_logic.py`](backend/app/models/core_logic.py) | +2 oszlop (pending_tier_id, pending_activated_at) mindkét subscription modellben |
| [`backend/app/services/subscription_service.py`](backend/app/services/subscription_service.py) | Új `is_downgrade()` metódus |
| [`backend/app/services/financial_manager.py`](backend/app/services/financial_manager.py) | Free tier bypass + downgrade detektálás |
| `backend/app/services/downgrade_executor.py` | **ÚJ fájl** — CRON-jellegű pending aktiváló |
| [`backend/app/api/v1/endpoints/subscriptions.py`](backend/app/api/v1/endpoints/subscriptions.py) | `has_pending_downgrade` mezők a `/my` végpontban |
---
## 🟠 Fázis 2: Mock Payment Gateway (Szimulált Fizetés)
**Gitea kártya:** [#430 - Issue #2: Mock Payment Gateway (Szimulált Fizetés) implementálása](https://gitea.profibot.hu/kincses/service-finder/issues/430)
### Jelenlegi állapot
A [`MockPaymentGateway`](backend/app/services/mock_payment_gateway.py:31) három módot támogat: `auto_approve`, `simulate_failure`, `simulate_timeout`. Hiányzik a valósághű fizetési flow (redirect → webhook → completion).
### Megoldás
1. **Új mód: `simulate_redirect`** — Alapértelmezetté tenni. `create_intent()` visszaadja a `checkout_url`-t és a `requires_action` státuszt.
2. **Checkout oldal:** `GET /mock-payment/checkout/{intent_id}` — egyszerű HTML fizetési oldal "Pay Now" gombbal.
3. **Webhook callback:** `POST /mock-payment/callback` — PaymentIntent → COMPLETED státusz, subscription aktiválás.
4. **Logging:** Minden `create_intent()` hívásnál `MOCK_PAYMENT_REQUEST` logolás.
### Érintett fájlok
| Fájl | Módosítás |
|------|-----------|
| [`backend/app/services/mock_payment_gateway.py`](backend/app/services/mock_payment_gateway.py) | Új `simulate_redirect` mód |
| [`backend/app/api/v1/endpoints/billing.py`](backend/app/api/v1/endpoints/billing.py) | Új 2 végpont: checkout page + webhook callback |
---
## 🟡 Fázis 3: Subscription Details Card (Flip Card) adatkötés javítása
**Gitea kártya:** [#431 - Issue #3: Subscription Details Card adatkötésének javítása](https://gitea.profibot.hu/kincses/service-finder/issues/431)
### Jelenlegi állapot
A [`FinanceMainView.vue`](frontend_app/src/views/FinanceMainView.vue:118-154) Card 2 a raw DB slug-ot (pl. `private_pro_v1`) jeleníti meg, nem mutat lejárati dátumot és járműhasználatot.
### Megoldás
1. **Backend:** [`GET /auth/me`](backend/app/api/v1/endpoints/users.py) bővítése `subscription_display_name`, `subscription_expires_at`, `subscription_tier_id` mezőkkel.
2. **Frontend:** [`auth.ts`](frontend_app/src/stores/auth.ts) `UserProfile` interface bővítése.
3. **Frontend:** [`FinanceMainView.vue`](frontend_app/src/views/FinanceMainView.vue) Card 2 template teljes átírása: fejléc, csomagnév, lejárati dátum, járműhasználati sáv, dinamikus CTA gomb.
4. **I18n:** `renewNow`, `upgradePlan` kulcsok felvétele.
### Érintett fájlok
| Fájl | Módosítás |
|------|-----------|
| [`backend/app/api/v1/endpoints/users.py`](backend/app/api/v1/endpoints/users.py) | +subscription_display_name, +subscription_expires_at, +subscription_tier_id |
| [`frontend_app/src/stores/auth.ts`](frontend_app/src/stores/auth.ts) | `UserProfile` interface bővítése |
| [`frontend_app/src/views/FinanceMainView.vue`](frontend_app/src/views/FinanceMainView.vue) | Card 2 template + computed property rewrite |
| [`frontend_app/src/i18n/hu.ts`](frontend_app/src/i18n/hu.ts) | Új kulcsok |
| [`frontend_app/src/i18n/en.ts`](frontend_app/src/i18n/en.ts) | Új kulcsok |
---
## 🟢 Fázis 4: Kiegészítő csomagok (Add-ons) kosár-logika
**Gitea kártya:** [#432 - Issue #4: Kiegészítő csomagok (Add-ons) kosár-logikájának és UI megjelenítésének integrálása](https://gitea.profibot.hu/kincses/service-finder/issues/432)
### Jelenlegi állapot
A [`SubscriptionTier`](backend/app/models/core_logic.py:68) modellben létezik a `type` mező (base/addon), de a frontend nem jeleníti meg az addon csomagokat, és nincs kosár-logika.
### Megoldás
1. **Backend:** [`GET /subscriptions/public`](backend/app/api/v1/endpoints/subscriptions.py:121) bővítése: `base_tiers` és `addon_tiers` külön mezők.
2. **Frontend:** [`SubscriptionPlansView.vue`](frontend_app/src/views/SubscriptionPlansView.vue) base és addon csomagok szétválasztott megjelenítése.
3. **Kosár-logika:** [`PlanDetailsModal.vue`](frontend_app/src/components/subscription/PlanDetailsModal.vue) addon checkboxok + összegzés.
4. **Backend:** [`POST /purchase-package`](backend/app/api/v1/endpoints/financial_manager.py) bővítése `addon_tier_ids` fogadására.
### Érintett fájlok
| Fájl | Módosítás |
|------|-----------|
| [`backend/app/api/v1/endpoints/subscriptions.py`](backend/app/api/v1/endpoints/subscriptions.py) | `base_tiers` + `addon_tiers` szétválasztás |
| [`backend/app/api/v1/endpoints/financial_manager.py`](backend/app/api/v1/endpoints/financial_manager.py) | `addon_tier_ids` paraméter fogadása |
| [`frontend_app/src/views/SubscriptionPlansView.vue`](frontend_app/src/views/SubscriptionPlansView.vue) | Base + addon szekciók |
| [`frontend_app/src/components/subscription/PlanDetailsModal.vue`](frontend_app/src/components/subscription/PlanDetailsModal.vue) | Addon checkboxok + kosár összegzés |
| [`frontend_app/src/i18n/hu.ts`](frontend_app/src/i18n/hu.ts) | Addon kulcsok |
| [`frontend_app/src/i18n/en.ts`](frontend_app/src/i18n/en.ts) | Addon kulcsok |
---
## 📊 Függőségi Sorrend (Kritikus!)
```
Fázis 1 (Backend: Free tier bypass + pending)
Fázis 2 (Backend: Mock Payment Gateway)
Fázis 3 (Backend + Frontend: Card adatkötés)
Fázis 4 (Frontend: Add-on kosár)
```
**Miért ebben a sorrendben?**
1. **Fázis 1** nélkül a teljes csomagváltás el van törve (minden ingyenes csomagra váltás hibát dob)
2. **Fázis 2** nélkül a fizetési folyamat nem tesztelhető végponttól-végpontig
3. **Fázis 3** nélkül a frontend kártya nem mutat valós adatokat (még ha az API már helyes is)
4. **Fázis 4** csak azután jöhet, hogy a base csomagok kezelése stabil
---
## 🧪 Tesztelési Stratégia
### Egységtesztek
- `test_is_downgrade()` — tier_level összehasonlítás
- `test_free_tier_bypass()` — 0 Ft-os csomag nem hoz létre PaymentIntent-et
- `test_mock_redirect_mode()` — checkout_url generálás
- `test_mock_webhook_callback()` — callback feldolgozás
- `test_pending_downgrade_executor()` — pending tier aktiválás lejárat után
### Integrációs tesztek
- Teljes flow: Prémium vásárlás → azonnali aktiválás
- Teljes flow: Váltás Ingyenesre → pending_tier_id beállítás
- Teljes flow: Uprade pending downgrade alatt → pending törlés, új tier azonnal
- Addon vásárlás base csomaggal együtt
### E2E tesztek (Playwright)
- Pending downgrade banner megjelenése a SubscriptionStatusWidget-ban
- "Csomagváltás folyamatban" üzenet sikeres downgrade rendelés után
- Base + addon kosár összegzés helyes megjelenítése
---
## 📎 Referenciák
- [`logic_spec_subscription_downgrade_and_mock_payment.md`](plans/logic_spec_subscription_downgrade_and_mock_payment.md) — Teljes műszaki specifikáció
- [`logic_spec_subscription_card_upgrade.md`](plans/logic_spec_subscription_card_upgrade.md) — Card upgrade specifikáció
- [`logic_spec_subscription_package_filtering_bug.md`](plans/logic_spec_subscription_package_filtering_bug.md) — Package filtering bug specifikáció
- [P0 Subscription JSONB Audit](docs/p0_subscription_jsonb_structural_audit_report.md) — Tier JSONB struktúra audit