fix(agenda): resolve program-agreement links via soviet::newresolved, not wallet::signagree
Typecheck / desktop (pull_request) Failing after 6m47s
Typecheck / controller (pull_request) Has been cancelled

Прошлый фикс менял receiver=coopname на data.coopname прямо в explorer-запросе
к wallet::signagree — рабочий, но не объясняющий, почему стандартный
receiver-фильтр не подходил именно здесь: wallet::signagree не делает
require_recipient(coopname) сам по себе, поэтому explorer индексирует его
только под receiver='wallet'.

На самом деле уведомление уже существует и не требует правки контракта:
Soviet::make_complete_document (lib/core/soviet/soviet.hpp) на КАЖДЫЙ вызов —
из soviet::sndagreement И из wallet::signagree одинаково — шлёт inline
soviet::newresolved/newsubmitted, а require_recipient(coopname/username)
зашит централизованно внутри самих newresolved.cpp/newsubmitted.cpp
(soviet/src/doc/*.cpp). Проверено на живом хэше оферты Благорост: newresolved
уже приходит с receiver=voskhod, receiver=veszmgpjteqs, receiver=soviet — без
единой правки на контрактах.

Правильный fallback для findLinkedAgreementDocument — искать soviet::newresolved
(с обычным receiver=coopname, как везде), а не действие wallet::signagree
напрямую (у которого никакого receiver-уведомления и не предполагалось).
Расширять notification-поверхность wallet::signagree не нужно — единственное
место для этого уже newresolved.cpp/newsubmitted.cpp.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
coopops
2026-07-19 13:48:57 +00:00
parent 1c605dd2a5
commit 2cfb37c5d7
@@ -6,7 +6,7 @@ import {
UserCertificateDomainService,
USER_CERTIFICATE_DOMAIN_SERVICE,
} from '~/domain/user/services/user-certificate-domain.service';
import { Cooperative, SovietContract, WalletContract } from 'cooptypes';
import { Cooperative, SovietContract } from 'cooptypes';
import { getActions } from '~/utils/getFetch';
import type { DocumentPackageAggregateDomainInterface } from '../interfaces/document-package-aggregate-domain.interface';
import type { StatementDetailAggregateDomainInterface } from '../interfaces/statement-detail-aggregate-domain.interface';
@@ -298,9 +298,17 @@ export class DocumentPackageV1Aggregator {
/**
* Находит on-chain действие-носитель подписанного связанного документа по doc_hash.
* Сначала ищет в реестре соглашений совета (soviet::newagreement), затем —
* в программных подписях кошелька (wallet::signagree). Возвращает поле document
* найденного действия либо null.
* Сначала ищет в реестре соглашений совета (soviet::newagreement — второе,
* явное уведомление, которое дополнительно шлёт soviet::sndagreement), затем —
* в общем уведомлении о завершённом документе (soviet::newresolved), которое
* централизованно шлёт make_complete_document (lib/core/soviet/soviet.hpp) на
* КАЖДЫЙ вызов — и из soviet::sndagreement, и из wallet::signagree — с
* require_recipient(coopname), заданным один раз внутри newresolved.cpp.
* Программные оферты (capital: Благорост/Генератор, program_id>0) идут через
* wallet::signagree и не порождают newagreement, но newresolved у них есть
* всегда — расширять notification-поверхность самого wallet::signagree не
* нужно, единственное место для этого уже newresolved.cpp.
* Возвращает поле document найденного действия либо null.
*/
private async findLinkedAgreementDocument(
linkHash: string
@@ -321,25 +329,19 @@ export class DocumentPackageV1Aggregator {
const sovietDocument = sovietAgreement?.results?.[0]?.data?.document;
if (sovietDocument) return sovietDocument;
// wallet::signagree не делает require_recipient(coopname) (в отличие от
// Soviet::make_complete_document), поэтому explorer индексирует его только
// с receiver='wallet' — фильтр по receiver=coopname здесь всегда возвращал
// 0 строк, и программные оферты (capital: Благорост/Генератор, program_id>0)
// молча пропадали из links повестки. Скоуп по кооперативу берём из
// data.coopname — единственного надёжного поля в самом payload действия.
const walletAgreement = await getActions(`${process.env.SIMPLE_EXPLORER_API}/get-actions`, {
const resolvedAgreement = await getActions(`${process.env.SIMPLE_EXPLORER_API}/get-actions`, {
filter: JSON.stringify({
account: WalletContract.contractName.production,
name: WalletContract.Actions.SignAgreement.actionName,
'data.coopname': process.env.COOPNAME,
account: SovietContract.contractName.production,
name: SovietContract.Actions.Registry.NewResolved.actionName,
receiver: process.env.COOPNAME,
'data.document.doc_hash': docHashFilter,
}),
page: 1,
limit: 1,
});
const walletDocument = walletAgreement?.results?.[0]?.data?.document;
if (walletDocument) return walletDocument;
const resolvedDocument = resolvedAgreement?.results?.[0]?.data?.document;
if (resolvedDocument) return resolvedDocument;
return null;
}