Neustrukturierung Customer / Lead / Booking Phase 2

This commit is contained in:
Kevin Adametz 2026-05-28 17:10:37 +02:00
parent 313f0dbf4e
commit 6df9c401af
69 changed files with 3809 additions and 374 deletions

View file

@ -0,0 +1,25 @@
<?php
namespace Database\Factories;
use App\Models\Contact;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Contact>
*/
class ContactFactory extends Factory
{
protected $model = Contact::class;
public function definition(): array
{
return [
'name' => fake()->lastName(),
'firstname' => fake()->firstName(),
'email' => fake()->unique()->safeEmail(),
'city' => fake()->city(),
'phone' => fake()->phoneNumber(),
];
}
}

View file

@ -0,0 +1,85 @@
<?php
namespace Database\Factories;
use App\Models\Contact;
use App\Models\Offer;
use App\Models\OfferVersion;
use App\User;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Offer>
*/
class OfferFactory extends Factory
{
protected $model = Offer::class;
public function definition(): array
{
$y = (int) now()->format('Y');
return [
'offer_number' => $y . '-' . str_pad((string) fake()->unique()->numberBetween(1, 99_999), 5, '0', STR_PAD_LEFT),
'contact_id' => Contact::factory(),
'inquiry_id' => null,
'booking_id' => null,
'status' => Offer::STATUS_DRAFT,
'current_version_id' => null,
'created_by' => User::factory(),
];
}
public function configure(): static
{
return $this->afterCreating(function (Offer $offer) {
if ($offer->current_version_id) {
return;
}
$v = OfferVersion::query()->create([
'offer_id' => $offer->id,
'version_no' => 1,
'status' => OfferVersion::STATUS_DRAFT,
'valid_until' => null,
'total_price' => 0,
'headline' => 'Test-Angebot',
'created_by' => $offer->created_by,
]);
$offer->update(['current_version_id' => $v->id]);
});
}
public function sent(): static
{
return $this
->state(['status' => Offer::STATUS_SENT])
->afterCreating(function (Offer $offer) {
$v = $offer->refresh()->currentVersion;
if (! $v) {
return;
}
$v->update([
'status' => OfferVersion::STATUS_SENT,
'sent_at' => now(),
]);
});
}
public function accepted(): static
{
return $this
->state(['status' => Offer::STATUS_ACCEPTED])
->afterCreating(function (Offer $offer) {
$v = $offer->refresh()->currentVersion;
if (! $v) {
return;
}
$v->update([
'status' => OfferVersion::STATUS_ACCEPTED,
'sent_at' => $v->sent_at ?? now(),
'accepted_at' => now(),
'accepted_via' => OfferVersion::ACCEPTED_VIA_ADMIN,
]);
});
}
}

View file

@ -0,0 +1,72 @@
<?php
namespace Database\Factories;
use App\Models\Offer;
use App\Models\OfferItem;
use App\Models\OfferVersion;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\OfferItem>
*/
class OfferItemFactory extends Factory
{
protected $model = OfferItem::class;
public function definition(): array
{
$qty = fake()->numberBetween(1, 4);
$ppu = (float) fake()->randomFloat(2, 200, 4_000);
return [
'position' => 0,
'type' => OfferItem::TYPE_TRAVEL,
'title' => fake()->sentence(3),
'description' => null,
'quantity' => $qty,
'price_per_unit' => $ppu,
'total_price' => round($qty * $ppu, 2),
'travel_program_id' => null,
'fewo_lodging_id' => null,
'metadata' => null,
];
}
public function asDiscount(float $absAmount = 150): static
{
return $this->state([
'type' => OfferItem::TYPE_DISCOUNT,
'title' => 'Rabatt',
'quantity' => 1,
'price_per_unit' => -1 * abs($absAmount),
'total_price' => -1 * abs($absAmount),
]);
}
/**
* Hängt die Position an die aktuelle Version eines per Factory erstellten Angebots.
*/
public function forCurrentVersionOf(Offer $offer): static
{
$v = $offer->currentVersion;
if (! $v) {
throw new \InvalidArgumentException('Offer hat keine currentVersion — zuerst Offer::factory() erzeugen.');
}
return $this->state(fn (array $a) => [
'offer_version_id' => $v->id,
'position' => (int) $v->items()->count(),
]);
}
public function forVersion(OfferVersion $version, ?int $position = null): static
{
return $this->state(function (array $a) use ($version, $position) {
$pos = $position ?? (int) $version->items()->count();
return [
'offer_version_id' => $version->id,
'position' => $pos,
];
});
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace Database\Factories;
use App\Models\OfferItem;
use App\Models\OfferTemplate;
use App\User;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\OfferTemplate>
*/
class OfferTemplateFactory extends Factory
{
protected $model = OfferTemplate::class;
public function definition(): array
{
return [
'branch_id' => null,
'name' => 'Vorlage ' . fake()->words(2, true),
'description' => fake()->optional()->sentence(),
'default_headline' => fake()->sentence(4),
'default_intro' => '<p>' . fake()->paragraph() . '</p>',
'default_itinerary' => null,
'default_closing' => null,
'default_items' => [
[
'type' => OfferItem::TYPE_TRAVEL,
'title' => 'Reiseleistung (Standard)',
'quantity' => 2,
'price_per_unit' => 1_250.00,
],
],
'is_active' => true,
'created_by' => User::factory(),
];
}
}

View file

@ -0,0 +1,70 @@
<?php
namespace Database\Factories;
use App\Models\Offer;
use App\Models\OfferVersion;
use App\User;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\OfferVersion>
*/
class OfferVersionFactory extends Factory
{
protected $model = OfferVersion::class;
public function definition(): array
{
// `Offer::factory()` legt V1 in OfferFactory::afterCreating an — V2+ ist
// pro (offer_id, version_no) unique.
return [
'offer_id' => Offer::factory(),
'version_no' => 2,
'status' => OfferVersion::STATUS_DRAFT,
'valid_until' => null,
'total_price' => fake()->randomFloat(2, 100, 15_000),
'headline' => fake()->sentence(4),
'intro_text' => '<p>' . fake()->paragraph() . '</p>',
'itinerary_text' => null,
'closing_text' => null,
'template_id' => null,
'pdf_path' => null,
'pdf_archived' => false,
'sent_at' => null,
'accepted_at' => null,
'accepted_via' => null,
'template_document_ids' => null,
'created_by' => User::factory(),
];
}
public function forOffer(Offer $offer, int $versionNo = 2): static
{
return $this->state(function (array $a) use ($offer, $versionNo) {
return [
'offer_id' => $offer->id,
'version_no' => $versionNo,
'created_by' => $offer->created_by,
];
});
}
public function versionSent(): static
{
return $this->state([
'status' => OfferVersion::STATUS_SENT,
'sent_at' => now(),
]);
}
public function versionAccepted(): static
{
return $this->state([
'status' => OfferVersion::STATUS_ACCEPTED,
'sent_at' => now(),
'accepted_at' => now(),
'accepted_via' => OfferVersion::ACCEPTED_VIA_ADMIN,
]);
}
}