fix(bot): refresh setup checklist after manual binds

This commit is contained in:
2026-03-11 11:23:33 +04:00
parent dd243d7edd
commit 4cd5622d63
5 changed files with 85 additions and 14 deletions

View File

@@ -810,11 +810,11 @@ describe('registerHouseholdSetupCommands', () => {
], ],
[ [
{ {
text: 'Create purchases', text: 'Create purchases topic',
callback_data: 'setup_topic:create:purchase' callback_data: 'setup_topic:create:purchase'
}, },
{ {
text: 'Bind purchases', text: 'Bind purchases topic',
callback_data: 'setup_topic:bind:purchase' callback_data: 'setup_topic:bind:purchase'
} }
] ]
@@ -1060,15 +1060,24 @@ describe('registerHouseholdSetupCommands', () => {
expect(await promptRepository.getPendingAction('-100123456', '123456')).toMatchObject({ expect(await promptRepository.getPendingAction('-100123456', '123456')).toMatchObject({
action: 'setup_topic_binding', action: 'setup_topic_binding',
payload: { payload: {
role: 'payments' role: 'payments',
setupMessageId: 91
} }
}) })
calls.length = 0 calls.length = 0
await bot.handleUpdate(topicMessageUpdate('hello from payments', 444) as never) await bot.handleUpdate(topicMessageUpdate('hello from payments', 444) as never)
expect(calls).toHaveLength(2) expect(calls).toHaveLength(3)
expect(calls[1]).toMatchObject({ expect(calls[1]).toMatchObject({
method: 'editMessageText',
payload: {
chat_id: -100123456,
message_id: 91,
text: expect.stringContaining('- payments: bound to thread 444')
}
})
expect(calls[2]).toMatchObject({
method: 'sendMessage', method: 'sendMessage',
payload: { payload: {
chat_id: -100123456, chat_id: -100123456,

View File

@@ -321,12 +321,20 @@ function isHouseholdTopicRole(value: string): value is HouseholdTopicRole {
function parseSetupBindPayload(payload: Record<string, unknown>): { function parseSetupBindPayload(payload: Record<string, unknown>): {
role: HouseholdTopicRole role: HouseholdTopicRole
setupMessageId?: number
} | null { } | null {
return typeof payload.role === 'string' && isHouseholdTopicRole(payload.role) if (typeof payload.role !== 'string' || !isHouseholdTopicRole(payload.role)) {
? { return null
role: payload.role }
}
: null return {
role: payload.role,
...(typeof payload.setupMessageId === 'number' && Number.isInteger(payload.setupMessageId)
? {
setupMessageId: payload.setupMessageId
}
: {})
}
} }
export function buildJoinMiniAppUrl( export function buildJoinMiniAppUrl(
@@ -527,6 +535,22 @@ export function registerHouseholdSetupCommands(options: {
return return
} }
if (payload.setupMessageId && options.householdConfigurationRepository) {
const reply = await buildSetupReplyForHousehold({
ctx,
locale,
household: result.household,
created: false
})
await ctx.api.editMessageText(
Number(telegramChatId),
payload.setupMessageId,
reply.text,
'reply_markup' in reply ? { reply_markup: reply.reply_markup } : {}
)
}
await ctx.reply( await ctx.reply(
bindTopicSuccessMessage( bindTopicSuccessMessage(
locale, locale,
@@ -1027,7 +1051,12 @@ export function registerHouseholdSetupCommands(options: {
telegramChatId, telegramChatId,
action: SETUP_BIND_TOPIC_ACTION, action: SETUP_BIND_TOPIC_ACTION,
payload: { payload: {
role role,
...(ctx.msg
? {
setupMessageId: ctx.msg.message_id
}
: {})
}, },
expiresAt: nowInstant().add({ milliseconds: SETUP_BIND_TOPIC_TTL_MS }) expiresAt: nowInstant().add({ milliseconds: SETUP_BIND_TOPIC_TTL_MS })
}) })

View File

@@ -60,8 +60,8 @@ export const enBotTranslations: BotTranslationCatalog = {
setupTopicsHeading: 'Topic setup:', setupTopicsHeading: 'Topic setup:',
setupTopicBound: (role, topic) => `- ${role}: bound to ${topic}`, setupTopicBound: (role, topic) => `- ${role}: bound to ${topic}`,
setupTopicMissing: (role) => `- ${role}: not configured`, setupTopicMissing: (role) => `- ${role}: not configured`,
setupTopicCreateButton: (role) => `Create ${role}`, setupTopicCreateButton: (role) => `Create ${role} topic`,
setupTopicBindButton: (role) => `Bind ${role}`, setupTopicBindButton: (role) => `Bind ${role} topic`,
setupTopicCreateFailed: setupTopicCreateFailed:
'I could not create that topic. Check bot admin permissions and forum settings.', 'I could not create that topic. Check bot admin permissions and forum settings.',
setupTopicCreateForbidden: setupTopicCreateForbidden:
@@ -260,8 +260,20 @@ export const enBotTranslations: BotTranslationCatalog = {
payments: { payments: {
topicMissing: topicMissing:
'Payments topic is not configured for this household yet. Ask an admin to run /bind_payments_topic.', 'Payments topic is not configured for this household yet. Ask an admin to run /bind_payments_topic.',
proposal: (kind, amount, currency) =>
`I can record this ${kind === 'rent' ? 'rent' : 'utilities'} payment: ${amount} ${currency}. Confirm or cancel below.`,
clarification:
'I could not confirm this payment yet. Please clarify whether this was rent or utilities and include the amount/currency if needed.',
unsupportedCurrency:
'I can only record payments in the household settlement currency for this topic right now.',
noBalance: 'There is no payable balance for that payment type right now.',
confirmButton: 'Confirm payment',
cancelButton: 'Cancel',
recorded: (kind, amount, currency) => recorded: (kind, amount, currency) =>
`Recorded ${kind === 'rent' ? 'rent' : 'utilities'} payment: ${amount} ${currency}`, `Recorded ${kind === 'rent' ? 'rent' : 'utilities'} payment: ${amount} ${currency}`,
cancelled: 'Payment proposal cancelled.',
proposalUnavailable: 'This payment proposal is no longer available.',
notYourProposal: 'Only the original sender can confirm or cancel this payment.',
savedForReview: 'Saved this payment confirmation for review.', savedForReview: 'Saved this payment confirmation for review.',
duplicate: 'This payment confirmation was already processed.' duplicate: 'This payment confirmation was already processed.'
} }

View File

@@ -62,8 +62,8 @@ export const ruBotTranslations: BotTranslationCatalog = {
setupTopicsHeading: 'Настройка топиков:', setupTopicsHeading: 'Настройка топиков:',
setupTopicBound: (role, topic) => `- ${role}: привязан к ${topic}`, setupTopicBound: (role, topic) => `- ${role}: привязан к ${topic}`,
setupTopicMissing: (role) => `- ${role}: не настроен`, setupTopicMissing: (role) => `- ${role}: не настроен`,
setupTopicCreateButton: (role) => `Создать ${role}`, setupTopicCreateButton: (role) => `Создать топик для ${role}`,
setupTopicBindButton: (role) => `Привязать ${role}`, setupTopicBindButton: (role) => `Привязать топик для ${role}`,
setupTopicCreateFailed: setupTopicCreateFailed:
'Не удалось создать этот топик. Проверьте права бота и включённые форум-топики в группе.', 'Не удалось создать этот топик. Проверьте права бота и включённые форум-топики в группе.',
setupTopicCreateForbidden: setupTopicCreateForbidden:
@@ -263,8 +263,20 @@ export const ruBotTranslations: BotTranslationCatalog = {
payments: { payments: {
topicMissing: topicMissing:
'Для этого дома ещё не настроен топик оплат. Попросите админа выполнить /bind_payments_topic.', 'Для этого дома ещё не настроен топик оплат. Попросите админа выполнить /bind_payments_topic.',
proposal: (kind, amount, currency) =>
`Я могу записать эту оплату ${kind === 'rent' ? 'аренды' : 'коммуналки'}: ${amount} ${currency}. Подтвердите или отмените ниже.`,
clarification:
'Пока не могу подтвердить эту оплату. Уточните, это аренда или коммуналка, и при необходимости напишите сумму и валюту.',
unsupportedCurrency:
'Сейчас я могу записывать оплаты в этом топике только в валюте расчётов по дому.',
noBalance: 'Сейчас для этого типа оплаты нет суммы к подтверждению.',
confirmButton: 'Подтвердить оплату',
cancelButton: 'Отменить',
recorded: (kind, amount, currency) => recorded: (kind, amount, currency) =>
`Оплата ${kind === 'rent' ? 'аренды' : 'коммуналки'} сохранена: ${amount} ${currency}`, `Оплата ${kind === 'rent' ? 'аренды' : 'коммуналки'} сохранена: ${amount} ${currency}`,
cancelled: 'Предложение оплаты отменено.',
proposalUnavailable: 'Это предложение оплаты уже недоступно.',
notYourProposal: 'Подтвердить или отменить эту оплату может только отправитель сообщения.',
savedForReview: 'Это подтверждение оплаты сохранено на проверку.', savedForReview: 'Это подтверждение оплаты сохранено на проверку.',
duplicate: 'Это подтверждение оплаты уже было обработано.' duplicate: 'Это подтверждение оплаты уже было обработано.'
} }

View File

@@ -249,6 +249,15 @@ export interface BotTranslationCatalog {
payments: { payments: {
topicMissing: string topicMissing: string
recorded: (kind: 'rent' | 'utilities', amount: string, currency: string) => string recorded: (kind: 'rent' | 'utilities', amount: string, currency: string) => string
proposal: (kind: 'rent' | 'utilities', amount: string, currency: string) => string
clarification: string
unsupportedCurrency: string
noBalance: string
confirmButton: string
cancelButton: string
cancelled: string
proposalUnavailable: string
notYourProposal: string
savedForReview: string savedForReview: string
duplicate: string duplicate: string
} }