widerrufsbelehrung hinzugefügt und in den checkout mit eingebunden. refund ins backend eingebaut.

This commit is contained in:
Codex Agent
2025-12-07 11:57:05 +01:00
parent e092f72475
commit 1d3d49e05a
44 changed files with 1143 additions and 71 deletions

View File

@@ -23,7 +23,12 @@ use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use App\Notifications\Ops\RefundProcessed;
use App\Notifications\Customer\RefundReceipt;
use App\Services\Paddle\PaddleTransactionService;
class PurchaseResource extends Resource
{
@@ -125,6 +130,21 @@ class PurchaseResource extends Resource
TextColumn::make('provider_id')
->copyable()
->toggleable(),
TextColumn::make('metadata.consents.legal_version')
->label('Legal Version')
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('metadata.consents.accepted_terms_at')
->label('Terms accepted')
->dateTime()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('metadata.consents.accepted_withdrawal_notice_at')
->label('Withdrawal notice')
->dateTime()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('metadata.consents.digital_content_waiver_at')
->label('Waiver (digital)')
->dateTime()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
SelectFilter::make('type')
@@ -162,10 +182,55 @@ class PurchaseResource extends Resource
->icon('heroicon-o-arrow-uturn-left')
->requiresConfirmation()
->visible(fn (PackagePurchase $record): bool => ! $record->refunded)
->action(function (PackagePurchase $record) {
$record->update(['refunded' => true]);
// TODO: Call Stripe/Paddle API for actual refund
Log::info('Refund processed for purchase ID: '.$record->id);
->form([
Textarea::make('reason')
->label('Refund reason (optional)')
->rows(2),
])
->action(function (PackagePurchase $record, array $data) {
$reason = $data['reason'] ?? null;
$refundSuccess = true;
$errorMessage = null;
if ($record->provider === 'paddle' && $record->provider_id) {
try {
/** @var PaddleTransactionService $paddle */
$paddle = App::make(PaddleTransactionService::class);
$paddle->refund($record->provider_id, ['reason' => $reason]);
} catch (\Throwable $exception) {
$refundSuccess = false;
$errorMessage = $exception->getMessage();
Log::warning('Paddle refund failed', [
'purchase_id' => $record->id,
'provider_id' => $record->provider_id,
'error' => $exception->getMessage(),
]);
}
}
$metadata = $record->metadata ?? [];
$metadata['refund_reason'] = $reason ?: ($metadata['refund_reason'] ?? null);
$record->update([
'refunded' => true,
'metadata' => $metadata,
]);
Log::info('Refund processed for purchase ID: '.$record->id, [
'provider' => $record->provider,
'provider_id' => $record->provider_id,
'reason' => $reason,
]);
$customerEmail = $record->tenant->contact_email ?? $record->tenant?->user?->email;
if ($customerEmail) {
Notification::route('mail', $customerEmail)->notify(new RefundReceipt($record, $reason));
}
$opsEmail = config('mail.ops_address');
if ($opsEmail) {
Notification::route('mail', $opsEmail)->notify(new RefundProcessed($record, $refundSuccess, $reason, $errorMessage));
}
}),
])
->bulkActions([