diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index 23eb2366..5955cabe 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -48,6 +48,8 @@ public function loginCallback() 'Please register for the Convention first before trying to obtain a fursuit badge.'); } + $isNewUser = User::where('remote_id', $socialLiteUser->getId())->doesntExist(); + $user = User::updateOrCreate([ 'remote_id' => $socialLiteUser->getId(), ], [ @@ -76,6 +78,34 @@ public function loginCallback() expiresIn: 3500 ); + if ($isNewUser) { + $fursuit = \Illuminate\Support\Facades\Http::attsrv() + ->withToken($socialLiteUser->token) + ->get('/attendees/' . $regId . '/packages/fursuit') + ->json(); + if ($fursuit['present'] && $fursuit['count'] > 0) { + + $fursuitAdditional = \Illuminate\Support\Facades\Http::attsrv() + ->withToken($socialLiteUser->token) + ->get('/attendees/' . $regId . '/packages/fursuitadd') + ->json(); + + $copies = $fursuitAdditional['present'] ? $fursuitAdditional['count'] : 0; + + $user->has_free_badge = true; + $user->free_badge_copies = $copies; + $user->save(); + + + \Illuminate\Support\Facades\Http::attsrv() + ->withToken($socialLiteUser->token) + ->post('/attendees/' . $regId . '/additional-info/fursuitbadge', [ + 'created' => false, + ]); + } + + } + Auth::login($user, true); if(Session::exists('catch-em-all-redirect')) { Session::forget('catch-em-all-redirect'); diff --git a/app/Http/Controllers/BadgeController.php b/app/Http/Controllers/BadgeController.php index 38df1b92..0b71f1f7 100644 --- a/app/Http/Controllers/BadgeController.php +++ b/app/Http/Controllers/BadgeController.php @@ -33,7 +33,8 @@ public function create(Request $request) Gate::authorize('create', Badge::class); return Inertia::render('Badges/BadgesCreate', [ 'species' => Species::has('fursuits', count: 5)->orWhere('checked', true)->get('name'), - 'isFree' => auth()->user()->badges()->where('is_free_badge', true)->doesntExist(), + 'isFree' => auth()->user()->hasFreeBadge(), + 'freeBadgeCopies' => auth()->user()->hasFreeBadge() ? auth()->user()->free_badge_copies : 0, ]); } @@ -71,7 +72,7 @@ public function store(BadgeCreateRequest $request) ]); // is Free Badge - $isFreeBadge = $request->user()->badges()->where('is_free_badge', true)->doesntExist(); + $isFreeBadge = $request->user()->hasFreeBadge(); // Returns in cents $total = BadgeCalculationService::calculate( @@ -98,7 +99,32 @@ public function store(BadgeCreateRequest $request) // Pay for Badge (force pay as we allow negative balance) $request->user()->forcePay($badge); - if ($validated['upgrades']['spareCopy']) { + if ($isFreeBadge) { + $total = BadgeCalculationService::calculate(isSpareCopy: true); + for ($i = 0; $i < $request->user()->free_badge_copies; $i++) { + $clone = $badge->replicate(); + $clone->is_free_badge = false; + $clone->extra_copy = true; + $clone->total = round($total); + $clone->subtotal = round($total / 1.19); + $clone->tax = round($clone->total - $clone->subtotal); + $clone->extra_copy_of = $badge->id; + $clone->save(); + $request->user()->forcePay($clone->fresh()); + } + $request->user()->wallet->deposit($total * $request->user()->free_badge_copies, ['title' => 'Fuirsuit Badge', 'description' => 'Already paid with the EF registration system']); + $request->user()->free_badge_copies = 0; + $request->user()->has_free_badge = false; + $request->user()->save(); + + // Mark fursuitbadge as created + \Illuminate\Support\Facades\Http::attsrv() + ->withToken($request->user()->token) + ->post('/attendees/' . $request->user()->attendee_id . '/additional-info/fursuitbadge', [ + 'created' => true, + ]); + + } elseif ($validated['upgrades']['spareCopy']) { $total = BadgeCalculationService::calculate(isSpareCopy: true); $clone = $badge->replicate(); $clone->is_free_badge = false; diff --git a/app/Models/Badge/Badge.php b/app/Models/Badge/Badge.php index 9374a1f2..d8d4ace3 100644 --- a/app/Models/Badge/Badge.php +++ b/app/Models/Badge/Badge.php @@ -81,4 +81,13 @@ public function getActivitylogOptions(): LogOptions return LogOptions::defaults() ->logOnly(['*']); } + + public function isCopyOfFreeBadge(): bool + { + if ($this->extra_copy_of !== null) { + $originalBadge = self::find($this->extra_copy_of); + return $originalBadge ? $originalBadge->is_free_badge : false; + } + return false; + } } diff --git a/app/Models/User.php b/app/Models/User.php index 31bc61a2..b78c5c95 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -51,6 +51,8 @@ class User extends Authenticatable implements FilamentUser, Wallet, WalletFloat, 'token' => 'encrypted', 'token_expires_at' => 'datetime', 'attendee_id' => 'integer', + 'has_free_badge' => 'bool', + "free_badge_copies" => "integer", ]; public function badges() @@ -72,4 +74,9 @@ public function canAccessPanel(Panel $panel): bool { return $this->is_admin || $this->is_reviewer; } + + public function hasFreeBadge(): bool + { + return $this->has_free_badge; + } } diff --git a/app/Services/BadgeCalculationService.php b/app/Services/BadgeCalculationService.php index ad11e667..273aeeac 100644 --- a/app/Services/BadgeCalculationService.php +++ b/app/Services/BadgeCalculationService.php @@ -19,7 +19,11 @@ public static function calculate( return 200; } - $baseFee = $isFreeBadge ? 0 : 200; + if ($isFreeBadge) { + return 0; + } + + $baseFee = 200; if ($isLate) { $baseFee += 200; } diff --git a/database/migrations/2025_07_13_181109_add_badge__intigration_to_users_table.php b/database/migrations/2025_07_13_181109_add_badge__intigration_to_users_table.php new file mode 100644 index 00000000..4b742f79 --- /dev/null +++ b/database/migrations/2025_07_13_181109_add_badge__intigration_to_users_table.php @@ -0,0 +1,19 @@ +boolean('has_free_badge')->default(false)->after('remember_token'); + $table->integer('free_badge_copies')->default(0)->after('has_free_badge'); + }); + } +}; diff --git a/resources/js/Pages/Badges/BadgesCreate.vue b/resources/js/Pages/Badges/BadgesCreate.vue index 3a4995a8..1887241e 100644 --- a/resources/js/Pages/Badges/BadgesCreate.vue +++ b/resources/js/Pages/Badges/BadgesCreate.vue @@ -21,7 +21,8 @@ defineOptions({ const props = defineProps({ species: Array, - isFree: Boolean + isFree: Boolean, + freeBadgeCopies: Number, }) const imageModalOpen = ref(false) @@ -36,7 +37,7 @@ const form = useForm('post', route('badges.store'), { publish: false, tos: false, upgrades: { - spareCopy: false + spareCopy: props.freeBadgeCopies > 0, } }) @@ -62,17 +63,24 @@ const basePrice = computed(() => { }) const latePrice = computed(() => { - if (dayjs().isAfter(dayjs(usePage().props.event.preorder_ends_at))) { + if (dayjs().isAfter(dayjs(usePage().props.event.preorder_ends_at)) && props.isFree === false) { return 2; } return 0; }) -const total = computed(() => { - let total = basePrice.value + latePrice.value; - if (form.upgrades.spareCopy) { - total += 2; +const copiesPrice = computed(() => { + let price = 0 + if (props.freeBadgeCopies > 0) { + price += props.freeBadgeCopies * 2; + } else if (form.upgrades.spareCopy) { + price += 2; } + return price; +}) + +const total = computed(() => { + let total = basePrice.value + latePrice.value + copiesPrice.value; return total; }) @@ -202,7 +210,7 @@ const total = computed(() => {