diff --git a/server/finance/views.ts b/server/finance/views.ts index e2c31df..171c482 100644 --- a/server/finance/views.ts +++ b/server/finance/views.ts @@ -67,8 +67,11 @@ export async function ensureViews(): Promise { } if (incomeExists) { + // CREATE OR REPLACE VIEW не умеет менять типы столбцов (тип stavkands в источнике + // изменился text ↔ varchar) — пересоздаём view целиком. Зависимых объектов нет. + await query(`DROP VIEW IF EXISTS vw_income_effective`); await query(` - CREATE OR REPLACE VIEW vw_income_effective AS + CREATE VIEW vw_income_effective AS SELECT t.*, o.category_id as _override_category_id FROM "${config.incomeTable}" t LEFT JOIN income_category_overrides o ON o.record_id = t.id::text @@ -76,8 +79,9 @@ export async function ensureViews(): Promise { } if (expenseExists) { + await query(`DROP VIEW IF EXISTS vw_expense_effective`); await query(` - CREATE OR REPLACE VIEW vw_expense_effective AS + CREATE VIEW vw_expense_effective AS SELECT t.*, o.category_id as _override_category_id FROM "${config.expenseTable}" t LEFT JOIN expense_category_overrides o ON o.record_id = t.id::text diff --git a/server/storage/system.storage.ts b/server/storage/system.storage.ts index fba223b..a7dee02 100644 --- a/server/storage/system.storage.ts +++ b/server/storage/system.storage.ts @@ -489,7 +489,13 @@ export class SystemStorage extends RolesStorage { operation, createdAt: new Date(), }) - .onConflictDoNothing({ target: [embeddingQueue.organizationId, embeddingQueue.entityType, embeddingQueue.entityId] }); + .onConflictDoNothing({ + target: [embeddingQueue.organizationId, embeddingQueue.entityType, embeddingQueue.entityId], + // Уникальный индекс embedding_queue_pending_entity_idx частичный + // (WHERE processed_at IS NULL) — без этого предиката Postgres не находит + // подходящий constraint и весь INSERT падает с ошибкой. + where: isNull(embeddingQueue.processedAt), + }); } async getPendingEmbeddingQueue(