Skip to content

SudoSOS Back-end API / payout-requests

Payout Requests ​

A payout-request is a user-initiated withdrawal: a member with a positive Balance asks for the money to be sent to a real bank account. In practice this is mostly the exit hatch for members leaving the association who want their leftover credit back; active members tend to just keep spending it.

Two-phase commit ​

Creating a payout request does not move money. POST /payoutrequests saves a PayoutRequest with status CREATED; the member is on the hook for nothing yet.

Money moves only when a treasurer approves it. POST /payoutrequests/{id}/status with state = APPROVED runs updateStatus, which creates a debit Transfer (from = requestedBy, to = null because the money leaves SudoSOS) and stamps approvedBy.

State machine ​

Statuses live on the related PayoutRequestStatus table as an append-only history, not as a single column. PayoutRequestState has four values and one start state:

  • CREATED is set on creation.
  • APPROVED is terminal and creates the transfer. Mutually exclusive with DENIED and CANCELLED.
  • DENIED is terminal. The treasurer rejected the request, so no transfer is written.
  • CANCELLED is terminal. The requester pulled it back, so no transfer is written.

canUpdateStatus guards the transitions: any of the three terminal states locks out the other two, and a state cannot be applied twice.

Bank details on the entity ​

Unlike most money movement in SudoSOS, the destination here is outside the system, so bankAccountNumber and bankAccountName are columns on PayoutRequest itself. They are captured at request time and frozen, since editing them after approval would desync the printed PDF.

Listing and PDFs ​

GET /payoutrequests paginates with filters (status, requestedBy, date range); GET /payoutrequests/{id} returns the full status history. PayoutRequest extends PdfAble, so GET /payoutrequests/{id}/pdf produces the treasurer's printable receipt with the bank details on it.

Versus seller-payouts ​

Both modules share BasePayout (requestedBy, amount, transfer) and both debit a single user, but they answer different questions. A payout-request is one member asking for their own credit back, gated on treasurer approval. A SellerPayout is the treasurer settling sales credit to an organ for a closed time window, with no approval step and an amount derived from a sales report rather than declared by the user.

Enumerations ​

EnumerationDescription
PayoutRequestState-

Classes ​

ClassDescription
PayoutRequest-
PayoutRequestControllerController for the /payoutrequests endpoints in the payout-requests module. Creation is open to members for their own balance; status transitions go through canUpdateStatus so that only the treasurer can move a request to a terminal state and the Transfer is created on APPROVED.
PayoutRequestPdf-
PayoutRequestService-
PayoutRequestStatus-

Interfaces ​

InterfaceDescription
BasePayoutRequestResponse-
PaginatedBasePayoutRequestResponse-
PayoutRequestFilters-
PayoutRequestRequest-
PayoutRequestResponse-
PayoutRequestStatusRequest-
PayoutRequestStatusResponse-

Functions ​

FunctionDescription
parseGetPayoutRequestsFilters-