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

@@ -1 +1 @@
{"id":"dev","timestamp":1785068325212}
{"id":"dev","timestamp":1785166100527}

View File

@@ -1 +1 @@
{"id":"dev","timestamp":1785068325212,"prerendered":[]}
{"id":"dev","timestamp":1785166100527,"prerendered":[]}

View File

@@ -1,5 +1,5 @@
{
"date": "2026-07-26T12:18:53.544Z",
"date": "2026-07-27T15:28:28.473Z",
"preset": "nitro-dev",
"framework": {
"name": "nuxt",
@@ -11,7 +11,7 @@
"dev": {
"pid": 19,
"workerAddress": {
"socketPath": "\u0000nitro-worker-19-1-1-8775.sock"
"socketPath": "\u0000nitro-worker-19-1-1-1764.sock"
}
}
}

View File

@@ -1,8 +1,8 @@
/// <reference types="@pinia/nuxt" />
/// <reference types="@nuxtjs/i18n" />
/// <reference types="@nuxt/devtools" />
/// <reference types="@nuxtjs/tailwindcss" />
/// <reference types="@nuxt/telemetry" />
/// <reference types="@pinia/nuxt" />
/// <reference types="@nuxt/devtools" />
/// <reference types="@nuxtjs/i18n" />
/// <reference path="types/nitro-layouts.d.ts" />
/// <reference path="types/builder-env.d.ts" />
/// <reference types="nuxt" />

View File

@@ -1,4 +1,4 @@
// generated by the @nuxtjs/tailwindcss <https://github.com/nuxt-modules/tailwindcss> module at 7/26/2026, 12:18:45 PM
// generated by the @nuxtjs/tailwindcss <https://github.com/nuxt-modules/tailwindcss> module at 7/28/2026, 12:21:03 PM
import "@nuxtjs/tailwindcss/config-ctx"
import configMerger from "@nuxtjs/tailwindcss/merger";

View File

@@ -704,6 +704,113 @@
<p class="text-xs text-slate-500 mt-1">{{ $t('packages.feature_capabilities_hint') }}</p>
<p v-if="featureCapabilitiesError" class="text-xs text-red-400 mt-1">{{ featureCapabilitiesError }}</p>
</div>
<!-- TAB 4: Auto-Renewal Rules -->
<div v-if="activeTab === 'renewal'" class="space-y-6">
<!-- Renewal Enabled Toggle -->
<div class="bg-slate-700/30 rounded-xl p-5">
<div class="flex items-center justify-between mb-4">
<div>
<h4 class="text-sm font-semibold text-slate-200">🔄 {{ $t('packages.renewal_title') || 'Auto-Renewal' }}</h4>
<p class="text-xs text-slate-400 mt-1">{{ $t('packages.renewal_subtitle') || 'Configure automatic subscription renewal rules for this package.' }}</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input
v-model="form.renewal_enabled"
type="checkbox"
class="sr-only peer"
/>
<div class="w-11 h-6 bg-slate-600 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-indigo-500 rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-indigo-600"></div>
<span class="ms-3 text-sm text-slate-300">{{ form.renewal_enabled ? 'Enabled' : 'Disabled' }}</span>
</label>
</div>
</div>
<!-- Renewal Settings (shown only when enabled) -->
<div v-if="form.renewal_enabled" class="space-y-5">
<!-- Auto-Renew Default Toggle -->
<div class="bg-slate-700/30 rounded-xl p-5">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-medium text-slate-200">{{ $t('packages.renewal_auto_default') || 'Auto-Renew by Default' }}</p>
<p class="text-xs text-slate-400 mt-0.5">{{ $t('packages.renewal_auto_default_hint') || 'New subscriptions will have auto-renew enabled by default.' }}</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input
v-model="form.renewal_auto_renew_default"
type="checkbox"
class="sr-only peer"
/>
<div class="w-11 h-6 bg-slate-600 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-indigo-500 rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-indigo-600"></div>
<span class="ms-3 text-sm text-slate-300">{{ form.renewal_auto_renew_default ? 'Yes' : 'No' }}</span>
</label>
</div>
</div>
<!-- Renewal Period (grid row) -->
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-slate-300 mb-1">{{ $t('packages.renewal_period') || 'Renewal Period (days)' }}</label>
<input
v-model.number="form.renewal_period_days"
type="number"
min="1"
max="365"
:placeholder="$t('packages.renewal_period_placeholder') || 'Leave empty = use duration.days'"
class="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
/>
<p class="text-xs text-slate-500 mt-1">{{ $t('packages.renewal_period_hint') || 'If empty, the subscription duration.days is used.' }}</p>
</div>
<div>
<label class="block text-sm font-medium text-slate-300 mb-1">{{ $t('packages.renewal_grace_period') || 'Grace Period (days)' }}</label>
<input
v-model.number="form.renewal_grace_period_days"
type="number"
min="0"
max="90"
class="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
/>
<p class="text-xs text-slate-500 mt-1">{{ $t('packages.renewal_grace_period_hint') || 'Days after expiry before subscription suspension.' }}</p>
</div>
</div>
<!-- Retry Settings (grid row) -->
<div class="bg-slate-700/30 rounded-xl p-5">
<h4 class="text-sm font-semibold text-slate-200 mb-4">{{ $t('packages.renewal_retry_title') || 'Retry on Failure' }}</h4>
<div class="grid grid-cols-2 gap-4">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-slate-300">{{ $t('packages.renewal_retry') || 'Retry on Failure' }}</p>
<p class="text-xs text-slate-400 mt-0.5">{{ $t('packages.renewal_retry_hint') || 'Retry failed payment attempts automatically.' }}</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input
v-model="form.renewal_retry_on_failure"
type="checkbox"
class="sr-only peer"
/>
<div class="w-11 h-6 bg-slate-600 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-indigo-500 rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-indigo-600"></div>
<span class="ms-3 text-sm text-slate-300">{{ form.renewal_retry_on_failure ? 'Yes' : 'No' }}</span>
</label>
</div>
<div>
<label class="block text-sm font-medium text-slate-300 mb-1">{{ $t('packages.renewal_max_retry') || 'Max Retry Count' }}</label>
<input
v-model.number="form.renewal_max_retry_count"
type="number"
min="0"
max="20"
class="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
/>
</div>
</div>
</div>
</div>
<!-- Legacy data notice (empty state when disabled) -->
<div v-if="!form.renewal_enabled" class="bg-slate-700/20 rounded-xl p-5 text-center">
<p class="text-sm text-slate-400">{{ $t('packages.renewal_disabled_hint') || 'Auto-renewal is disabled for this package. Toggle the switch above to enable it.' }}</p>
</div>
</div>
</div>
</div>
@@ -825,6 +932,14 @@ interface SubscriptionTier {
is_public?: boolean
available_until?: string | null
} | null
renewal?: {
enabled?: boolean
auto_renew_default?: boolean
renewal_period_days?: number | null
retry_on_failure?: boolean
max_retry_count?: number
grace_period_days?: number
} | null
}
is_custom: boolean
tier_level: number
@@ -855,6 +970,13 @@ interface PackageForm {
trial_days_on_signup: number
feature_capabilities_json: string
pricing_zones: Record<string, { monthly_price: number; yearly_price: number; credit_price: number; currency: string }>
// ── P0 Phase E: Auto-renewal rules ──
renewal_enabled: boolean
renewal_auto_renew_default: boolean
renewal_period_days: number | null
renewal_retry_on_failure: boolean
renewal_max_retry_count: number
renewal_grace_period_days: number
}
// ── Tab Configuration ──────────────────────────────────────────────
@@ -863,6 +985,7 @@ const tabs = [
{ key: 'basic', label: '📋 Basic Info' },
{ key: 'pricing', label: '💰 Pricing' },
{ key: 'features', label: '⚡ Features' },
{ key: 'renewal', label: '🔄 Auto-Renewal' },
]
const activeTab = ref('basic')
@@ -956,7 +1079,14 @@ const defaultForm: PackageForm = {
is_default_fallback: false,
trial_days_on_signup: 0,
feature_capabilities_json: '{\n "ai_analysis": false,\n "priority_support": false,\n "api_access": false\n}',
pricing_zones: {}
pricing_zones: {},
// ── P0 Phase E: Auto-renewal defaults ──
renewal_enabled: false,
renewal_auto_renew_default: false,
renewal_period_days: null,
renewal_retry_on_failure: true,
renewal_max_retry_count: 3,
renewal_grace_period_days: 7,
}
const form = reactive<PackageForm>({ ...defaultForm })
@@ -1181,6 +1311,15 @@ function openEditModal(pkg: SubscriptionTier) {
// Load feature capabilities as JSON string
form.feature_capabilities_json = JSON.stringify(pkg.feature_capabilities || {}, null, 2)
// ── P0 Phase E: Load auto-renewal rules ──
const renewalFromRules = rules.renewal || {}
form.renewal_enabled = renewalFromRules.enabled ?? false
form.renewal_auto_renew_default = renewalFromRules.auto_renew_default ?? false
form.renewal_period_days = renewalFromRules.renewal_period_days ?? null
form.renewal_retry_on_failure = renewalFromRules.retry_on_failure ?? true
form.renewal_max_retry_count = renewalFromRules.max_retry_count ?? 3
form.renewal_grace_period_days = renewalFromRules.grace_period_days ?? 7
showModal.value = true
}
@@ -1301,6 +1440,15 @@ async function savePackage() {
lifecycle: {
is_public: true,
},
// ── P0 Phase E: Auto-renewal rules ──
renewal: {
enabled: form.renewal_enabled,
auto_renew_default: form.renewal_auto_renew_default,
renewal_period_days: form.renewal_period_days,
retry_on_failure: form.renewal_retry_on_failure,
max_retry_count: form.renewal_max_retry_count,
grace_period_days: form.renewal_grace_period_days,
},
}
if (isCreating.value) {