Migrate billing from Paddle to Lemon Squeezy

This commit is contained in:
Codex Agent
2026-02-03 10:59:54 +01:00
parent 2f4ebfefd4
commit a0ef90e13a
228 changed files with 4369 additions and 4067 deletions

View File

@@ -4,8 +4,8 @@ namespace App\Filament\Resources;
use App\Filament\Clusters\WeeklyOps\WeeklyOpsCluster;
use App\Filament\Resources\PackageResource\Pages;
use App\Jobs\PullPackageFromPaddle;
use App\Jobs\SyncPackageToPaddle;
use App\Jobs\PullPackageFromLemonSqueezy;
use App\Jobs\SyncPackageToLemonSqueezy;
use App\Models\Package;
use App\Services\Audit\SuperAdminAuditLogger;
use BackedEnum;
@@ -172,31 +172,31 @@ class PackageResource extends Resource
->columnSpanFull()
->default([]),
]),
Section::make('Paddle Billing')
Section::make('Lemon Squeezy Billing')
->columns(2)
->schema([
TextInput::make('paddle_product_id')
->label('Paddle Produkt-ID')
TextInput::make('lemonsqueezy_product_id')
->label('Lemon Squeezy Produkt-ID')
->maxLength(191)
->helperText('Produkt aus Paddle Billing. Leer lassen, wenn noch nicht synchronisiert.')
->helperText('Produkt aus Lemon Squeezy. Leer lassen, wenn noch nicht synchronisiert.')
->placeholder('nicht verknüpft'),
TextInput::make('paddle_price_id')
->label('Paddle Preis-ID')
TextInput::make('lemonsqueezy_variant_id')
->label('Lemon Squeezy Variant-ID')
->maxLength(191)
->helperText('Preis-ID aus Paddle Billing, verknüpft mit diesem Paket.')
->helperText('Variant-ID aus Lemon Squeezy, verknüpft mit diesem Paket.')
->placeholder('nicht verknüpft'),
Placeholder::make('paddle_sync_status')
Placeholder::make('lemonsqueezy_sync_status')
->label('Sync-Status')
->content(fn (?Package $record) => $record?->paddle_sync_status ? Str::headline($record->paddle_sync_status) : '')
->content(fn (?Package $record) => $record?->lemonsqueezy_sync_status ? Str::headline($record->lemonsqueezy_sync_status) : '')
->columnSpanFull(),
Placeholder::make('paddle_synced_at')
Placeholder::make('lemonsqueezy_synced_at')
->label('Zuletzt synchronisiert')
->content(fn (?Package $record) => $record?->paddle_synced_at ? $record->paddle_synced_at->diffForHumans() : '')
->content(fn (?Package $record) => $record?->lemonsqueezy_synced_at ? $record->lemonsqueezy_synced_at->diffForHumans() : '')
->columnSpanFull(),
Placeholder::make('paddle_sync_error')
Placeholder::make('lemonsqueezy_sync_error')
->label('Letzter Fehler')
->content(fn (?Package $record) => $record?->paddle_sync_error_message ?? '')
->visible(fn (?Package $record) => filled($record?->paddle_sync_error_message))
->content(fn (?Package $record) => $record?->lemonsqueezy_sync_error_message ?? '')
->visible(fn (?Package $record) => filled($record?->lemonsqueezy_sync_error_message))
->columnSpanFull(),
]),
]);
@@ -263,15 +263,15 @@ class PackageResource extends Resource
->label('Features')
->wrap()
->formatStateUsing(fn ($state) => static::formatFeaturesForDisplay($state)),
TextColumn::make('paddle_product_id')
->label('Paddle Produkt')
TextColumn::make('lemonsqueezy_product_id')
->label('Lemon Squeezy Produkt')
->toggleable(isToggledHiddenByDefault: true)
->formatStateUsing(fn ($state) => $state ?: '-'),
TextColumn::make('paddle_price_id')
->label('Paddle Preis')
TextColumn::make('lemonsqueezy_variant_id')
->label('Lemon Squeezy Variant')
->toggleable(isToggledHiddenByDefault: true)
->formatStateUsing(fn ($state) => $state ?: '-'),
BadgeColumn::make('paddle_sync_status')
BadgeColumn::make('lemonsqueezy_sync_status')
->label('Sync-Status')
->colors([
'success' => 'synced',
@@ -281,13 +281,13 @@ class PackageResource extends Resource
])
->formatStateUsing(fn ($state) => $state ? Str::headline($state) : null)
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('paddle_synced_at')
TextColumn::make('lemonsqueezy_synced_at')
->label('Sync am')
->dateTime()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('paddle_sync_error_message')
TextColumn::make('lemonsqueezy_sync_error_message')
->label('Sync-Fehler')
->getStateUsing(fn (Package $record) => $record->paddle_sync_error_message)
->getStateUsing(fn (Package $record) => $record->lemonsqueezy_sync_error_message)
->wrap()
->toggleable(isToggledHiddenByDefault: true),
])
@@ -301,43 +301,43 @@ class PackageResource extends Resource
TrashedFilter::make(),
])
->actions([
Actions\Action::make('syncPaddle')
->label('Mit Paddle abgleichen')
Actions\Action::make('syncLemonSqueezy')
->label('Mit Lemon Squeezy abgleichen')
->icon('heroicon-o-cloud-arrow-up')
->color('success')
->requiresConfirmation()
->disabled(fn (Package $record) => $record->paddle_sync_status === 'syncing')
->disabled(fn (Package $record) => $record->lemonsqueezy_sync_status === 'syncing')
->action(function (Package $record) {
SyncPackageToPaddle::dispatch($record->id);
SyncPackageToLemonSqueezy::dispatch($record->id);
Notification::make()
->success()
->title('Paddle-Sync gestartet')
->body('Das Paket wird im Hintergrund mit Paddle abgeglichen.')
->title('Lemon Squeezy-Sync gestartet')
->body('Das Paket wird im Hintergrund mit Lemon Squeezy abgeglichen.')
->send();
}),
Actions\Action::make('linkPaddle')
->label('Paddle verknüpfen')
Actions\Action::make('linkLemonSqueezy')
->label('Lemon Squeezy verknüpfen')
->icon('heroicon-o-link')
->color('info')
->form([
TextInput::make('paddle_product_id')
->label('Paddle Produkt-ID')
TextInput::make('lemonsqueezy_product_id')
->label('Lemon Squeezy Produkt-ID')
->required()
->maxLength(191),
TextInput::make('paddle_price_id')
->label('Paddle Preis-ID')
TextInput::make('lemonsqueezy_variant_id')
->label('Lemon Squeezy Variant-ID')
->required()
->maxLength(191),
])
->fillForm(fn (Package $record) => [
'paddle_product_id' => $record->paddle_product_id,
'paddle_price_id' => $record->paddle_price_id,
'lemonsqueezy_product_id' => $record->lemonsqueezy_product_id,
'lemonsqueezy_variant_id' => $record->lemonsqueezy_variant_id,
])
->action(function (Package $record, array $data): void {
$record->linkPaddleIds($data['paddle_product_id'], $data['paddle_price_id']);
$record->linkLemonSqueezyIds($data['lemonsqueezy_product_id'], $data['lemonsqueezy_variant_id']);
PullPackageFromPaddle::dispatch($record->id);
PullPackageFromLemonSqueezy::dispatch($record->id);
app(SuperAdminAuditLogger::class)->recordModelMutation(
'linked',
@@ -348,22 +348,22 @@ class PackageResource extends Resource
Notification::make()
->success()
->title('Paddle-Verknüpfung gespeichert')
->title('Lemon Squeezy-Verknüpfung gespeichert')
->body('Die IDs wurden gespeichert und ein Pull wurde angestoßen.')
->send();
}),
Actions\Action::make('pullPaddle')
->label('Status von Paddle holen')
Actions\Action::make('pullLemonSqueezy')
->label('Status von Lemon Squeezy holen')
->icon('heroicon-o-cloud-arrow-down')
->disabled(fn (Package $record) => ! $record->paddle_product_id && ! $record->paddle_price_id)
->disabled(fn (Package $record) => ! $record->lemonsqueezy_product_id && ! $record->lemonsqueezy_variant_id)
->requiresConfirmation()
->action(function (Package $record) {
PullPackageFromPaddle::dispatch($record->id);
PullPackageFromLemonSqueezy::dispatch($record->id);
Notification::make()
->info()
->title('Paddle-Abgleich angefordert')
->body('Der aktuelle Stand aus Paddle wird geladen und hier hinterlegt.')
->title('Lemon Squeezy-Abgleich angefordert')
->body('Der aktuelle Stand aus Lemon Squeezy wird geladen und hier hinterlegt.')
->send();
}),
ViewAction::make(),