2025-10-24 07:11:28 +02:00
<? 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 ;
2025-10-31 13:55:05 +01:00
use Livewire\Attributes\Title ;
2025-10-24 07:11:28 +02:00
use Livewire\Volt\Component ;
use Livewire\WithPagination ;
2025-11-20 11:08:23 +01:00
new #[ Layout ( 'components.layouts.app' ), Title ( 'Unternehmensauskunft Transaktionen' )] class extends Component
{
2025-10-24 07:11:28 +02:00
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 ()
2025-11-20 11:08:23 +01:00
-> mapWithKeys ( fn ( $row ) => [
2025-10-24 07:11:28 +02:00
$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 ;
}
2025-11-20 11:08:23 +01:00
#[ 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' ,
],
],
],
],
],
2025-11-20 12:16:00 +01:00
[
'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' ],
],
],
],
],
2025-11-20 11:08:23 +01:00
];
}
2025-10-24 07:11:28 +02:00
protected function filteredQuery () : Builder
{
return $this -> baseQuery ()
2025-11-20 11:08:23 +01:00
-> when ( $this -> status !== 'all' , fn ( Builder $query ) => $query -> where ( 'status' , $this -> status ))
-> when ( $this -> channel !== 'all' , fn ( Builder $query ) => $query -> where ( 'channel' , $this -> channel ));
2025-10-24 07:11:28 +02:00
}
protected function baseQuery () : Builder
{
return Transaction :: query () -> where ( 'company_id' , $this -> company -> id );
}
};
?>
@php
2025-11-07 13:52:36 +01:00
/** @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');
2025-11-20 11:08:23 +01:00
$detailStructure = $this->transactionDetailStructure;
2025-10-24 07:11:28 +02:00
2025-11-07 13:52:36 +01:00
$formatCurrency = static fn (float $value): string => number_format($value, 2, ',', '.') . ' €';
2025-11-10 14:08:26 +01:00
$formatCurrencyCompact = static function (float $value): string {
if ($value >= 1000000) {
return number_format($value / 1000000, 0, ',', '.') . ' Mio. €';
}
return number_format($value, 2, ',', '.') . ' €';
};
2025-11-07 13:52:36 +01:00
$formatAmount = static fn (float $value, string $currency): string => number_format($value, 2, ',', '.') . ' ' . $currency;
2025-10-24 07:11:28 +02:00
2025-11-07 13:52:36 +01:00
$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)]',
];
2025-10-24 07:11:28 +02:00
2025-11-07 13:52:36 +01:00
$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.'),
];
2025-10-24 07:11:28 +02:00
@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>
2025-11-10 14:08:26 +01:00
<p class="text-xs text-slate-500 dark:text-slate-300">{{ __('Volumen') }} {{ $formatCurrencyCompact($metrics['total_volume']) }}</p>
2025-10-24 07:11:28 +02:00
</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>
2025-11-10 14:08:26 +01:00
<p class="text-xs text-emerald-700 dark:text-emerald-100">{{ __('Volumen') }} {{ $formatCurrencyCompact($metrics['open_alerts']['amount']) }}</p>
2025-10-24 07:11:28 +02:00
</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>
2025-11-07 13:52:36 +01:00
</section>
2025-10-24 07:11:28 +02:00
2025-11-10 11:25:18 +01:00
<div class="space-y-6">
2025-10-24 07:11:28 +02:00
@if ($selected)
2025-11-07 13:52:36 +01:00
@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 = [];
2025-10-31 13:33:59 +01:00
2025-11-07 13:52:36 +01:00
foreach ($sections as $section) {
$notes = array_merge($notes, $section['notes'] ?? []);
}
2025-10-31 13:33:59 +01:00
2025-11-07 13:52:36 +01:00
return $notes;
};
2025-10-31 13:33:59 +01:00
2025-11-07 13:52:36 +01:00
$clusterFactory = static function (string $title, array $sections) use ($combineNotes): array {
$leadSection = $sections[0] ?? null;
$contexts = array_slice($sections, 1);
2025-10-31 13:33:59 +01:00
2025-11-07 13:52:36 +01:00
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),
];
};
2025-10-31 13:33:59 +01:00
2025-11-07 13:52:36 +01:00
$transactionSections = array_slice($analysisSections, 0, 2);
$riskSections = array_slice($analysisSections, 2, 6);
$dueSections = array_slice($analysisSections, 8);
2025-10-31 13:33:59 +01:00
2025-11-07 13:52:36 +01:00
$analysisClusters = [
$clusterFactory(__('Transaktion & Zweck'), $transactionSections),
$clusterFactory(__('Risikoperspektive'), $riskSections),
$clusterFactory(__('Due Diligence & Abschluss'), $dueSections),
];
2025-10-31 13:33:59 +01:00
2025-11-07 13:52:36 +01:00
$analysisClusterCount = array_sum(array_map(static fn (array $cluster): int => $cluster['count'], $analysisClusters));
2025-10-31 13:33:59 +01:00
2025-11-07 13:52:36 +01:00
$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';
2025-10-31 14:01:38 +01:00
2025-11-07 13:52:36 +01:00
$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
2025-10-31 13:33:59 +01:00
2025-11-07 13:52:36 +01:00
<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,
2025-10-31 14:01:38 +01:00
])>
2025-11-07 13:52:36 +01:00
<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>
2025-10-31 13:33:59 +01:00
</div>
2025-11-07 13:52:36 +01:00
<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>
2025-10-31 13:33:59 +01:00
</div>
2025-11-07 13:52:36 +01:00
</div>
2025-10-31 13:33:59 +01:00
2025-11-07 13:52:36 +01:00
<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>
2025-10-31 13:33:59 +01:00
</div>
2025-11-07 13:52:36 +01:00
<div class="flex justify-between gap-3">
<dt>{{ __('Sitz') }}</dt>
<dd class="text-right">{{ $company->headquarters ?? __('Nicht verifiziert') }}</dd>
2025-10-31 13:33:59 +01:00
</div>
2025-11-07 13:52:36 +01:00
<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>
2025-10-31 13:33:59 +01:00
</div>
2025-11-07 13:52:36 +01:00
<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>
2025-10-31 13:33:59 +01:00
</div>
</div>
2025-11-07 13:52:36 +01:00
</div>
2025-10-31 13:33:59 +01:00
2025-11-07 13:52:36 +01:00
<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>
2025-10-31 13:33:59 +01:00
</div>
2025-11-07 13:52:36 +01:00
<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>
2025-10-31 13:33:59 +01:00
<p class="mt-2 leading-relaxed">
2025-11-07 13:52:36 +01:00
{{ __('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.', [
2025-10-31 13:33:59 +01:00
'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'),
]) }}
2025-11-07 13:52:36 +01:00
</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.') }}
2025-10-24 07:11:28 +02:00
</p>
</div>
2025-11-07 13:52:36 +01:00
@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'] }}
2025-10-31 13:33:59 +01:00
</p>
</div>
2025-11-07 13:52:36 +01:00
<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>
2025-10-24 07:11:28 +02:00
2025-11-07 13:52:36 +01:00
@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>
2025-10-24 07:11:28 +02:00
@endforeach
</div>
2025-11-07 13:52:36 +01:00
@endif
2025-10-24 07:11:28 +02:00
2025-11-07 13:52:36 +01:00
@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>
2025-10-31 13:33:59 +01:00
@endforeach
</ul>
</div>
2025-11-07 13:52:36 +01:00
@endif
</div>
@endforeach
2025-10-24 07:11:28 +02:00
</div>
2025-11-07 13:52:36 +01:00
@endif
2025-10-24 07:11:28 +02:00
2025-11-07 13:52:36 +01:00
@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
2025-11-20 11:08:23 +01:00
@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
2025-11-07 13:52:36 +01:00
</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>
2025-10-24 07:11:28 +02:00
</div>
2025-11-07 13:52:36 +01:00
@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
2025-10-31 13:33:59 +01:00
</div>
2025-10-24 07:11:28 +02:00
</div>
</div>
2025-11-07 13:52:36 +01:00
</div>
2025-10-24 07:11:28 +02:00
@else
2025-11-07 13:52:36 +01:00
<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>
2025-10-24 07:11:28 +02:00
@endif
</div>
</div>
2025-11-07 13:52:36 +01:00
</div>