übergang auf pakete, integration von stripe und paypal, blog hinzugefügt.
This commit is contained in:
@@ -10,8 +10,8 @@ return new class extends Migration {
|
||||
Schema::create('events', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('tenant_id')->constrained()->onDelete('cascade');
|
||||
$table->string('name');
|
||||
$table->text('description')->nullable();
|
||||
$table->json('name');
|
||||
$table->json('description')->nullable();
|
||||
$table->dateTime('date');
|
||||
$table->string('slug')->unique();
|
||||
$table->string('location')->nullable();
|
||||
|
||||
@@ -12,9 +12,9 @@ return new class extends Migration {
|
||||
$table->foreignId('tenant_id')->constrained()->onDelete('cascade');
|
||||
$table->unsignedBigInteger('emotion_id')->nullable();
|
||||
$table->unsignedBigInteger('event_type_id')->nullable();
|
||||
$table->string('title');
|
||||
$table->text('description')->nullable();
|
||||
$table->text('example_text')->nullable();
|
||||
$table->json('title');
|
||||
$table->json('description')->nullable();
|
||||
$table->json('example_text')->nullable();
|
||||
$table->dateTime('due_date')->nullable();
|
||||
$table->boolean('is_completed')->default(false);
|
||||
$table->enum('priority', ['low', 'medium', 'high', 'urgent'])->default('medium');
|
||||
|
||||
@@ -72,7 +72,7 @@ return new class extends Migration
|
||||
}
|
||||
|
||||
// Migrate tenant credits to tenant_packages (Free package)
|
||||
DB::table('tenants')->where('event_credits_balance', '>', 0)->chunk(100, function ($tenants) {
|
||||
DB::table('tenants')->where('event_credits_balance', '>', 0)->orderBy('id')->chunk(100, function ($tenants) {
|
||||
foreach ($tenants as $tenant) {
|
||||
$freePackageId = DB::table('packages')->where('name', 'Free/Test')->first()->id;
|
||||
DB::table('tenant_packages')->insert([
|
||||
@@ -106,7 +106,7 @@ return new class extends Migration
|
||||
});
|
||||
|
||||
// Migrate event purchases to event_packages (if any existing events)
|
||||
DB::table('events')->chunk(100, function ($events) {
|
||||
DB::table('events')->orderBy('id')->chunk(100, function ($events) {
|
||||
foreach ($events as $event) {
|
||||
if ($event->tenant->event_credits_balance > 0) { // or check if event was created with credits
|
||||
$freePackageId = DB::table('packages')->where('name', 'Free/Test')->first()->id;
|
||||
@@ -15,15 +15,37 @@ return new class extends Migration
|
||||
Schema::dropIfExists('purchase_history');
|
||||
Schema::dropIfExists('event_purchases');
|
||||
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->dropColumn([
|
||||
'event_credits_balance',
|
||||
'subscription_tier',
|
||||
'subscription_expires_at',
|
||||
'free_event_granted_at',
|
||||
'total_revenue'
|
||||
]);
|
||||
});
|
||||
if (Schema::hasTable('package_purchases')) {
|
||||
Schema::table('package_purchases', function (Blueprint $table) {
|
||||
$table->dropIndex(['tenant_id', 'purchased_at']);
|
||||
});
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('tenants', 'event_credits_balance')) {
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->dropColumn('event_credits_balance');
|
||||
});
|
||||
}
|
||||
if (Schema::hasColumn('tenants', 'subscription_tier')) {
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->dropColumn('subscription_tier');
|
||||
});
|
||||
}
|
||||
if (Schema::hasColumn('tenants', 'subscription_expires_at')) {
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->dropColumn('subscription_expires_at');
|
||||
});
|
||||
}
|
||||
if (Schema::hasColumn('tenants', 'free_event_granted_at')) {
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->dropColumn('free_event_granted_at');
|
||||
});
|
||||
}
|
||||
if (Schema::hasColumn('tenants', 'total_revenue')) {
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->dropColumn('total_revenue');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->string('first_name')->nullable()->after('name');
|
||||
$table->string('last_name')->nullable()->after('first_name');
|
||||
$table->text('address')->nullable()->after('last_name');
|
||||
$table->string('phone')->nullable()->after('address');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn(['first_name', 'last_name', 'address', 'phone']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->foreignId('user_id')->nullable()->constrained('users')->onDelete('cascade')->after('id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('tenants', function (Blueprint $table) {
|
||||
$table->dropForeign(['user_id']);
|
||||
$table->dropColumn('user_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('package_purchases', function (Blueprint $table) {
|
||||
$table->dropForeign(['tenant_id']);
|
||||
$table->foreignId('tenant_id')->constrained()->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('package_purchases', function (Blueprint $table) {
|
||||
$table->dropForeign(['tenant_id']);
|
||||
$table->foreignId('tenant_id')->nullable()->constrained()->change();
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->unique('username');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropUnique(['username']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
@@ -14,6 +14,7 @@ class DatabaseSeeder extends Seeder
|
||||
// Seed basic system data
|
||||
$this->call([
|
||||
LegalPagesSeeder::class,
|
||||
PackageSeeder::class,
|
||||
]);
|
||||
|
||||
// Seed core demo data for frontend previews
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
|
||||
@@ -11,7 +11,10 @@ class DemoEventSeeder extends Seeder
|
||||
{
|
||||
$type = EventType::where('slug','wedding')->first();
|
||||
if(!$type){ return; }
|
||||
$demoTenant = \App\Models\Tenant::where('slug', 'demo')->first();
|
||||
if (!$demoTenant) { return; }
|
||||
Event::updateOrCreate(['slug'=>'demo-wedding-2025'], [
|
||||
'tenant_id' => $demoTenant->id,
|
||||
'name' => ['de'=>'Demo Hochzeit 2025','en'=>'Demo Wedding 2025'],
|
||||
'description' => ['de'=>'Demo-Event','en'=>'Demo event'],
|
||||
'date' => now()->addMonths(3)->toDateString(),
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Models\Package;
|
||||
use App\Enums\PackageType;
|
||||
|
||||
class PackageSeeder extends Seeder
|
||||
{
|
||||
@@ -15,124 +16,98 @@ class PackageSeeder extends Seeder
|
||||
// Endcustomer Packages
|
||||
Package::create([
|
||||
'name' => 'Free / Test',
|
||||
'type' => 'endcustomer',
|
||||
'type' => PackageType::ENDCUSTOMER,
|
||||
'price' => 0.00,
|
||||
'max_photos' => 30,
|
||||
'max_guests' => 10,
|
||||
'gallery_days' => 3,
|
||||
'max_guests' => 50,
|
||||
'gallery_days' => 7,
|
||||
'max_tasks' => 5,
|
||||
'watermark_allowed' => false,
|
||||
'watermark_allowed' => true,
|
||||
'branding_allowed' => false,
|
||||
'features' => json_encode([
|
||||
'basic_uploads' => true,
|
||||
'limited_sharing' => true,
|
||||
'no_branding' => true,
|
||||
]),
|
||||
'description' => 'Ideal für kleine Test-Events oder erste Erfahrungen.',
|
||||
]);
|
||||
|
||||
Package::create([
|
||||
'name' => 'Starter',
|
||||
'type' => 'endcustomer',
|
||||
'price' => 19.00,
|
||||
'max_photos' => 300,
|
||||
'max_guests' => 50,
|
||||
'gallery_days' => 14,
|
||||
'max_tasks' => 20,
|
||||
'type' => PackageType::ENDCUSTOMER,
|
||||
'price' => 29.00,
|
||||
'max_photos' => 200,
|
||||
'max_guests' => 100,
|
||||
'gallery_days' => 30,
|
||||
'max_tasks' => 10,
|
||||
'watermark_allowed' => true,
|
||||
'branding_allowed' => false,
|
||||
'features' => json_encode([
|
||||
'extended_gallery' => true,
|
||||
'guest_sharing' => true,
|
||||
'basic_analytics' => true,
|
||||
'basic_uploads' => true,
|
||||
'unlimited_sharing' => true,
|
||||
'no_watermark' => true,
|
||||
'custom_tasks' => true,
|
||||
]),
|
||||
'description' => 'Perfekt für kleine Events wie Geburtstage oder Firmenfeiern.',
|
||||
]);
|
||||
|
||||
Package::create([
|
||||
'name' => 'Pro',
|
||||
'type' => 'endcustomer',
|
||||
'price' => 49.00,
|
||||
'type' => PackageType::ENDCUSTOMER,
|
||||
'price' => 79.00,
|
||||
'max_photos' => 1000,
|
||||
'max_guests' => 200,
|
||||
'gallery_days' => 30,
|
||||
'max_tasks' => 50,
|
||||
'max_guests' => 500,
|
||||
'gallery_days' => 90,
|
||||
'max_tasks' => 20,
|
||||
'watermark_allowed' => false,
|
||||
'branding_allowed' => false,
|
||||
'features' => json_encode([
|
||||
'basic_uploads' => true,
|
||||
'unlimited_sharing' => true,
|
||||
'no_watermark' => true,
|
||||
'custom_tasks' => true,
|
||||
'advanced_analytics' => true,
|
||||
'priority_support' => true,
|
||||
]),
|
||||
]);
|
||||
|
||||
// Reseller Packages
|
||||
Package::create([
|
||||
'name' => 'S (Small Reseller)',
|
||||
'type' => PackageType::RESELLER,
|
||||
'price' => 199.00,
|
||||
'max_photos' => 500, // per event limit
|
||||
'max_guests' => null, // unlimited
|
||||
'gallery_days' => null,
|
||||
'max_tasks' => null, // unlimited
|
||||
'watermark_allowed' => true,
|
||||
'branding_allowed' => true,
|
||||
'max_events_per_year' => 5,
|
||||
'expires_after' => now()->addYear(),
|
||||
'features' => json_encode([
|
||||
'unlimited_sharing' => true,
|
||||
'advanced_analytics' => true,
|
||||
'reseller_dashboard' => true,
|
||||
'custom_branding' => true,
|
||||
'priority_support' => true,
|
||||
]),
|
||||
'description' => 'Für große Events wie Hochzeiten oder Konferenzen.',
|
||||
]);
|
||||
|
||||
// Reseller Packages (jährliche Subscriptions)
|
||||
Package::create([
|
||||
'name' => 'Reseller S',
|
||||
'type' => 'reseller',
|
||||
'price' => 149.00,
|
||||
'max_events_per_year' => 5,
|
||||
'max_photos' => null, // Kein globales Limit, pro Event
|
||||
'max_guests' => null,
|
||||
'name' => 'M (Medium Reseller)',
|
||||
'type' => PackageType::RESELLER,
|
||||
'price' => 399.00,
|
||||
'max_photos' => 1000, // per event limit
|
||||
'max_guests' => null, // unlimited
|
||||
'gallery_days' => null,
|
||||
'max_tasks' => null,
|
||||
'max_tasks' => null, // unlimited
|
||||
'watermark_allowed' => true,
|
||||
'branding_allowed' => true,
|
||||
'expires_after' => now()->addYear(), // Jährlich
|
||||
'features' => json_encode([
|
||||
'event_management' => true,
|
||||
'reseller_dashboard' => true,
|
||||
'bulk_event_creation' => true,
|
||||
'5_events_included' => true,
|
||||
]),
|
||||
'description' => 'Einstieg für kleine Agenturen: 5 Events pro Jahr.',
|
||||
]);
|
||||
|
||||
Package::create([
|
||||
'name' => 'Reseller M',
|
||||
'type' => 'reseller',
|
||||
'price' => 299.00,
|
||||
'max_events_per_year' => 15,
|
||||
'max_photos' => null,
|
||||
'max_guests' => null,
|
||||
'gallery_days' => null,
|
||||
'max_tasks' => null,
|
||||
'watermark_allowed' => true,
|
||||
'branding_allowed' => true,
|
||||
'expires_after' => now()->addYear(),
|
||||
'features' => json_encode([
|
||||
'event_management' => true,
|
||||
'reseller_dashboard' => true,
|
||||
'bulk_event_creation' => true,
|
||||
'custom_branding' => true,
|
||||
'priority_support' => true,
|
||||
'advanced_reporting' => true,
|
||||
'15_events_included' => true,
|
||||
]),
|
||||
'description' => 'Für wachsende Agenturen: 15 Events pro Jahr.',
|
||||
]);
|
||||
|
||||
Package::create([
|
||||
'name' => 'Reseller L',
|
||||
'type' => 'reseller',
|
||||
'price' => 499.00,
|
||||
'max_events_per_year' => 30,
|
||||
'max_photos' => null,
|
||||
'max_guests' => null,
|
||||
'gallery_days' => null,
|
||||
'max_tasks' => null,
|
||||
'watermark_allowed' => true,
|
||||
'branding_allowed' => true,
|
||||
'expires_after' => now()->addYear(),
|
||||
'features' => json_encode([
|
||||
'event_management' => true,
|
||||
'reseller_dashboard' => true,
|
||||
'bulk_event_creation' => true,
|
||||
'priority_support' => true,
|
||||
'custom_integration' => true,
|
||||
'30_events_included' => true,
|
||||
]),
|
||||
'description' => 'Für große Agenturen: 30 Events pro Jahr mit Premium-Features.',
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user