fix(slack): don't let one tap flatten a hand-made split
ci / lint-test (push) Successful in 43s

Splits on orders are made by hand, so a third participant or an uneven
share is a deliberate decision — and "Make it just me" deleted every
split row regardless. A one-tap button silently destroying an
arrangement made with more care than the tap that undid it is the same
failure shape as the rewrite that dropped `settled`.

Now it refuses when a participant other than the two consumers is
present, or when the share is not 50. Verified against the running stack:
a three-way split and a 70/30 both survive a press; a plain 50/50 still
toggles off and back on.

Also: the nudge reads share state instead of assuming false. Today a
freshly ingested order has no splits — the 140 that do were split by hand
after the backfill, not by a rule — but the label drives a destructive
button, so a wrong assumption there costs data rather than a cosmetic
error. One query is cheaper.
This commit is contained in:
2026-07-28 16:40:53 +10:00
parent 14d6b40578
commit 50c5b7c430
2 changed files with 37 additions and 4 deletions
+16 -2
View File
@@ -4,6 +4,7 @@ import { verifySlackSignature, participantForSlackUser } from "@/lib/slack-verif
import { nudgeBlocks, detailsModal } from "@/lib/slack-blocks";
import {
RATINGS,
OWNER_PARTICIPANT_ID,
SECOND_CONSUMER_ID,
merchantVerdict,
type Rating,
@@ -200,10 +201,23 @@ async function handleModalSubmit(payload: {
* 2026-01-09 — so there is no settled historical obligation to lose.
*/
async function toggleShare(transactionId: number) {
const existing = await queryRaw<{ participant_id: number }>(
`SELECT participant_id FROM transaction_splits WHERE transaction_id = $1`,
const existing = await queryRaw<{ participant_id: number; share_percent: string }>(
`SELECT participant_id, share_percent FROM transaction_splits WHERE transaction_id = $1`,
[transactionId]
);
// Refuse to touch an arrangement this button cannot express. Splits are made
// by hand here, so a third participant or an uneven share is deliberate — and
// a one-tap button that silently flattened it would destroy a decision made
// with more care than the tap that undid it.
const foreign = existing.filter(
(e) => e.participant_id !== SECOND_CONSUMER_ID && e.participant_id !== OWNER_PARTICIPANT_ID
);
const uneven = existing.some(
(e) => e.participant_id === SECOND_CONSUMER_ID && Number(e.share_percent) !== 50
);
if (foreign.length || uneven) return;
if (existing.some((e) => e.participant_id === SECOND_CONSUMER_ID)) {
await queryRaw(`DELETE FROM transaction_splits WHERE transaction_id = $1`, [
transactionId,