migration
This commit is contained in:
+5
-3
@@ -7,16 +7,18 @@ import { PaymentStatusEnum } from '../src/domain/gateway/enums/payment-status.en
|
||||
import { PaymentTypeEnum, PaymentDirectionEnum, getPaymentDirection } from '../src/domain/gateway/enums/payment-type.enum';
|
||||
import type { PaymentDomainInterface } from '../src/domain/gateway/interfaces/payment-domain.interface';
|
||||
import { sha256 } from '../src/utils/sha256';
|
||||
import { generator } from '../src/services/document.service';
|
||||
|
||||
export default {
|
||||
name: 'Миграция платежей из MongoDB в PostgreSQL (унифицированная модель)',
|
||||
isTest: true, // Включаем тестовый режим
|
||||
validUntil: new Date('2024-12-31'), // Действует до конца года
|
||||
validUntil: new Date('2025-07-03'), // Действует до
|
||||
|
||||
async up(): Promise<boolean> {
|
||||
console.log('Выполнение миграции: Перенос платежей из MongoDB в PostgreSQL (унифицированная модель)');
|
||||
|
||||
try {
|
||||
await generator.connect(config.mongoose.url);
|
||||
|
||||
// Инициализируем подключение к PostgreSQL
|
||||
const dataSource = new DataSource({
|
||||
type: 'postgres',
|
||||
@@ -36,7 +38,7 @@ export default {
|
||||
const paymentRepository = new TypeOrmPaymentRepository(dataSource.getRepository(PaymentEntity));
|
||||
|
||||
// Получаем все заказы из MongoDB
|
||||
const orders = await Order.find().populate('user');
|
||||
const orders = await Order.find();
|
||||
console.log(`Найдено ${orders.length} заказов в MongoDB`);
|
||||
|
||||
let migratedCount = 0;
|
||||
@@ -145,9 +145,7 @@ export class MigrationManager {
|
||||
});
|
||||
}
|
||||
|
||||
async runMigration(migration: Migration, version: string, description: string): Promise<boolean> {
|
||||
const isTest = version.includes('__test');
|
||||
|
||||
async runMigration(migration: Migration, version: string, description: string, isTest: boolean): Promise<boolean> {
|
||||
try {
|
||||
if (isTest) {
|
||||
logger.info(`[ТЕСТОВАЯ МИГРАЦИЯ] Запуск миграции ${version} (${description}): ${migration.name}`);
|
||||
@@ -157,7 +155,11 @@ export class MigrationManager {
|
||||
|
||||
// Предоставляем блокчейн-сервис в миграцию
|
||||
const result = await migration.up({ blockchain: this.blockchainService });
|
||||
await this.markMigrationAsApplied(version, migration.name, result, isTest);
|
||||
|
||||
// Отмечаем как примененную только если миграция успешна И не является тестовой
|
||||
if (result && !isTest) {
|
||||
await this.markMigrationAsApplied(version, migration.name, true, false);
|
||||
}
|
||||
|
||||
if (isTest) {
|
||||
logger.info(
|
||||
@@ -170,7 +172,12 @@ export class MigrationManager {
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error(`Ошибка при выполнении миграции ${version} (${description}):`, error);
|
||||
await this.markMigrationAsApplied(version, migration.name, false, isTest);
|
||||
|
||||
// Отмечаем как неуспешную только если это НЕ тестовая миграция
|
||||
if (!isTest) {
|
||||
await this.markMigrationAsApplied(version, migration.name, false, false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -230,9 +237,10 @@ export class MigrationManager {
|
||||
}
|
||||
|
||||
// Запускаем миграцию
|
||||
const success = await this.runMigration(migration, version, description);
|
||||
const success = await this.runMigration(migration, version, description, isTest);
|
||||
|
||||
if (!success) {
|
||||
// Останавливаем процесс только при ошибке в НЕ тестовых миграциях
|
||||
if (!success && !isTest) {
|
||||
logger.error(`Миграция ${version} (${description}) завершена с ошибкой, останавливаем процесс`);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
<template lang="pug">
|
||||
q-page.padding
|
||||
ListOfDocumentsWidget(
|
||||
:username="coopname"
|
||||
:filter="{}"
|
||||
:showFilter="true"
|
||||
:initialDocumentType="typeForToggle"
|
||||
:username='coopname',
|
||||
:filter='{}',
|
||||
:showFilter='false',
|
||||
:initialDocumentType='typeForToggle'
|
||||
)
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useSystemStore } from 'src/entities/System/model'
|
||||
import { ListOfDocumentsWidget } from 'src/widgets/Cooperative/Documents/ListOfDocuments/ui'
|
||||
import type { DocumentType } from 'src/entities/Document/model/types'
|
||||
import { ref, computed } from 'vue';
|
||||
import { useSystemStore } from 'src/entities/System/model';
|
||||
import { ListOfDocumentsWidget } from 'src/widgets/Cooperative/Documents/ListOfDocuments/ui';
|
||||
import type { DocumentType } from 'src/entities/Document/model/types';
|
||||
|
||||
// Получаем системную информацию
|
||||
const { info } = useSystemStore()
|
||||
const coopname = computed(() => info.coopname)
|
||||
const { info } = useSystemStore();
|
||||
const coopname = computed(() => info.coopname);
|
||||
|
||||
// Переменная для отслеживания типа в интерфейсе
|
||||
const typeForToggle = ref<DocumentType>('newsubmitted')
|
||||
|
||||
const typeForToggle = ref<DocumentType>('newresolved');
|
||||
</script>
|
||||
|
||||
@@ -172,7 +172,6 @@ const shadowStyles = computed(
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f4f4f4;
|
||||
width: 30% !important;
|
||||
max-width: 30% !important;
|
||||
word-break: break-word !important;
|
||||
@@ -219,7 +218,6 @@ const shadowStyles = computed(
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f4f4f4;
|
||||
width: 30% !important;
|
||||
max-width: 30% !important;
|
||||
word-break: break-word !important;
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
width: 100%;
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||
background-color: var(--q-surface);
|
||||
|
||||
.q-dark & {
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +22,7 @@
|
||||
|
||||
.q-dark & {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@@ -38,7 +40,7 @@
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.q-dark & {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,10 +50,12 @@
|
||||
border-radius: 16px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||
background-color: var(--q-surface);
|
||||
|
||||
.q-dark & {
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
@@ -82,10 +86,12 @@
|
||||
border-radius: 16px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||
background-color: var(--q-surface);
|
||||
|
||||
.q-dark & {
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
@@ -114,7 +120,7 @@
|
||||
|
||||
.q-dark & {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@@ -127,7 +133,7 @@
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.q-dark & {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,12 +54,19 @@ const meetStatus = useMeetStatus(props.meet);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
// Дополнительная стилизация для темной темы
|
||||
.q-dark & {
|
||||
background-color: rgba(255, 255, 255, 0.07) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.25) !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
|
||||
|
||||
.q-dark & {
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
|
||||
background-color: rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
.balance-card {
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
"prepublishOnly": "nr build",
|
||||
"release": "bumpp && npm publish",
|
||||
"test": "vitest --dir test --testTimeout=240000 --exclude documents --watch=false",
|
||||
"typecheck": "tsc --noEmit"
|
||||
"typecheck": "tsc --noEmit",
|
||||
"setup-indexes": "tsx scripts/setup-indexes.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "^8.13.0",
|
||||
|
||||
@@ -17,6 +17,11 @@ export class SearchService {
|
||||
this.storage = storage
|
||||
}
|
||||
|
||||
// Экранирование специальных символов регулярных выражений
|
||||
private escapeRegex(text: string): string {
|
||||
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||
}
|
||||
|
||||
async search(query: string): Promise<ISearchResult[]> {
|
||||
if (!query || query.trim().length === 0) {
|
||||
return []
|
||||
@@ -25,35 +30,45 @@ export class SearchService {
|
||||
const results: ISearchResult[] = []
|
||||
const trimmedQuery = query.trim()
|
||||
|
||||
// Создаем регулярное выражение для поиска без учета регистра
|
||||
const regex = new RegExp(trimmedQuery, 'i')
|
||||
console.log(`[SearchService] Поиск по запросу: "${trimmedQuery}"`)
|
||||
|
||||
// Экранируем специальные символы для безопасного использования в regex
|
||||
const escapedQuery = this.escapeRegex(trimmedQuery)
|
||||
|
||||
// Разбиваем запрос на слова для поиска по полному ФИО
|
||||
const queryWords = trimmedQuery.split(/\s+/).filter(word => word.length > 0)
|
||||
|
||||
try {
|
||||
// Поиск в коллекции individuals
|
||||
const individualResults = await this.searchIndividuals(regex, queryWords)
|
||||
console.log(`[SearchService] Поиск в individuals...`)
|
||||
const individualResults = await this.searchIndividuals(escapedQuery, queryWords, trimmedQuery)
|
||||
console.log(`[SearchService] Найдено individuals: ${individualResults.length}`)
|
||||
results.push(...individualResults)
|
||||
|
||||
// Поиск в коллекции entrepreneurs
|
||||
const entrepreneurResults = await this.searchEntrepreneurs(regex, queryWords)
|
||||
console.log(`[SearchService] Поиск в entrepreneurs...`)
|
||||
const entrepreneurResults = await this.searchEntrepreneurs(escapedQuery, queryWords, trimmedQuery)
|
||||
console.log(`[SearchService] Найдено entrepreneurs: ${entrepreneurResults.length}`)
|
||||
results.push(...entrepreneurResults)
|
||||
|
||||
// Поиск в коллекции organizations
|
||||
const organizationResults = await this.searchOrganizations(regex)
|
||||
console.log(`[SearchService] Поиск в organizations...`)
|
||||
const organizationResults = await this.searchOrganizations(escapedQuery)
|
||||
console.log(`[SearchService] Найдено organizations: ${organizationResults.length}`)
|
||||
results.push(...organizationResults)
|
||||
|
||||
console.log(`[SearchService] Общее количество результатов: ${results.length}`)
|
||||
|
||||
// Ограничиваем общее количество результатов до 10
|
||||
return results.slice(0, 10)
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error during search:', error)
|
||||
console.error('[SearchService] Ошибка при поиске:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
private async searchIndividuals(regex: RegExp, queryWords: string[]): Promise<ISearchResult[]> {
|
||||
private async searchIndividuals(regexPattern: string, queryWords: string[], originalQuery: string): Promise<ISearchResult[]> {
|
||||
const individualModel = new Individual(this.storage)
|
||||
const results: ISearchResult[] = []
|
||||
|
||||
@@ -66,16 +81,16 @@ export class SearchService {
|
||||
deleted: false,
|
||||
$or: [
|
||||
// Поиск по отдельным полям
|
||||
{ first_name: { $regex: regex } },
|
||||
{ last_name: { $regex: regex } },
|
||||
{ middle_name: { $regex: regex } },
|
||||
{ first_name: { $regex: regexPattern, $options: 'i' } },
|
||||
{ last_name: { $regex: regexPattern, $options: 'i' } },
|
||||
{ middle_name: { $regex: regexPattern, $options: 'i' } },
|
||||
// Поиск по полному ФИО (все слова должны быть найдены)
|
||||
{
|
||||
$and: queryWords.map(word => ({
|
||||
$or: [
|
||||
{ first_name: { $regex: new RegExp(word, 'i') } },
|
||||
{ last_name: { $regex: new RegExp(word, 'i') } },
|
||||
{ middle_name: { $regex: new RegExp(word, 'i') } },
|
||||
{ first_name: { $regex: this.escapeRegex(word), $options: 'i' } },
|
||||
{ last_name: { $regex: this.escapeRegex(word), $options: 'i' } },
|
||||
{ middle_name: { $regex: this.escapeRegex(word), $options: 'i' } },
|
||||
],
|
||||
})),
|
||||
},
|
||||
@@ -87,28 +102,40 @@ export class SearchService {
|
||||
filter = {
|
||||
deleted: false,
|
||||
$or: [
|
||||
{ first_name: { $regex: regex } },
|
||||
{ last_name: { $regex: regex } },
|
||||
{ middle_name: { $regex: regex } },
|
||||
{ first_name: { $regex: regexPattern, $options: 'i' } },
|
||||
{ last_name: { $regex: regexPattern, $options: 'i' } },
|
||||
{ middle_name: { $regex: regexPattern, $options: 'i' } },
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[SearchService] Фильтр для individuals:`, JSON.stringify(filter, null, 2))
|
||||
|
||||
const individuals = await individualModel.getMany(filter)
|
||||
|
||||
console.log(`[SearchService] Результаты поиска individuals:`, {
|
||||
total: individuals.totalResults,
|
||||
found: individuals.results.length,
|
||||
query: originalQuery,
|
||||
names: individuals.results.map(ind => `${ind.last_name} ${ind.first_name} ${ind.middle_name || ''} (deleted: ${ind.deleted || false})`),
|
||||
})
|
||||
|
||||
for (const individual of individuals.results) {
|
||||
const highlightedFields = []
|
||||
|
||||
// Создаем RegExp для проверки подсветки
|
||||
const testRegex = new RegExp(regexPattern, 'i')
|
||||
|
||||
// Проверяем отдельные поля
|
||||
if (regex.test(individual.first_name))
|
||||
if (individual.first_name && testRegex.test(individual.first_name))
|
||||
highlightedFields.push('first_name')
|
||||
if (regex.test(individual.last_name))
|
||||
if (individual.last_name && testRegex.test(individual.last_name))
|
||||
highlightedFields.push('last_name')
|
||||
if (regex.test(individual.middle_name))
|
||||
if (individual.middle_name && testRegex.test(individual.middle_name))
|
||||
highlightedFields.push('middle_name')
|
||||
|
||||
// Проверяем полное ФИО
|
||||
const fullName = `${individual.last_name} ${individual.first_name} ${individual.middle_name}`.trim()
|
||||
const fullName = `${individual.last_name || ''} ${individual.first_name || ''} ${individual.middle_name || ''}`.trim()
|
||||
if (this.matchesFullName(fullName, queryWords)) {
|
||||
highlightedFields.push('full_name')
|
||||
}
|
||||
@@ -123,7 +150,7 @@ export class SearchService {
|
||||
return results
|
||||
}
|
||||
|
||||
private async searchEntrepreneurs(regex: RegExp, queryWords: string[]): Promise<ISearchResult[]> {
|
||||
private async searchEntrepreneurs(regexPattern: string, queryWords: string[], originalQuery: string): Promise<ISearchResult[]> {
|
||||
const entrepreneurModel = new Entrepreneur(this.storage)
|
||||
const results: ISearchResult[] = []
|
||||
|
||||
@@ -136,18 +163,18 @@ export class SearchService {
|
||||
deleted: false,
|
||||
$or: [
|
||||
// Поиск по отдельным полям
|
||||
{ first_name: { $regex: regex } },
|
||||
{ last_name: { $regex: regex } },
|
||||
{ middle_name: { $regex: regex } },
|
||||
{ 'details.inn': { $regex: regex } },
|
||||
{ 'details.ogrn': { $regex: regex } },
|
||||
{ first_name: { $regex: regexPattern, $options: 'i' } },
|
||||
{ last_name: { $regex: regexPattern, $options: 'i' } },
|
||||
{ middle_name: { $regex: regexPattern, $options: 'i' } },
|
||||
{ 'details.inn': { $regex: regexPattern, $options: 'i' } },
|
||||
{ 'details.ogrn': { $regex: regexPattern, $options: 'i' } },
|
||||
// Поиск по полному ФИО
|
||||
{
|
||||
$and: queryWords.map(word => ({
|
||||
$or: [
|
||||
{ first_name: { $regex: new RegExp(word, 'i') } },
|
||||
{ last_name: { $regex: new RegExp(word, 'i') } },
|
||||
{ middle_name: { $regex: new RegExp(word, 'i') } },
|
||||
{ first_name: { $regex: this.escapeRegex(word), $options: 'i' } },
|
||||
{ last_name: { $regex: this.escapeRegex(word), $options: 'i' } },
|
||||
{ middle_name: { $regex: this.escapeRegex(word), $options: 'i' } },
|
||||
],
|
||||
})),
|
||||
},
|
||||
@@ -159,34 +186,46 @@ export class SearchService {
|
||||
filter = {
|
||||
deleted: false,
|
||||
$or: [
|
||||
{ first_name: { $regex: regex } },
|
||||
{ last_name: { $regex: regex } },
|
||||
{ middle_name: { $regex: regex } },
|
||||
{ 'details.inn': { $regex: regex } },
|
||||
{ 'details.ogrn': { $regex: regex } },
|
||||
{ first_name: { $regex: regexPattern, $options: 'i' } },
|
||||
{ last_name: { $regex: regexPattern, $options: 'i' } },
|
||||
{ middle_name: { $regex: regexPattern, $options: 'i' } },
|
||||
{ 'details.inn': { $regex: regexPattern, $options: 'i' } },
|
||||
{ 'details.ogrn': { $regex: regexPattern, $options: 'i' } },
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[SearchService] Фильтр для entrepreneurs:`, JSON.stringify(filter, null, 2))
|
||||
|
||||
const entrepreneurs = await entrepreneurModel.getMany(filter)
|
||||
|
||||
console.log(`[SearchService] Результаты поиска entrepreneurs:`, {
|
||||
total: entrepreneurs.totalResults,
|
||||
found: entrepreneurs.results.length,
|
||||
query: originalQuery,
|
||||
names: entrepreneurs.results.map(ent => `${ent.last_name} ${ent.first_name} ${ent.middle_name || ''} (deleted: ${ent.deleted || false})`),
|
||||
})
|
||||
|
||||
for (const entrepreneur of entrepreneurs.results) {
|
||||
const highlightedFields = []
|
||||
|
||||
// Создаем RegExp для проверки подсветки
|
||||
const testRegex = new RegExp(regexPattern, 'i')
|
||||
|
||||
// Проверяем отдельные поля
|
||||
if (regex.test(entrepreneur.first_name))
|
||||
if (entrepreneur.first_name && testRegex.test(entrepreneur.first_name))
|
||||
highlightedFields.push('first_name')
|
||||
if (regex.test(entrepreneur.last_name))
|
||||
if (entrepreneur.last_name && testRegex.test(entrepreneur.last_name))
|
||||
highlightedFields.push('last_name')
|
||||
if (regex.test(entrepreneur.middle_name))
|
||||
if (entrepreneur.middle_name && testRegex.test(entrepreneur.middle_name))
|
||||
highlightedFields.push('middle_name')
|
||||
if (entrepreneur.details?.inn && regex.test(entrepreneur.details.inn))
|
||||
if (entrepreneur.details?.inn && testRegex.test(entrepreneur.details.inn))
|
||||
highlightedFields.push('details.inn')
|
||||
if (entrepreneur.details?.ogrn && regex.test(entrepreneur.details.ogrn))
|
||||
if (entrepreneur.details?.ogrn && testRegex.test(entrepreneur.details.ogrn))
|
||||
highlightedFields.push('details.ogrn')
|
||||
|
||||
// Проверяем полное ФИО
|
||||
const fullName = `${entrepreneur.last_name} ${entrepreneur.first_name} ${entrepreneur.middle_name}`.trim()
|
||||
const fullName = `${entrepreneur.last_name || ''} ${entrepreneur.first_name || ''} ${entrepreneur.middle_name || ''}`.trim()
|
||||
if (this.matchesFullName(fullName, queryWords)) {
|
||||
highlightedFields.push('full_name')
|
||||
}
|
||||
@@ -201,27 +240,30 @@ export class SearchService {
|
||||
return results
|
||||
}
|
||||
|
||||
private async searchOrganizations(regex: RegExp): Promise<ISearchResult[]> {
|
||||
private async searchOrganizations(regexPattern: string): Promise<ISearchResult[]> {
|
||||
const organizationModel = new Organization(this.storage)
|
||||
const results: ISearchResult[] = []
|
||||
|
||||
const organizations = await organizationModel.getMany({
|
||||
deleted: false,
|
||||
$or: [
|
||||
{ short_name: { $regex: regex } },
|
||||
{ 'details.inn': { $regex: regex } },
|
||||
{ 'details.ogrn': { $regex: regex } },
|
||||
{ short_name: { $regex: regexPattern, $options: 'i' } },
|
||||
{ 'details.inn': { $regex: regexPattern, $options: 'i' } },
|
||||
{ 'details.ogrn': { $regex: regexPattern, $options: 'i' } },
|
||||
],
|
||||
})
|
||||
|
||||
for (const organization of organizations.results) {
|
||||
const highlightedFields = []
|
||||
|
||||
if (regex.test(organization.short_name))
|
||||
// Создаем RegExp для проверки подсветки
|
||||
const testRegex = new RegExp(regexPattern, 'i')
|
||||
|
||||
if (testRegex.test(organization.short_name))
|
||||
highlightedFields.push('short_name')
|
||||
if (organization.details?.inn && regex.test(organization.details.inn))
|
||||
if (organization.details?.inn && testRegex.test(organization.details.inn))
|
||||
highlightedFields.push('details.inn')
|
||||
if (organization.details?.ogrn && regex.test(organization.details.ogrn))
|
||||
if (organization.details?.ogrn && testRegex.test(organization.details.ogrn))
|
||||
highlightedFields.push('details.ogrn')
|
||||
|
||||
results.push({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION: v2025.6.14
|
||||
FROM DATE: 2025-05-14 (10:00 - это для нового релиза, TODO: учесть время)
|
||||
FROM DATE: 2025-05-14T10:00:00+03:00
|
||||
COMMENT:
|
||||
Реализован модуль проведения очередных общих собраний пайщиков.
|
||||
|
||||
Reference in New Issue
Block a user