implemented event package addons with filament resource, event-admin purchase path and notifications, showing up in purchase history
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('event_packages', function (Blueprint $table) {
|
||||
if (! Schema::hasColumn('event_packages', 'limits_snapshot')) {
|
||||
$table->json('limits_snapshot')->nullable()->after('package_id');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('event_packages', 'extra_photos')) {
|
||||
$table->integer('extra_photos')->default(0)->after('used_photos');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('event_packages', 'extra_guests')) {
|
||||
$table->integer('extra_guests')->default(0)->after('used_guests');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('event_packages', 'extra_gallery_days')) {
|
||||
$table->integer('extra_gallery_days')->default(0)->after('gallery_expires_at');
|
||||
}
|
||||
});
|
||||
|
||||
// Backfill snapshots from current package limits where missing.
|
||||
if (Schema::hasTable('event_packages') && Schema::hasTable('packages')) {
|
||||
DB::table('event_packages')
|
||||
->whereNull('limits_snapshot')
|
||||
->orderBy('id')
|
||||
->chunkById(200, function ($rows) {
|
||||
foreach ($rows as $row) {
|
||||
$package = DB::table('packages')
|
||||
->where('id', $row->package_id)
|
||||
->first([
|
||||
'max_photos',
|
||||
'max_guests',
|
||||
'gallery_days',
|
||||
'max_tasks',
|
||||
'max_events_per_year',
|
||||
]);
|
||||
|
||||
if (! $package) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$snapshot = array_filter([
|
||||
'max_photos' => $package->max_photos,
|
||||
'max_guests' => $package->max_guests,
|
||||
'gallery_days' => $package->gallery_days,
|
||||
'max_tasks' => $package->max_tasks,
|
||||
'max_events_per_year' => $package->max_events_per_year,
|
||||
], fn ($value) => $value !== null);
|
||||
|
||||
if ($snapshot === []) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('event_packages')
|
||||
->where('id', $row->id)
|
||||
->update(['limits_snapshot' => json_encode($snapshot)]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('event_packages', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('event_packages', 'limits_snapshot')) {
|
||||
$table->dropColumn('limits_snapshot');
|
||||
}
|
||||
if (Schema::hasColumn('event_packages', 'extra_photos')) {
|
||||
$table->dropColumn('extra_photos');
|
||||
}
|
||||
if (Schema::hasColumn('event_packages', 'extra_guests')) {
|
||||
$table->dropColumn('extra_guests');
|
||||
}
|
||||
if (Schema::hasColumn('event_packages', 'extra_gallery_days')) {
|
||||
$table->dropColumn('extra_gallery_days');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('event_package_addons', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('event_package_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('event_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('tenant_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('addon_key');
|
||||
$table->integer('quantity')->default(1);
|
||||
$table->integer('extra_photos')->default(0);
|
||||
$table->integer('extra_guests')->default(0);
|
||||
$table->integer('extra_gallery_days')->default(0);
|
||||
$table->string('price_id')->nullable();
|
||||
$table->string('checkout_id')->nullable();
|
||||
$table->string('transaction_id')->nullable();
|
||||
$table->enum('status', ['pending', 'completed', 'failed'])->default('pending');
|
||||
$table->decimal('amount', 10, 2)->nullable();
|
||||
$table->string('currency', 3)->nullable();
|
||||
$table->json('metadata')->nullable();
|
||||
$table->json('receipt_payload')->nullable();
|
||||
$table->string('error')->nullable();
|
||||
$table->timestamp('purchased_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['tenant_id', 'event_id']);
|
||||
$table->index(['checkout_id']);
|
||||
$table->index(['transaction_id']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('event_package_addons');
|
||||
}
|
||||
};
|
||||
@@ -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
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('package_addons', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('key')->unique();
|
||||
$table->string('label');
|
||||
$table->string('price_id')->nullable();
|
||||
$table->integer('extra_photos')->default(0);
|
||||
$table->integer('extra_guests')->default(0);
|
||||
$table->integer('extra_gallery_days')->default(0);
|
||||
$table->boolean('active')->default(true);
|
||||
$table->unsignedInteger('sort')->default(0);
|
||||
$table->json('metadata')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('package_addons');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?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('event_package_addons', function (Blueprint $table) {
|
||||
if (! Schema::hasColumn('event_package_addons', 'receipt_payload')) {
|
||||
$table->json('receipt_payload')->nullable()->after('metadata');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('event_package_addons', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('event_package_addons', 'receipt_payload')) {
|
||||
$table->dropColumn('receipt_payload');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -16,6 +16,7 @@ class DatabaseSeeder extends Seeder
|
||||
MediaStorageTargetSeeder::class,
|
||||
LegalPagesSeeder::class,
|
||||
PackageSeeder::class,
|
||||
PackageAddonSeeder::class,
|
||||
EventTypesSeeder::class,
|
||||
EmotionsSeeder::class,
|
||||
TaskCollectionsSeeder::class,
|
||||
|
||||
143
database/seeders/PackageAddonSeeder.php
Normal file
143
database/seeders/PackageAddonSeeder.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\PackageAddon;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class PackageAddonSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$addons = [
|
||||
[
|
||||
'key' => 'extra_photos_500',
|
||||
'label' => '+500 Fotos',
|
||||
'price_id' => null,
|
||||
'extra_photos' => 500,
|
||||
'extra_guests' => 0,
|
||||
'extra_gallery_days' => 0,
|
||||
'active' => true,
|
||||
'sort' => 10,
|
||||
'metadata' => ['price_eur' => 5],
|
||||
],
|
||||
[
|
||||
'key' => 'extra_photos_2000',
|
||||
'label' => '+2.000 Fotos',
|
||||
'price_id' => null,
|
||||
'extra_photos' => 2000,
|
||||
'extra_guests' => 0,
|
||||
'extra_gallery_days' => 0,
|
||||
'active' => true,
|
||||
'sort' => 11,
|
||||
'metadata' => ['price_eur' => 12],
|
||||
],
|
||||
[
|
||||
'key' => 'extra_photos_5000',
|
||||
'label' => '+5.000 Fotos',
|
||||
'price_id' => null,
|
||||
'extra_photos' => 5000,
|
||||
'extra_guests' => 0,
|
||||
'extra_gallery_days' => 0,
|
||||
'active' => true,
|
||||
'sort' => 12,
|
||||
'metadata' => ['price_eur' => 25],
|
||||
],
|
||||
[
|
||||
'key' => 'extra_guests_50',
|
||||
'label' => '+50 Gäste',
|
||||
'price_id' => null,
|
||||
'extra_photos' => 0,
|
||||
'extra_guests' => 50,
|
||||
'extra_gallery_days' => 0,
|
||||
'active' => true,
|
||||
'sort' => 18,
|
||||
'metadata' => ['price_eur' => 3],
|
||||
],
|
||||
[
|
||||
'key' => 'extra_guests_100',
|
||||
'label' => '+100 Gäste',
|
||||
'price_id' => null,
|
||||
'extra_photos' => 0,
|
||||
'extra_guests' => 100,
|
||||
'extra_gallery_days' => 0,
|
||||
'active' => true,
|
||||
'sort' => 19,
|
||||
'metadata' => ['price_eur' => 5],
|
||||
],
|
||||
[
|
||||
'key' => 'extra_guests_300',
|
||||
'label' => '+300 Gäste',
|
||||
'price_id' => null,
|
||||
'extra_photos' => 0,
|
||||
'extra_guests' => 300,
|
||||
'extra_gallery_days' => 0,
|
||||
'active' => true,
|
||||
'sort' => 20,
|
||||
'metadata' => ['price_eur' => 12],
|
||||
],
|
||||
[
|
||||
'key' => 'extend_gallery_30d',
|
||||
'label' => 'Galerie +30 Tage',
|
||||
'price_id' => null,
|
||||
'extra_photos' => 0,
|
||||
'extra_guests' => 0,
|
||||
'extra_gallery_days' => 30,
|
||||
'active' => true,
|
||||
'sort' => 30,
|
||||
'metadata' => ['price_eur' => 4],
|
||||
],
|
||||
[
|
||||
'key' => 'extend_gallery_90d',
|
||||
'label' => 'Galerie +90 Tage',
|
||||
'price_id' => null,
|
||||
'extra_photos' => 0,
|
||||
'extra_guests' => 0,
|
||||
'extra_gallery_days' => 90,
|
||||
'active' => true,
|
||||
'sort' => 31,
|
||||
'metadata' => ['price_eur' => 10],
|
||||
],
|
||||
[
|
||||
'key' => 'extend_gallery_180d',
|
||||
'label' => 'Galerie +180 Tage',
|
||||
'price_id' => null,
|
||||
'extra_photos' => 0,
|
||||
'extra_guests' => 0,
|
||||
'extra_gallery_days' => 180,
|
||||
'active' => true,
|
||||
'sort' => 32,
|
||||
'metadata' => ['price_eur' => 20],
|
||||
],
|
||||
[
|
||||
'key' => 'event_boost_medium',
|
||||
'label' => 'Event-Boost (100 Gäste, 2.000 Fotos, +30 Tage)',
|
||||
'price_id' => null,
|
||||
'extra_photos' => 2000,
|
||||
'extra_guests' => 100,
|
||||
'extra_gallery_days' => 30,
|
||||
'active' => true,
|
||||
'sort' => 40,
|
||||
'metadata' => ['price_eur' => 18],
|
||||
],
|
||||
[
|
||||
'key' => 'event_boost_large',
|
||||
'label' => 'Event-Boost (300 Gäste, 5.000 Fotos, +90 Tage)',
|
||||
'price_id' => null,
|
||||
'extra_photos' => 5000,
|
||||
'extra_guests' => 300,
|
||||
'extra_gallery_days' => 90,
|
||||
'active' => true,
|
||||
'sort' => 41,
|
||||
'metadata' => ['price_eur' => 38],
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($addons as $addon) {
|
||||
PackageAddon::updateOrCreate(
|
||||
['key' => $addon['key']],
|
||||
$addon,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user