fix(whatsapp-inbox): name both ways to route receipts for multi-company senders (#1424)

Field feedback after the first live receipt: the link confirmation told a
multi-company sender only to set a default company in the panel, so the
per-receipt path looked unsupported even though it is the one that
actually runs when no default is set. Now it names both: set a default,
or send one receipt at a time and answer the company question after each.

The guidance also moves to its own paragraph. Run together with the AI
disclosure it read as one sentence, which is how a real user came away
believing the bot had called itself a "mänsklig AI-assistent".

New copy test asserts the promise (both options present, disclosure kept
in its own paragraph, single-company message unchanged) rather than the
exact wording, so a rewrite stays free but a dropped option fails.
Mutation-checked against the previous copy.

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-08-05 19:43:37 +02:00
committed by GitHub
parent 77d20287b9
commit c84f951a5c
2 changed files with 44 additions and 2 deletions
@@ -0,0 +1,37 @@
import { describe, it, expect } from 'vitest'
import { botCopy } from '@/extensions/general/whatsapp-inbox/lib/messages'
/**
* Copy contracts that a rewrite must not quietly break. These assert the
* PROMISE the message makes to the user, not its exact wording: rephrasing
* is fine, dropping one of the two routing options is not.
*/
describe('m3Linked, multi-company sender', () => {
for (const locale of ['sv', 'en'] as const) {
it(`${locale}: names BOTH ways to route receipts`, () => {
const msg = botCopy(locale).m3Linked({ companyName: 'Arcim Technology AB', companyCount: 7 })
// Option 1: a default company set in the panel.
expect(msg).toMatch(locale === 'sv' ? /standardföretag/i : /default company/i)
// Option 2: per receipt, answered right after each one. Field feedback
// 2026-08-05: the old copy named only option 1, which read as if the
// per-receipt path did not exist.
expect(msg).toMatch(locale === 'sv' ? /ett kvitto i taget/i : /one receipt at a time/i)
})
it(`${locale}: keeps the routing guidance out of the AI-disclosure paragraph`, () => {
// Run together they read as a single sentence, which is how a real
// user mis-read the disclosure. Own paragraph, always.
const msg = botCopy(locale).m3Linked({ companyName: 'Arcim Technology AB', companyCount: 7 })
const disclosureParagraph = msg.split('\n\n').find((p) => /AI[- ]assistant|AI-assistent/i.test(p))
expect(disclosureParagraph).toBeDefined()
expect(disclosureParagraph).not.toMatch(/standardföretag|default company/i)
})
}
it('says nothing about company routing when the sender has exactly one company', () => {
const msg = botCopy('sv').m3Linked({ companyName: 'Arcim Technology AB', companyCount: 1 })
expect(msg).not.toMatch(/standardföretag/i)
expect(msg).toMatch(/AI-assistent/)
})
})
@@ -77,9 +77,13 @@ const SV = {
'Två tips: skicka som _dokument_ (gem-ikonen) för bästa skärpa, och en fil per kvitto. Flersidiga kvitton skickas som PDF.'
const outro =
'Jag är en AI-assistent. Skriv *hjälp* för mänsklig support, *stopp* för att koppla från.'
// Two real ways to route a receipt, and the old copy named only one,
// which read as if the per-receipt path did not exist. Own paragraph:
// run together with the outro it read as a single sentence.
const multi =
companyCount > 1
? `Du är med i ${companyCount} företag i Accounted. Välj standardföretag i panelen så hamnar kvitton rätt. `
? `Du är med i ${companyCount} företag i Accounted. Välj antingen ett standardföretag i panelen, ` +
'eller skicka ett kvitto i taget så frågar jag vilket företag det gäller direkt efter varje kvitto.\n\n'
: ''
return `${intro}\n\n${tips}\n\n${multi}${outro}`
},
@@ -206,7 +210,8 @@ const EN: typeof SV = {
'I am an AI assistant. Type *hjälp* for human support, *stopp* to disconnect.'
const multi =
companyCount > 1
? `You belong to ${companyCount} companies in Accounted. Pick a default company in the panel so receipts land in the right one. `
? `You belong to ${companyCount} companies in Accounted. Either pick a default company in the panel, ` +
'or send one receipt at a time and I will ask which company it belongs to right after each one.\n\n'
: ''
return `${intro}\n\n${tips}\n\n${multi}${outro}`
},