Files
fotospiel-app/app/Http/Controllers/Testing/TestCouponController.php
Codex Agent 7ea34b3b20
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled
Gate testing API for staging E2E
2026-01-03 15:00:33 +01:00

151 lines
5.4 KiB
PHP

<?php
namespace App\Http\Controllers\Testing;
use App\Enums\CouponStatus;
use App\Enums\CouponType;
use App\Http\Controllers\Controller;
use App\Models\Coupon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Validation\ValidationException;
class TestCouponController extends Controller
{
public function store(Request $request): JsonResponse
{
abort_unless(config('e2e.testing_enabled'), 404);
$payload = $request->input('coupons');
$definitions = collect(is_array($payload) ? $payload : [])
->map(fn ($definition) => $this->normalizeDefinition($definition))
->filter()
->values();
if ($definitions->isEmpty()) {
$definitions = collect($this->defaultDefinitions());
}
$created = $definitions->map(function (array $definition) {
$coupon = Coupon::updateOrCreate(
['code' => strtoupper($definition['code'])],
[
'name' => $definition['name'] ?? $definition['code'],
'type' => CouponType::from($definition['type']),
'status' => CouponStatus::from($definition['status'] ?? CouponStatus::ACTIVE->value),
'amount' => $definition['amount'],
'currency' => $definition['currency'],
'description' => $definition['description'] ?? null,
'enabled_for_checkout' => $definition['enabled_for_checkout'],
'auto_apply' => $definition['auto_apply'],
'is_stackable' => $definition['is_stackable'],
'usage_limit' => $definition['usage_limit'],
'per_customer_limit' => $definition['per_customer_limit'],
'starts_at' => $definition['starts_at'],
'ends_at' => $definition['ends_at'],
]
);
if (array_key_exists('packages', $definition)) {
$coupon->packages()->sync($definition['packages']);
}
return $coupon->fresh(['packages']);
});
return response()->json([
'data' => $created->map(fn (Coupon $coupon) => [
'id' => $coupon->id,
'code' => $coupon->code,
'type' => $coupon->type->value,
'status' => $coupon->status->value,
]),
]);
}
private function normalizeDefinition(array $definition): array
{
$code = strtoupper((string) ($definition['code'] ?? ''));
$type = $definition['type'] ?? CouponType::PERCENTAGE->value;
if ($code === '') {
throw ValidationException::withMessages(['code' => 'Coupon code is required.']);
}
$amount = (float) ($definition['amount'] ?? 0);
if ($amount <= 0) {
throw ValidationException::withMessages(['amount' => 'Coupon amount must be greater than zero.']);
}
$currency = $definition['currency'] ?? null;
if ($type !== CouponType::PERCENTAGE->value && ! $currency) {
$currency = 'EUR';
}
return [
'code' => $code,
'name' => $definition['name'] ?? null,
'type' => $type,
'status' => $definition['status'] ?? CouponStatus::ACTIVE->value,
'amount' => $amount,
'currency' => $currency ? strtoupper((string) $currency) : null,
'description' => $definition['description'] ?? null,
'enabled_for_checkout' => Arr::get($definition, 'enabled_for_checkout', true),
'auto_apply' => Arr::get($definition, 'auto_apply', false),
'is_stackable' => Arr::get($definition, 'is_stackable', false),
'usage_limit' => Arr::get($definition, 'usage_limit'),
'per_customer_limit' => Arr::get($definition, 'per_customer_limit'),
'starts_at' => $this->parseDate($definition['starts_at'] ?? null),
'ends_at' => $this->parseDate($definition['ends_at'] ?? null),
'packages' => Arr::get($definition, 'packages'),
];
}
private function parseDate(mixed $value): ?Carbon
{
if (! $value) {
return null;
}
if ($value instanceof Carbon) {
return $value;
}
return Carbon::parse($value);
}
private function defaultDefinitions(): array
{
return [
[
'code' => 'PERCENT10',
'name' => '10% off',
'type' => CouponType::PERCENTAGE->value,
'amount' => 10,
'description' => '10% discount for package flows',
'usage_limit' => 500,
],
[
'code' => 'FLAT50',
'name' => '50 EUR off',
'type' => CouponType::FLAT->value,
'amount' => 50,
'currency' => 'EUR',
'description' => '50€ discount on qualifying packages',
'usage_limit' => 200,
],
[
'code' => 'EXPIRED25',
'name' => 'Expired 25%',
'type' => CouponType::PERCENTAGE->value,
'amount' => 25,
'description' => 'Expired coupon for error handling tests',
'starts_at' => now()->subWeeks(2),
'ends_at' => now()->subDays(2),
],
];
}
}