The orders utilities module (src/utils/orders/) is a set of focused helpers that sit on top of the database abstraction layer. It handles pagination/query wrappers, pure UI formatters, business-rule predicates, a security gate for the admin-bypass pattern, and an org-wide service-count aggregator.

src/utils/orders.ts was refactored into a folder so each concern lives in its own file. The public import path #utils/orders is unchanged — a barrel index.ts re-exports everything.

src/utils/orders/
├── index.ts ← barrel (public API — always import from here)
├── data-access.ts ← DB query wrappers + getServiceCountsForDate
├── formatters.ts ← pure UI helpers (currency, status labels/badges)
├── predicates.ts ← business-rule booleans (editable, deletable)
└── privilege.ts ← admin-bypass gate (resolveOrderPrivilege)

Rule: Always import from #utils/orders. Only import from submodules directly if you specifically need to reference a single concern in isolation (e.g. #utils/orders/privilege in a security audit).

// ✅ Standard — always use the barrel
import { getAllOrders, formatCurrency, resolveOrderPrivilege } from '#utils/orders'
// ✅ Acceptable for security-sensitive code that wants an explicit audit trail
import { resolveOrderPrivilege } from '#utils/orders/privilege'
// ❌ Avoid — leaks internal structure unnecessarily
import { getAllOrders } from '#utils/orders/data-access'

Pre-defined field list for optimized list/card views. Pass to db.getOrders({ fields }) to avoid fetching columns that are not needed for display.

export const ORDER_LIST_FIELDS: (keyof Order)[] = [
'id',
'order_number',
'client_name',
'status',
'order_date',
'total_amount',
'created_at',
]

getAllOrders(userId, limit?, offset?, fields?)

Section titled “getAllOrders(userId, limit?, offset?, fields?)”

Fetches all orders for a user, newest first. Validates parameters and wraps the db.getOrders() call with structured error logging. Pass fields to retrieve a column subset for list/card views; omit it to get full rows.

ParamTypeDefaultNotes
userIdstring—Required, non-empty
limitnumber101–100; logs warning >100
offsetnumber0Non-negative
fields(keyof Order)[]undefinedColumn subset; omit for full rows
import { getAllOrders } from '#utils/orders'
// First page
const orders = await getAllOrders(userId)
// Second page
const page2 = await getAllOrders(userId, 10, 10)

List/card views — getAllOrders(..., ORDER_LIST_FIELDS)

Section titled “List/card views — getAllOrders(..., ORDER_LIST_FIELDS)”

For list/card views where you do not need the full row, pass ORDER_LIST_FIELDS as the fields argument to getAllOrders. This replaces the former dedicated list helper.

import { getAllOrders, ORDER_LIST_FIELDS } from '#utils/orders'
const orders = await getAllOrders(userId, 25, 0, ORDER_LIST_FIELDS)
orders.forEach(o => console.log(`${o.order_number} - ${o.client_name}`))

Fetches a single order by UUID with ownership enforcement.

import { getOrderById } from '#utils/orders'
const order = await getOrderById(orderId, userId)
if (!order) {
// Not found or not owned by this user
}

Returns the total number of orders for a user. Use with getAllOrders to build paginated UIs.

import { getOrdersCount } from '#utils/orders'
const total = await getOrdersCount(userId)
const totalPages = Math.ceil(total / pageSize)

Returns a per-service count map (Record<ServiceId, number>) across all users for a given date. All service IDs from the catalog are present in the result; services with no orders that day have value 0. Cancelled orders are excluded from all counts.

Security: This function intentionally omits the user_id filter (admin-bypass path). Callers must gate usage behind resolveOrderPrivilege(locals) before exposing the result to a user.

ParamTypeNotes
datestringYYYY-MM-DD format required

Implementation details:

  • Pages through db.getOrders() in 200-row pages
  • Hard cap of 50 pages (10 000 orders) — logs a warning and returns a partial count if exceeded
  • Defends against timezone drift: filters by from_date/to_date and validates each row’s order_date starts with the requested date string
import { getServiceCountsForDate, resolveOrderPrivilege } from '#utils/orders'
// In an Astro page or API route:
const isPrivileged = resolveOrderPrivilege(Astro.locals)
if (!isPrivileged) {
return new Response(null, { status: 403 })
}
const counts = await getServiceCountsForDate('2026-04-06')
// → { clothing: 12, haircuts: 7, showers: 3, hygiene: 5, other: 1 }
---
import { getServiceCountsForDate, resolveOrderPrivilege } from '#utils/orders'
if (!resolveOrderPrivilege(Astro.locals)) {
return Astro.redirect('/403')
}
const today = new Date().toISOString().split('T')[0]
const counts = await getServiceCountsForDate(today)
---
<ul>
{Object.entries(counts).map(([service, count]) => (
<li>{service}: {count}</li>
))}
</ul>

Pure functions — no database or logger imports. Safe to call on the client side.

Formats a number as USD with two decimal places.

import { formatCurrency } from '#utils/orders'
formatCurrency(1234.56) // "$1,234.56"
formatCurrency(100) // "$100.00"
formatCurrency(0) // "$0.00"

Returns a human-readable label and a semantic color string for a status badge.

import { formatOrderStatus } from '#utils/orders'
formatOrderStatus('open') // { label: 'Open', color: 'blue' }
formatOrderStatus('pending') // { label: 'Pending', color: 'yellow' }
formatOrderStatus('ready') // { label: 'Ready', color: 'purple' }
formatOrderStatus('complete') // { label: 'Complete', color: 'green' }
formatOrderStatus('cancelled') // { label: 'Cancelled', color: 'red' }

Returns a @fpkit/acss badge class string. Use when rendering status chips inside React components.

import { getOrderStatusBadgeClass } from '#utils/orders'
getOrderStatusBadgeClass('open') // 'badge-info'
getOrderStatusBadgeClass('pending') // 'badge-warning'
getOrderStatusBadgeClass('ready') // 'badge-primary'
getOrderStatusBadgeClass('complete') // 'badge-success'
getOrderStatusBadgeClass('cancelled') // 'badge-error'

Pure boolean functions encoding order business rules. No database or logger imports.

Returns true unless the order is complete or cancelled. Use before rendering edit controls or allowing form submissions.

import { isOrderEditable } from '#utils/orders'
if (!isOrderEditable(order)) {
return new Response(JSON.stringify({ error: 'Order cannot be edited' }), { status: 422 })
}

Returns true only for open, pending, or cancelled orders. Orders that are ready or complete should be archived, not deleted.

import { canDeleteOrder } from '#utils/orders'
// In the delete API route, after fetching the order:
if (!canDeleteOrder(order)) {
return new Response(JSON.stringify({ error: 'Order cannot be deleted' }), { status: 422 })
}

Security-sensitive. The single authorized decision point for the order admin-bypass pattern.

All order DB methods (getOrderById, deleteOrder, updateOrder, getServiceCountsForDate) accept an optional userId. When userId is omitted, the ownership WHERE clause is skipped — granting unrestricted access to every order in the database. This function is the only code that should decide whether to omit it.

Bypass threshold: team_manager or higher (see ROLE_HIERARCHY in config/roles.config.ts).

import { resolveOrderPrivilege } from '#utils/orders'
// In any order API route:
const isPrivileged = resolveOrderPrivilege(Astro.locals)
const order = isPrivileged
? await db.getOrderById(orderId) // admin path — ownership filter skipped
: await db.getOrderById(orderId, userDbId) // member path — ownership enforced

Roles that receive the bypass:

RoleBypass?
super_adminYes
adminYes
team_adminYes
team_managerYes
volunteerNo
memberNo

ExportModuleType
ORDER_LIST_FIELDSdata-accessconst
getAllOrdersdata-accessasync fn
getOrderByIddata-accessasync fn
getOrdersCountdata-accessasync fn
getServiceCountsForDatedata-accessasync fn
formatCurrencyformattersfn
formatOrderStatusformattersfn
getOrderStatusBadgeClassformattersfn
isOrderEditablepredicatesfn
canDeleteOrderpredicatesfn
resolveOrderPrivilegeprivilegefn