Files
mkd/types.ts

2049 lines
65 KiB
TypeScript
Raw Normal View History

2026-02-04 00:17:04 +05:00
import { LucideIcon } from 'lucide-react';
/** Реэкспорт из единого источника прав (constants/roleAccess.ts) */
export type { UserRole } from './constants/roleAccess';
export interface User {
id: string;
userId?: string | number;
name: string;
givenName?: string | null;
familyName?: string | null;
email?: string;
emailVerified?: boolean;
phone?: string | null;
role: UserRole;
avatar: string | null;
birthDate?: string | null;
position?: string | null;
/** Назначенные участки (несколько у мастера). */
assignedDistrictIds?: string[] | null;
assignedDistrictId?: string | null;
messengerLogins?: { messenger: 'Max' | 'Telegram'; login: string }[];
language?: string;
theme?: string;
notificationEmail?: boolean;
notificationPush?: boolean;
lastLogin?: string | null;
createdAt?: string | null;
updatedAt?: string | null;
allowedSections?: string[];
permissions?: string[] | null;
scope?: 'all' | 'own_district';
}
export interface UserPreferences {
language: string;
theme: string;
notificationEmail: boolean;
notificationPush: boolean;
}
export interface NavItem {
id: string;
label: string;
icon: LucideIcon;
}
export interface District {
id: string;
name: string;
managerName: string;
inventory?: BuildingInventoryItem[]; // Склад участка
}
/** Справочник должностей (панель управления) */
export interface Position {
id: string;
name: string;
isManagerial: boolean;
sortOrder?: number;
createdAt?: string;
updatedAt?: string;
}
export interface Employee {
id: string;
name: string; // ФИО
position: string; // Должность
phone: string; // Номер телефона
status: 'active' | 'vacation' | 'inactive';
salary: number;
/** Назначенные участки (многие ко многим). Приоритет над assignedDistrictId. */
assignedDistrictIds?: string[];
/** Один участок — для обратной совместимости; первый из assignedDistrictIds или старое поле. */
assignedDistrictId?: string | null; // Участок
managerId?: string; // ID руководителя сотрудника
birthDate?: string; // Дата рождения (ISO date string)
messengerLogins?: { // Логины мессенджеров
messenger: 'Max' | 'Telegram';
login: string;
}[];
photoUrl?: string; // Фото сотрудника
registrationDate?: string; // Дата регистрации (ISO date string)
hrData?: { // Данные для HR и Бухгалтерии
passportData?: {
series: string;
number: string;
issuedBy: string;
issuedDate: string;
registrationAddress: string;
};
laborBook?: {
number: string;
series?: string;
entries?: Array<{
date: string;
organization: string;
position: string;
}>;
};
certificates?: Array<{ // Заказ справок
type: string; // Тип справки (2-НДФЛ, справка с места работы и т.д.)
requestedDate: string;
issuedDate?: string;
status: 'requested' | 'issued' | 'ready';
}>;
otherDocuments?: Array<{
name: string;
type: string;
date: string;
fileUrl?: string;
}>;
accountingData?: { // Бухгалтерская информация
inn?: string; // ИНН
snils?: string; // СНИЛС
bankName?: string; // Название банка
bankAccount?: string; // Расчетный счет
correspondentAccount?: string; // Корреспондентский счет
bik?: string; // БИК
taxId?: string; // КПП
};
contracts?: Array<{ // Характеристики договора
id?: number;
contractType: string; // Тип договора (трудовой, ГПХ, срочный и т.д.)
contractNumber?: string; // Номер договора
startDate: string; // Дата начала
endDate?: string; // Дата окончания (для бессрочного - undefined)
probationPeriodDays?: number; // Испытательный срок в днях
workSchedule?: string; // График работы
workMode?: string; // Режим работы (офис, удаленно, гибрид)
contractTerms?: string; // Дополнительные условия
}>;
vacations?: EmployeeVacation[]; // Отпуска
sickLeaves?: EmployeeSickLeave[]; // Больничные
terminations?: EmployeeTermination[]; // Увольнения
absences?: EmployeeAbsence[]; // Отгулы и прогулы
};
}
// Отпуск сотрудника
export interface EmployeeVacation {
id: number;
employeeId: string;
startDate: string; // ISO date string
endDate: string; // ISO date string
daysCount: number;
vacationType: 'annual' | 'unpaid' | 'study' | 'maternity' | 'other'; // Тип отпуска
status: 'planned' | 'approved' | 'active' | 'completed' | 'canceled';
requiresApproval?: boolean; // Требуется ли согласование
approvedBy?: string;
approvedAt?: string; // ISO datetime string
approvedSignature?: string; // Подпись руководителя
rejectedBy?: string;
rejectedAt?: string; // ISO datetime string
rejectionReason?: string; // Причина отклонения
notes?: string;
createdAt: string; // ISO datetime string
updatedAt: string; // ISO datetime string
}
// Больничный сотрудника
export interface EmployeeSickLeave {
id: number;
employeeId: string;
startDate: string; // ISO date string
endDate?: string; // ISO date string (может быть NULL, если больничный еще не закрыт)
expectedReturnDate?: string; // Предварительная дата выхода (ISO date)
daysCount?: number;
sickLeaveNumber?: string; // Номер больничного листа (обязателен при выходе с больничного)
diagnosis?: string; // Диагноз
medicalInstitution?: string; // Медицинское учреждение
status: 'active' | 'closed' | 'canceled';
requiresApproval?: boolean; // Требуется ли согласование
approvedBy?: string;
approvedAt?: string; // ISO datetime string
approvedSignature?: string; // Подпись руководителя
closedAt?: string; // ISO datetime string
notes?: string;
fileUrl?: string; // Ссылка на отсканированный больничный лист
createdAt: string; // ISO datetime string
updatedAt: string; // ISO datetime string
}
// Отгул или прогул сотрудника
export interface EmployeeAbsence {
id: number;
employeeId: string;
absenceType: 'day_off' | 'absence' | 'late' | 'early_leave'; // Тип: отгул, прогул, опоздание, ранний уход
startDate: string; // ISO date string
endDate?: string; // ISO date string (может быть NULL для однодневных отгулов)
startTime?: string; // Время начала (HH:mm) для опозданий и ранних уходов
endTime?: string; // Время окончания (HH:mm) для опозданий и ранних уходов
daysCount: number; // Количество дней (может быть дробным для части дня)
reason?: string; // Причина отсутствия
requiresApproval: boolean; // Требуется ли согласование
status: 'pending' | 'approved' | 'rejected' | 'canceled'; // Статус согласования
approvedBy?: string; // Кто утвердил (руководитель)
approvedAt?: string; // ISO datetime string
approvedSignature?: string; // Подпись руководителя (текст или путь к файлу)
rejectedBy?: string; // Кто отклонил
rejectedAt?: string; // ISO datetime string
rejectionReason?: string; // Причина отклонения
notes?: string; // Примечания
createdAt: string; // ISO datetime string
updatedAt: string; // ISO datetime string
}
// Увольнение сотрудника
// Обучение сотрудников (инструктажи и курсы)
export type TrainingType = 'instruction' | 'course' | 'certification' | 'exam' | 'other';
export type TrainingCategory = 'safety' | 'fire_safety' | 'electrical' | 'first_aid' | 'professional' | 'compliance' | 'other';
export type TrainingStatus = 'not_started' | 'in_progress' | 'completed' | 'failed' | 'expired' | 'cancelled';
export interface TrainingProgram {
id: string;
title: string;
description?: string;
type: TrainingType;
category: TrainingCategory;
durationHours?: number;
validityMonths?: number; // Срок действия в месяцах (null = бессрочно)
isRequired: boolean;
requiredForPositions?: string[]; // Должности, для которых обязательно
instructorName?: string;
materialsUrl?: string;
createdAt?: string;
updatedAt?: string;
}
export interface EmployeeTraining {
id: number;
employeeId: string;
programId: string;
status: TrainingStatus;
startDate?: string;
completionDate?: string;
expiryDate?: string; // Дата окончания срока действия
score?: number;
passed?: boolean;
certificateNumber?: string;
certificateUrl?: string;
notes?: string;
instructorName?: string;
location?: string;
createdAt?: string;
updatedAt?: string;
// Дополнительные поля при получении с JOIN
programTitle?: string;
programType?: TrainingType;
programCategory?: TrainingCategory;
programDurationHours?: number;
programValidityMonths?: number;
employeeName?: string;
employeePosition?: string;
}
export interface EmployeeTermination {
id: number;
employeeId: string;
terminationDate: string; // ISO date string
reason: string; // Причина увольнения
initiatedBy: string; // Кто инициировал увольнение
initiatedAt: string; // ISO datetime string
status: 'initiated' | 'in_progress' | 'completed' | 'canceled';
// Договор на увольнение
terminationContractNumber?: string;
terminationContractDate?: string; // ISO date string
terminationContractFileUrl?: string;
// Расчеты
finalSettlementAmount?: number;
unusedVacationDays?: number;
compensationAmount?: number; // Компенсация за неиспользованный отпуск
severancePay?: number; // Выходное пособие
otherPayments?: number; // Прочие выплаты
deductions?: number; // Удержания
settlementDocumentNumber?: string;
settlementDocumentDate?: string; // ISO date string
settlementDocumentFileUrl?: string;
// Дополнительная информация
notes?: string;
completedAt?: string; // ISO datetime string
createdAt: string; // ISO datetime string
updatedAt: string; // ISO datetime string
}
export interface CandidateEvent {
id: string;
candidateId: string;
eventType: 'call' | 'interview_1' | 'interview_2' | 'interview_3' | 'test_task' | 'offer' | 'offer_accepted' | 'offer_rejected' | 'probation_start' | 'hired' | 'rejected' | 'other';
eventDate: string; // ISO date string
notes?: string;
result?: 'success' | 'failed' | 'pending' | 'cancelled';
interviewer?: string;
location?: string;
durationMinutes?: number;
createdAt?: string;
updatedAt?: string;
}
export interface Candidate {
id: string;
name: string;
position: string;
vacancyId?: string; // Связь с вакансией
stage: 'new' | 'interview' | 'probation' | 'hired' | 'rejected';
phone: string;
email?: string;
resumeUrl?: string;
coverLetter?: string;
interviewDate?: string;
interviewNotes?: string;
offerSalary?: number;
offerDate?: string;
hiredDate?: string;
rejectedReason?: string;
events?: CandidateEvent[]; // События кандидата
createdAt?: string;
updatedAt?: string;
}
export interface Vacancy {
id: string;
position: string;
department: string;
status: 'urgent' | 'active' | 'paused' | 'closed';
salary?: string;
applicantsCount: number;
postedDate: string;
description: string;
requirements?: string; // Требования к кандидату
conditions?: string; // Условия работы
responsibilities?: string; // Обязанности
closingDate?: string; // Дата закрытия вакансии
createdAt?: string;
updatedAt?: string;
}
export interface SMMChannel {
id: number;
name: string;
type: 'tg' | 'vk' | 'wa' | 'other';
url?: string;
sortOrder?: number;
createdAt?: string;
lastSnapshot?: SMMSubscriberSnapshot | null;
subscribersCount?: number | null;
}
export interface SMMSubscriberSnapshot {
id: number;
channelId: number;
subscribersCount: number;
recordedAt: string;
note?: string;
createdAt?: string;
}
export interface SMMChannelsSummary {
total: number;
byChannel: Array<{ id: number; name: string; type: string; subscribersCount: number }>;
}
export interface AttractionAction {
id: number;
title: string;
description?: string;
channelId?: number | null;
actionType: 'mailing' | 'event' | 'post' | 'other';
actionDate: string;
newSubscribersAttributed?: number | null;
eventId?: number | null;
createdAt?: string;
createdBy?: string;
channelName?: string;
channelType?: string;
}
export interface PostTopic {
id: number;
title: string;
description?: string;
scheduledDate: string; // дата планируемой публикации
month: string; // YYYY-MM для фильтрации
status: 'draft' | 'pending_approval' | 'approved' | 'rejected';
createdAt?: string;
createdBy?: string;
approvedAt?: string;
approvedBy?: string;
rejectionReason?: string;
}
export interface ScheduledPost {
id: number;
title: string;
content: string;
channelIds: number[];
scheduledAt: string;
status: 'draft' | 'pending_approval' | 'approved' | 'rejected' | 'edited' | 'published';
topicId?: number | null;
imageUrl?: string | null;
createdAt?: string;
createdBy?: string;
approvedAt?: string;
approvedBy?: string;
rejectionReason?: string;
editedContent?: string;
publishedAt?: string;
}
export interface PREventPhoto {
id: number;
event_id?: number;
photoUrl: string;
caption?: string;
locationType?: 'building' | 'office';
locationBuildingId?: string;
createdAt?: string;
}
export interface PREvent {
id: string | number;
title: string;
date: string;
type: 'resident' | 'internal';
category: 'holiday' | 'eco' | 'sport' | 'training' | 'meeting';
status: 'planned' | 'in_progress' | 'completed' | 'canceled';
location: string;
attendeesCount: number;
budget?: number;
shortPlan?: string;
announcement?: string;
locationType?: 'building' | 'office';
locationBuildingId?: string;
/** Для жителей: участок или дома отдельно */
locationPlaceType?: 'district' | 'buildings';
locationDistrictId?: string;
locationBuildingIds?: string[];
assignedEmployeeIds?: string[];
photos?: PREventPhoto[];
invoices?: Array<{ id: number; invoiceNumber: string; status: string; totalAmount?: number }>;
createdAt?: string;
updatedAt?: string;
createdBy?: string;
}
/** Живая статистика по отчёту — актуальные данные из БД на момент запроса */
export interface ResidentReportLiveStats {
applicationsTotal: number;
npsScore: number;
fundsCollected: number;
}
export interface ResidentReport {
id: string | number;
buildingId: string;
address?: string;
month: string;
periodStart?: string;
periodEnd?: string;
status: 'draft' | 'published';
publishedAt?: string;
content?: ResidentReportContent;
/** Живая статистика (заявки, NPS, собрано) — подставляется с бэкенда при запросе списка */
liveStats?: ResidentReportLiveStats;
createdAt?: string;
updatedAt?: string;
// Старые поля для обратной совместимости
stats?: {
appsDone: number;
budgetSpent: number;
cleaningQuality: number;
};
}
export interface ResidentReportContent {
// Информация о доме
buildingInfo?: {
address: string;
apartmentsCount?: number;
floors?: number;
};
// Заявки за период
applications?: {
total: number;
completed: number;
inProgress: number;
new: number;
list?: Array<{
id: number;
number: string;
description: string;
status: string;
createdAt: string;
}>;
};
// Статистика по дому
statistics?: {
nps?: number;
collectionRate?: number;
totalDebt?: number;
debtorsCount?: number;
};
// Работа с должниками
debtors?: Array<{
name: string;
apartment: string;
debt: number;
}>;
// Финансы предприятия
finances?: {
income: number;
expenses: number;
balance: number;
incomeByItems?: Record<string, number>;
expensesByItems?: Record<string, number>;
};
// Фото отчеты
workPhotos?: WorkPhoto[];
// AI сгенерированный текст
generatedText?: string;
// Структура отчета собственника (из оборотно-сальдовой ведомости)
parameters?: {
periodStart: string;
periodEnd: string;
building: string;
residentialArea?: number;
nonResidentialArea?: number;
parkingArea?: number;
totalArea?: number;
};
tariffs?: {
tariff: number;
reserveFund: number;
};
services?: Array<{
name: string;
debt: number;
accrued: number;
paid: number;
percentOfPlan: number;
order: number;
}>;
balance?: {
fromAccrued: number;
fromReceived: number;
reserveFundFromAccrued: number;
reserveFundFromReceived: number;
};
expenseItems?: Array<{
number: string;
name: string;
perMonth: number;
total: number;
perSquareMeter: number;
children?: Array<{
number: string;
name: string;
perMonth: number;
total: number;
perSquareMeter: number;
children?: Array<{
number: string;
name: string;
perMonth: number;
total: number;
perSquareMeter: number;
}>;
}>;
}>;
totals?: {
totalExpenses: number;
vat: number;
recalculation: number;
totalWithRecalculation: number;
totalWithRecalculationWithVAT: number;
debtReturn: number;
totalTariff: number;
otherIncome: number;
};
financialResults?: {
maintenanceFromAccrued: number;
maintenanceFromReceived: number;
reserveFundFromAccrued: number;
reserveFundFromReceived: number;
};
}
// ========= PR и NPS: ФОТО ОТЧЕТЫ =========
export interface WorkPhoto {
id: number;
buildingId: string;
residentReportId?: number;
taskId?: string; // Привязка к задаче (фото отчёт до/после)
workName: string;
workDate: string;
description?: string;
photoBeforeUrl?: string;
photoAfterUrl?: string;
createdAt: string;
updatedAt: string;
// Дополнительные поля для отображения
address?: string;
}
// ========= PR и NPS: NPS ОПРОСЫ =========
export type NPSSurveyStatus = 'draft' | 'active' | 'closed';
export interface NPSSurvey {
id: number;
buildingId: string;
title: string;
description?: string;
status: NPSSurveyStatus;
accessKey: string;
publishedAt?: string;
expiresAt?: string;
createdBy: string;
createdAt: string;
updatedAt: string;
// Дополнительные поля для отображения
address?: string;
responsesCount?: number;
avgScore?: number;
}
export interface NPSResponse {
id: number;
surveyId: number;
buildingId: string;
score: number; // 0-10
comment?: string;
respondentName?: string;
apartment?: string;
phone?: string;
email?: string;
createdAt: string;
}
export interface NPSSurveyStats {
totalResponses: number;
avgScore: number;
promoters: number; // 9-10
passives: number; // 7-8
detractors: number; // 0-6
nps: number; // (promoters% - detractors%)
promoterPercent: number;
detractorPercent: number;
}
// ========= PR и NPS: НАСТРОЙКИ ПАРСИНГА =========
export type ParsingSource = 'yandex_maps' | '2gis';
export interface ParsingSettings {
id: number;
source: ParsingSource;
enabled: boolean;
urlTemplate?: string;
apiKey?: string;
parsingIntervalHours: number;
lastParsedAt?: string;
settings?: Record<string, any>;
buildingId?: string; // ID дома, к которому привязаны отзывы (извлекается из settings.building_id)
createdAt: string;
updatedAt: string;
}
export type Department = 'production' | 'pr' | 'finance' | 'development' | 'legal' | 'hr';
export type CompanyNewsStatus = 'draft' | 'pending' | 'published';
export interface CompanyNews {
id: number;
title: string;
body: string | null;
status: CompanyNewsStatus;
createdAt: string;
updatedAt: string;
publishedAt: string | null;
createdBy: number | null;
createdByName?: string | null;
notifyDepartments?: Department[];
notifyEmployeeIds?: string[];
}
export interface StrategicGoal {
id: string;
department: Department;
title: string;
description: string;
currentValue: number;
targetValue: number;
unit: string;
deadline: string;
}
export interface ResidentFeedback {
id: string;
buildingId: string;
address: string;
date: string;
text: string;
source: string;
rating: number;
}
export interface AnalyzedFeedback extends ResidentFeedback {
category: string;
sentiment: 'Positive' | 'Negative' | 'Neutral';
}
// ========= PR и NPS: ОТЗЫВЫ =========
export type ReviewSource = 'yandex_maps' | '2gis' | 'internal' | 'other';
export type ReviewStatus = 'new' | 'processed' | 'archived';
export interface Review {
id: number;
buildingId: string;
source: ReviewSource;
sourceUrl?: string;
authorName?: string;
text: string;
rating: number; // 1-10
date: string;
status: ReviewStatus;
processedAt?: string;
processedBy?: string;
createdAt: string;
updatedAt: string;
// Дополнительные поля для отображения
address?: string;
}
// ========= PR и NPS: ИНЦИДЕНТЫ =========
export type IncidentType = 'property_damage' | 'debtor_complaint' | 'service_quality' | 'other';
export type IncidentStatus = 'new' | 'in_progress' | 'resolved' | 'closed';
export type IncidentPriority = 'low' | 'medium' | 'high' | 'urgent';
export interface Incident {
id: number;
reviewId?: number;
buildingId: string;
type: IncidentType;
title: string;
description: string;
status: IncidentStatus;
priority: IncidentPriority;
assignedTo?: string;
createdBy: string;
createdAt: string;
resolvedAt?: string;
resolutionNotes?: string;
updatedAt: string;
// Дополнительные поля для отображения
address?: string;
review?: Review;
}
export interface AIAnalysisResult {
analyzedFeedback: AnalyzedFeedback[];
summary: {
positive: string[];
negative: string[];
};
}
export type DomaApplicationStatus = 'new' | 'in_progress' | 'deferred' | 'done' | 'canceled';
export interface DomaApplication {
id: number;
number: string;
status: DomaApplicationStatus;
description: string;
address: string;
apartment: string;
clientName: string;
createdAt: string;
deadlineAt: string;
performer?: { name: string };
isOverdue?: boolean;
domaId?: string;
source?: 'doma' | 'manual';
sourceChannel?: string;
contactPhone?: string;
contactName?: string;
placeIncident?: string;
workType?: string;
problemDetail?: string;
executorName?: string;
responsibleName?: string;
observersText?: string;
updatedAt?: string;
buildingId?: string;
}
/** Комментарий к заявке (внутренний или с жителем) */
export interface ApplicationComment {
id: number;
applicationId: number;
authorName: string;
type: 'internal' | 'resident';
text: string;
createdAt: string;
}
/** Запись истории изменений заявки */
export interface ApplicationHistoryEntry {
id: number;
applicationId: number;
changedBy: string;
changedAt: string;
fieldName: string;
oldValue?: string | null;
newValue?: string | null;
}
/** Payload для создания заявки вручную (карточка диспетчерской) */
export interface CreateApplicationPayload {
address: string;
description: string;
apartment?: string;
sourceChannel?: string;
isFromResident?: boolean;
contactPhone?: string;
contactName?: string;
placeIncident?: string;
workType?: string;
problemDetail?: string;
isEmergency?: boolean;
isPaid?: boolean;
isWarranty?: boolean;
deadlineAt?: string;
executorName?: string;
responsibleName?: string;
observersText?: string;
showInApp?: boolean;
buildingId?: string;
}
/** Запись журнала отключений */
export type OutageWorkType = 'absent' | 'planned' | 'emergency';
export interface Outage {
id: number;
buildingId: string;
startAt: string;
endAt?: string | null;
type?: string | null;
description?: string | null;
active: boolean;
createdAt: string;
updatedAt: string;
buildingAddress?: string;
authorName?: string | null;
category?: string | null;
problemDetail?: string | null;
workType?: OutageWorkType | string | null;
residentMessage?: string | null;
generateNews?: boolean;
}
export interface CreateOutagePayload {
buildingId?: string;
buildingIds?: string[];
startAt: string;
endAt?: string;
type?: string;
description: string;
active?: boolean;
authorName?: string;
category?: string;
problemDetail?: string;
workType?: OutageWorkType | string;
residentMessage?: string;
generateNews?: boolean;
}
export interface OfficeRequest {
id: number | string; // number из БД, string для моков
requesterName: string;
category: string;
itemName: string;
quantity?: number;
issuedQuantity?: number; // Количество выданного сотруднику
unit?: string;
date?: string; // Дата создания (created_at)
status: 'new' | 'approved' | 'ordered' | 'received' | 'canceled' | 'archived' | 'collected';
amount: number;
priority: 'low' | 'medium' | 'high' | 'urgent';
approvedBy?: string;
approvedAt?: string;
orderedAt?: string;
receivedAt?: string;
notes?: string;
createdAt?: string;
updatedAt?: string;
}
export interface OfficeInventoryItem {
id: number | string; // number из БД, string для моков
name: string;
category?: string;
quantity: number;
unit: string;
minThreshold: number;
lastRestock?: string | null; // DATE из БД
lastRestockBy?: string;
location?: string;
notes?: string;
createdAt?: string;
updatedAt?: string;
}
export interface OfficeDocument {
id: number | string; // number из БД, string для моков
regNumber: string;
title: string;
correspondent: string;
date: string;
status: 'registered' | 'processed' | 'sent' | 'archived';
// FIX: added type property to fix TS errors in OfficeSummary.tsx and DocumentFlow.tsx
type: 'incoming' | 'outgoing'; // document_type в БД
letterType?: 'email' | 'paper'; // Тип письма: Email или бумага
assignedTo?: string;
trackingNumber?: string;
fileUrl?: string; // URL загруженного файла (скан или текстовый файл)
notes?: string;
createdBy: string; // Кто создал/зарегистрировал
createdAt?: string;
updatedAt?: string;
}
export interface OfficeAsset {
id: string;
name: string;
type: 'laptop' | 'appliance' | 'furniture' | 'other';
assignedTo?: string;
purchaseDate: string;
condition: 'good' | 'poor' | 'fair';
serialNumber: string;
nextMaintenanceDate?: string;
}
export type ContractStatus = 'draft' | 'finance_approval' | 'counterparty_approval' | 'signing' | 'active' | 'archived';
export interface LegalContract {
id: string;
number: string;
type: string;
counterparty: string;
counterpartyInn?: string;
amount: number;
status: ContractStatus;
startDate: string;
endDate: string;
autoProlongation: boolean;
manager: string;
hasDisagreements: boolean;
contractFileUrl?: string;
notes?: string;
createdAt?: string;
updatedAt?: string;
}
/** Этап ФССП в цепочке взыскания */
export type FsspStage = 'writ_submitted' | 'ip_initiated' | 'bank_requests' | 'money_on_deposit' | 'transferred_to_uk';
export interface LegalCourtCase {
id: string;
caseNumber: string;
type: 'arbitration' | 'civil' | 'debt_recovery';
role: 'plaintiff' | 'defendant';
subject: string;
debtorName?: string;
address?: string;
amount: number; // Присужденная сумма
recoveredAmount?: number; // Реально пришло в УК
amountAtBailiffs?: number; // Деньги на счетах ФССП
status: 'pre_trial' | 'litigation' | 'decision_received' | 'enforcement' | 'closed';
fsspStatus?: string;
bailiffName?: string;
fsspLastActionDate?: string;
nextHearingDate?: string;
judge?: string;
/** Номер исполнительного производства */
enforcementNumber?: string;
/** Дата возбуждения ИП */
enforcementStartDate?: string;
/** Этап ФССП: ИЛ предъявлен → ИП возбуждено → запросы в банки → деньги на депозите → в УК */
fsspStage?: FsspStage | null;
/** Сумма пени по делу */
penaltyAmount?: number;
/** Дата начала просрочки оплаты */
overdueSince?: string;
/** Название суда */
courtName?: string;
/** Примечания */
notes?: string;
/** Ссылка на материалы дела */
caseFileUrl?: string;
}
export interface LegalPoA {
id: string;
number: string;
issuedTo: string;
issueDate: string;
expiryDate: string;
status: 'active' | 'expired' | 'revoked';
authority: string;
}
export interface LegalCounterparty {
id: string;
name: string;
inn: string;
status: 'active' | 'inactive';
riskLevel: 'low' | 'medium' | 'high';
checkedDate: string;
notes?: string;
}
export type DevPipelineStatus =
| 'incoming' // Входящие
| 'analysis' // Анализ
| 'agenda_approval' // Согласование повестки
| 'in_person' // Очная часть
| 'absentee' // Заочная часть
| 'protocol_formation' // Формирование протокола
| 'protocol_to_gzhi' // Отправка протокола в ГЖИ
| 'gzhi_order' // Приказ ГЖИ
| 'success' // Успех
| 'failure'; // Провал
export interface DevPipelineItem {
id: string;
address: string;
type: 'old' | 'new';
floors: number;
area: number;
apartments: number;
status: DevPipelineStatus;
probability: number;
expectedRevenue: number;
manager: string;
buildingId?: string | null;
notes?: string | null;
}
export interface DevOSSSession {
id: string;
buildingId: string;
address: string;
startDate: string;
endDate: string;
quorumCurrent: number;
quorumTotal: number;
status: 'active' | 'planned' | 'completed';
type: 'annual' | 'extraordinary';
description?: string | null;
agendaItems?: string[];
}
/** Статус аудита */
export type DevAuditStatus = 'new' | 'in_progress' | 'completed';
/** Оценка подпункта: 15 (1 — худшее, 5 — лучшее). Итог по пункту — среднее арифметическое. */
export type InspectionSubItemRating = number; // 1 | 2 | 3 | 4 | 5
/** Подпункт осмотра (label берётся из справочника по key) */
export interface InspectionSubItem {
key: string;
label?: string;
/** Оценка 15; не участвует в среднем при noAccess/notPresent */
rating: number | null;
description: string | null;
noAccess: boolean;
notPresent: boolean;
}
/** Данные по одному пункту осмотра (категория). overall — среднее по подпунктам (вычисляемое или сохранённое). */
export interface InspectionCategoryData {
subItems: InspectionSubItem[];
/** Среднее арифметическое оценок подпунктов (15), вычисляется из subItems */
overall?: number | null;
}
/** Ключи пунктов осмотра: кровля, фасад, подъезды, инфраструктура, придомовой участок */
export type InspectionCategoryKey = 'roof' | 'facade' | 'entrances' | 'infrastructure' | 'yard';
/** Данные осмотра по всем пунктам */
export type InspectionData = Partial<Record<InspectionCategoryKey, InspectionCategoryData>>;
export interface DevAuditData {
id: string;
buildingId: string;
address: string;
status: DevAuditStatus;
wearPercent: number;
roofCondition: 'good' | 'poor' | 'fair';
basementCondition: 'good' | 'poor' | 'fair';
calculatedTariff: number;
projectedMargin: number;
complexityIndex: number | null;
inspectionData: InspectionData | null;
auditDate?: string;
auditorName?: string | null;
notes?: string | null;
}
export interface DevMarketingActivity {
id: string;
buildingId: string;
address: string;
activistsCount: number;
meetingsHeld: number;
adsDistributed: number;
competitor: string;
status: 'voting' | 'my_house' | 'competitor_house';
}
export interface MeterReading {
date: string;
value: number;
consumption: number;
source: 'app' | 'manual' | 'iot';
}
export interface AccountMeter {
id: string;
type: 'ХВС' | 'ГВС' | 'Э/Э' | 'Газ' | 'Other';
make: string;
number: string;
name?: string; // Название прибора (для кастомных)
manufacturer?: string; // Производитель
installDate?: string; // Дата установки
lastVerification: string;
nextVerification: string;
currentReading?: number; // Текущее показание
unit?: string; // Единица измерения (м³, кВт⋅ч и т.д.)
readings: MeterReading[];
documents?: string[]; // Файлы документов (паспорт, акты поверки и т.д.)
notes?: string; // Примечания
}
export interface ResidentProfile {
sentiment: 'negative' | 'toxic' | 'positive' | 'loyal' | 'neutral';
birthday?: string; // ISO date string (YYYY-MM-DD)
notes?: string;
preferredContactMethod?: 'phone' | 'email' | 'chat' | 'in_person';
email?: string;
lastInteractionDate?: string; // ISO date string
specialNeeds?: string[];
paymentHistory?: {
onTime: number;
late: number;
averageDelayDays: number;
};
}
export interface RegisteredPerson {
id: string;
fullName: string;
phone?: string;
email?: string;
residentProfile?: ResidentProfile; // Портрет клиента для каждого прописанного
}
export interface PersonalAccount {
id: string;
accountNumber: string;
apartmentNumber: string;
type: 'apartment' | 'parking' | 'storage' | 'office';
floor: number;
entranceNumber?: number; // Номер подъезда (если известен)
owners: {
fullName: string,
phone: string;
residentProfile?: ResidentProfile; // Портрет клиента для собственника
}[];
registered: RegisteredPerson[]; // Прописанные с их данными и портретами
areaTotal: number;
areaLiving: number;
areaNonLiving: number;
meters: AccountMeter[];
isMeterInstallationFeasible: boolean;
surveyActNumber?: string;
surveyActDate?: string;
premiseNotes?: string; // Примечания по помещению (ремонты, особенности, проблемы и т.д.)
}
export interface Debtor {
apartment: string;
amount: number;
months: number;
status: 'new' | 'pending' | 'legal';
}
// ========= ЮРИДИЧЕСКИЙ ОТДЕЛ: ДОСУДЕБНАЯ РАБОТА =========
export interface LegalDebtor {
id: number;
buildingId: string;
apartment: string;
debtorName?: string;
phone?: string;
email?: string;
address: string;
debtAmount: number;
debtMonths: number;
status: 'new' | 'in_progress' | 'promised_payment' | 'transferred_to_court' | 'resolved';
transferredFromFinance: boolean;
createdAt: string;
updatedAt: string;
}
export interface PreTrialWork {
id: number;
debtorId: number;
assignedTo?: string;
status: 'new' | 'in_progress' | 'promised_payment' | 'transferred_to_court' | 'resolved';
promisedPaymentDate?: string;
promisedPaymentAmount?: number;
transferredToCourt: boolean;
courtCaseId?: string;
notes?: string;
createdAt: string;
updatedAt: string;
debtor?: LegalDebtor;
actions?: PreTrialAction[];
promisedPayments?: PromisedPayment[];
}
export interface PreTrialAction {
id: number;
workId: number;
actionType: 'call' | 'letter' | 'visit';
actionDate: string;
performedBy: string;
result?: string;
notes?: string;
attachments?: string[];
createdAt: string;
}
export interface PromisedPayment {
id: number;
workId: number;
promisedDate: string;
promisedAmount: number;
actualPaymentDate?: string;
actualPaymentAmount?: number;
isPaid: boolean;
reminderSent: boolean;
reminderDate?: string;
notes?: string;
createdAt: string;
updatedAt: string;
}
export type InvoiceStatus = 'draft' | 'pending_approval' | 'approved' | 'scheduled' | 'paid' | 'rejected' | 'overdue' | 'clarification';
export interface Invoice {
id: string;
buildingId: string;
address: string;
contractorName: string;
serviceName: string;
amount: number;
date: string;
paymentDeadline?: string;
scheduledDate?: string;
status: InvoiceStatus;
priority: 'low' | 'medium' | 'high';
closingDocsReceived: boolean;
paymentRef?: string;
}
// Типы для новой системы счетов на оплату
export type PaymentInvoiceStatus =
| 'draft'
| 'pending_manager_approval'
| 'pending_finance_manager_approval'
| 'approved'
| 'scheduled'
| 'paid'
| 'postponed'
| 'cancelled'
| 'rejected'
| 'completed';
export type PaymentInvoicePurposeType = 'building' | 'district' | 'legal' | 'office' | 'hr' | 'other' | 'event';
export type PaymentInvoiceFormat = 'prepayment' | 'postpayment' | 'advance';
export type DistributionMethod = 'equal' | 'by_area' | 'manual';
export type PaymentInvoiceItemType = 'service' | 'materials';
export interface ApprovalHistoryEntry {
userId: string;
userRole: string;
action: 'approve' | 'reject' | 'revision';
comment?: string;
date: string;
}
// Элемент услуги в счете
export interface ServiceItem {
name: string; // Название услуги
amount: number; // Сумма за услугу
}
// Элемент ТМЦ в счете
export interface MaterialItem {
name: string; // Наименование ТМЦ
quantity: number; // Количество
unit: string; // Единица измерения (шт, кг, м и т.д.)
pricePerUnit: number; // Цена за единицу
amount: number; // Сумма (quantity * pricePerUnit)
}
export interface PaymentInvoice {
id: number;
invoiceNumber: string;
createdBy: string;
createdAt: string;
updatedAt: string;
purposeType: PaymentInvoicePurposeType;
purposeBuildingIds: string[];
purposeDistrictIds: string[];
purposeDescription?: string;
purposeEventId?: number | null; // ID мероприятия (pr_events), если purposeType = 'event'
/** Пункт плана работ (Участки → Дом → План работ). Связь план/факт. */
planItemId?: string | null;
planItemBuildingId?: string | null;
paymentFormat: PaymentInvoiceFormat;
itemType: PaymentInvoiceItemType; // Услуга или ТМЦ
contractorName: string;
contractorInn?: string;
serviceDescription: string; // Описание услуги или ТМЦ (для обратной совместимости)
serviceItems?: ServiceItem[]; // Список услуг (если itemType = 'service')
materialItems?: MaterialItem[]; // Список ТМЦ (если itemType = 'materials')
totalAmount: number;
distributionMethod?: DistributionMethod;
distributionData: Record<string, any>;
status: PaymentInvoiceStatus;
currentApproverRole?: string;
approvalHistory: ApprovalHistoryEntry[];
rejectionReason?: string;
scheduledDate?: string;
paymentDate?: string;
/** Номер платежного поручения / платежки */
paymentRef?: string | null;
/** Оплата наличными */
isCash?: boolean;
/** Дата переноса (при отложении) */
postponedDate?: string | null;
/** Причина отмены */
cancelReason?: string | null;
isCompleted: boolean;
closingDocsReceived: boolean;
closingDocsFiles?: any[];
notes?: string;
fileUrls: string[];
}
// Платежный календарь: типы записей
export type PaymentType = 'invoice' | 'manual' | 'cash';
export type PaymentDirection = 'outgoing' | 'incoming';
export type PaymentProbability = 'confirmed' | 'high' | 'medium' | 'low';
export interface PaymentCalendarEntry {
id: number;
direction: PaymentDirection;
type: PaymentType;
paymentInvoiceId?: number | null;
category: string;
description: string;
amount: number;
scheduledDate: string;
paymentDate?: string | null;
probability: PaymentProbability;
currency: string;
isCash: boolean;
contractorName: string;
notes?: string | null;
createdAt: string;
updatedAt: string;
createdBy?: string;
}
/** Статья доходов/расходов (справочник) */
export interface PaymentCategory {
id: number;
name: string;
code?: string | null;
direction: 'income' | 'expense';
parentId?: number | null;
isActive: boolean;
sortOrder?: number;
}
/** Банковский счёт или кошелёк (наличка) для календаря оплат */
export interface FinanceAccount {
id: number;
type: 'bank' | 'cash';
name: string;
balance: number;
currency: string;
sortOrder?: number;
}
export interface ApproverUserRole {
id: number;
userId: string;
role: 'manager' | 'finance_manager' | 'financier' | 'finance_director' | 'director' | 'top_management';
createdAt: string;
}
export interface BuildingFinancials {
balance: number;
debt: number;
collectionRate: number;
topDebtors: Debtor[];
invoices: Invoice[];
}
export interface PassportMeter {
id?: string; // Уникальный ID прибора
resource: 'Heat' | 'Water' | 'Electricity' | 'Gas' | 'Other';
hasMeter: boolean;
name?: string; // Название прибора (для кастомных)
model?: string;
number?: string;
manufacturer?: string; // Производитель
installDate?: string; // Дата установки
lastVerification?: string; // Дата последней поверки
nextVerification?: string; // Дата следующей поверки
currentReading?: number; // Текущее показание
unit?: string; // Единица измерения (Гкал, м³, кВт⋅ч и т.д.)
readings?: MeterReading[]; // История показаний
documents?: string[]; // Файлы документов (паспорт, акты поверки и т.д.)
notes?: string; // Примечания
}
export interface PassportServiceContract {
id: string;
serviceType: string;
providerName: string;
contractNumber: string;
contractDate: string;
expiryDate?: string;
}
export interface EntranceSection {
id: string;
title: string;
elements: {
id: string;
name: string;
generalStatus: 'NOT_SELECTED' | 'OK' | 'WARNING' | 'CRITICAL';
electroStatus: 'NOT_SELECTED' | 'OK' | 'WARNING' | 'CRITICAL';
weldingStatus: 'NOT_SELECTED' | 'OK' | 'WARNING' | 'CRITICAL';
}[];
}
export interface PlanItem {
id: string;
year: number;
month: string;
workName: string;
status: 'current' | 'future' | 'completed' | 'carried_over';
progress: number;
estimatedCost: number;
actualCost?: number;
originalYear?: number;
postponeReason?: string;
carryOverReason?: string;
sourceInspectionId?: string;
sourceElementId?: string;
sourceSectionTitle?: string;
/** Силами УК (без бюджета подрядчика) */
byManagement?: boolean;
/** ID счетов на оплату, привязанных к этой работе (план/факт) */
linkedInvoiceIds?: number[];
}
export interface BuildingInventoryItem {
id: string;
name: string;
category: 'tool' | 'material' | 'door' | 'consumable';
quantity: number;
unit: string;
lastCheck: string;
source?: 'district' | 'invoice'; // Откуда взята позиция: со склада участка или из счета
unitPrice?: number; // Цена за единицу товара (стоимость / количество)
totalAmount?: number; // Общая стоимость товара (которую должны получить/заплатили)
}
// Акт списания товаров со склада
export interface WriteOffAct {
id: string;
date: string; // Дата списания (ISO date string)
items: WriteOffItem[]; // Список списанных позиций
totalAmount: number; // Общая сумма списания
performer: string; // Кто выполнил списание
reason?: string; // Причина списания (общая для всех позиций)
}
// Позиция в акте списания
export interface WriteOffItem {
itemId: string; // ID позиции в инвентаре
name: string; // Наименование товара
quantity: number; // Количество списанных единиц
unit: string; // Единица измерения
unitPrice: number; // Цена за единицу на момент списания
amount: number; // Сумма списания (quantity * unitPrice)
reason?: string; // Причина списания для этой позиции
}
export interface InspectionItem {
id: string;
category: 'structural' | 'engineering';
label: string;
status: 'ok' | 'repair_needed' | 'not_checked';
description?: string;
wearPercent?: number;
photos?: string[];
}
// Элемент МКД для детального осмотра (как в БИСРИК)
export interface InspectionMKDElement {
id: string;
name: string; // Название элемента (например, "Напольное покрытие", "Освещение")
generalStatus: 'NOT_SELECTED' | 'OK' | 'WARNING' | 'CRITICAL'; // Общий строй
electroStatus: 'NOT_SELECTED' | 'OK' | 'WARNING' | 'CRITICAL'; // Электроснабжение
weldingStatus: 'NOT_SELECTED' | 'OK' | 'WARNING' | 'CRITICAL'; // Слесарные, сварочные работы
repairType?: string; // Вид требуемого ремонта
mainPhoto?: string; // Гл. фото
additionalPhotos?: string[]; // Доп. фото
}
// Секция осмотра (подъезд, этаж, лифт и т.д.)
export interface InspectionSection {
id: string;
type: 'entrance' | 'floor' | 'lift' | 'common'; // Тип секции
number?: number; // Номер подъезда/этажа/лифта
title: string; // Название секции
elements: InspectionMKDElement[]; // Элементы МКД в этой секции
isCollapsed?: boolean; // Свернута ли секция
}
// Общая секция (кровля, подвал, фасад и т.д.)
export interface InspectionCommonSection {
id: string;
title: string; // "Кровля", "Подвал", "Фундамент" и т.д.
elements: InspectionMKDElement[];
isCollapsed?: boolean;
}
export interface InspectionAct {
id: string;
number: string;
date: string;
inspector: string;
type: 'scheduled_spring' | 'scheduled_autumn' | 'emergency' | 'acceptance';
status: 'draft' | 'completed';
issuesCount: number;
checklist?: InspectionItem[]; // Старый формат (для обратной совместимости)
// Новый формат с динамическими секциями
sections?: InspectionSection[]; // Подъезды, этажи, лифты
commonSections?: InspectionCommonSection[]; // Общие секции (кровля, подвал и т.д.)
basis?: string;
commissionMembers?: string;
ownerRepresentative?: string;
geolocation?: { lat: number, lng: number, timestamp: string };
signatureUrl?: string;
workCategory?: 'maintenance' | 'capital' | 'emergency';
isReadyForWinter?: boolean;
}
export interface MeterCheckRound {
id: string;
date: string;
inspector: string;
status: 'active' | 'completed';
buildingId: string;
roundType: 'odpu' | 'apartments' | 'all'; // Тип обхода: только ОДПУ, только квартиры, или все
// Фильтры для обхода
selectedEntrances?: number[]; // Выбранные подъезды (если пусто - все)
selectedFloors?: number[]; // Выбранные этажи (если пусто - все)
apartments?: {
apartmentNumber: string;
entranceNumber?: number; // Номер подъезда
floor?: number; // Этаж
status: 'pending' | 'verified' | 'no_access';
checkedAt?: string;
readings: {
meterId: string;
meterType: string;
previousValue: number;
currentValue?: number;
}[];
}[];
odpuMeters?: {
meterId: string;
meterIndex: number; // Индекс в массиве meters
meterType: string;
meterName: string;
previousValue: number;
currentValue?: number;
status: 'pending' | 'verified' | 'no_access';
checkedAt?: string;
}[];
}
// Комментарий к задаче
export interface TaskComment {
id: string;
authorId?: string;
authorName: string;
text: string;
createdAt: string; // ISO date string
}
export interface BuildingTask {
id: string;
title: string;
description?: string;
deadline: string; // ISO date string
status: 'new' | 'in_progress' | 'done' | 'cancelled';
priority: 'low' | 'medium' | 'high' | 'urgent';
assignedTo?: string; // ID или имя ответственного
assignedToName?: string; // Имя ответственного для отображения
createdAt: string; // ISO date string
updatedAt: string; // ISO date string
createdBy?: string; // ID создателя (постановщик)
createdByName?: string; // Имя постановщика для отображения
category?: string; // Категория задачи
tags?: string[]; // Теги
estimatedHours?: number; // Оценка времени в часах
actualHours?: number; // Фактически потраченное время
buildingId: string; // ID дома (пустая строка — общая задача)
buildingAddress?: string; // Адрес дома для отображения в сводке
comments?: TaskComment[]; // Комментарии
requirePhotoReport?: boolean; // Требуется фото отчёт до/после (по умолчанию true)
photoReportId?: number; // ID записи work_photos, привязанной к задаче
/** Соисполнители (ID пользователей) */
coAssignees?: string[];
coAssigneesNames?: string[];
/** Наблюдатели (ID пользователей) */
observers?: string[];
observersNames?: string[];
}
export interface Building {
id: string;
districtId: string;
imageUrl: string;
nps: number;
passport: {
address: string;
apartmentsCount: number;
general: {
address: string;
fiasCode: string;
constructionYear: number;
commissionYear: number;
seriesType: string;
floors: number;
undergroundFloors: number;
totalArea: number;
livingArea: number;
nonLivingArea: number;
commonArea: number;
cadastralNumberBuild: string;
cadastralNumberLand: string;
lastRepairYear?: number;
// Новые поля
entrancesCount?: number; // Кол-во подъездов
hasDifferentFloors?: boolean; // Разноэтажность
officesCount?: number; // Кол-во офисов
// Вычисляемые поля (будут считаться из accounts)
residentialAccountsCount?: number; // Кол-во жилых лицевых счетов
nonResidentialAccountsCount?: number; // Кол-во нежилых лицевых счетов
officesAccountsCount?: number; // Кол-во офисов (из лицевых счетов)
apartmentsCount?: number; // Кол-во квартир (из лицевых счетов)
nonLivingCommonArea?: number; // Площадь нежилых помещений в составе ОДИ
// Дополнительные поля для файлов
customFields?: { [key: string]: { value: any; type: string; files?: string[] } };
};
construction: {
foundationType: string;
foundationMaterial: string;
wallMaterial: string;
floorMaterial: string;
roofType: string;
roofMaterial: string;
roofArea: number;
facadeType: string;
facadeInsulation: boolean;
windowType: string;
// Новые поля
wearPercent?: number; // Процент износа
hasBasement?: boolean; // Подвал
hasTechFloor?: boolean; // Тех этаж
hasAttic?: boolean; // Чердак
hasBasementFloor?: boolean; // Цоколь
// Дополнительные поля для файлов
customFields?: { [key: string]: { value: any; type: string; files?: string[] } };
};
engineering: {
heatingType: string;
heatingWiring: string;
hasITP: boolean;
waterSupplyMaterial: string;
waterSupplyType: string;
sewerMaterial: string;
electricityEntries: number;
hasVRU: boolean;
gasType: string;
ventilationType: string;
// Процент износа для каждой системы
heatingWearPercent?: number;
waterSupplyWearPercent?: number;
sewerWearPercent?: number;
electricityWearPercent?: number;
gasWearPercent?: number;
ventilationWearPercent?: number;
// Дополнительные поля для файлов
customFields?: { [key: string]: { value: any; type: string; files?: string[] } };
};
odpu: {
// Дополнительные поля для файлов
customFields?: { [key: string]: { value: any; type: string; files?: string[] } };
};
meters: PassportMeter[];
lifts: {
count: number;
type: string;
capacity: number;
speed: number;
installYear: number;
factoryNumber: string;
// Новые поля
manufacturer?: string; // Производитель
lastMaintenanceDate?: string; // Дата последнего обслуживания
nextMaintenanceDate?: string; // Дата следующего обслуживания
wearPercent?: number; // Процент износа
status?: string; // Статус (работает, на ремонте и т.д.)
documents?: string[]; // Файлы документов
// Дополнительные поля
customFields?: { [key: string]: { value: any; type: string; files?: string[] } };
}[];
land: {
area: number;
hasPlayground: boolean;
hasSportsGround: boolean;
hasParking: boolean;
hasFencing: boolean;
hasContainerSite: boolean;
// Дополнительные поля для файлов
customFields?: { [key: string]: { value: any; type: string; files?: string[] } };
};
management: {
contractDate: string;
contractNumber: string;
servicesList: string[];
tariffMaintenance: number;
reserveFund?: number; // Резервный фонд (%)
serviceContracts: PassportServiceContract[];
// Дополнительные поля для файлов
customFields?: { [key: string]: { value: any; type: string; files?: string[] } };
};
};
staff: { id: string, role: string, company: string, name: string }[];
entrances: {
id: string;
number: number;
floors: number;
liftsCount: number;
hasBasement: 'NOT_SELECTED' | 'YES' | 'NO';
hasTechFloor: 'NOT_SELECTED' | 'YES' | 'NO';
hasAttic: 'NOT_SELECTED' | 'YES' | 'NO';
hasParking: 'NOT_SELECTED' | 'YES' | 'NO';
hasMansard: 'NOT_SELECTED' | 'YES' | 'NO';
entranceGroupsCount: number;
sections: EntranceSection[];
// Технические характеристики подъезда (сохраняются после первого обхода)
technicalCharacteristics?: {
hasBasement?: 'NOT_SELECTED' | 'YES' | 'NO';
hasTechFloor?: 'NOT_SELECTED' | 'YES' | 'NO';
hasParking?: 'NOT_SELECTED' | 'YES' | 'NO';
hasAttic?: 'NOT_SELECTED' | 'YES' | 'NO';
floorsCount?: number; // Количество этажей в подъезде
liftsCount?: number; // Количество лифтов в подъезде
hasMansard?: 'NOT_SELECTED' | 'YES' | 'NO';
entranceGroupsCount?: number; // Количество входных групп
};
// Элементы МКД по этажам (сохраняются после первого обхода)
floorElements?: {
[floorNumber: number]: InspectionMKDElement[]; // Элементы МКД для каждого этажа
};
}[];
commonSections: EntranceSection[];
accounts: PersonalAccount[];
financials: BuildingFinancials;
requests: { new: number, inProgress: number, overdue: number };
inspectionHistory: InspectionAct[];
tasks: BuildingTask[];
annualPlan: PlanItem[];
inventory: BuildingInventoryItem[];
writeOffHistory: WriteOffAct[];
residents: { id: string, name: string, role: string, apartment: string, mood: string, lastContact: string }[];
reports: { id: string, month: string, status: string }[];
isDirty: boolean;
meterCheckRounds?: MeterCheckRound[];
}
// ========= ФИНАНСОВЫЕ ДАННЫЕ ИЗ 1С =========
export interface FinancialReport {
id: number;
filename: string;
fileType: 'CSV' | 'XLSX';
reportType?: 'debtors' | 'balance_sheet' | 'balance_sheet_76' | 'other';
uploadedAt: string;
uploadedBy?: string;
status: 'processing' | 'completed' | 'failed' | 'partial';
totalRows?: number;
processedRows: number;
errorRows: number;
errorLog?: any;
mappingId?: number;
}
export interface FinancialReportMapping {
id: number;
name: string;
description?: string;
isDefault: boolean;
columnMappings: Record<string, string>; // { "source_column": "target_field" }
createdAt: string;
updatedAt: string;
}
export interface BuildingFinancialData {
id: number;
buildingId: string;
reportId?: number;
periodStart: string; // ISO date
periodEnd: string; // ISO date
periodType: 'month' | 'quarter' | 'year';
totalIncome: number;
incomeByItems: Record<string, number>;
totalExpenses: number;
expensesByItems: Record<string, number>;
balance: number;
metadata?: any;
createdAt: string;
updatedAt: string;
}
export interface ProcessingJob {
jobId: string;
status: 'pending' | 'processing' | 'completed' | 'failed';
progress: number; // 0-100
currentStep?: string;
errors: ProcessingError[];
warnings: string[];
result?: {
totalRows: number;
processedRows: number;
errorRows: number;
buildingsFound: number;
};
}
export interface ProcessingError {
row: number;
column?: string;
message: string;
suggestion?: string;
data?: any;
}
// ========= ОФИС: ЗАЯВКИ НА РЕМОНТ ТЕХНИКИ =========
export type OfficeEquipmentType = 'pc' | 'laptop' | 'air_conditioner' | 'printer' | 'other';
export type RepairRequestStatus =
| 'new'
| 'search_contractor' // Поиск подрядчика
| 'agreed_with_contractor' // Договорились с подрядчиком
| 'waiting_delivery' // Ожидание поставки
| 'taken_for_repair' // Увезли на ремонт
| 'self_repair' // Ремонт самостоятельно
| 'in_progress' // В работе
| 'completed' // Выполнена
| 'canceled'; // Отменена
export interface OfficeEquipment {
id: number;
name: string;
type: OfficeEquipmentType;
brand?: string;
model?: string;
serialNumber?: string;
assignedTo?: string;
purchaseDate?: string;
warrantyUntil?: string;
condition: 'good' | 'fair' | 'poor';
notes?: string;
createdAt: string;
updatedAt: string;
}
export type OfficeEquipmentHistoryType = 'purchase' | 'issue' | 'transfer' | 'repair' | 'write_off';
export interface OfficeEquipmentHistoryItem {
id: number | string;
equipment_id: number;
event_type: OfficeEquipmentHistoryType;
event_date: string;
assigned_to?: string;
assigned_from?: string;
reason?: string;
created_at: string;
}
export interface OfficeRepairRequest {
id: number;
equipmentId: number;
equipment?: OfficeEquipment;
requesterName: string;
description: string;
priority: 'low' | 'medium' | 'high' | 'urgent';
status: RepairRequestStatus;
assignedTo?: string;
createdAt: string;
startedAt?: string;
completedAt?: string;
canceledAt?: string;
cancelReason?: string;
expectedReturnDate?: string; // Ожидаемая дата возврата из ремонта
waitingDeliveryDeadline?: string; // Примерный срок при ожидание поставки
waitingDeliveryContacts?: string; // Контакты для уточнения поставки
takenForRepairDeadline?: string; // Срок при увезли на ремонт
takenForRepairContacts?: string; // Контакты при увезли на ремонт
agreedContractorPrice?: number; // Цена при договорились с подрядчиком
solution?: string;
attachments?: string[];
comments?: Array<{
author: string;
text: string;
createdAt: string;
}>;
isPaid?: boolean; // Платный ремонт
cost?: number; // Стоимость ремонта
costEstimated?: boolean; // Стоимость предварительная (требуется диагностика)
invoiceId?: number; // ID счета на оплату
invoiceUrl?: string; // Ссылка на счет
}
// ========= ОФИС: БАЗА ЗНАНИЙ =========
export interface KnowledgeBaseCategory {
id: number;
name: string;
slug: string;
parentId?: number;
parent?: KnowledgeBaseCategory;
description?: string;
icon?: string;
sortOrder: number;
createdAt: string;
updatedAt: string;
children?: KnowledgeBaseCategory[];
}
export interface KnowledgeBaseArticle {
id: number;
title: string;
slug: string;
categoryId?: number;
category?: KnowledgeBaseCategory;
content: string;
contentType: 'markdown' | 'html';
author: string;
version: number;
parentVersionId?: number;
isPublished: boolean;
tags?: string[];
attachments?: string[];
viewCount: number;
createdAt: string;
updatedAt: string;
publishedAt?: string;
}
// ========= ОФИС: СОВЕЩАНИЯ И ПЕРЕГОВОРНЫЕ =========
export interface MeetingRoom {
id: number;
name: string;
capacity: number;
location?: string;
equipment?: string[]; // ['projector', 'whiteboard', 'video_conference']
description?: string;
isActive: boolean;
createdAt: string;
updatedAt: string;
}
export type MeetingStatus = 'scheduled' | 'in_progress' | 'completed' | 'canceled';
export interface Meeting {
id: number;
title: string;
description?: string;
organizer: string;
startTime: string; // ISO datetime
endTime: string; // ISO datetime
roomId?: number;
room?: MeetingRoom;
participants: string[];
agenda?: string;
notes?: string;
conclusions?: string; // Заключения совещания
status: MeetingStatus;
reminderSent: boolean;
reminderTime?: string;
attachments?: string[];
createdAt: string;
updatedAt: string;
}
export type MeetingBookingStatus = 'active' | 'completed' | 'canceled';
export interface MeetingBooking {
id: number;
roomId: number;
room?: MeetingRoom;
meetingId?: number;
meeting?: Meeting;
bookedBy: string;
startTime: string; // ISO datetime
endTime: string; // ISO datetime
purpose?: string;
status: MeetingBookingStatus;
createdAt: string;
updatedAt: string;
}