Fees, reserves and contracts
What it is
Four related pricing concepts:
- Funding particulars
-
The supplier-level funding record: facility limit, legal-signed flag, guarantor, covenants, and the current fee schedule.
- Fee schedules and tiers
-
Reusable pricing definitions maintained centrally under Manage, assigned to a supplier or to a supplier-marketplace link.
- Reserve
-
The percentage of incoming marketplace funds withheld — configured per marketplace link, together with minimum-fee overrides and opt-in periods.
- Long-term contracts
-
The signed agreement, templated per marketplace, with a history.
Where it lives
| Concern | Location |
|---|---|
Supplier fees tab |
|
Fees service |
|
Fee models |
|
Funding particulars |
|
Per-marketplace pricing |
|
Central fee settings |
|
Contracts |
|
Funding particulars
FundingParticularsModel is deliberately small:
export class FundingParticularsModel {
legalSigned: boolean;
fundPartStatus: string;
fundFacilityLimit: number;
guarantor: string;
supplierCovenants: string;
}
It is loaded as part of the supplier aggregate forkJoin (and is null for
ADVANCE_AUDITORS users), and is one of the two models that
UPDATE_MODEL_PART_SUCCESS merges saved card values into — so a card editing
fundFacilityLimit updates both this and SupplierDetailsModel. See
partial editing.
Endpoints (internalApiUrl, via SupplierFeesService):
GET suppliers/:key/funding_particulars supplier-level record
PUT suppliers/:key/funding_particulars update
GET suppliers/:key/funding_particulars/:marketplaceKey per-marketplace record
PUT suppliers/:key/funding_particulars/:marketplaceKey { currentFeeScheduleKey }
PUT suppliers/:key { loadNetEarnings }
Two things stand out:
-
Assigning a fee schedule to a marketplace is a
PUTof a single field (currentFeeScheduleKey) on the per-marketplace funding record. The schedule itself is defined centrally. -
loadNetEarnings— whether earnings are loaded gross or net — is a supplier-levelPUTon the supplier resource, even though it appears under Fees.
Per-marketplace pricing
Everything below hangs off the marketplace link (mpSupKey), not the supplier.
All under suppliers/:key/funding_particulars/:mpSupKey:
| Endpoint | Managed by |
|---|---|
|
|
|
|
|
|
In the store these land in SupplierModel as three maps keyed by mpSupKey:
marketplaceFundingModels, marketplaceOptInPeriodModels,
marketplaceMinFeeOverridesModels.
Opt-in rows have dedicated actions in the supplier slice —
ADD_OPT_IN_ROW, DELETE_OPT_IN_ROW (each with _SUCCESS / _ERROR) and
ADD_OPT_IN_ROW_CLEAR — with addOptInProgress / deleteOptInProgress flags for
button state.
|
|
The fees tab
| Child route | Screen |
|---|---|
|
|
|
|
|
|
|
|
Unlike most supplier tabs, the fees routes carry no extra permission restriction —
the fees parent has no RESTRICTED_*_CONFIG spread. Access control for fee edits
rests on the INT_FEE_UPD permission being enforced by the backend and on UI-level
ngxPermissions directives inside the components.
Central fee settings
/manage/fee-settings maintains the reusable schedules. FeeSettingsService on
internalApiUrl:
| Endpoint | Purpose |
|---|---|
|
The available schedule types (drives the add/edit form). |
|
Create a schedule. |
|
Rename / retype ( |
|
Replace the tier table ( |
|
Toggle free access ( |
|
Delete. |
|
Endpoint naming is inconsistent — plural Also note |
Adjusting a fee on an individual transaction is a different operation — the Adjust Payability Fee action, see lifecycle actions.
Long-term contracts
LongTermContractsService (in shared/services/, with an abstract base and a mock)
on internalApiUrl under long_term_contract:
| Endpoint | Purpose |
|---|---|
|
The standard template for a marketplace. |
|
All templates. |
|
One template group. |
|
Create a template for a marketplace. |
|
The supplier’s current contracts. |
|
Contract history. |
|
One contract. |
|
Create a contract for a marketplace link. |
|
The active contract for a link. |
Note the path-parameter ambiguity: long_term_contract/:x is used with a
supplier key, a contract key and a marketplace-supplier key depending on the
method. The distinction lives only in the method names.
Contracts are loaded as part of the supplier aggregate — both current and historical
— which is why opening any supplier tab issues two contract calls (and none at all
for ADVANCE_AUDITORS users). See suppliers.
Screens:
-
/suppliers/:key/contracts—SupplierContractsComponent, the per-supplier view. -
/manage/contracts—ContractsComponent, template administration. -
suppliers/supplier/add-contract/— the "Add New Default Contract" action from the Actions menu, shown only when the supplier is active.
The CONTRACTS__REFRESH iframe message type exists so that an EVA-rendered contract
view can ask the parent to refresh — see
iframe messaging.
Business rules
| Rule | Detail |
|---|---|
Pricing is layered |
Central fee schedule → assigned to the supplier-marketplace funding record → optionally overridden per link by minimum-fee overrides. The most specific level wins, and the resolution happens in the backend. |
Reserve lives on the link |
There is no single supplier reserve percentage; each marketplace link has its own.
The advance calculator’s |
Opt-in gates funding |
A marketplace only contributes funding inside an opt-in period. |
|
|
Gotchas
-
MIN_TOTAL_FEE/MAX_TOTAL_FEEin the advance calculator (5 % / 40 %) are advance fee bounds, unrelated to fee schedules here. -
isMpReserveForPaymentEmptyon the calculator state refers to the marketplace reserve being zero — the one place the two reserve concepts touch. -
SupplierFeesServicebuildsapiUrlasinternalApiUrl + 'suppliers'(no trailing slash) and prefixes paths with/. The marketplace pricing services do the same. Other supplier services use a trailing slash. Read before appending.