Files
AFC-Demo/resources/views/livewire/companies/transactions.blade.php
T

1823 lines
108 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
use App\Models\Company;
use App\Models\Transaction;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Volt\Component;
use Livewire\WithPagination;
new #[Layout('components.layouts.app'), Title('Unternehmensauskunft Transaktionen')] class extends Component
{
use WithPagination;
public Company $company;
public ?int $selectedTransactionId = null;
public string $status = 'all';
public string $channel = 'all';
protected int $perPage = 10;
/**
* @var array<string, array<string, mixed>>
*/
protected $queryString = [
'status' => ['except' => 'all'],
'channel' => ['except' => 'all'],
'page' => ['except' => 1],
'selectedTransactionId' => ['except' => null, 'as' => 'transaction'],
];
public function mount(Company $company, ?int $transaction = null): void
{
$this->company = $company;
if ($transaction) {
$this->selectedTransactionId = $this->baseQuery()
->whereKey($transaction)
->value('id');
}
if (! $this->selectedTransactionId) {
$this->selectedTransactionId = $this->baseQuery()
->orderByDesc('requires_review')
->orderByDesc('risk_score')
->orderByDesc('executed_at')
->value('id');
}
}
public function selectTransaction(int $transactionId): void
{
$this->selectedTransactionId = $transactionId;
}
public function updatingStatus(): void
{
$this->resetPage();
}
public function updatedStatus(): void
{
$this->refreshSelection();
}
public function updatingChannel(): void
{
$this->resetPage();
}
public function updatedChannel(): void
{
$this->refreshSelection();
}
public function updatedPage(): void
{
$this->refreshSelection();
}
protected function refreshSelection(): void
{
$first = $this->filteredQuery()
->orderByDesc('requires_review')
->orderByDesc('risk_score')
->orderByDesc('executed_at')
->forPage($this->getPage(), $this->perPage)
->first();
$this->selectedTransactionId = $first?->id;
}
#[Computed]
public function statusOptions(): array
{
return [
'all' => __('Alle Status'),
Transaction::STATUS_TRUE_POSITIVE => __('Bestätigte Treffer'),
Transaction::STATUS_FALSE_POSITIVE => __('Fehlalarme'),
Transaction::STATUS_CLEARED => __('Freigegeben'),
];
}
#[Computed]
public function channelOptions(): array
{
$channels = $this->baseQuery()
->select('channel')
->distinct()
->orderBy('channel')
->pluck('channel')
->filter()
->values();
$options = [
'all' => __('Alle Kanäle'),
];
foreach ($channels as $channel) {
$options[$channel] = $channel;
}
return $options;
}
#[Computed]
public function metrics(): array
{
$baseQuery = $this->baseQuery();
$totalCount = (clone $baseQuery)->count();
$totalVolume = (clone $baseQuery)->sum('amount');
$openAlertsQuery = $this->baseQuery()->where('requires_review', true);
$openAlertsCount = (clone $openAlertsQuery)->count();
$openAlertsVolume = (clone $openAlertsQuery)->sum('amount');
$highRiskCount = $totalCount > 0
? $this->baseQuery()->where('risk_score', '>=', 80)->count()
: 0;
$last30DaysQuery = $this->baseQuery()->where('executed_at', '>=', now()->subDays(30));
$last30DaysCount = (clone $last30DaysQuery)->count();
$last30DaysVolume = (clone $last30DaysQuery)->sum('amount');
$statusBreakdown = (clone $baseQuery)
->selectRaw('status, COUNT(*) as total, COALESCE(SUM(amount), 0) as volume')
->groupBy('status')
->get()
->mapWithKeys(fn ($row) => [
$row->status => [
'count' => (int) $row->total,
'amount' => (float) $row->volume,
],
])
->toArray();
return [
'total_count' => $totalCount,
'total_volume' => $totalVolume,
'open_alerts' => [
'count' => $openAlertsCount,
'amount' => $openAlertsVolume,
],
'high_risk_share' => $totalCount > 0 ? (int) round(($highRiskCount / $totalCount) * 100) : 0,
'last_30_days' => [
'count' => $last30DaysCount,
'amount' => $last30DaysVolume,
],
'by_status' => $statusBreakdown,
];
}
#[Computed]
public function transactions(): LengthAwarePaginator
{
return $this->filteredQuery()
->with('company')
->orderByDesc('requires_review')
->orderByDesc('risk_score')
->orderByDesc('executed_at')
->paginate($this->perPage);
}
#[Computed]
public function selectedTransaction(): ?Transaction
{
$transaction = $this->transactions->firstWhere('id', $this->selectedTransactionId);
if (! $transaction && $this->selectedTransactionId) {
$transaction = $this->baseQuery()
->with('company')
->whereKey($this->selectedTransactionId)
->first();
}
return $transaction ?? $this->transactions->first();
}
#[Computed]
public function counterpartyHistory(): Collection
{
$selected = $this->selectedTransaction;
if (! $selected) {
return collect();
}
return $this->baseQuery()
->where('counterparty', $selected->counterparty)
->orderByDesc('executed_at')
->limit(6)
->get();
}
#[Computed]
public function recentAlerts(): Collection
{
return $this->baseQuery()
->where('requires_review', true)
->orderByDesc('executed_at')
->limit(5)
->get();
}
#[Computed]
public function actionChecklist(): array
{
$selected = $this->selectedTransaction;
$items = [
[
'title' => __('KYC- und Screening-Daten abgleichen'),
'description' => __('Prüfen Sie Unternehmens- und Gegenparteidaten gegen Sanktionslisten, PEP-Register und interne Sperrlisten.'),
],
[
'title' => __('Transaktionsverlauf analysieren'),
'description' => __('Bewerten Sie Häufigkeit, Muster und Gegenparteien der letzten Monate, um ungewöhnliche Aktivitäten zu erkennen.'),
],
[
'title' => __('Vier-Augen-Prinzip sicherstellen'),
'description' => __('Organisieren Sie eine Zweitprüfung und dokumentieren Sie alle Entscheidungen revisionssicher.'),
],
];
if ($selected?->status === Transaction::STATUS_TRUE_POSITIVE) {
array_unshift($items, [
'title' => __('Verdachtsmeldung vorbereiten'),
'description' => __('Erstellen Sie den Meldeentwurf für die FIU, sammeln Sie Belege und stellen Sie eine Eskalation sicher.'),
]);
}
return $items;
}
#[Computed]
public function transactionDetailStructure(): array
{
return [
[
'level' => 1,
'title' => 'Transaktion',
'sections' => [
[
'title' => 'Analyse Transaktionsbetrag',
'description' => null,
'fields' => [
[
'label' => 'Plausibilität Betrag',
'key' => 'tranx_TX_AMOUNT',
'prompt_id' => '51',
],
[
'label' => 'Plausibilität Transaktionszeitpunkt',
'key' => 'tranx_seasonality',
'prompt_id' => '59',
],
[
'label' => 'Plausibilität Transaktionsbetrag umsatzbezogen',
'key' => 'tranx_revenueimpact',
'prompt_id' => '67',
],
[
'label' => 'Plausibilität Transaktionsbetrag ergebnisbezogen',
'key' => 'tranx_profitimpact',
'prompt_id' => '68',
],
[
'label' => 'Plausibilität Transaktionsbetrag Branchüblichkeit',
'key' => 'tranx_turnoverimpact',
'prompt_id' => '69',
],
],
],
[
'title' => 'Analyse Transaktionszweck & außerbetragliche Parameter',
'description' => null,
'fields' => [
[
'label' => 'Verwendungszweck',
'key' => 'tranx_TX_PURPOSE',
'prompt_id' => '53',
],
[
'label' => 'Plausibilität Zahlungszweck',
'key' => 'tranx_PURPOSEbase',
'prompt_id' => '57',
],
[
'label' => 'Plausibilität Geschäftsbeziehung',
'key' => 'tranx_businesslogic',
'prompt_id' => '62',
],
[
'label' => 'Plausibilität Transaktionsbetrag Branchenadäquanz',
'key' => 'tranx_plausibilty',
'prompt_id' => '64',
],
[
'label' => 'Bewertung',
'key' => 'tranx_report',
'prompt_id' => '56',
],
[
'label' => 'Plausibilität Transaktionsumfang',
'key' => 'tranx_performanceperiod',
'prompt_id' => '58',
],
[
'label' => 'Auffälligkeiten Transaktion',
'key' => 'tranx_pattern2',
'prompt_id' => '80',
],
[
'label' => 'Plausibilität Transaktion Marktüblichkeit',
'key' => 'tranx_contracttenor',
'prompt_id' => '83',
],
[
'label' => 'Transaktion Namensabgleich',
'key' => 'tranx_mismatch',
'prompt_id' => '85',
],
[
'label' => 'Titel fehlt',
'key' => 'tranx_outliers',
'prompt_id' => '65',
],
[
'label' => 'Plausibilität Instruktion Transaktion',
'key' => 'tranx_weekday',
'prompt_id' => '95',
],
[
'label' => 'Prüfung letztendliche wirtschaftliche Eigentümer',
'key' => 'tranx_holdingobfuscation',
'prompt_id' => '96',
],
],
],
[
'title' => 'Anzeige historischer Transaktionen mit Sender und/oder Empfänger aus der Transaktion inklusive der dokumentierten Auffälligkeiten zu AML pro Datensatz',
'description' => null,
'fields' => [
[
'label' => 'Transaktionshistorie',
'key' => 'tranx_historical',
'prompt_id' => '52',
],
[
'label' => 'Smurfing',
'key' => 'tranx_duplicate',
'prompt_id' => '79',
],
[
'label' => 'Historische Transaktionen',
'key' => 'tranx_patterns',
'prompt_id' => '66',
],
[
'label' => 'Bankverbindung',
'key' => 'tranx_newbankaccount',
'prompt_id' => '93',
],
],
],
[
'title' => 'Zusätzliche Feststellungen (KYC/EDD)',
'description' => null,
'fields' => [
[
'label' => 'Gegenpartei',
'key' => 'tranx_counterpartyassessment',
'prompt_id' => '54',
],
],
],
[
'title' => 'Export controls/trade restrictions',
'description' => null,
'fields' => [
[
'label' => 'Sanktionen (Entity)',
'key' => 'entity_corporate_exportcontrol',
'prompt_id' => '81',
],
[
'label' => 'Sanktionen (Counterparty)',
'key' => 'counterparty_corporate_exportcontrol',
'prompt_id' => '81',
],
],
],
],
],
[
'level' => 2,
'title' => 'Stammdaten',
'sections' => [
[
'title' => 'Rechtlicher Name (aktuell) / Firma',
'description' => null,
'fields' => [
[
'label' => 'Name',
'key' => 'entity_corporate_name',
'prompt_id' => '9',
],
[
'label' => 'Name der Gegenpartei',
'key' => 'counterparty_corporate_name',
'prompt_id' => '9',
],
[
'label' => 'Warnmitteilung',
'key' => 'entity_corporate_warnings',
'prompt_id' => '42',
],
[
'label' => 'Warnmitteilung der Gegenpartei',
'key' => 'counterparty_corporate_warnings',
'prompt_id' => '42',
],
],
],
[
'title' => 'Rechtsform',
'description' => null,
'fields' => [
[
'label' => 'Rechtsform',
'key' => 'entity_corporate_form',
'prompt_id' => '10',
],
[
'label' => 'Rechtsform d. Gegenpartei',
'key' => 'counterparty_corporate_form',
'prompt_id' => '10',
],
],
],
[
'title' => 'Registergericht & Nummer',
'description' => null,
'fields' => [
[
'label' => 'Registernummer',
'key' => 'entity_corporate_forum',
'prompt_id' => '11',
],
[
'label' => 'Registernummer d. Gegenpartei',
'key' => 'counterparty_corporate_forum',
'prompt_id' => '11',
],
],
],
[
'title' => 'Sitz / eingetragene Adresse',
'description' => null,
'fields' => [
[
'label' => 'Sitzadresse',
'key' => 'entity_corporate_HQ',
'prompt_id' => '12',
],
[
'label' => 'Sitzadresse d. Gegenpartei',
'key' => 'counterparty_corporate_HQ',
'prompt_id' => '12',
],
[
'label' => 'Korruption',
'key' => 'entity_corporate_corruptionexposure',
'prompt_id' => '48',
],
[
'label' => 'Korruption d. Gegenpartei',
'key' => 'counterparty_corporate_corruptionexposure',
'prompt_id' => '48',
],
[
'label' => 'Länderrisiko',
'key' => 'entity_corporate_CTYexposure',
'prompt_id' => '50',
],
[
'label' => 'Länderrisiko d. Gegenpartei',
'key' => 'counterparty_corporate_CTYexposure',
'prompt_id' => '50',
],
[
'label' => 'Korruption Land',
'key' => 'entity_corruption_country',
'prompt_id' => '74',
],
[
'label' => 'Korruption Land d. Gegenpartei',
'key' => 'counterparty_corruption_country',
'prompt_id' => '74',
],
[
'label' => 'Risikoländer',
'key' => 'entity_country_risk',
'prompt_id' => '86',
],
[
'label' => 'Risikoländer d. Gegenpartei',
'key' => 'counterparty_country_risk',
'prompt_id' => '86',
],
],
],
[
'title' => 'Handelsname/Marke',
'description' => null,
'fields' => [
[
'label' => 'Handelsnamen',
'key' => 'entity_corporate_brands',
'prompt_id' => '34',
],
[
'label' => 'Handelsnamen d. Gegenpartei',
'key' => 'counterparty_corporate_brands',
'prompt_id' => '34',
],
[
'label' => 'Warnmitteilungen',
'key' => 'entity_corporate_warnings',
'prompt_id' => '42',
],
[
'label' => 'Warnmitteilungen d. Gegenpartei',
'key' => 'counterparty_corporate_warnings',
'prompt_id' => '42',
],
],
],
[
'title' => 'Summary Geschäftsmodell',
'description' => null,
'fields' => [
[
'label' => 'Geschäft',
'key' => 'entity_corporate_purpose',
'prompt_id' => '3',
],
[
'label' => 'Geschäft d. Gegenpartei',
'key' => 'counterparty_corporate_purpose',
'prompt_id' => '3',
],
],
],
[
'title' => 'Brief History of the company',
'description' => null,
'fields' => [
[
'label' => 'Historie',
'key' => 'entity_corporate_history',
'prompt_id' => '2',
],
[
'label' => 'Historie d. Gegenpartei',
'key' => 'counterparty_corporate_history',
'prompt_id' => '2',
],
],
],
[
'title' => 'IBAN/BIC der Firma (alle, Listenform)',
'description' => null,
'fields' => [
[
'label' => 'IBAN / BIC',
'key' => 'entity_corporate_IBAN',
'prompt_id' => '37',
],
[
'label' => 'IBAN / BIC d. Gegenpartei',
'key' => 'counterparty_corporate_IBAN',
'prompt_id' => '37',
],
],
],
[
'title' => 'Mitarbeiteranzahl',
'description' => null,
'fields' => [
[
'label' => 'Mitarbeiteranzahl',
'key' => 'entity_corporate_employeecount',
'prompt_id' => '22',
],
[
'label' => 'Mitarbeiteranzahl d. Gegenpartei',
'key' => 'counterparty_corporate_employeecount',
'prompt_id' => '22',
],
],
],
[
'title' => 'LEI (Legal Entity Identification Number)',
'description' => null,
'fields' => [
[
'label' => 'LEI',
'key' => 'entity_corporate_LEI',
'prompt_id' => '20',
],
[
'label' => 'LEI d. Gegenpartei',
'key' => 'counterparty_corporate_LEI',
'prompt_id' => '20',
],
],
],
[
'title' => 'USt-IdNr. (VAT)',
'description' => null,
'fields' => [
[
'label' => 'Umsatzsteuer-Identifikationsnummer',
'key' => 'entity_corporate_taxID',
'prompt_id' => '19',
],
[
'label' => 'Umsatzsteuer-Identifikationsnummer d. Gegenpartei',
'key' => 'counterparty_corporate_taxID',
'prompt_id' => '19',
],
],
],
[
'title' => 'Offizielle Website',
'description' => null,
'fields' => [
[
'label' => 'Website',
'key' => 'entity_corporate_website',
'prompt_id' => '35',
],
[
'label' => 'Website d. Gegenpartei',
'key' => 'counterparty_corporate_website',
'prompt_id' => '35',
],
],
],
[
'title' => 'Domain(s) & WHOIS',
'description' => null,
'fields' => [
[
'label' => 'Domains',
'key' => 'entity_corporate_domain',
'prompt_id' => '36',
],
[
'label' => 'Domains d. Gegenpartei',
'key' => 'counterparty_corporate_domain',
'prompt_id' => '36',
],
],
],
],
],
[
'level' => 3,
'title' => 'Unternehmens-Status',
'sections' => [
[
'title' => 'Liquidation/Stilllegung',
'description' => null,
'fields' => [
[
'label' => 'Liquidation',
'key' => 'entity_corporate_liquidation',
'prompt_id' => '29',
],
[
'label' => 'Liquidation d. Gegenpartei',
'key' => 'counterparty_corporate_liquidation',
'prompt_id' => '29',
],
],
],
[
'title' => 'Insolvenzeröffnungen',
'description' => null,
'fields' => [
[
'label' => 'Insolvenzverfahren',
'key' => 'entity_corporate_insolvency',
'prompt_id' => '28',
],
[
'label' => 'Insolvenzverfahren d. Gegenpartei',
'key' => 'counterparty_corporate_insolvency',
'prompt_id' => '28',
],
],
],
[
'title' => 'Rechtliche /gerichtliche Verfahren',
'description' => null,
'fields' => [
[
'label' => 'Rechtsverletzungen',
'key' => 'entity_corporate_courtcases',
'prompt_id' => '89',
],
[
'label' => 'Rechtsverletzungen d. Gegenpartei',
'key' => 'counterparty_corporate_courtcases',
'prompt_id' => '89',
],
],
],
[
'title' => 'M&A',
'description' => null,
'fields' => [
[
'label' => 'M&A',
'key' => 'entity_corporate_manda',
'prompt_id' => '90',
],
[
'label' => 'M&A d. Gegenpartei',
'key' => 'counterparty_corporate_manda',
'prompt_id' => '90',
],
],
],
[
'title' => 'Betrug',
'description' => null,
'fields' => [
[
'label' => 'Transaktion Betrugstypologie',
'key' => 'tranx_fakepurposecheck',
'prompt_id' => '91',
],
],
],
],
],
[
'level' => 4,
'title' => 'Branche(n)',
'sections' => [
[
'title' => 'Tätigkeitsbeschreibung',
'description' => null,
'fields' => [
['label' => 'Kurzporträt', 'key' => 'entity_corporate_summary', 'prompt_id' => '1'],
['label' => 'Kurzporträt d. Gegenpartei', 'key' => 'counterparty_corporate_summary', 'prompt_id' => '1'],
['label' => 'Sektor', 'key' => 'entity_corporate_sector', 'prompt_id' => '4'],
['label' => 'Sektor d. Gegenpartei', 'key' => 'counterparty_corporate_sector', 'prompt_id' => '4'],
['label' => 'Rating', 'key' => 'entity_corporate_ESG', 'prompt_id' => '40'],
['label' => 'Rating d. Gegenpartei', 'key' => 'counterparty_corporate_ESG', 'prompt_id' => '40'],
['label' => 'Korruption', 'key' => 'entity_corporate_corruptionexposure', 'prompt_id' => '48'],
['label' => 'Korruption d. Gegenpartei', 'key' => 'counterparty_corporate_corruptionexposure', 'prompt_id' => '48'],
['label' => 'Korruption Geschäftspartner', 'key' => 'entity_corruption_relationship', 'prompt_id' => '75'],
['label' => 'Korruption Geschäftspartner d. Gegenpartei', 'key' => 'counterparty_corruption_relationship', 'prompt_id' => '75'],
['label' => 'Reputationsrisiken', 'key' => 'entity_corporate_adverse2', 'prompt_id' => '78'],
['label' => 'Reputationsrisiken d. Gegenpartei', 'key' => 'counterparty_corporate_adverse2', 'prompt_id' => '78'],
],
],
[
'title' => 'Branche',
'description' => null,
'fields' => [
['label' => 'NACE / NAICS Code', 'key' => 'entity_corporate_nace', 'prompt_id' => '5'],
['label' => 'NACE / NAICS Code d. Gegenpartei', 'key' => 'counterparty_corporate_nace', 'prompt_id' => '5'],
['label' => 'Niederlassungen', 'key' => 'entity_corporate_locations', 'prompt_id' => '13'],
['label' => 'Niederlassungen d. Gegenpartei', 'key' => 'counterparty_corporate_locations', 'prompt_id' => '13'],
['label' => 'Warnmitteilungen', 'key' => 'entity_corporate_warnings', 'prompt_id' => '42'],
['label' => 'Warnmitteilungen d. Gegenpartei', 'key' => 'counterparty_corporate_warnings', 'prompt_id' => '42'],
['label' => 'Korruption', 'key' => 'entity_corporate_corruptionexposure', 'prompt_id' => '48'],
['label' => 'Korruption d. Gegenpartei', 'key' => 'counterparty_corporate_corruptionexposure', 'prompt_id' => '48'],
['label' => 'Rating', 'key' => 'entity_corporate_ESG', 'prompt_id' => '40'],
['label' => 'Rating d. Gegenpartei', 'key' => 'counterparty_corporate_ESG', 'prompt_id' => '40'],
['label' => 'Korruption Sektor', 'key' => 'entity_corruption_sector', 'prompt_id' => '73'],
['label' => 'Korruption Sektor d. Gegenpartei', 'key' => 'counterparty_corruption_sector', 'prompt_id' => '73'],
],
],
[
'title' => 'Warengruppen/Dienstleistungen',
'description' => null,
'fields' => [
['label' => 'Produkte / Leistungen', 'key' => 'entity_corporate_products', 'prompt_id' => '6'],
['label' => 'Produkte / Leistungen d. Gegenpartei', 'key' => 'counterparty_corporate_products', 'prompt_id' => '6'],
['label' => 'Rating', 'key' => 'entity_corporate_ESG', 'prompt_id' => '40'],
['label' => 'Rating d. Gegenpartei', 'key' => 'counterparty_corporate_ESG', 'prompt_id' => '40'],
],
],
[
'title' => 'Lieferkettenhinweise',
'description' => null,
'fields' => [
['label' => 'Lieferbeziehungen', 'key' => 'entity_corporate_supply', 'prompt_id' => '8'],
['label' => 'Lieferbeziehungen d. Gegenpartei', 'key' => 'counterparty_corporate_supply', 'prompt_id' => '8'],
['label' => 'Sanktionen', 'key' => 'entity_sanctions_circumvention', 'prompt_id' => '72'],
['label' => 'Sanktionen d. Gegenpartei', 'key' => 'counterparty_sanctions_circumvention', 'prompt_id' => '72'],
],
],
],
],
[
'level' => 5,
'title' => 'Länder',
'sections' => [
[
'title' => 'Hauptsitz (Stadt/Land)',
'description' => null,
'fields' => [
['label' => 'Korruption Land', 'key' => 'entity_corruption_country', 'prompt_id' => '74'],
['label' => 'Korruption Land d. Gegenpartei', 'key' => 'counterparty_corruption_country', 'prompt_id' => '74'],
['label' => 'Länderrisiko', 'key' => 'entity_corporate_CTYexposure', 'prompt_id' => '50'],
['label' => 'Länderrisiko d. Gegenpartei', 'key' => 'counterparty_corporate_CTYexposure', 'prompt_id' => '50'],
['label' => 'Risikoländer', 'key' => 'entity_country_risk', 'prompt_id' => '86'],
['label' => 'Risikoländer d. Gegenpartei', 'key' => 'counterparty_country_risk', 'prompt_id' => '86'],
['label' => 'Geocoding', 'key' => 'entity_corporate_haven', 'prompt_id' => '84'],
['label' => 'Geocoding d. Gegenpartei', 'key' => 'counterparty_corporate_haven', 'prompt_id' => '84'],
],
],
[
'title' => 'Betriebsstätten/Filialen',
'description' => null,
'fields' => [
['label' => 'Geocoding', 'key' => 'entity_corporate_haven', 'prompt_id' => '84'],
['label' => 'Geocoding d. Gegenpartei', 'key' => 'counterparty_corporate_haven', 'prompt_id' => '84'],
['label' => 'Niederlassungen', 'key' => 'entity_corporate_locations', 'prompt_id' => '13'],
['label' => 'Niederlassungen d. Gegenpartei', 'key' => 'counterparty_corporate_locations', 'prompt_id' => '13'],
['label' => 'Länderrisiko', 'key' => 'entity_corporate_CTYexposure', 'prompt_id' => '50'],
['label' => 'Länderrisiko d. Gegenpartei', 'key' => 'counterparty_corporate_CTYexposure', 'prompt_id' => '50'],
['label' => 'Risikoländer', 'key' => 'entity_country_risk', 'prompt_id' => '86'],
['label' => 'Risikoländer d. Gegenpartei', 'key' => 'counterparty_country_risk', 'prompt_id' => '86'],
],
],
[
'title' => 'Kundensegmente/Regionen',
'description' => null,
'fields' => [
['label' => 'Markt', 'key' => 'entity_corporate_markets', 'prompt_id' => '7'],
['label' => 'Markt d. Gegenpartei', 'key' => 'counterparty_corporate_markets', 'prompt_id' => '7'],
['label' => 'Länderrisiko', 'key' => 'entity_corporate_CTYexposure', 'prompt_id' => '50'],
['label' => 'Länderrisiko d. Gegenpartei', 'key' => 'counterparty_corporate_CTYexposure', 'prompt_id' => '50'],
['label' => 'Risikoländer', 'key' => 'entity_country_risk', 'prompt_id' => '86'],
['label' => 'Risikoländer d. Gegenpartei', 'key' => 'counterparty_country_risk', 'prompt_id' => '86'],
['label' => 'Geocoding', 'key' => 'entity_corporate_haven', 'prompt_id' => '84'],
['label' => 'Geocoding d. Gegenpartei', 'key' => 'counterparty_corporate_haven', 'prompt_id' => '84'],
],
],
[
'title' => 'Corruption Perception Index (CPI)',
'description' => null,
'fields' => [
['label' => 'Länderrisiko', 'key' => 'entity_corporate_CTYexposure', 'prompt_id' => '50'],
['label' => 'Länderrisiko d. Gegenpartei', 'key' => 'counterparty_corporate_CTYexposure', 'prompt_id' => '50'],
],
],
],
],
[
'level' => 6,
'title' => 'Strukturen & Verflechtungen',
'sections' => [
[
'title' => 'Obergesellschaft(en)',
'description' => null,
'fields' => [
['label' => 'Muttergesellschaft', 'key' => 'entity_corporate_holding', 'prompt_id' => '14'],
['label' => 'Muttergesellschaft d. Gegenpartei', 'key' => 'counterparty_corporate_holding', 'prompt_id' => '14'],
],
],
],
],
[
'level' => 7,
'title' => 'Natürliche Personen',
'sections' => [
[
'title' => 'Geschäftsführer/Vorstand',
'description' => null,
'fields' => [
['label' => 'Unternehmensführung', 'key' => 'entity_corporate_board', 'prompt_id' => '16'],
['label' => 'Unternehmensführung d. Gegenpartei', 'key' => 'counterparty_corporate_board', 'prompt_id' => '16'],
['label' => 'Sanktionen (EU)', 'key' => 'entity_corporate_eusanctions', 'prompt_id' => '43'],
['label' => 'Sanktionen (EU) d. Gegenpartei', 'key' => 'counterparty_corporate_eusanctions', 'prompt_id' => '43'],
['label' => 'Sanktionen (OFAC)', 'key' => 'entity_corporate_ofacsanctions', 'prompt_id' => '44'],
['label' => 'Sanktionen (OFAC) d. Gegenpartei', 'key' => 'counterparty_corporate_ofacsanctions', 'prompt_id' => '44'],
['label' => 'Sanktionen (UK)', 'key' => 'entity_corporate_uksanctions', 'prompt_id' => '45'],
['label' => 'Sanktionen (UK) d. Gegenpartei', 'key' => 'counterparty_corporate_uksanctions', 'prompt_id' => '45'],
['label' => 'PEP', 'key' => 'entity_corporate_pep', 'prompt_id' => '77'],
['label' => 'PEP d. Gegenpartei', 'key' => 'counterparty_corporate_pep', 'prompt_id' => '77'],
],
],
[
'title' => 'Aufsichtsrat/Beirat',
'description' => null,
'fields' => [
['label' => 'Kontrollorgan', 'key' => 'entity_corporate_supervisory', 'prompt_id' => '17'],
['label' => 'Kontrollorgan d. Gegenpartei', 'key' => 'counterparty_corporate_supervisory', 'prompt_id' => '17'],
['label' => 'Sanktionen (EU)', 'key' => 'entity_corporate_eusanctions', 'prompt_id' => '43'],
['label' => 'Sanktionen (EU) d. Gegenpartei', 'key' => 'counterparty_corporate_eusanctions', 'prompt_id' => '43'],
['label' => 'Sanktionen (OFAC)', 'key' => 'entity_corporate_ofacsanctions', 'prompt_id' => '44'],
['label' => 'Sanktionen (OFAC) d. Gegenpartei', 'key' => 'counterparty_corporate_ofacsanctions', 'prompt_id' => '44'],
['label' => 'Sanktionen (UK)', 'key' => 'entity_corporate_uksanctions', 'prompt_id' => '45'],
['label' => 'Sanktionen (UK) d. Gegenpartei', 'key' => 'counterparty_corporate_uksanctions', 'prompt_id' => '45'],
['label' => 'PEP', 'key' => 'entity_corporate_pep', 'prompt_id' => '77'],
['label' => 'PEP d. Gegenpartei', 'key' => 'counterparty_corporate_pep', 'prompt_id' => '77'],
],
],
[
'title' => 'Anteilseignerliste',
'description' => null,
'fields' => [
['label' => 'Gesellschafter', 'key' => 'entity_corporate_shareholders', 'prompt_id' => '15'],
['label' => 'Gesellschafter d. Gegenpartei', 'key' => 'counterparty_corporate_shareholders', 'prompt_id' => '15'],
['label' => 'Sanktionen (EU)', 'key' => 'entity_corporate_eusanctions', 'prompt_id' => '43'],
['label' => 'Sanktionen (EU) d. Gegenpartei', 'key' => 'counterparty_corporate_eusanctions', 'prompt_id' => '43'],
['label' => 'Sanktionen (OFAC)', 'key' => 'entity_corporate_ofacsanctions', 'prompt_id' => '44'],
['label' => 'Sanktionen (OFAC) d. Gegenpartei', 'key' => 'counterparty_corporate_ofacsanctions', 'prompt_id' => '44'],
['label' => 'Sanktionen (UK)', 'key' => 'entity_corporate_uksanctions', 'prompt_id' => '45'],
['label' => 'Sanktionen (UK) d. Gegenpartei', 'key' => 'counterparty_corporate_uksanctions', 'prompt_id' => '45'],
['label' => 'PEP', 'key' => 'entity_corporate_pep', 'prompt_id' => '77'],
['label' => 'PEP d. Gegenpartei', 'key' => 'counterparty_corporate_pep', 'prompt_id' => '77'],
],
],
[
'title' => 'Wirtschaftlich Berechtigte (UBOs)',
'description' => null,
'fields' => [
['label' => 'Letztendliche wirtschaftliche Eigentümer', 'key' => 'entity_corporate_UBO', 'prompt_id' => '21'],
['label' => 'Letztendliche wirtschaftliche Eigentümer d. Gegenpartei', 'key' => 'counterparty_corporate_UBO', 'prompt_id' => '21'],
['label' => 'Sanktionen (EU)', 'key' => 'entity_corporate_eusanctions', 'prompt_id' => '43'],
['label' => 'Sanktionen (EU) d. Gegenpartei', 'key' => 'counterparty_corporate_eusanctions', 'prompt_id' => '43'],
['label' => 'Sanktionen (OFAC)', 'key' => 'entity_corporate_ofacsanctions', 'prompt_id' => '44'],
['label' => 'Sanktionen (OFAC) d. Gegenpartei', 'key' => 'counterparty_corporate_ofacsanctions', 'prompt_id' => '44'],
['label' => 'Sanktionen (UK)', 'key' => 'entity_corporate_uksanctions', 'prompt_id' => '45'],
['label' => 'Sanktionen (UK) d. Gegenpartei', 'key' => 'counterparty_corporate_uksanctions', 'prompt_id' => '45'],
['label' => 'PEP Exposure', 'key' => 'entity_corporate_pepexposure', 'prompt_id' => '46'],
['label' => 'PEP Exposure d. Gegenpartei', 'key' => 'counterparty_corporate_pepexposure', 'prompt_id' => '46'],
],
],
[
'title' => 'Zeichnungsberechtigte',
'description' => null,
'fields' => [
['label' => 'Bevollmächtigte', 'key' => 'entity_corporate_powerofattorney', 'prompt_id' => '18'],
['label' => 'Bevollmächtigte d. Gegenpartei', 'key' => 'counterparty_corporate_powerofattorney', 'prompt_id' => '18'],
['label' => 'Sanktionen (EU)', 'key' => 'entity_corporate_eusanctions', 'prompt_id' => '43'],
['label' => 'Sanktionen (EU) d. Gegenpartei', 'key' => 'counterparty_corporate_eusanctions', 'prompt_id' => '43'],
['label' => 'Sanktionen (OFAC)', 'key' => 'entity_corporate_ofacsanctions', 'prompt_id' => '44'],
['label' => 'Sanktionen (OFAC) d. Gegenpartei', 'key' => 'counterparty_corporate_ofacsanctions', 'prompt_id' => '44'],
['label' => 'Sanktionen (UK)', 'key' => 'entity_corporate_uksanctions', 'prompt_id' => '45'],
['label' => 'Sanktionen (UK) d. Gegenpartei', 'key' => 'counterparty_corporate_uksanctions', 'prompt_id' => '45'],
['label' => 'PEP', 'key' => 'entity_corporate_pep', 'prompt_id' => '77'],
['label' => 'PEP d. Gegenpartei', 'key' => 'counterparty_corporate_pep', 'prompt_id' => '77'],
],
],
],
],
[
'level' => 8,
'title' => 'Zusätzliche Informationen',
'sections' => [
[
'title' => 'Adverse Media (negative Medienberichte)',
'description' => null,
'fields' => [
['label' => 'Adverse Media', 'key' => 'entity_corporate_adversemediascanning', 'prompt_id' => '47'],
['label' => 'Adverse Media d. Gegenpartei', 'key' => 'counterparty_corporate_adversemediascanning', 'prompt_id' => '47'],
],
],
[
'title' => 'Jahresabschlüsse',
'description' => null,
'fields' => [
['label' => 'Umsatz', 'key' => 'entity_corporate_turnover', 'prompt_id' => '23'],
['label' => 'Umsatz d. Gegenpartei', 'key' => 'counterparty_corporate_turnover', 'prompt_id' => '23'],
['label' => 'EBIT/EBITDA', 'key' => 'entity_corporate_EBIT', 'prompt_id' => '24'],
['label' => 'EBIT/EBITDA d. Gegenpartei', 'key' => 'counterparty_corporate_EBIT', 'prompt_id' => '24'],
['label' => 'Nettogewinn', 'key' => 'entity_corporate_netprofits', 'prompt_id' => '25'],
['label' => 'Nettogewinn d. Gegenpartei', 'key' => 'counterparty_corporate_netprofits', 'prompt_id' => '25'],
['label' => 'Gesamtvermögen', 'key' => 'entity_corporate_balancesheet', 'prompt_id' => '26'],
['label' => 'Gesamtvermögen d. Gegenpartei', 'key' => 'counterparty_corporate_balancesheet', 'prompt_id' => '26'],
],
],
[
'title' => 'AdHoc Meldungen, Corporate News',
'description' => null,
'fields' => [
['label' => 'Adhoc Berichte', 'key' => 'entity_corporate_adhoc', 'prompt_id' => '30'],
['label' => 'Adhoc Berichte d. Gegenpartei', 'key' => 'counterparty_corporate_adhoc', 'prompt_id' => '30'],
['label' => 'Führungspersonal', 'key' => 'entity_corporate_adverse', 'prompt_id' => '76'],
['label' => 'Führungspersonal d. Gegenpartei', 'key' => 'counterparty_corporate_adverse', 'prompt_id' => '76'],
['label' => 'Mitteilungen', 'key' => 'entity_corporate_mediamatch', 'prompt_id' => '82'],
['label' => 'Mitteilungen d. Gegenpartei', 'key' => 'counterparty_corporate_mediamatch', 'prompt_id' => '82'],
],
],
[
'title' => 'Pressemitteilungen',
'description' => null,
'fields' => [
['label' => 'Presseberichte', 'key' => 'entity_corporate_pressrelease', 'prompt_id' => '31'],
['label' => 'Presseberichte d. Gegenpartei', 'key' => 'counterparty_corporate_pressrelease', 'prompt_id' => '31'],
],
],
[
'title' => 'Stimmrechtsmitteilungen',
'description' => null,
'fields' => [
['label' => 'Stimmrechtsmitteilungen', 'key' => 'entity_corporate_votes', 'prompt_id' => '32'],
['label' => 'Stimmrechtsmitteilungen d. Gegenpartei', 'key' => 'counterparty_corporate_votes', 'prompt_id' => '32'],
],
],
[
'title' => 'Audit-Hinweise (Bestätigungsvermerk)',
'description' => null,
'fields' => [
['label' => 'Prüfberichte', 'key' => 'entity_corporate_auditfindings', 'prompt_id' => '27'],
['label' => 'Prüfberichte d. Gegenpartei', 'key' => 'counterparty_corporate_auditfindings', 'prompt_id' => '27'],
],
],
[
'title' => 'Ratings',
'description' => null,
'fields' => [
['label' => 'Rating (Solvency)', 'key' => 'entity_corporate_solvency', 'prompt_id' => '38'],
['label' => 'Rating (Solvency) d. Gegenpartei', 'key' => 'counterparty_corporate_solvency', 'prompt_id' => '38'],
['label' => 'Rating', 'key' => 'entity_corporate_rating', 'prompt_id' => '39'],
['label' => 'Rating d. Gegenpartei', 'key' => 'counterparty_corporate_rating', 'prompt_id' => '39'],
],
],
[
'title' => 'Schufa, Hermes, Creditreform auf Zahlungsverhalten/Bonität',
'description' => null,
'fields' => [
['label' => 'Rating', 'key' => 'entity_corporate_solvency', 'prompt_id' => '38'],
['label' => 'Rating d. Gegenpartei', 'key' => 'counterparty_corporate_solvency', 'prompt_id' => '38'],
],
],
[
'title' => 'ESG Rating',
'description' => null,
'fields' => [
['label' => 'Rating', 'key' => 'entity_corporate_ESG', 'prompt_id' => '40'],
['label' => 'Rating d. Gegenpartei', 'key' => 'counterparty_corporate_ESG', 'prompt_id' => '40'],
],
],
],
],
];
}
protected function filteredQuery(): Builder
{
return $this->baseQuery()
->when($this->status !== 'all', fn (Builder $query) => $query->where('status', $this->status))
->when($this->channel !== 'all', fn (Builder $query) => $query->where('channel', $this->channel));
}
protected function baseQuery(): Builder
{
return Transaction::query()->where('company_id', $this->company->id);
}
};
?>
@php
/** @var \Illuminate\Contracts\Pagination\LengthAwarePaginator $transactions */
$transactions = $this->transactions;
/** @var \App\Models\Transaction|null $selected */
$selected = $this->selectedTransaction;
$metrics = $this->metrics;
$statusOptions = $this->statusOptions;
$channelOptions = $this->channelOptions;
$counterpartyHistory = $this->counterpartyHistory;
$recentAlerts = $this->recentAlerts;
$actionChecklist = $this->actionChecklist;
$checklistIntro = __('Fokusbereiche für diesen Fall');
$detailStructure = $this->transactionDetailStructure;
$formatCurrency = static fn (float $value): string => number_format($value, 2, ',', '.') . ' €';
$formatCurrencyCompact = static function (float $value): string {
if ($value >= 1000000) {
return number_format($value / 1000000, 0, ',', '.') . ' Mio. €';
}
return number_format($value, 2, ',', '.') . ' €';
};
$formatAmount = static fn (float $value, string $currency): string => number_format($value, 2, ',', '.') . ' ' . $currency;
$statusStyles = [
Transaction::STATUS_TRUE_POSITIVE => 'bg-gradient-to-r from-rose-500/25 via-rose-500/10 to-rose-400/20 text-rose-700 dark:text-rose-200 border border-rose-500/30 shadow-[0_0_25px_-14px_rgba(244,63,94,0.85)]',
Transaction::STATUS_FALSE_POSITIVE => 'bg-gradient-to-r from-amber-400/25 via-amber-400/10 to-amber-300/20 text-amber-700 dark:text-amber-200 border border-amber-400/30 shadow-[0_0_25px_-14px_rgba(251,191,36,0.85)]',
Transaction::STATUS_CLEARED => 'bg-gradient-to-r from-emerald-400/25 via-emerald-400/10 to-emerald-300/20 text-emerald-700 dark:text-emerald-200 border border-emerald-400/30 shadow-[0_0_25px_-14px_rgba(52,211,153,0.85)]',
];
$statusCopy = [
Transaction::STATUS_TRUE_POSITIVE => __('Ein schwerwiegender Verdacht liegt vor. Priorisieren Sie die Eskalation und bereiten Sie eine Verdachtsmeldung vor.'),
Transaction::STATUS_FALSE_POSITIVE => __('Alarm konnte entkräftet werden. Dokumentieren Sie die Begründung und schließen Sie den Fall.'),
Transaction::STATUS_CLEARED => __('Keine Auffälligkeiten. Dokumentieren und archivieren Sie den Prüfschritt.'),
];
@endphp
<div class="flex flex-col gap-8">
<section class="rounded-3xl border border-slate-200/70 bg-white/95 p-8 shadow-sm backdrop-blur dark:border-slate-700/70 dark:bg-slate-900/90">
<div class="flex flex-wrap items-start justify-between gap-6">
<div class="max-w-2xl space-y-2">
<flux:link :href="route('transaction-review')" wire:navigate class="inline-flex items-center gap-2 text-sm font-semibold text-slate-500 hover:text-slate-700 dark:text-slate-300 dark:hover:text-white">
<flux:icon name="arrow-left" class="h-4 w-4" />
{{ __('Zurück zur Transaktionsprüfung') }}
</flux:link>
<flux:heading size="xl">
{{ $company->legal_name }}
</flux:heading>
<flux:text class="text-sm text-slate-500 dark:text-slate-300">
{{ $company->summary }}
</flux:text>
<div class="flex flex-wrap gap-2 text-xs text-slate-600 dark:text-slate-300">
<span class="inline-flex items-center gap-2 rounded-full bg-slate-100/60 px-3 py-1 font-medium uppercase tracking-wide text-slate-600 dark:bg-slate-800/70 dark:text-slate-200">
{{ __('Ticker') }} {{ $company->ticker }}
</span>
<span class="inline-flex items-center gap-2 rounded-full bg-indigo-100/60 px-3 py-1 font-medium uppercase tracking-wide text-indigo-600 dark:bg-indigo-500/20 dark:text-indigo-200">
{{ $company->sector }}
</span>
<span class="inline-flex items-center gap-2 rounded-full bg-emerald-100/60 px-3 py-1 font-medium uppercase tracking-wide text-emerald-700 dark:bg-emerald-500/20 dark:text-emerald-100">
{{ __('KYC-Risiko') }} {{ \Illuminate\Support\Str::title($company->kyc_risk_level) }}
</span>
</div>
</div>
<div class="grid grid-cols-2 gap-4 text-sm sm:grid-cols-3">
<div class="rounded-2xl border border-slate-200/70 bg-slate-50/80 p-4 dark:border-slate-700/70 dark:bg-slate-800/80">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Transaktionen gesamt') }}</p>
<p class="mt-2 text-2xl font-semibold text-slate-900 dark:text-white">{{ $metrics['total_count'] }}</p>
<p class="text-xs text-slate-500 dark:text-slate-300">{{ __('Volumen') }} {{ $formatCurrencyCompact($metrics['total_volume']) }}</p>
</div>
<div class="rounded-2xl border border-emerald-400/40 bg-emerald-400/10 p-4 shadow-sm shadow-emerald-900/10">
<p class="text-xs font-semibold uppercase tracking-wide text-emerald-700 dark:text-emerald-200">{{ __('Offene Alerts') }}</p>
<p class="mt-2 text-2xl font-semibold text-emerald-900 dark:text-emerald-100">{{ $metrics['open_alerts']['count'] }}</p>
<p class="text-xs text-emerald-700 dark:text-emerald-100">{{ __('Volumen') }} {{ $formatCurrencyCompact($metrics['open_alerts']['amount']) }}</p>
</div>
<div class="rounded-2xl border border-indigo-400/40 bg-indigo-500/10 p-4 shadow-sm shadow-indigo-900/10">
<p class="text-xs font-semibold uppercase tracking-wide text-indigo-800 dark:text-indigo-200">{{ __('High-Risk-Anteil') }}</p>
<p class="mt-2 text-2xl font-semibold text-indigo-900 dark:text-indigo-100">{{ $metrics['high_risk_share'] }}%</p>
<p class="text-xs text-indigo-700 dark:text-indigo-200">{{ __('Letzte 30 Tage') }} {{ $metrics['last_30_days']['count'] }}</p>
</div>
</div>
</div>
</section>
<div class="space-y-6">
@if ($selected)
@php
$badgeStyle = $statusStyles[$selected->status] ?? 'bg-zinc-500/10 text-zinc-600 border border-zinc-500/20';
$riskLevel = match (true) {
$selected->risk_score >= 80 => __('Hoch'),
$selected->risk_score >= 60 => __('Erhöht'),
$selected->risk_score >= 40 => __('Moderat'),
default => __('Niedrig'),
};
$riskNarrative = match (true) {
$selected->risk_score >= 80 => __('Die Einstufung über 80 Punkten signalisiert einen erhöhten AML-Prüffokus. Eskalation und enges Monitoring sind angeraten.'),
$selected->risk_score >= 60 => __('Das Risiko liegt im oberen Mittelfeld. Prüfen Sie Plausibilitäten und dokumentieren Sie Gegenmaßnahmen.'),
$selected->risk_score >= 40 => __('Die Einstufung erscheint moderat. Stellen Sie sicher, dass grundlegende Prüfungen vollständig dokumentiert sind.'),
default => __('Der Score deutet auf ein geringes AML-Risiko hin. Ein strukturierter Nachweis der Prüfung ist dennoch erforderlich.'),
};
$statusGuidance = $statusCopy[$selected->status] ?? __('Review abschließen und Audit-Trail ergänzen.');
$executedDate = $selected->executed_at?->format('d.m.Y');
$executedTime = $selected->executed_at?->format('H:i');
$amountValue = $formatAmount($selected->amount, $selected->currency);
$companyName = $company->legal_name ?? $company->name;
$companyCountryLabel = $company->country ?? __('Jurisdiktion offen');
$counterpartyCountryLabel = $selected->counterparty_country ?? __('Jurisdiktion offen');
$referenceLabel = $selected->reference ?: __('Keine Referenz angegeben');
$flaggedReasonLabel = $selected->flagged_reason ?: __('Nicht dokumentiert');
$domesticFlow = $company->country && $selected->counterparty_country && strcasecmp($company->country, $selected->counterparty_country) === 0;
$purposeDescription = __('Die Zahlung nutzt den Referenztext ":reference" und wurde mit dem Flag ":reason" markiert. Prüfen Sie Rechnungs- und Liefernachweise, um den wirtschaftlichen Anlass zu bestätigen.', [
'reference' => $referenceLabel,
'reason' => $flaggedReasonLabel,
]);
$countryNotes = [];
if ($domesticFlow) {
$countryNotes[] = __('Transparency International CPI 2024: 75/100 (Rang 15).');
} else {
$countryNotes[] = __('Ermitteln Sie länderspezifische Restrisiken (Sanktionen, Exportkontrolle, Devisenauflagen).');
}
if (! $company->country || ! $selected->counterparty_country) {
$countryNotes[] = __('Länderangaben unvollständig KYC-Stammdaten aktualisieren.');
}
$analysisSections = [
[
'title' => __('Verwendungszweck'),
'description' => $purposeDescription,
'notes' => [
__('Rechnungskopie inkl. HR-/VAT-/IBAN-Angaben anfordern.'),
__('3-Way-Match (POGRInvoice) vollständig dokumentieren.'),
],
],
[
'title' => __('LEI'),
'description' => __('Für :company und :counterparty liegt kein verifizierter LEI im Datensatz vor. Ein Direktabruf im GLEIF-Register wird empfohlen.', [
'company' => $companyName,
'counterparty' => $selected->counterparty,
]),
'notes' => [
__('Status: not verified.'),
__('Bankinterne LEI-Prüfung vor Freigabe abschließen.'),
],
],
[
'title' => __('Länderanalyse'),
'description' => $domesticFlow
? __('Vorliegende Daten deuten auf eine Inlandszahlung (:from → :to) hin. Das systemische Korruptionsrisiko gilt als niedrig.', [
'from' => $companyCountryLabel,
'to' => $counterpartyCountryLabel,
])
: __('Transaktion verläuft von :from nach :to. Prüfen Sie Export-/Importauflagen sowie mögliche Hochrisikofaktoren.', [
'from' => $companyCountryLabel,
'to' => $counterpartyCountryLabel,
]),
'notes' => $countryNotes,
],
[
'title' => __('PEP-Exposure'),
'description' => __('Es liegen keine Hinweise auf PEP-Einfluss in den Stammdaten vor. Screening der wirtschaftlich Berechtigten bleibt fortzuführen.'),
'notes' => [
__('Manuelles Screening der Management- und Eigentümerebene abschließen (Status: not verified).'),
],
],
[
'title' => __('AML Exposure (transaktionsbezogen)'),
'description' => __('Klarer Leistungszweck und etablierte Gegenparteien wirken risikomindernd. Restrisiko besteht in der eindeutigen Identifikation der Rechnungseinheit und des Zahlungswegs.'),
'notes' => [
__('Kontoinhaber und IBAN mit der Rechnungseinheit matchen.'),
__('Preis- und Mengenabweichungen gegen Bestellung analysieren.'),
],
],
[
'title' => __('Sanktions-Exposure'),
'description' => __('Bisherige Namenstests ergaben keine Treffer. Automatisierte Listenprüfungen sind auf den finalen Rechtsträger erneut auszuführen.'),
'notes' => [
__('EU-/OFAC-Abgleich sowie interne Sanktionslisten auf finaler Rechnungseinheit bestätigen.'),
],
],
[
'title' => __('Korruptions-/Bestechungs-Exposure'),
'description' => __('Makrorisiko im deutschen Markt ist gering. Beschaffungsrisiken (Kick-backs, Scheinrechnungen) bleiben bei Großvolumina bestehen.'),
'notes' => [
__('Zahlungen ausschließlich an bestätigte Gesellschaftskonten leisten.'),
__('Vier-Augen-Prinzip und Liefernachweise dokumentieren.'),
],
],
[
'title' => __('Adverse Media Scanning (≤ 12 Monate)'),
'description' => __('In den letzten 12 Monaten wurden keine AML-relevanten Negativmeldungen identifiziert. Restrisiko: laufende Restrukturierungs- und Compliance-News beobachten.'),
'notes' => [
__('Interne Newsfeeds und Watchlists weiterführen.'),
],
],
[
'title' => __('KYC/EDD Feststellungen'),
'description' => __('KYC-Dossier aktualisieren: rechtliche Einheit, wirtschaftlich Berechtigte und Zahlungsweg eindeutig dokumentieren.'),
'notes' => [
__('IBAN/BIC sowie Steuerkennzeichen im Dossier hinterlegen.'),
__('Rechnungskopie, Liefernachweis und Vertragsgrundlage einholen.'),
],
],
[
'title' => __('Gesamtbeurteilung (AML-Sicht)'),
'description' => __('Die Transaktion über :amount zwischen :company und :counterparty wirkt branchenüblich. Freigabe ist möglich, sobald Rechnungseinheit, Zahlungsweg und Screening final bestätigt sind.', [
'amount' => $amountValue,
'company' => $companyName,
'counterparty' => $selected->counterparty,
]),
'notes' => [
__('Votum: Freigabefähig unter Auflagen (Rechnung, 3-Way-Match, Screening, Exportkontrolle).'),
],
],
];
$combineNotes = static function (array $sections): array {
$notes = [];
foreach ($sections as $section) {
$notes = array_merge($notes, $section['notes'] ?? []);
}
return $notes;
};
$clusterFactory = static function (string $title, array $sections) use ($combineNotes): array {
$leadSection = $sections[0] ?? null;
$contexts = array_slice($sections, 1);
return [
'title' => $title,
'lead_label' => $leadSection['title'] ?? null,
'lead' => $leadSection['description'] ?? '',
'contexts' => array_map(
static fn (array $section): array => [
'label' => $section['title'],
'body' => $section['description'],
],
$contexts
),
'actions' => $combineNotes($sections),
'count' => count($sections),
];
};
$transactionSections = array_slice($analysisSections, 0, 2);
$riskSections = array_slice($analysisSections, 2, 6);
$dueSections = array_slice($analysisSections, 8);
$analysisClusters = [
$clusterFactory(__('Transaktion & Zweck'), $transactionSections),
$clusterFactory(__('Risikoperspektive'), $riskSections),
$clusterFactory(__('Due Diligence & Abschluss'), $dueSections),
];
$analysisClusterCount = array_sum(array_map(static fn (array $cluster): int => $cluster['count'], $analysisClusters));
$caseBoxStyles = [
Transaction::STATUS_TRUE_POSITIVE => 'border border-rose-300/60 bg-gradient-to-br from-rose-50 via-rose-100/80 to-white dark:border-rose-500/40 dark:from-rose-500/20 dark:via-rose-500/10 dark:to-slate-900/85',
Transaction::STATUS_FALSE_POSITIVE => 'border border-amber-300/60 bg-gradient-to-br from-amber-50 via-amber-100/80 to-white dark:border-amber-500/40 dark:from-amber-500/20 dark:via-amber-500/10 dark:to-slate-900/85',
Transaction::STATUS_CLEARED => 'border border-emerald-300/60 bg-gradient-to-br from-emerald-50 via-emerald-100/70 to-white dark:border-emerald-500/40 dark:from-emerald-500/15 dark:via-emerald-500/10 dark:to-slate-900/85',
];
$caseBoxClass = $caseBoxStyles[$selected->status] ?? 'border border-slate-200/70 bg-white/95 dark:border-slate-700/70 dark:bg-slate-900/90';
$sources = array_values(array_filter([
$companyName ? __('Unternehmensprofil :company (:country) interne KYC-Stammdaten.', [
'company' => $companyName,
'country' => $companyCountryLabel,
]) : null,
__('Transaktionsdatensatz #:id Core Banking Export.', ['id' => $selected->id]),
$selected->reference ? __('Rechnungsreferenz ":reference" Plausibilisierung steht aus.', ['reference' => $referenceLabel]) : null,
__('GLEIF LEI Register (Direktabruf, Status: not verified).'),
__('Transparency International CPI 2024 (Deutschland 75/100).'),
__('EU/OFAC Sanktionsportale orientierender Namensabgleich (endgültige Prüfung intern).'),
]));
@endphp
<div class="grid gap-6 xl:grid-cols-[minmax(0,1.65fr)_minmax(0,1fr)]">
<div @class([ 'rounded-3xl p-7 shadow-lg shadow-slate-900/5 backdrop-blur' ,
$caseBoxClass,
])>
<div class="flex flex-wrap items-start justify-between gap-6">
<div class="space-y-2">
<span class="inline-flex items-center gap-2 rounded-full border border-indigo-200/70 bg-indigo-500/10 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-indigo-700 shadow-sm dark:border-indigo-500/40 dark:bg-indigo-500/20 dark:text-indigo-100">
{{ __('Case ID') }} {{ $selected->id }}
</span>
<h3 class="text-2xl font-semibold text-slate-900 dark:text-white">
{{ $selected->counterparty }} — {{ $amountValue }}
</h3>
<p class="text-sm text-slate-500 dark:text-slate-300">
{{ __('Ausgeführt am') }} {{ $executedDate ?? __('Nicht verfügbar') }}
@if ($executedTime)
• {{ $executedTime }}
@endif
• {{ $selected->channel ?: __('Kanal offen') }}
</p>
</div>
<div class="flex flex-col items-end gap-2">
<span class="inline-flex items-center gap-2 rounded-full px-3 py-1 text-xs font-semibold {{ $badgeStyle }}">
{{ $selected->statusLabel() }}
</span>
<span class="inline-flex items-center gap-1 rounded-md bg-slate-900/10 px-3 py-1 font-semibold text-slate-800 dark:bg-slate-200/10 dark:text-slate-200">
{{ __('Risikowert') }} {{ $selected->risk_score }} ({{ $riskLevel }})
</span>
</div>
</div>
<div class="mt-7 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<div class="rounded-2xl border border-slate-200/70 bg-slate-50/80 p-4 dark:border-slate-700/70 dark:bg-slate-800/70">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Stichtag') }}</p>
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $executedDate ?? __('Nicht verfügbar') }}</p>
<p class="text-xs text-slate-500 dark:text-slate-300">{{ $executedTime ? __('Zeit') . ' ' . $executedTime : __('Zeitpunkt offen') }}</p>
</div>
<div class="rounded-2xl border border-slate-200/70 bg-slate-50/80 p-4 dark:border-slate-700/70 dark:bg-slate-800/70">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Kanal & Referenz') }}</p>
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $selected->channel ?: __('Unbekannt') }}</p>
<p class="text-xs text-slate-500 dark:text-slate-300">{{ $selected->reference ?: __('Keine Referenz hinterlegt') }}</p>
</div>
<div class="rounded-2xl border border-slate-200/70 bg-slate-50/80 p-4 dark:border-slate-700/70 dark:bg-slate-800/70">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Flagging durch') }}</p>
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $selected->flagged_by ?: __('Automatisiertes Monitoring') }}</p>
<p class="text-xs text-slate-500 dark:text-slate-300">{{ $selected->flagged_reason ?: __('Flagging-Grund nicht dokumentiert') }}</p>
</div>
<div class="rounded-2xl border border-indigo-300/60 bg-indigo-500/10 p-4 text-indigo-900 shadow-sm shadow-indigo-900/10 dark:border-indigo-500/40 dark:bg-indigo-500/10 dark:text-indigo-100">
<p class="text-xs font-semibold uppercase tracking-wide">{{ __('Empfohlene Maßnahme') }}</p>
<p class="mt-1 text-sm font-medium leading-relaxed">{{ $statusGuidance }}</p>
</div>
</div>
<div class="mt-8">
<h4 class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Parteiprofile') }}</h4>
<div class="mt-3 grid gap-4 lg:grid-cols-2">
<div class="group rounded-2xl border border-slate-200/80 bg-white/70 p-4 transition hover:border-indigo-300/70 hover:shadow-md dark:border-slate-700/70 dark:bg-slate-900/70 dark:hover:border-indigo-400/50">
<div class="flex items-center justify-between">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400 dark:text-slate-500">{{ __('Sending party') }}</p>
<span class="inline-flex items-center rounded-full border border-indigo-300/60 bg-indigo-500/10 px-2.5 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-indigo-700 dark:border-indigo-500/40 dark:bg-indigo-500/20 dark:text-indigo-100">
{{ __('Unternehmensprofil') }}
</span>
</div>
<p class="mt-2 text-sm font-semibold text-slate-900 dark:text-white">{{ $selected->company?->legal_name ?? $company->legal_name ?? $company->name }}</p>
<dl class="mt-3 space-y-1 text-xs text-slate-600 dark:text-slate-300">
<div class="flex justify-between gap-3">
<dt>{{ __('Jurisdiktion') }}</dt>
<dd class="text-right">{{ $company->country ?? __('Nicht verifiziert') }}</dd>
</div>
<div class="flex justify-between gap-3">
<dt>{{ __('Sitz') }}</dt>
<dd class="text-right">{{ $company->headquarters ?? __('Nicht verifiziert') }}</dd>
</div>
<div class="flex justify-between gap-3">
<dt>{{ __('Sektor') }}</dt>
<dd class="text-right">{{ $company->sector ?? __('Nicht verifiziert') }}</dd>
</div>
</dl>
</div>
<div class="group rounded-2xl border border-slate-200/80 bg-white/70 p-4 transition hover:border-indigo-300/70 hover:shadow-md dark:border-slate-700/70 dark:bg-slate-900/70 dark:hover:border-indigo-400/50">
<div class="flex items-center justify-between">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400 dark:text-slate-500">{{ __('Receiving party') }}</p>
<span class="inline-flex items-center rounded-full border border-zinc-300/60 bg-zinc-100/60 px-2.5 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-zinc-700 dark:border-zinc-600/50 dark:bg-zinc-800/60 dark:text-zinc-200">
{{ __('Verifizierung offen') }}
</span>
</div>
<p class="mt-2 text-sm font-semibold text-slate-900 dark:text-white">{{ $selected->counterparty }}</p>
<dl class="mt-3 space-y-1 text-xs text-slate-600 dark:text-slate-300">
<div class="flex justify-between gap-3">
<dt>{{ __('Jurisdiktion') }}</dt>
<dd class="text-right">{{ $selected->counterparty_country ?? __('Nicht verifiziert') }}</dd>
</div>
<div class="flex justify-between gap-3">
<dt>{{ __('Referenzhinweis') }}</dt>
<dd class="text-right">{{ $selected->reference ?: __('Keine Angabe') }}</dd>
</div>
<div class="flex justify-between gap-3">
<dt>{{ __('Next step') }}</dt>
<dd class="text-right">{{ __('IBAN/Beneficiary eindeutig zuordnen') }}</dd>
</div>
</dl>
</div>
</div>
</div>
<div class="mt-8 grid gap-4 lg:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]">
<div class="rounded-2xl border border-slate-200/70 bg-slate-50/80 p-5 dark:border-slate-700/70 dark:bg-slate-800/70">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Transaktionsbewertung') }}</p>
<p class="mt-2 text-sm text-slate-700 dark:text-slate-200">{{ $riskNarrative }}</p>
<ul class="mt-3 space-y-2 text-xs text-slate-500 dark:text-slate-300">
<li>• {{ __('Betrag') }} {{ $amountValue }}</li>
<li>• {{ __('Flagging-Grund') }}: {{ $selected->flagged_reason ?: __('nicht dokumentiert') }}</li>
<li>• {{ __('Kanal') }}: {{ $selected->channel ?: __('unbekannt') }}</li>
</ul>
</div>
<div class="rounded-2xl border border-emerald-400/40 bg-emerald-500/10 p-5 text-sm text-emerald-900 shadow-sm shadow-emerald-900/10 dark:border-emerald-500/40 dark:bg-emerald-500/10 dark:text-emerald-100">
<p class="text-xs font-semibold uppercase tracking-wide">{{ __('Kontrollaufgaben (Zusammenfassung)') }}</p>
<p class="mt-2 leading-relaxed">
{{ __('Sicherstellen, dass Rechnungskopf, Beneficiary-Daten und 3-Way-Match (POGRInvoice) dokumentiert sind. Interne Listenabgleiche (Sanktionen/PEP) auf den konkreten Rechtsträger erneut ausführen.') }}
</p>
</div>
</div>
@if (! empty($selected->signals))
<div class="mt-8">
<h4 class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Detektionssignale') }}</h4>
<div class="mt-3 flex flex-wrap gap-2">
@foreach ($selected->signals as $signal)
<span class="inline-flex items-center gap-2 rounded-full border border-slate-300/70 bg-slate-100/70 px-3 py-1 text-xs font-medium text-slate-700 dark:border-slate-600 dark:bg-slate-800/60 dark:text-slate-200">
<span class="h-1.5 w-1.5 rounded-full bg-emerald-500"></span>
{{ data_get($signal, 'type') }} — {{ data_get($signal, 'value') }}
</span>
@endforeach
</div>
</div>
@endif
<div class="mt-8 rounded-2xl border border-indigo-200/60 bg-indigo-500/10 p-5 text-sm text-indigo-900 dark:border-indigo-500/30 dark:bg-indigo-500/10 dark:text-indigo-100">
<p class="text-xs font-semibold uppercase tracking-wide">{{ __('Narrative Zusammenfassung') }}</p>
<p class="mt-2 leading-relaxed">
{{ __('Die Transaktion verbindet :company (:jurisdiction) mit :counterparty (:country). Der Betrag von :amount wurde über den Kanal :channel ausgeführt. Für die abschließende AML-Beurteilung ist der Nachweis der wirtschaftlich Berechtigten sowie ein Abgleich der Zahlungsempfänger-Daten erforderlich.', [
'company' => $company->legal_name ?? $company->name,
'jurisdiction' => $company->country ?? __('Jurisdiktion offen'),
'counterparty' => $selected->counterparty,
'country' => $selected->counterparty_country ?? __('Jurisdiktion offen'),
'amount' => $amountValue,
'channel' => $selected->channel ?: __('unbekannt'),
]) }}
</p>
<p class="mt-2 text-xs text-indigo-800 dark:text-indigo-200">
{{ __('Hinweis: Interne Quellen (ERP, KYC-Stammdaten, Screening) ergänzen, um den Verifizierungsstatus auf „abgeschlossen“ anzuheben.') }}
</p>
</div>
@if (! empty($analysisClusters))
<div class="mt-8 space-y-5">
<div class="rounded-3xl border border-slate-200/70 bg-white/95 p-6 shadow-sm transition hover:shadow-md dark:border-slate-700/70 dark:bg-slate-900/90">
<div class="flex flex-wrap items-center justify-between gap-3">
<h4 class="text-sm font-semibold uppercase tracking-wide text-slate-600 dark:text-slate-200">{{ __('Vertiefte Analysefelder') }}</h4>
<span class="inline-flex items-center gap-2 rounded-full border border-slate-200/70 bg-slate-50/80 px-3 py-1 text-[11px] font-semibold uppercase tracking-wide text-slate-500 dark:border-slate-600/60 dark:bg-slate-800/70 dark:text-slate-200">
{{ $analysisClusterCount }} {{ __('Prüfpunkte') }}
</span>
</div>
<p class="mt-3 text-sm leading-relaxed text-slate-600 dark:text-slate-300">
{{ __('Verdichten Sie die Prüfung auf drei Themenblöcke. Jeder Block fasst die wesentlichen Anforderungen zusammen.') }}
</p>
</div>
@foreach ($analysisClusters as $clusterIndex => $cluster)
<div class="rounded-3xl border border-slate-200/70 bg-white/95 p-6 shadow-sm dark:border-slate-700/70 dark:bg-slate-900/90">
<div class="flex flex-wrap items-start justify-between gap-4">
<div class="max-w-2xl space-y-2">
@if ($cluster['lead_label'])
<span class="inline-flex items-center rounded-full border border-slate-300/70 bg-slate-100/60 px-2.5 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-slate-600 dark:border-slate-600/60 dark:bg-slate-800/70 dark:text-slate-200">
{{ $cluster['lead_label'] }}
</span>
@endif
<h5 class="text-lg font-semibold text-slate-900 dark:text-white">
{{ sprintf('%02d', $clusterIndex + 1) }} — {{ $cluster['title'] }}
</h5>
<p class="text-sm leading-relaxed text-slate-700 dark:text-slate-200">
{{ $cluster['lead'] }}
</p>
</div>
<span class="inline-flex items-center rounded-full border border-slate-200/70 bg-slate-50/80 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-slate-500 dark:border-slate-600/60 dark:bg-slate-800/70 dark:text-slate-300">
{{ $cluster['count'] }} {{ __('Teilfelder') }}
</span>
</div>
@if (! empty($cluster['contexts']))
<div class="mt-5 grid gap-3 md:grid-cols-2">
@foreach ($cluster['contexts'] as $context)
<div class="rounded-2xl border border-slate-200/60 bg-slate-50/70 p-4 dark:border-slate-700/60 dark:bg-slate-800/70">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-300">{{ $context['label'] }}</p>
<p class="mt-1 text-sm leading-relaxed text-slate-600 dark:text-slate-200">{{ $context['body'] }}</p>
</div>
@endforeach
</div>
@endif
@if (! empty($cluster['actions']))
<div class="mt-5 rounded-2xl border border-dashed border-slate-300/60 bg-slate-50/70 p-4 text-xs text-slate-600 dark:border-slate-600/60 dark:bg-slate-800/70 dark:text-slate-200">
<p class="font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-200">{{ __('Schlüsselmaßnahmen') }}</p>
<ul class="mt-2 space-y-1 leading-relaxed">
@foreach ($cluster['actions'] as $action)
<li class="flex items-start gap-2">
<span class="mt-1 h-1 w-1 shrink-0 rounded-full bg-slate-400 dark:bg-slate-300"></span>
<span>{{ $action }}</span>
</li>
@endforeach
</ul>
</div>
@endif
</div>
@endforeach
</div>
@endif
@if (! empty($sources))
<div class="mt-6 rounded-2xl border border-slate-200/70 bg-slate-50/80 p-5 dark:border-slate-700/70 dark:bg-slate-800/70">
<h5 class="text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">{{ __('Quellen & Verifizierungsstand (≤ 365 Tage)') }}</h5>
<ul class="mt-3 list-disc space-y-1 pl-4 text-xs text-slate-600 dark:text-slate-300">
@foreach ($sources as $source)
<li>{{ $source }}</li>
@endforeach
</ul>
</div>
@endif
@if (! empty($detailStructure))
<div class="mt-8 rounded-3xl border border-slate-200/70 bg-white/95 p-6 shadow-sm dark:border-slate-700/70 dark:bg-slate-900/90">
<div class="flex items-center justify-between gap-4 border-b border-slate-200/70 pb-4 dark:border-slate-700/60">
<h4 class="text-sm font-semibold uppercase tracking-wide text-slate-600 dark:text-slate-200">
{{ __('Strukturierte Transaktionsanalyse') }}
</h4>
<span class="inline-flex items-center rounded-full border border-indigo-200/70 bg-indigo-500/10 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-indigo-700 dark:border-indigo-500/40 dark:bg-indigo-500/20 dark:text-indigo-100">
{{ __('Detailfelder') }}
</span>
</div>
<div class="mt-6 space-y-4">
@foreach ($detailStructure as $mainCategoryIndex => $mainCategory)
{{-- Ebene 0: Hauptthema (z.B. "Transaktion") --}}
<div
x-data="{ openMain: false }"
class="rounded-2xl border-2 border-indigo-200/70 bg-gradient-to-br from-indigo-50/70 to-slate-50/70 transition dark:border-indigo-700/70 dark:from-indigo-900/20 dark:to-slate-800/70"
>
<button
@click="openMain = !openMain"
type="button"
class="flex w-full items-center justify-between gap-4 p-6 text-left transition hover:bg-indigo-100/50 dark:hover:bg-indigo-900/30"
>
<div class="flex-1 space-y-2">
<div class="flex items-center gap-3">
<span class="inline-flex items-center rounded-full border border-indigo-400/70 bg-indigo-500/20 px-3 py-1 text-xs font-bold uppercase tracking-wide text-indigo-700 dark:border-indigo-500/60 dark:bg-indigo-500/30 dark:text-indigo-200">
{{ __('Hauptthema') }} {{ $mainCategoryIndex + 1 }}
</span>
<h4 class="text-lg font-bold text-slate-900 dark:text-white">
{{ $mainCategory['title'] }}
</h4>
</div>
<p class="text-xs text-slate-500 dark:text-slate-400">
{{ count($mainCategory['sections']) }} {{ __('Sektionen') }}
</p>
</div>
<div class="flex items-center gap-2">
<flux:icon
name="chevron-down"
class="h-6 w-6 text-indigo-600 transition-transform duration-200 dark:text-indigo-400"
::class="{ 'rotate-180': openMain }"
/>
</div>
</button>
<div
x-show="openMain"
x-collapse
class="border-t-2 border-indigo-200/70 dark:border-indigo-700/60"
>
<div class="space-y-3 p-4">
{{-- Ebene 1: Sektionen --}}
@foreach ($mainCategory['sections'] as $sectionIndex => $section)
<div
x-data="{ open: false }"
class="rounded-2xl border border-slate-200/70 bg-white/90 transition dark:border-slate-700/70 dark:bg-slate-800/90"
>
<button
@click="open = !open"
type="button"
class="flex w-full items-center justify-between gap-4 p-5 text-left transition hover:bg-slate-100/70 dark:hover:bg-slate-700/60"
>
<div class="flex-1 space-y-1">
<div class="flex items-center gap-3">
<span class="inline-flex items-center rounded-full border border-slate-300/70 bg-slate-100/60 px-2.5 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-slate-600 dark:border-slate-600/60 dark:bg-slate-800/70 dark:text-slate-200">
{{ __('Sektion') }} {{ $sectionIndex + 1 }}
</span>
<h5 class="text-base font-semibold text-slate-900 dark:text-white">
{{ $section['title'] }}
</h5>
</div>
@if ($section['description'])
<p class="text-sm text-slate-500 dark:text-slate-400">
{{ $section['description'] }}
</p>
@endif
<p class="text-xs text-slate-400 dark:text-slate-500">
{{ count($section['fields']) }} {{ __('Felder') }}
</p>
</div>
<div class="flex items-center gap-2">
<flux:icon
name="chevron-down"
class="h-5 w-5 text-slate-400 transition-transform duration-200 dark:text-slate-500"
::class="{ 'rotate-180': open }"
/>
</div>
</button>
<div
x-show="open"
x-collapse
class="border-t border-slate-200/70 dark:border-slate-700/60"
>
<div class="grid gap-3 p-5 md:grid-cols-2">
@foreach ($section['fields'] as $field)
<div class="rounded-xl border border-slate-200/60 bg-white/80 p-4 shadow-sm dark:border-slate-700/60 dark:bg-slate-900/70">
<div class="flex items-start justify-between gap-3">
<div class="flex-1 space-y-2">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
{{ $field['label'] }}
</p>
<div class="space-y-1">
@php
$fieldValue = data_get($selected, $field['key']);
$answer = null;
$sources = null;
if (is_array($fieldValue) || is_object($fieldValue)) {
$fieldArray = json_decode(json_encode($fieldValue), true);
$answer = $fieldArray['answer'] ?? null;
$sources = $fieldArray['sources'] ?? null;
} else {
$answer = $fieldValue;
}
$hasValue = $answer !== null && $answer !== '' || ($sources !== null && !empty($sources));
@endphp
@if ($hasValue)
@if ($answer)
<div class="rounded-lg bg-slate-50/80 p-3 dark:bg-slate-800/80">
<p class="text-sm font-medium leading-relaxed text-slate-900 dark:text-slate-100" style="white-space: pre-wrap; word-break: break-word;">{{ $answer }}</p>
</div>
@endif
@if ($sources && is_array($sources) && !empty($sources))
<div class="mt-2 space-y-1">
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">{{ __('Quellen') }}:</p>
<div class="flex flex-wrap gap-2">
@foreach ($sources as $source)
<a
href="{{ is_string($source) ? $source : '#' }}"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center gap-1 rounded-md border border-indigo-200/70 bg-indigo-50/80 px-2 py-1 text-xs font-medium text-indigo-700 transition hover:bg-indigo-100/80 dark:border-indigo-500/40 dark:bg-indigo-500/10 dark:text-indigo-200 dark:hover:bg-indigo-500/20"
>
<flux:icon name="link" class="h-3 w-3" />
{{ is_string($source) ? (strlen($source) > 40 ? substr($source, 0, 40) . '...' : $source) : __('Quelle') }}
</a>
@endforeach
</div>
</div>
@endif
@else
<p class="text-sm italic text-slate-400 dark:text-slate-500">
{{ __('Nicht verfügbar') }}
</p>
@endif
<p class="text-xs text-slate-400 dark:text-slate-500">
{{ __('Feld') }}: {{ $field['key'] }}
</p>
</div>
</div>
<span class="inline-flex items-center rounded-md border border-slate-200/70 bg-slate-50/80 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-slate-500 dark:border-slate-600/60 dark:bg-slate-800/70 dark:text-slate-400">
ID {{ $field['prompt_id'] }}
</span>
</div>
</div>
@endforeach
</div>
</div>
</div>
@endforeach
</div>
</div>
</div>
@endforeach
</div>
<div class="mt-6 rounded-2xl border border-dashed border-slate-300/60 bg-slate-50/70 p-4 text-xs text-slate-600 dark:border-slate-600/60 dark:bg-slate-800/70 dark:text-slate-200">
<p class="font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
{{ __('Hinweis zur Datenstruktur') }}
</p>
<p class="mt-2 leading-relaxed">
{{ __('Diese Felder basieren auf der strukturierten Analyse-Konfiguration. Fehlende Werte können durch erweiterte Datenquellen oder manuelle Eingaben ergänzt werden.') }}
</p>
</div>
</div>
@endif
</div>
<div class="space-y-6">
<div class="rounded-3xl border border-zinc-200/70 bg-white/95 p-6 shadow-sm backdrop-blur dark:border-zinc-700/70 dark:bg-zinc-900/90">
<h4 class="text-sm font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">{{ __('Historie mit dieser Gegenpartei') }}</h4>
<div class="mt-4 space-y-3">
@forelse ($counterpartyHistory as $history)
<div class="flex flex-wrap items-center justify-between gap-3 rounded-2xl border border-zinc-100/70 bg-zinc-50/70 p-4 text-sm text-zinc-600 dark:border-zinc-700/70 dark:bg-zinc-800/70 dark:text-zinc-300">
<div>
<p class="font-semibold text-zinc-900 dark:text-zinc-100">{{ $history->executed_at?->format('d.m.Y H:i') }}</p>
<p class="text-xs text-zinc-500 dark:text-zinc-400">{{ $history->channel }} • {{ $history->reference }}</p>
</div>
<div class="flex flex-col items-end gap-1">
<span class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">{{ $formatAmount($history->amount, $history->currency) }}</span>
<span class="inline-flex items-center gap-1 rounded-md bg-slate-100/60 px-2 py-0.5 text-xs font-semibold text-slate-700 dark:bg-slate-800/80 dark:text-slate-200">
{{ __('Risiko') }} {{ $history->risk_score }}
</span>
</div>
</div>
@empty
<div class="rounded-2xl border border-dashed border-zinc-300/60 bg-zinc-50/60 p-4 text-center text-xs text-zinc-500 dark:border-zinc-600/50 dark:bg-zinc-900/60">
{{ __('Keine weiteren Transaktionen mit dieser Gegenpartei gefunden.') }}
</div>
@endforelse
</div>
</div>
</div>
</div>
@else
<div class="rounded-3xl border border-dashed border-zinc-300/70 bg-white/80 p-8 text-center text-sm text-zinc-500 shadow-sm dark:border-zinc-600/50 dark:bg-zinc-900/60 dark:text-zinc-300">
{{ __('Wählen Sie links eine Transaktion aus, um die vollständige Fallansicht zu öffnen.') }}
</div>
@endif
</div>
</div>
</div>