156 lines
5.2 KiB
PHP
156 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Domains\Event\Actions\CreateEvent\CreateEventCommand;
|
|
use App\Domains\Event\Actions\CreateEvent\CreateEventRequest;
|
|
use App\Enumerations\EatingHabit;
|
|
use App\Enumerations\ParticipationFeeType;
|
|
use App\Models\Event;
|
|
use App\Models\Tenant;
|
|
use App\RelationModels\EventParticipationFee;
|
|
use App\Resources\EventResource;
|
|
use DateTime;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Tests\TestCase;
|
|
|
|
class EventVatPricingTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private Tenant $tenant;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$this->tenant = Tenant::create([
|
|
'slug' => 'tv',
|
|
'name' => 'Test',
|
|
'email' => 't@example.com',
|
|
'email_finance' => 'finance@example.com',
|
|
'url' => 'test.local',
|
|
'account_name' => 'Test e.V.',
|
|
'account_iban' => 'DE00',
|
|
'account_bic' => 'XY',
|
|
'city' => 'Stadt',
|
|
'postcode' => '00000',
|
|
'is_active_local_group' => true,
|
|
'has_active_instance' => true,
|
|
]);
|
|
|
|
app()->instance('tenant', $this->tenant);
|
|
|
|
DB::table('participation_types')->insert(['slug' => 'participant', 'name' => 'Teilnehmer']);
|
|
DB::table('participation_fee_types')->insert(['slug' => 'fixed', 'name' => 'Fix']);
|
|
EatingHabit::create(['slug' => EatingHabit::EATING_HABIT_VEGAN, 'name' => 'Vegan']);
|
|
EatingHabit::create(['slug' => EatingHabit::EATING_HABIT_VEGETARIAN, 'name' => 'Vegetarisch']);
|
|
}
|
|
|
|
private function makeFee(float $amountStandard): EventParticipationFee
|
|
{
|
|
return EventParticipationFee::create([
|
|
'tenant' => $this->tenant->slug,
|
|
'type' => 'participant',
|
|
'name' => 'Standard',
|
|
'description' => null,
|
|
'amount_standard' => $amountStandard,
|
|
'amount_reduced' => null,
|
|
'amount_solidarity' => null,
|
|
]);
|
|
}
|
|
|
|
private function makeEvent(bool $taxLiable, int $vatRate, string $mode, int $feeId): Event
|
|
{
|
|
return Event::create([
|
|
'tenant' => $this->tenant->slug,
|
|
'name' => 'Event',
|
|
'identifier' => 'evt-' . uniqid(),
|
|
'location' => 'Ort',
|
|
'postal_code' => '00000',
|
|
'email' => 'e@example.com',
|
|
'start_date' => '2026-09-01',
|
|
'end_date' => '2026-09-05',
|
|
'early_bird_end' => '2026-08-20',
|
|
'registration_final_end' => '2026-08-25',
|
|
'early_bird_end_amount_increase' => 0,
|
|
'account_owner' => 'Owner',
|
|
'account_iban' => 'DE00',
|
|
'participation_fee_type' => 'fixed',
|
|
'participation_fee_1' => $feeId,
|
|
'pay_per_day' => false,
|
|
'pay_direct' => false,
|
|
'tax_liable' => $taxLiable,
|
|
'vat_rate' => $vatRate,
|
|
'vat_pricing_mode' => $mode,
|
|
]);
|
|
}
|
|
|
|
private function calculate(Event $event): float
|
|
{
|
|
return new EventResource($event)->calculateAmount(
|
|
'participant',
|
|
'standard',
|
|
new DateTime('2026-09-01'),
|
|
new DateTime('2026-09-01'),
|
|
false,
|
|
)->getAmount();
|
|
}
|
|
|
|
public function test_add_on_mode_adds_vat_on_top(): void
|
|
{
|
|
$event = $this->makeEvent(taxLiable: true, vatRate: 19, mode: 'add_on', feeId: $this->makeFee(100.0)->id);
|
|
|
|
$this->assertEqualsWithDelta(119.0, $this->calculate($event), 0.001);
|
|
}
|
|
|
|
public function test_inclusive_mode_keeps_amount(): void
|
|
{
|
|
$event = $this->makeEvent(taxLiable: true, vatRate: 19, mode: 'inclusive', feeId: $this->makeFee(100.0)->id);
|
|
|
|
$this->assertEqualsWithDelta(100.0, $this->calculate($event), 0.001);
|
|
}
|
|
|
|
public function test_not_liable_ignores_add_on_mode(): void
|
|
{
|
|
$event = $this->makeEvent(taxLiable: false, vatRate: 19, mode: 'add_on', feeId: $this->makeFee(100.0)->id);
|
|
|
|
$this->assertEqualsWithDelta(100.0, $this->calculate($event), 0.001);
|
|
}
|
|
|
|
public function test_create_event_snapshots_tenant_tax_config(): void
|
|
{
|
|
$this->tenant->update([
|
|
'tax_liable' => true,
|
|
'vat_rate' => 7,
|
|
'vat_pricing_mode' => 'add_on',
|
|
'tax_exemption_reason' => null,
|
|
'tax_exemption_note' => null,
|
|
]);
|
|
|
|
$response = new CreateEventCommand(new CreateEventRequest(
|
|
name: 'Sommerlager',
|
|
location: 'Ort',
|
|
postalCode: '00000',
|
|
email: 'e@example.com',
|
|
begin: new DateTime('2026-09-01'),
|
|
end: new DateTime('2026-09-05'),
|
|
earlyBirdEnd: new DateTime('2026-08-20'),
|
|
registrationFinalEnd: new DateTime('2026-08-25'),
|
|
earlyBirdEndAmountIncrease: 0,
|
|
participationFeeType: ParticipationFeeType::where('slug', 'fixed')->first(),
|
|
accountOwner: 'Owner',
|
|
accountIban: 'DE00',
|
|
payPerDay: false,
|
|
))->execute();
|
|
|
|
$this->assertTrue($response->success);
|
|
|
|
$event = $response->event->fresh();
|
|
$this->assertTrue($event->tax_liable);
|
|
$this->assertSame(7, $event->vat_rate);
|
|
$this->assertSame('add_on', $event->vat_pricing_mode);
|
|
}
|
|
}
|