When the assistant stages several verifikat and the user approves only some,
the rest lingered as pending_operations in Granskning until the 30-day expiry —
manual per-item cleanup. Now:
- lib/agent/pending/reject-conversation-pending.ts rejects a conversation's
still-pending proposals in one update (guarded on status='pending' so it never
stamps over a committed verifikat; company-scoped; keyed on the conversation).
- POST /api/agent/conversations/[id]/reject-pending — the chat's "Rensa förslag
som inte godkänts" button (appears when the thread has staged proposals; drops
the cards from view).
- Auto-clear on archive: archiving a thread ("I'm done") clears its leftover
proposals in the PATCH, best-effort.
Kept durable-by-default (proposals still come back on resume) — the button is
explicit user intent, not an auto-reject on every panel close, so resume still
works. 10 tests (helper + endpoint 401/404/404/happy); lint + guards + scoped
typecheck clean. UI button awaits founder visual sign-off.
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
34 lines
1.3 KiB
TypeScript
34 lines
1.3 KiB
TypeScript
import type { SupabaseClient } from '@supabase/supabase-js'
|
|
|
|
/**
|
|
* Reject every still-pending proposal the assistant staged in one conversation.
|
|
*
|
|
* When the assistant proposes several verifikat and the user approves only some,
|
|
* the rest linger as pending_operations in Granskning until the 30-day expiry —
|
|
* the "manually clean up afterward" friction users reported. This clears the
|
|
* leftovers in one shot: the chat's "clear the rest" button and the auto-clean
|
|
* on conversation archive both call it.
|
|
*
|
|
* Only `status = 'pending'` rows are touched (never a committing/committed one,
|
|
* which would stamp 'rejected' over a posted verifikat — the same guard the
|
|
* single/bulk reject routes use). Company-scoped. Returns how many were cleared.
|
|
*/
|
|
export async function rejectPendingForConversation(
|
|
supabase: SupabaseClient,
|
|
companyId: string,
|
|
conversationId: string,
|
|
): Promise<number> {
|
|
const { data } = await supabase
|
|
.from('pending_operations')
|
|
.update({
|
|
status: 'rejected',
|
|
resolved_at: new Date().toISOString(),
|
|
rejection_reason: 'Ej godkänd i assistenten',
|
|
})
|
|
.eq('company_id', companyId)
|
|
.eq('status', 'pending')
|
|
.eq('agent_metadata->>conversation_id', conversationId)
|
|
.select('id')
|
|
return data?.length ?? 0
|
|
}
|