mein-sterntours/app/Repositories/OfferTemplateRepository.php

104 lines
3.3 KiB
PHP

<?php
namespace App\Repositories;
use App\Models\OfferItem;
use App\Models\OfferTemplate;
use App\Models\OfferVersion;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
/**
* Repository für Angebots-Vorlagen.
*
* Vorlagen bestehen aus Default-Texten (Headline/Intro/Itinerary/Closing)
* und einer Default-Positionsliste (JSON in `default_items`). Über
* {@see applyTo()} wird eine Vorlage in eine existierende Draft-Version
* hineinkopiert (Texte + Positionen).
*/
class OfferTemplateRepository extends BaseRepository
{
public function __construct(OfferTemplate $model)
{
$this->model = $model;
}
/**
* @param array<string,mixed> $data
*/
public function create(array $data): OfferTemplate
{
return OfferTemplate::create($data);
}
/**
* @param array<string,mixed> $data
*/
public function update(OfferTemplate $template, array $data): OfferTemplate
{
$template->fill($data);
$template->save();
return $template->fresh();
}
/**
* Aktive Vorlagen, optional gefiltert nach Branch (inkl. global = branch_id NULL).
*
* @return Collection<int, OfferTemplate>
*/
public function listActive(?int $branchId = null): Collection
{
return OfferTemplate::query()
->active()
->forBranch($branchId)
->orderBy('name')
->get();
}
/**
* Wendet eine Vorlage auf eine Draft-Version an:
* - kopiert Default-Texte (nur in leere Felder, bestehender Text wird nicht überschrieben)
* - legt Positionen aus `default_items` an (ersetzt bestehende Items komplett)
* - merkt sich die Vorlage in `offer_version.template_id`
*
* @return OfferVersion fresh, inkl. items
*/
public function applyTo(OfferTemplate $template, OfferVersion $version): OfferVersion
{
if (! $version->isEditable()) {
throw new \DomainException(
"OfferVersion #{$version->id} ist eingefroren (status={$version->status}); "
. 'Vorlage kann nicht mehr angewendet werden.'
);
}
return DB::transaction(function () use ($template, $version) {
$version->template_id = $template->id;
$version->headline = $version->headline ?: $template->default_headline;
$version->intro_text = $version->intro_text ?: $template->default_intro;
$version->itinerary_text = $version->itinerary_text ?: $template->default_itinerary;
$version->closing_text = $version->closing_text ?: $template->default_closing;
$version->save();
OfferItem::where('offer_version_id', $version->id)->delete();
$position = 0;
$sum = 0.0;
foreach ((array) $template->default_items as $itemData) {
$item = new OfferItem(array_merge($itemData, [
'offer_version_id' => $version->id,
'position' => $position++,
]));
$item->recomputeTotal();
$item->save();
$sum += (float) $item->total_price;
}
$version->total_price = $sum;
$version->save();
return $version->fresh(['items']);
});
}
}