Files
mkd/components/legal/ComplianceCheck.tsx
2026-02-04 00:17:04 +05:00

852 lines
48 KiB
TypeScript
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState } from 'react';
// FIX: Added missing ChevronRight import
import { Search, ShieldCheck, AlertTriangle, Info, ShieldAlert, CheckCircle2, History, ChevronRight, Loader2, X, FileText, Phone, Mail } from 'lucide-react';
import { authFetch } from '../../services/apiClient';
interface LicenseItem {
number?: string;
series?: string;
validFrom?: number;
validTo?: number;
activities?: string[];
issueAuthority?: string;
}
interface CounterpartyCheckResult {
inn: string;
kpp?: string;
ogrn?: string;
name: string;
shortName?: string;
type: string;
status: string;
registrationDate?: string;
liquidationDate?: string;
address?: string;
okved?: string;
okveds?: any[];
management?: {
name: string;
post?: string;
};
finance?: {
taxSystem?: string;
income?: number;
revenue?: number;
expense?: number;
debt?: number;
penalty?: number;
year?: number;
};
authorities?: any;
phones?: any[];
emails?: any[];
employeeCount?: number;
capital?: { type?: string; value?: number };
smb?: { category?: string; issueDate?: number };
licenses?: LicenseItem[];
addressInvalidity?: any;
foundersInvalidity?: Array<{ name?: string; invalidity?: any }>;
managersInvalidity?: Array<{ name?: string; post?: string; invalidity?: any }>;
managementDisqualified?: boolean;
riskLevel: 'low' | 'medium' | 'high';
riskReasons: string[];
checkedDate: string;
rawData?: any;
}
export const ComplianceCheck: React.FC = () => {
const [inn, setInn] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [checkResult, setCheckResult] = useState<CounterpartyCheckResult | null>(null);
const [checkedCounterparties, setCheckedCounterparties] = useState<any[]>([]);
const [loadingHistory, setLoadingHistory] = useState(true);
const [selectedReport, setSelectedReport] = useState<any | null>(null);
const [showReportModal, setShowReportModal] = useState(false);
// Загружаем историю проверок при монтировании компонента
React.useEffect(() => {
loadHistory();
}, []);
const loadHistory = async () => {
try {
setLoadingHistory(true);
const response = await authFetch('/api/legal/counterparties');
if (response.ok) {
const data = await response.json();
setCheckedCounterparties(data);
}
} catch (error) {
console.error('Error loading history:', error);
} finally {
setLoadingHistory(false);
}
};
const handleCheck = async () => {
if (!inn.trim()) {
setError('Введите ИНН организации');
return;
}
setLoading(true);
setError(null);
setCheckResult(null);
try {
const response = await authFetch('/api/legal/check-counterparty', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ inn: inn.trim() })
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Ошибка при проверке контрагента');
}
const result = await response.json();
setCheckResult(result);
// Обновляем историю проверок
await loadHistory();
} catch (err) {
console.error('Error checking counterparty:', err);
setError(err instanceof Error ? err.message : 'Ошибка при проверке контрагента');
} finally {
setLoading(false);
}
};
const handleKeyPress = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
handleCheck();
}
};
return (
<div className="space-y-6 animate-fade-in">
{/* Search Tool */}
<div className="bg-slate-900 rounded-[2.5rem] p-8 text-white shadow-xl relative overflow-hidden">
<ShieldCheck className="absolute -bottom-4 -right-4 w-48 h-48 opacity-10 rotate-12" />
<div className="relative z-10 max-w-lg">
<h3 className="text-2xl font-black mb-2">Проверка контрагента</h3>
<p className="text-xs text-slate-400 font-medium mb-6">Автоматическая сверка по базам ФНС через DaData API.</p>
<div className="flex gap-2">
<input
type="text"
placeholder="Введите ИНН организации (10 или 12 цифр)..."
value={inn}
onChange={(e) => {
setInn(e.target.value.replace(/\D/g, ''));
setError(null);
}}
onKeyPress={handleKeyPress}
className="flex-1 px-5 py-3 bg-white/10 border border-white/20 rounded-2xl text-sm outline-none focus:ring-2 focus:ring-primary-500 transition-all placeholder:text-slate-500"
maxLength={12}
/>
<button
onClick={handleCheck}
disabled={loading || !inn.trim()}
className="bg-white text-slate-900 px-6 py-3 rounded-2xl font-black text-xs uppercase tracking-widest hover:bg-slate-100 transition-all active:scale-95 shadow-lg disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2"
>
{loading ? (
<>
<Loader2 className="w-4 h-4 animate-spin" />
Проверка...
</>
) : (
'Проверить'
)}
</button>
</div>
{error && (
<div className="mt-4 p-3 bg-red-500/20 border border-red-500/50 rounded-xl text-red-200 text-sm">
{error}
</div>
)}
</div>
</div>
{/* Check Result */}
{checkResult && (
<div className="bg-white rounded-[2rem] border border-slate-200 shadow-lg p-6">
<div className="flex justify-between items-start mb-4">
<div className="flex items-center gap-4">
<div className={`p-4 rounded-2xl ${
checkResult.riskLevel === 'high' ? 'bg-red-50 text-red-600' :
checkResult.riskLevel === 'medium' ? 'bg-amber-50 text-amber-600' :
'bg-emerald-50 text-emerald-600'
}`}>
{checkResult.riskLevel === 'high' ? <ShieldAlert className="w-7 h-7" /> :
checkResult.riskLevel === 'medium' ? <AlertTriangle className="w-7 h-7" /> :
<CheckCircle2 className="w-7 h-7" />}
</div>
<div>
<h4 className="font-black text-slate-800 text-lg leading-tight">{checkResult.name}</h4>
<p className="text-xs text-slate-500 mt-1">
ИНН: {checkResult.inn}
{checkResult.kpp && ` • КПП: ${checkResult.kpp}`}
{checkResult.ogrn && ` • ОГРН: ${checkResult.ogrn}`}
</p>
</div>
</div>
<button
onClick={() => setCheckResult(null)}
className="p-2 text-slate-400 hover:text-slate-600"
>
<X className="w-5 h-5" />
</button>
</div>
<div className="space-y-4">
{/* Risk Level */}
<div className={`p-4 rounded-xl border-2 ${
checkResult.riskLevel === 'high' ? 'bg-red-50 border-red-200' :
checkResult.riskLevel === 'medium' ? 'bg-amber-50 border-amber-200' :
'bg-emerald-50 border-emerald-200'
}`}>
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-black text-slate-800">Уровень риска:</span>
<span className={`text-sm font-black uppercase ${
checkResult.riskLevel === 'high' ? 'text-red-600' :
checkResult.riskLevel === 'medium' ? 'text-amber-600' :
'text-emerald-600'
}`}>
{checkResult.riskLevel === 'high' ? 'Высокий риск' :
checkResult.riskLevel === 'medium' ? 'Средний риск' :
'Благонадежен'}
</span>
</div>
{checkResult.riskReasons.length > 0 && (
<ul className="text-xs text-slate-700 mt-2 space-y-1">
{checkResult.riskReasons.map((reason, idx) => (
<li key={idx} className="flex items-start gap-2">
<span className="text-red-500 mt-0.5"></span>
<span>{reason}</span>
</li>
))}
</ul>
)}
</div>
{/* Status */}
<div className="grid grid-cols-2 gap-4">
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Статус</p>
<p className="text-sm font-bold text-slate-800">
{checkResult.status === 'ACTIVE' ? 'Действующая' :
checkResult.status === 'LIQUIDATED' ? 'Ликвидирована' :
checkResult.status === 'LIQUIDATING' ? 'Ликвидируется' :
checkResult.status === 'BANKRUPT' ? 'Банкрот' :
checkResult.status === 'REORGANIZING' ? 'Реорганизуется' :
checkResult.status}
</p>
</div>
{checkResult.registrationDate && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Дата регистрации</p>
<p className="text-sm font-bold text-slate-800">
{new Date(checkResult.registrationDate).toLocaleDateString('ru-RU')}
</p>
</div>
)}
</div>
{/* Address */}
{checkResult.address && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Адрес</p>
<p className="text-sm text-slate-700">{checkResult.address}</p>
</div>
)}
{/* Finance */}
{checkResult.finance && (
<div className="bg-slate-50 rounded-xl p-4">
<p className="text-xs font-black text-slate-500 uppercase mb-3">Финансовые показатели</p>
<div className="grid grid-cols-2 gap-4 text-sm">
{checkResult.finance.revenue && (
<div>
<p className="text-slate-500">Выручка ({checkResult.finance.year})</p>
<p className="font-bold text-slate-800">
{checkResult.finance.revenue.toLocaleString('ru-RU')}
</p>
</div>
)}
{checkResult.finance.income && (
<div>
<p className="text-slate-500">Доходы ({checkResult.finance.year})</p>
<p className="font-bold text-slate-800">
{checkResult.finance.income.toLocaleString('ru-RU')}
</p>
</div>
)}
{checkResult.finance.debt && checkResult.finance.debt > 0 && (
<div>
<p className="text-red-600">Недоимки</p>
<p className="font-bold text-red-600">
{checkResult.finance.debt.toLocaleString('ru-RU')}
</p>
</div>
)}
{checkResult.finance.penalty && checkResult.finance.penalty > 0 && (
<div>
<p className="text-red-600">Штрафы</p>
<p className="font-bold text-red-600">
{checkResult.finance.penalty.toLocaleString('ru-RU')}
</p>
</div>
)}
</div>
</div>
)}
{/* Management */}
{checkResult.management && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Руководитель</p>
<p className="text-sm text-slate-700">
{checkResult.management.name}
{checkResult.management.post && `${checkResult.management.post}`}
</p>
</div>
)}
{/* OKVED */}
{checkResult.okved && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Основной ОКВЭД</p>
<p className="text-sm text-slate-700">
{checkResult.okved} {checkResult.okveds?.find(o => o.main)?.name || ''}
</p>
</div>
)}
{/* Capital */}
{checkResult.capital != null && checkResult.capital.value != null && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Уставный капитал</p>
<p className="text-sm font-bold text-slate-800">
{checkResult.capital.value.toLocaleString('ru-RU')}
{checkResult.capital.type && <span className="text-slate-500 font-normal ml-1">({checkResult.capital.type})</span>}
</p>
</div>
)}
{/* SMB */}
{checkResult.smb?.category && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Категория МСП</p>
<p className="text-sm text-slate-700">
{checkResult.smb.category === 'MICRO' ? 'Микропредприятие' :
checkResult.smb.category === 'SMALL' ? 'Малое' :
checkResult.smb.category === 'MEDIUM' ? 'Среднее' : checkResult.smb.category}
{checkResult.smb.issueDate && (
<span className="text-slate-500 text-xs ml-1">
(реестр с {new Date(checkResult.smb.issueDate).toLocaleDateString('ru-RU')})
</span>
)}
</p>
</div>
)}
{/* Licenses */}
{checkResult.licenses && checkResult.licenses.length > 0 && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Лицензии</p>
<ul className="text-sm text-slate-700 space-y-1">
{checkResult.licenses.map((lic, idx) => {
const validTo = lic.validTo ? new Date(lic.validTo).getTime() : null;
const expired = validTo != null && validTo < Date.now();
return (
<li key={idx} className={expired ? 'text-amber-600' : ''}>
{lic.number && <span className="font-medium">{lic.number}</span>}
{lic.validTo && (
<span className="ml-1">
{expired ? 'истекла' : 'до'} {new Date(lic.validTo).toLocaleDateString('ru-RU')}
</span>
)}
{lic.activities?.length ? `${lic.activities.join(', ')}` : ''}
</li>
);
})}
</ul>
</div>
)}
{/* Management disqualified */}
{checkResult.managementDisqualified && (
<div className="p-3 bg-red-50 border border-red-200 rounded-xl">
<p className="text-xs font-black text-red-600 uppercase mb-1">Руководитель дисквалифицирован</p>
<p className="text-sm text-red-700">Директор не имеет права заключать сделки</p>
</div>
)}
{/* Invalidity details */}
{(checkResult.addressInvalidity || (checkResult.foundersInvalidity && checkResult.foundersInvalidity.length > 0) || (checkResult.managersInvalidity && checkResult.managersInvalidity.length > 0)) && (
<div className="p-3 bg-amber-50 border border-amber-200 rounded-xl">
<p className="text-xs font-black text-amber-700 uppercase mb-1">Недостоверные сведения</p>
<ul className="text-xs text-amber-800 space-y-0.5">
{checkResult.addressInvalidity && <li> Адрес признан недостоверным (ФНС)</li>}
{checkResult.foundersInvalidity?.length ? <li> Сведения об учредителях недостоверны</li> : null}
{checkResult.managersInvalidity?.length ? <li> Сведения о руководителе недостоверны</li> : null}
</ul>
</div>
)}
</div>
</div>
)}
{/* Check History */}
<div className="space-y-4">
<div className="flex justify-between items-center px-1">
<h3 className="font-black text-slate-500 text-[10px] uppercase tracking-[0.2em]">История проверок</h3>
<button
onClick={loadHistory}
className="text-[10px] font-black text-primary-600 uppercase hover:underline"
>
Обновить
</button>
</div>
{loadingHistory ? (
<div className="flex items-center justify-center py-8">
<Loader2 className="w-5 h-5 animate-spin text-slate-400" />
</div>
) : checkedCounterparties.length === 0 ? (
<div className="bg-white p-8 rounded-xl border border-slate-200 text-center">
<p className="text-slate-400">История проверок пуста</p>
<p className="text-xs text-slate-500 mt-2">Проверьте контрагента, чтобы добавить запись в историю</p>
</div>
) : (
checkedCounterparties.map(cp => {
const isHighRisk = cp.riskLevel === 'high';
const isMediumRisk = cp.riskLevel === 'medium';
return (
<div key={cp.id} className="bg-white p-5 rounded-[2rem] border border-slate-200 shadow-sm flex flex-col md:flex-row justify-between gap-6 hover:shadow-md transition-all group">
<div className="flex items-center gap-4">
<div className={`p-4 rounded-2xl ${isHighRisk ? 'bg-red-50 text-red-600' : isMediumRisk ? 'bg-amber-50 text-amber-600' : 'bg-emerald-50 text-emerald-600'}`}>
{isHighRisk ? <ShieldAlert className="w-7 h-7" /> : isMediumRisk ? <AlertTriangle className="w-7 h-7" /> : <CheckCircle2 className="w-7 h-7" />}
</div>
<div>
<h4 className="font-black text-slate-800 text-base leading-tight">{cp.name}</h4>
<p className="text-[10px] text-slate-400 font-bold uppercase mt-1">
ИНН: {cp.inn} Проверен: {cp.checkedDate ? new Date(cp.checkedDate).toLocaleDateString('ru-RU') : 'Не указано'}
</p>
</div>
</div>
<div className="flex items-center justify-between md:justify-end gap-6 border-t md:border-t-0 border-slate-100 pt-4 md:pt-0">
<div className="text-right">
<p className={`text-[10px] font-black uppercase tracking-widest ${isHighRisk ? 'text-red-500' : isMediumRisk ? 'text-amber-500' : 'text-emerald-500'}`}>
{isHighRisk ? 'Высокий риск' : isMediumRisk ? 'Средний риск' : 'Благонадежен'}
</p>
<button
onClick={async () => {
try {
const response = await authFetch(`/api/legal/counterparties/${cp.id}`);
if (response.ok) {
const report = await response.json();
setSelectedReport(report);
setShowReportModal(true);
}
} catch (error) {
console.error('Error loading report:', error);
}
}}
className="text-[10px] font-black text-primary-600 uppercase mt-1 hover:underline"
>
Подробный отчет
</button>
</div>
<div className="w-10 h-10 rounded-full bg-slate-50 flex items-center justify-center text-slate-300 group-hover:text-primary-500 transition-colors cursor-pointer"
onClick={async () => {
try {
const response = await authFetch(`/api/legal/counterparties/${cp.id}`);
if (response.ok) {
const report = await response.json();
setSelectedReport(report);
setShowReportModal(true);
}
} catch (error) {
console.error('Error loading report:', error);
}
}}
>
<ChevronRight className="w-6 h-6"/>
</div>
</div>
</div>
);
}))}
</div>
<div className="flex items-center gap-3 p-4 bg-blue-50 rounded-2xl border border-blue-100">
<Info className="w-5 h-5 text-blue-500 flex-shrink-0" />
<p className="text-[11px] text-blue-700 leading-snug font-medium">
Система автоматически блокирует создание договоров с контрагентами, имеющими статус «Высокий риск» до ручного подтверждения Директором.
</p>
</div>
{/* Report Modal */}
{showReportModal && selectedReport && (
<ReportModal
report={selectedReport}
onClose={() => {
setShowReportModal(false);
setSelectedReport(null);
}}
/>
)}
</div>
);
};
// Report Modal Component
interface ReportModalProps {
report: any;
onClose: () => void;
}
const ReportModal: React.FC<ReportModalProps> = ({ report, onClose }) => {
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4 overflow-y-auto">
<div className="bg-white rounded-2xl p-6 max-w-4xl w-full max-h-[90vh] overflow-y-auto">
<div className="flex justify-between items-center mb-6">
<h3 className="text-xl font-black text-slate-800">Детальный отчет о проверке</h3>
<button onClick={onClose} className="p-2 text-slate-400 hover:text-slate-600">
<X className="w-5 h-5" />
</button>
</div>
<div className="space-y-6">
{/* Header Info */}
<div className="bg-slate-50 rounded-xl p-4">
<h4 className="text-lg font-black text-slate-800 mb-2">{report.name}</h4>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4 text-sm">
<div>
<p className="text-slate-500 text-xs">ИНН</p>
<p className="font-bold text-slate-800">{report.inn}</p>
</div>
{report.kpp && (
<div>
<p className="text-slate-500 text-xs">КПП</p>
<p className="font-bold text-slate-800">{report.kpp}</p>
</div>
)}
{report.ogrn && (
<div>
<p className="text-slate-500 text-xs">ОГРН</p>
<p className="font-bold text-slate-800">{report.ogrn}</p>
</div>
)}
<div>
<p className="text-slate-500 text-xs">Дата проверки</p>
<p className="font-bold text-slate-800">
{new Date(report.checkedDate).toLocaleString('ru-RU')}
</p>
</div>
</div>
</div>
{/* Risk Level */}
<div className={`p-4 rounded-xl border-2 ${
report.riskLevel === 'high' ? 'bg-red-50 border-red-200' :
report.riskLevel === 'medium' ? 'bg-amber-50 border-amber-200' :
'bg-emerald-50 border-emerald-200'
}`}>
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-black text-slate-800">Уровень риска:</span>
<span className={`text-sm font-black uppercase ${
report.riskLevel === 'high' ? 'text-red-600' :
report.riskLevel === 'medium' ? 'text-amber-600' :
'text-emerald-600'
}`}>
{report.riskLevel === 'high' ? 'Высокий риск' :
report.riskLevel === 'medium' ? 'Средний риск' :
'Благонадежен'}
</span>
</div>
{report.riskReasons && report.riskReasons.length > 0 && (
<ul className="text-xs text-slate-700 mt-2 space-y-1">
{report.riskReasons.map((reason: string, idx: number) => (
<li key={idx} className="flex items-start gap-2">
<span className="text-red-500 mt-0.5"></span>
<span>{reason}</span>
</li>
))}
</ul>
)}
</div>
{/* Status and Dates */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Статус</p>
<p className="text-sm font-bold text-slate-800">
{report.status === 'ACTIVE' ? 'Действующая' :
report.status === 'LIQUIDATED' ? 'Ликвидирована' :
report.status === 'LIQUIDATING' ? 'Ликвидируется' :
report.status === 'BANKRUPT' ? 'Банкрот' :
report.status === 'REORGANIZING' ? 'Реорганизуется' :
report.status}
</p>
</div>
{report.registrationDate && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Дата регистрации</p>
<p className="text-sm font-bold text-slate-800">
{new Date(report.registrationDate).toLocaleDateString('ru-RU')}
</p>
</div>
)}
{report.liquidationDate && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Дата ликвидации</p>
<p className="text-sm font-bold text-red-600">
{new Date(report.liquidationDate).toLocaleDateString('ru-RU')}
</p>
</div>
)}
</div>
{/* Address */}
{report.address && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Адрес</p>
<p className="text-sm text-slate-700">{report.address}</p>
</div>
)}
{/* Management */}
{report.managementName && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Руководитель</p>
<p className="text-sm text-slate-700">
{report.managementName}
{report.managementPost && `${report.managementPost}`}
</p>
</div>
)}
{/* OKVED */}
{report.okved && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Основной ОКВЭД</p>
<p className="text-sm text-slate-700">
{report.okved} {report.okveds?.find((o: any) => o.main)?.name || ''}
</p>
</div>
)}
{/* Finance */}
{report.finance && (
<div className="bg-slate-50 rounded-xl p-4">
<p className="text-xs font-black text-slate-500 uppercase mb-3">Финансовые показатели</p>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 text-sm">
{report.finance.revenue !== undefined && report.finance.revenue !== null && (
<div>
<p className="text-slate-500">Выручка ({report.finance.year})</p>
<p className="font-bold text-slate-800">
{report.finance.revenue.toLocaleString('ru-RU')}
</p>
</div>
)}
{report.finance.income !== undefined && report.finance.income !== null && (
<div>
<p className="text-slate-500">Доходы ({report.finance.year})</p>
<p className="font-bold text-slate-800">
{report.finance.income.toLocaleString('ru-RU')}
</p>
</div>
)}
{report.finance.expense !== undefined && report.finance.expense !== null && (
<div>
<p className="text-slate-500">Расходы ({report.finance.year})</p>
<p className="font-bold text-slate-800">
{report.finance.expense.toLocaleString('ru-RU')}
</p>
</div>
)}
{report.finance.debt !== undefined && report.finance.debt !== null && report.finance.debt > 0 && (
<div>
<p className="text-red-600">Недоимки</p>
<p className="font-bold text-red-600">
{report.finance.debt.toLocaleString('ru-RU')}
</p>
</div>
)}
{report.finance.penalty !== undefined && report.finance.penalty !== null && report.finance.penalty > 0 && (
<div>
<p className="text-red-600">Штрафы</p>
<p className="font-bold text-red-600">
{report.finance.penalty.toLocaleString('ru-RU')}
</p>
</div>
)}
{report.finance.taxSystem && (
<div>
<p className="text-slate-500">Система налогообложения</p>
<p className="font-bold text-slate-800">{report.finance.taxSystem}</p>
</div>
)}
</div>
</div>
)}
{/* Authorities */}
{report.authorities && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-2">Государственные органы</p>
<div className="space-y-2 text-sm">
{report.authorities.ftsRegistration && (
<div className="bg-slate-50 rounded-lg p-3">
<p className="font-bold text-slate-800">ИФНС регистрации</p>
<p className="text-slate-600">{report.authorities.ftsRegistration.name}</p>
{report.authorities.ftsRegistration.address && (
<p className="text-xs text-slate-500 mt-1">{report.authorities.ftsRegistration.address}</p>
)}
</div>
)}
{report.authorities.ftsReport && (
<div className="bg-slate-50 rounded-lg p-3">
<p className="font-bold text-slate-800">ИФНС отчётности</p>
<p className="text-slate-600">{report.authorities.ftsReport.name}</p>
</div>
)}
</div>
</div>
)}
{/* Phones and Emails */}
{(report.phones?.length > 0 || report.emails?.length > 0) && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-2">Контакты</p>
<div className="space-y-2 text-sm">
{report.phones?.map((phone: any, idx: number) => (
<div key={idx} className="flex items-center gap-2">
<Phone className="w-4 h-4 text-slate-400" />
<span className="text-slate-700">{phone.value || phone}</span>
</div>
))}
{report.emails?.map((email: any, idx: number) => (
<div key={idx} className="flex items-center gap-2">
<Mail className="w-4 h-4 text-slate-400" />
<span className="text-slate-700">{email.value || email}</span>
</div>
))}
</div>
</div>
)}
{/* Employee Count */}
{report.employeeCount && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Среднесписочная численность</p>
<p className="text-sm font-bold text-slate-800">{report.employeeCount} человек</p>
</div>
)}
{/* Capital */}
{report.capital != null && report.capital.value != null && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Уставный капитал</p>
<p className="text-sm font-bold text-slate-800">
{report.capital.value.toLocaleString('ru-RU')}
{report.capital.type && <span className="text-slate-500 font-normal ml-1">({report.capital.type})</span>}
</p>
</div>
)}
{/* SMB */}
{report.smb?.category && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Категория МСП</p>
<p className="text-sm text-slate-700">
{report.smb.category === 'MICRO' ? 'Микропредприятие' :
report.smb.category === 'SMALL' ? 'Малое' :
report.smb.category === 'MEDIUM' ? 'Среднее' : report.smb.category}
{report.smb.issueDate && (
<span className="text-slate-500 text-xs ml-1">
(реестр с {new Date(report.smb.issueDate).toLocaleDateString('ru-RU')})
</span>
)}
</p>
</div>
)}
{/* Licenses */}
{report.licenses && report.licenses.length > 0 && (
<div className="bg-slate-50 rounded-xl p-4">
<p className="text-xs font-black text-slate-500 uppercase mb-2">Лицензии</p>
<ul className="text-sm text-slate-700 space-y-2">
{report.licenses.map((lic: { number?: string; validTo?: number; validFrom?: number; activities?: string[] }, idx: number) => {
const validTo = lic.validTo ? new Date(lic.validTo).getTime() : null;
const expired = validTo != null && validTo < Date.now();
return (
<li key={idx} className={expired ? 'text-amber-600' : ''}>
{lic.number && <span className="font-bold">{lic.number}</span>}
{lic.validFrom && (
<span className="ml-1 text-slate-500">с {new Date(lic.validFrom).toLocaleDateString('ru-RU')}</span>
)}
{lic.validTo && (
<span className="ml-1">
{expired ? 'истекла' : 'до'} {new Date(lic.validTo).toLocaleDateString('ru-RU')}
</span>
)}
{lic.activities?.length ? (
<p className="text-xs text-slate-600 mt-0.5">{lic.activities.join(', ')}</p>
) : null}
</li>
);
})}
</ul>
</div>
)}
{/* Management disqualified */}
{report.managementDisqualified && (
<div className="p-4 bg-red-50 border-2 border-red-200 rounded-xl">
<p className="text-xs font-black text-red-600 uppercase mb-1">Руководитель дисквалифицирован</p>
<p className="text-sm text-red-700">Директор не имеет права заключать сделки</p>
</div>
)}
{/* Invalidity details */}
{(report.addressInvalidity || (report.foundersInvalidity && report.foundersInvalidity.length > 0) || (report.managersInvalidity && report.managersInvalidity.length > 0)) && (
<div className="p-4 bg-amber-50 border-2 border-amber-200 rounded-xl">
<p className="text-xs font-black text-amber-700 uppercase mb-2">Недостоверные сведения</p>
<ul className="text-sm text-amber-800 space-y-1">
{report.addressInvalidity && <li> Адрес признан недостоверным (ФНС)</li>}
{report.foundersInvalidity?.length ? <li> Сведения об учредителях недостоверны</li> : null}
{report.managersInvalidity?.length ? <li> Сведения о руководителе недостоверны</li> : null}
</ul>
</div>
)}
{/* Notes */}
{report.notes && (
<div>
<p className="text-xs font-black text-slate-500 uppercase mb-1">Примечания</p>
<p className="text-sm text-slate-700 bg-slate-50 p-3 rounded-lg">{report.notes}</p>
</div>
)}
</div>
<div className="mt-6 flex justify-end">
<button
onClick={onClose}
className="px-6 py-2.5 bg-primary-600 text-white rounded-xl text-xs font-black uppercase hover:bg-primary-700 transition-colors"
>
Закрыть
</button>
</div>
</div>
</div>
);
};