teqo/src/utilities/access/allocationDecisions.ts
Francisco Solla 368f138282 feat(campaign): C88 deliberação na atualização — responsável, fio e resolvido (Closes #397)
Migration 20260823_161905_add_municipality_update_deliberation + access por mutationKind + ilha client nas 3 superfícies + specs unit/int/e2e.
2026-08-23 18:58:26 -03:00

50 lines
2 KiB
TypeScript

// ---------------------------------------------------------------------------
// Allocation decisions (E14 movements, triage outcomes)
// ---------------------------------------------------------------------------
import type { Access } from 'payload'
import { relationshipId } from '@/lib/relationship'
import { getAccessibleMunicipalityIds } from '@/utilities/access/municipalities'
import {
advisorEditingAccess,
getFreshCampaignUser,
isCampaignLeader,
isCampaignUnrestricted,
isPayloadAdmin,
payloadAdminOnly,
} from '@/utilities/access/shared'
export { canReadMunicipalityUpdate as canReadAllocationDecision } from '@/utilities/access/municipalityUpdates'
/**
* Allocation decisions are coordination records (E14 movements, triage
* outcomes): raw updates stay admin-only. Deliberate no longer aliases the
* municipality-update update gate — that gate is C88's deliberative
* `mutationKind` channel, which must never reach this collection.
*/
export const canMutateAllocationDecision: Access = payloadAdminOnly
/**
* C141 — allocation decisions record coordination movements (E14) and triage
* outcomes: Edição "Tudo" does NOT widen the create scope, unlike the generic
* municipality-update create the old alias inherited. The carteira stays the
* ceiling for advisors on BOTH profile axes; `somente_leitura` closes the
* write path entirely. The E14 action itself stays unrestricted-gated.
*/
export const canCreateAllocationDecision: Access = async ({ data, req }) => {
if (isPayloadAdmin(req.user)) return true
const currentUser = await getFreshCampaignUser(req)
if (!currentUser || isCampaignLeader(currentUser)) return false
if (isCampaignUnrestricted(currentUser)) return true
const editingAccess = advisorEditingAccess(currentUser)
if (editingAccess === 'none') return false
const municipalityID = relationshipId(data?.municipality)
if (!municipalityID) return false
const municipalityIDs = await getAccessibleMunicipalityIds(req, currentUser)
return municipalityIDs?.includes(municipalityID) ?? false
}