feat: new UI for Fallansicht
This commit is contained in:
@@ -289,6 +289,7 @@ new #[Layout('components.layouts.app')] class extends Component {
|
||||
$counterpartyHistory = $this->counterpartyHistory;
|
||||
$recentAlerts = $this->recentAlerts;
|
||||
$actionChecklist = $this->actionChecklist;
|
||||
$checklistIntro = __('Fokusbereiche für diesen Fall');
|
||||
|
||||
$formatCurrency = static fn (float $value): string => number_format($value, 2, ',', '.') . ' €';
|
||||
$formatAmount = static fn (float $value, string $currency): string => number_format($value, 2, ',', '.') . ' ' . $currency;
|
||||
@@ -353,10 +354,42 @@ new #[Layout('components.layouts.app')] class extends Component {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<div class="grid gap-6 xl:grid-cols-[minmax(0,1.15fr)_minmax(0,1.85fr)]">
|
||||
<div class="space-y-4">
|
||||
@if (! empty($actionChecklist))
|
||||
<section class="rounded-3xl border border-indigo-300/60 bg-gradient-to-br from-white via-indigo-50/60 to-purple-100/50 p-6 shadow-sm backdrop-blur dark:border-indigo-500/40 dark:bg-indigo-950/80 dark:from-indigo-950/70 dark:via-purple-900/60 dark:to-indigo-900/70">
|
||||
<div class="flex flex-wrap items-center justify-between gap-4">
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold uppercase tracking-wide text-indigo-800 dark:text-indigo-100">{{ $checklistIntro }}</h3>
|
||||
<p class="mt-1 text-xs text-indigo-800/80 dark:text-indigo-200/80">
|
||||
{{ __('Bearbeiten Sie die wichtigsten Schritte nacheinander, um den Fallabschluss vorzubereiten.') }}
|
||||
</p>
|
||||
</div>
|
||||
<span class="inline-flex items-center rounded-full border border-indigo-300/60 bg-white/80 px-3 py-1 text-[11px] font-semibold uppercase tracking-wide text-indigo-700 dark:border-indigo-500/40 dark:bg-indigo-500/20 dark:text-indigo-100">
|
||||
{{ count($actionChecklist) }} {{ __('Schritte') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-5 overflow-x-auto">
|
||||
<ol class="flex min-w-full gap-4">
|
||||
@foreach ($actionChecklist as $index => $item)
|
||||
<li class="group flex min-w-[240px] items-start gap-3 rounded-2xl border border-indigo-200/60 bg-white/95 p-4 shadow-sm transition hover:-translate-y-0.5 hover:border-indigo-300/70 hover:shadow-indigo-500/10 dark:border-indigo-500/30 dark:bg-indigo-900/70">
|
||||
<span class="mt-0.5 inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md border border-indigo-300/60 bg-indigo-500/10 text-xs font-semibold text-indigo-700 dark:border-indigo-500/40 dark:bg-indigo-500/25 dark:text-indigo-100">
|
||||
{{ sprintf('%02d', $index + 1) }}
|
||||
</span>
|
||||
<div class="space-y-1">
|
||||
<p class="font-semibold text-indigo-900 transition group-hover:text-indigo-700 dark:text-indigo-100 dark:group-hover:text-indigo-200">{{ $item['title'] }}</p>
|
||||
<p class="text-xs leading-relaxed text-indigo-800/80 dark:text-indigo-100/80">{{ $item['description'] }}</p>
|
||||
</div>
|
||||
</li>
|
||||
@endforeach
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
@endif
|
||||
|
||||
<div class="grid gap-6 xl:grid-cols-[minmax(0,1.15fr)_minmax(0,1.85fr)]">
|
||||
<div class="space-y-4">
|
||||
<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">
|
||||
<div class="flex flex-wrap items-center justify-between gap-4">
|
||||
<div>
|
||||
@@ -481,114 +514,443 @@ new #[Layout('components.layouts.app')] class extends Component {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-5">
|
||||
<div class="space-y-6">
|
||||
@if ($selected)
|
||||
<div class="rounded-3xl border border-slate-200/70 bg-white/95 p-7 shadow-lg shadow-slate-900/5 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="space-y-2">
|
||||
<flux:badge variant="outline">
|
||||
{{ __('Case ID') }} {{ $selected->id }}
|
||||
</flux:badge>
|
||||
<h3 class="text-2xl font-semibold text-slate-900 dark:text-white">
|
||||
{{ $selected->counterparty }} — {{ $formatAmount($selected->amount, $selected->currency) }}
|
||||
</h3>
|
||||
<p class="text-sm text-slate-500 dark:text-slate-300">
|
||||
{{ __('Ausgeführt am') }} {{ $selected->executed_at?->format('d.m.Y, H:i') }} • {{ $selected->channel }}
|
||||
@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 (PO–GR–Invoice) 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));
|
||||
|
||||
$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 border border-slate-200/70 bg-white/95 p-7 shadow-lg shadow-slate-900/5 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="space-y-2">
|
||||
<flux:badge variant="outline">
|
||||
{{ __('Case ID') }} {{ $selected->id }}
|
||||
</flux:badge>
|
||||
<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 (PO–GR–Invoice) 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>
|
||||
|
||||
<div class="flex flex-col items-end gap-2">
|
||||
@php($badgeStyle = $statusStyles[$selected->status] ?? 'bg-zinc-500/10 text-zinc-600 border border-zinc-500/20')
|
||||
<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 }}
|
||||
</span>
|
||||
</div>
|
||||
</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>
|
||||
|
||||
<div class="mt-6 grid gap-4 sm:grid-cols-2">
|
||||
<div class="rounded-2xl bg-slate-50/80 p-4 dark:bg-slate-800/70">
|
||||
<p class="text-xs uppercase tracking-wide text-slate-400">{{ __('Gegenpartei') }}</p>
|
||||
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $selected->counterparty }}</p>
|
||||
<p class="text-xs text-slate-500 dark:text-slate-300">{{ $selected->counterparty_country }}</p>
|
||||
</div>
|
||||
<div class="rounded-2xl bg-slate-50/80 p-4 dark:bg-slate-800/70">
|
||||
<p class="text-xs uppercase tracking-wide text-slate-400">{{ __('Referenz') }}</p>
|
||||
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $selected->reference }}</p>
|
||||
<p class="text-xs text-slate-500 dark:text-slate-300">{{ $selected->flagged_by }}</p>
|
||||
</div>
|
||||
<div class="rounded-2xl bg-slate-50/80 p-4 dark:bg-slate-800/70">
|
||||
<p class="text-xs uppercase tracking-wide text-slate-400">{{ __('Flagging-Grund') }}</p>
|
||||
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $selected->flagged_reason }}</p>
|
||||
</div>
|
||||
<div class="rounded-2xl bg-slate-50/80 p-4 dark:bg-slate-800/70">
|
||||
<p class="text-xs uppercase tracking-wide text-slate-400">{{ __('Empfohlene Maßnahme') }}</p>
|
||||
<p class="mt-1 text-sm font-medium text-slate-900 dark:text-slate-100">{{ $statusCopy[$selected->status] ?? __('Review abschließen und Audit-Trail ergänzen.') }}</p>
|
||||
</div>
|
||||
</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($selected->signals))
|
||||
<div class="mt-6">
|
||||
<h4 class="text-xs font-semibold uppercase tracking-wide text-slate-400">{{ __('Detektionssignale') }}</h4>
|
||||
<div class="mt-2 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/60 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>
|
||||
@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>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
<div class="mt-6 rounded-2xl border border-indigo-200/60 bg-indigo-500/10 p-4 text-sm text-indigo-900 dark:border-indigo-500/30 dark:bg-indigo-500/10 dark:text-indigo-100">
|
||||
<p class="font-medium">{{ __('Fallleitlinie') }}</p>
|
||||
<p class="mt-1 leading-relaxed">
|
||||
{{ __('Führen Sie eine ganzheitliche Bewertung durch: prüfen Sie Geschäftsbeziehung, Transaktionshistorie und Monitoring-Regeln. Stellen Sie sicher, dass alle Entscheidungswege und Maßnahmen dokumentiert und für Audits nachvollziehbar sind.') }}
|
||||
</p>
|
||||
@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
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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">{{ __('Aktions-Checkliste') }}</h4>
|
||||
<ol class="mt-4 space-y-3 text-sm text-zinc-600 dark:text-zinc-300">
|
||||
@foreach ($actionChecklist as $index => $item)
|
||||
<li class="flex gap-3 rounded-2xl border border-zinc-100/70 bg-zinc-50/70 p-4 dark:border-zinc-700/70 dark:bg-zinc-800/70">
|
||||
<span class="mt-1 inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-indigo-500/10 font-semibold text-indigo-600 dark:bg-indigo-500/20 dark:text-indigo-200">
|
||||
{{ $index + 1 }}
|
||||
</span>
|
||||
<div>
|
||||
<p class="font-semibold text-zinc-900 dark:text-zinc-100">{{ $item['title'] }}</p>
|
||||
<p class="text-xs text-zinc-500 dark:text-zinc-400">{{ $item['description'] }}</p>
|
||||
</div>
|
||||
</li>
|
||||
@endforeach
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<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 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>
|
||||
@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>
|
||||
@else
|
||||
|
||||
Reference in New Issue
Block a user