@hyperscale0/hsx 5.6.0 → 5.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/src/compile.d.ts.map +1 -1
- package/dist/src/compile.js +74 -3
- package/dist/src/compile.js.map +1 -1
- package/dist/src/examples-bundle.js +3 -3
- package/dist/src/examples-bundle.js.map +1 -1
- package/dist/src/std-bundle.js +1 -1
- package/dist/src/std-bundle.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/docs/README.md +45 -11
- package/docs/examples.md +1 -1
- package/examples/collections.hsx +8 -2
- package/examples/financing.hsx +5 -0
- package/examples/lending.hsx +7 -1
- package/package.json +3 -3
- package/src/compile.ts +95 -3
- package/src/examples-bundle.ts +3 -3
- package/src/std-bundle.ts +1 -1
- package/src/version.ts +1 -1
- package/std/financing.hsx +3 -1
package/src/std-bundle.ts
CHANGED
|
@@ -4,7 +4,7 @@ export const BUNDLED_STD_FILES: ReadonlyMap<string, string> = new Map<string, st
|
|
|
4
4
|
["cards.hsx", "header cards\n\n// Activate holder and card before creating and approving an authorization.\n// Expose authorization.create, approve and capture; expose decline and reverse\n// separately if callers need those paths. Issuer declines only from pending;\n// merchant captures or reverses an approved reservation. Expiry voids approved\n// reservations or abandons pending ones; it does not delay a captured refund.\n// Create one transaction for the captured authorization and expose its refund.\n// Refund is available immediately from posted, even before authorization.expiresAt,\n// and moves the whole captured amount from merchant to holder under programOperator.\n// No partial capture, repeated capture or partial transaction refund is provided.\n// Disputes need a posted transaction, issuer review and win before their deadline;\n// win invokes the same refund. The alias never changes the declared action actor.\n\n// Cost: authorization approve, capture and reverse each declare one transfer\n// instruction. Transaction refund declares one transfer; a successful dispute\n// invokes that refund. Card state changes alone declare no transfers.\n\ninstrument cardholder(holder: party) {\n summary: \"An account holder whose card access can be activated, suspended or closed.\"\n fields { holder: account of holder }\n lifecycle { states: [pending, active, suspended, closed], initial: pending }\n action create {}\n action activate { from: pending, to: active }\n action suspend { from: active, to: suspended }\n action resume { from: suspended, to: active }\n action close { from: [active, suspended], to: closed }\n}\n\ninstrument card(holder: ref<cards.cardholder>, spend_limit: money) {\n summary: \"A card with a per-spend ceiling that can be activated, frozen or cancelled.\"\n fields { holder: ref<holder>, spendLimit: money = spend_limit }\n lifecycle { states: [issued, active, frozen, cancelled], initial: issued }\n action create { requires self.holder in [active] }\n action activate { from: issued, to: active, requires self.holder in [active] }\n action freeze { from: active, to: frozen }\n action unfreeze { from: frozen, to: active, requires self.holder in [active] }\n action cancel { from: [issued, active, frozen], to: cancelled }\n}\n\ninstrument authorization(card: ref<cards.card>, merchant: party, issuer: party = programOperator) {\n summary: \"Reserve a card payment for the merchant, then capture it or release the reservation.\"\n fields { card: ref<card>, merchant: account of merchant, amount: money, expiresAt: date, reservation: text? }\n lifecycle { states: [pending, approved, captured, declined, reversed, expired], initial: pending }\n action create {\n requires self.card in [active]\n requires self.card.holder in [active]\n requires self.amount <= self.card.spendLimit\n }\n action approve {\n from: pending, to: approved, actor: { party: issuer }, deadline: { at: self.expiresAt }\n requires self.card in [active]\n requires self.card.holder in [active]\n moves reserve self.amount from self.card.holder.holder to merchant capture \"reservation\"\n }\n action capture { from: approved, to: captured, actor: { party: merchant }, deadline: { at: self.expiresAt }, moves post self.reservation }\n action reverse { from: approved, to: reversed, actor: { party: merchant }, moves void self.reservation }\n action decline { from: pending, to: declined, actor: { party: issuer } }\n action expire { from: approved, to: expired, actor: clock, due: { at: self.expiresAt }, moves void self.reservation }\n action abandon { from: pending, to: expired, actor: clock, due: { at: self.expiresAt } }\n}\n\ninstrument transaction(authorization: ref<cards.authorization>) {\n summary: \"Record a captured card payment and return its amount when refunded.\"\n fields { authorization: ref<authorization>, amount: money = self.authorization.amount }\n lifecycle { states: [posted, refunded], initial: posted }\n action create { requires self.authorization in [captured]; requires unique \"captured_authorization\" on [self.authorization] }\n action refund {\n from: posted, to: refunded, actor: { party: programOperator }, input { reason: text }\n moves self.amount from self.authorization.merchant to self.authorization.card.holder.holder\n }\n}\n\ninstrument dispute(transaction: ref<cards.transaction>, issuer: party = programOperator, within: duration = 90d) {\n summary: \"Review a disputed card payment before its deadline and refund it when the dispute is won.\"\n fields { transaction: ref<transaction>, evidence: text, expiresAt: date = after(self.createdAt, within) }\n lifecycle { states: [filed, reviewing, won, lost], initial: filed }\n action create { requires self.transaction in [posted]; requires unique \"disputed_transaction\" on [self.transaction] }\n action review { from: filed, to: reviewing, actor: { party: issuer } }\n action win {\n from: reviewing, to: won, actor: { party: issuer }, deadline: { at: self.expiresAt }\n invoke: [{ reference: self.transaction, action: refund, input: { reason: { field: self.evidence } } }]\n }\n action lose { from: [filed, reviewing], to: lost, actor: clock, due: { at: self.expiresAt } }\n}\n"],
|
|
5
5
|
["collections.hsx", "header collections\n\n// Economics: Company capital pays agencies as participant payouts; outside capital passes through.\n// A company agency earns outside capital fees; its own capital fee is internal.\n\n// Expose case.create, assign and recover as separate steps. Creation needs overdue\n// outstanding principal and a matching slice/plan. Assignment belongs to capital;\n// recovery belongs to agency and pays the linked payment before the agency fee.\n// Payment must belong to the same plan. Recovered means that payment was processed,\n// not that the entire debt was repaid. Fee debits plan.capital, not the borrower.\n// Expose recall for capital and return_uncollected for agency when needed.\n// Contacts need an assigned case, matching agency, local hours and rolling count.\n// Contact outcomes are separate records. Reminder dispatch is operator-owned;\n// before_due/overdue are clock-owned and require active debt. Scheduled admission\n// does not prove delivery or retry. No collector can infer authority from an alias.\n\n// Cost: case recovery invokes the linked payment and then charges its agency\n// fee. Its count includes those child effects. Contact and reminder delivery costs\n// are not provider prices in hsx cost; the executor supplies commercial tariffs.\n\ninstrument case(on: ref<financing.installments>[], agency: party, capital: party = programOperator, overdue: duration = 3d, fee: percent = 20%) {\n revisioned: true\n summary: \"Refer an overdue installment without creating another debt.\"\n fields { assignedAgency: account of agency, plan: ref<on>, slice: ref<on.slice>, payment: ref<on.payment>, eligibleAt: date = after(self.slice.dueAt, overdue), agencyFee: money = rate(self.payment.amount, fee) }\n lifecycle { states: [opened, assigned, recovered, recalled, returned_uncollected], initial: opened }\n action create {\n due: { at: self.eligibleAt }\n requires self.plan == self.slice.plan\n requires self.slice.principalReceivable.balance > \"0\"\n requires unique \"overdue_referral\" on [self.slice]\n }\n action assign { from: opened, to: assigned, actor: { party: capital } }\n action recover { expansionLimit: 8192, from: assigned, to: recovered, actor: { party: agency }, requires self.payment.plan == self.plan, invoke: [{ reference: self.payment, action: pay, input: {} }, { reference: self.id, action: pay_fee, input: {} }] }\n action pay_fee { allowZero: true, from: recovered, to: recovered, actor: { parent: current() }, moves self.agencyFee from self.plan.capital to agency economics { recipient: agency, company: { recipient: capital, company: { purpose: internal, sourceParty: capital }, participant: { purpose: earning, sourceParty: capital } }, participant: { recipient: capital, company: { purpose: participant_payout, sourceParty: capital }, participant: { purpose: pass_through, sourceParty: capital } } } }\n action recall { from: [opened, assigned], to: recalled, actor: { party: capital } }\n action return_uncollected { from: assigned, to: returned_uncollected, actor: { party: agency } }\n}\n\ninstrument contact(case: ref<collections.case>[], agency: party, max_contacts: integer = 10, window: duration = 30d, contact_from: integer(0, 23) = 8, contact_until: integer(1, 23) = 20, timezone: text = \"Asia/Riyadh\") {\n constraints { contact_from: less_than(contact_until) }\n summary: \"An agency contact admitted against the locked rolling count and local hours.\"\n fields { agency: account of agency, case: ref<case>, attemptedAt: date?, evidence: text, maximum: integer = max_contacts }\n lifecycle { states: [recorded], initial: recorded }\n invariants count of { instrument: current(), reference: \"case\", anchor: self.case, states: [recorded], limit: 366, window: { field: attemptedAt, milliseconds: window } } <= self.maximum\n action create {\n actor: { party: agency }\n set: { attemptedAt: { field: self.now } }\n requires self.agency == self.case.assignedAgency; requires self.case in [assigned]; requires hours self.now between contact_from and contact_until timezone timezone\n }\n records {\n outcome: {\n fields { contact: ref<parent>, agency: account of agency, outcome: enum(reached, no_answer, promise_to_pay, disputed, wrong_contact, refused), evidence: text, recordedAt: date? }\n lifecycle { states: [recorded], initial: recorded }\n action create {\n actor: { party: agency }\n requires self.agency == self.contact.case.assignedAgency\n set: { recordedAt: { field: self.now } }\n }\n }\n }\n}\n\n\ninstrument reminder(on: ref<financing.installments>[], operator: party = programOperator, before_days: integer(0, 366) = 3, overdue_days: integer(1, 366) = 1, max_per_day: integer(1, 10) = 1, send_from: integer(0, 23) = 8, send_until: integer(1, 24) = 20, timezone: text = \"Asia/Riyadh\") {\n constraints { send_from: less_than(send_until) }\n summary: \"Send an email to the installment borrower's stored contact address.\"\n fields { slice: ref<on.slice> }\n lifecycle { states: [ready], initial: ready }\n action create { requires unique \"installment_reminder\" on [self.slice] }\n action dispatch {\n from: ready, to: ready, actor: { party: operator }\n invoke: [{ reference: self.id, action: send, input: {} }]\n }\n action before_due {\n from: ready, to: ready, actor: clock\n due: { at: self.slice.dueAt, localDay: { days: before_days, direction: \"before\", hour: send_from, timezone: timezone } }\n invoke: [{ selection: { instrument: current(), reference: \"slice\", anchor: self.slice, states: [ready], limit: 1, where: { slice.plan.status: { literal: \"active\" } } }, action: send, guard: { kind: compare, left: { field: self.slice.principalReceivable.balance }, operator: \">\", right: { literal: \"0\" } }, input: {} }]\n }\n action overdue {\n from: ready, to: ready, actor: clock\n due: { at: self.slice.dueAt, localDay: { days: overdue_days, direction: \"after\", hour: send_from, timezone: timezone } }\n invoke: [{ selection: { instrument: current(), reference: \"slice\", anchor: self.slice, states: [ready], limit: 1, where: { slice.plan.status: { literal: \"active\" } } }, action: send, guard: { kind: compare, left: { field: self.slice.principalReceivable.balance }, operator: \">\", right: { literal: \"0\" } }, input: {} }]\n }\n action send {\n from: ready, to: ready, actor: { parent: current() }\n requires self.slice.plan in [active]\n requires self.slice.principalReceivable.balance > \"0\"\n reminder: { installment: self.slice, recipient: self.slice.plan.borrower, dueAt: self.slice.dueAt, channel: \"email\", template: \"payment_reminder\", beforeDays: before_days, overdueDays: overdue_days, maxPerDay: max_per_day, startHour: send_from, endHour: send_until, timezone: timezone }\n }\n}\n"],
|
|
6
6
|
["escrow.hsx", "header escrow\n\n// Economics: Funding and unspent returns are principal. Acceptance realizes earnings for\n// the company or a payout to a bound outside seller; tax is pass-through.\n\n// Expose create, fund, deliver and accept for the purchase path. Create captures\n// subject.price; acceptance pays payee less the configured fee, not payer.\n// Expose dispute, verify_return and refund separately for the return path.\n// Payer disputes delivered goods; payee verifies return evidence from disputed;\n// payee refunds the entire held price from return_verified by default.\n// Acceptance expiry enters disputed, never released. Neither verify_return nor\n// refund becomes public merely because dispute is exposed. Clock actions remain\n// internal. Expose cancel for a pending hold, including a checkout-funded hold;\n// it returns its credited balance to payer before cancelling. Confirm requires\n// the whole captured price in held. This flow has no partial release or refund.\n\n// Cost: create declares one owned account. Fund and refund each declare one\n// transfer; accept expands the configured fee and tax into moves. Run hsx cost\n// on the composed program for instruction counts. The executor supplies prices.\n\ninstrument hold(payer: party = party(person), payee: party = programOperator, accept_within: duration = 48h, fee: fee = { seller: 0%, tax: 0% }, dispute: policy = { refund_after: return_verified }) {\n revisioned: true\n summary: \"Hold the subject price through delivery, acceptance and verified return.\"\n fields {\n payer: account of payer, payee: account of payee\n held: account of self, deliveredAt: date?\n price: money = subject.price\n }\n lifecycle { states: [pending, funded, delivered, disputed, return_verified, released, refunded, cancelled], initial: pending }\n action create {\n subject { price: money }\n actor: { party: payer }\n }\n action fund {\n from: pending, to: funded, actor: { party: payer }\n subject { price: money }\n moves self.price from payer to self.held economics { purpose: principal, sourceParty: payer }\n }\n action confirm {\n from: pending, to: funded\n requires self.held.balance == self.price\n }\n action deliver {\n from: funded, to: delivered, actor: { party: payee }\n set: { deliveredAt: { field: self.now } }\n }\n action accept { allowZero: true, requires self.price > \"0\";\n from: delivered, to: released, actor: { party: payer }\n input { acceptanceReference: text }\n deadline: { at: self.deliveredAt, offset: accept_within }\n moves self.price from self.held to payee fee fee economics { payee: { recipient: payee, company: { purpose: earning, sourceParty: payer }, participant: { purpose: participant_payout, sourceParty: programOperator } }, fee: { purpose: earning, sourceParty: payer }, tax: { purpose: pass_through, sourceParty: programOperator } }\n }\n action expire_acceptance {\n from: delivered, to: disputed, actor: clock\n due: { at: self.deliveredAt, offset: accept_within }\n }\n action dispute {\n from: delivered, to: disputed, actor: { party: payer }\n deadline: { at: self.deliveredAt, offset: accept_within }\n }\n action verify_return {\n from: disputed, to: return_verified, actor: { party: payee }\n input { returnEvidence: text }\n }\n action refund {\n from: dispute.refund_after, to: refunded, actor: { party: payee }\n moves self.price from self.held to payer economics { purpose: principal, sourceParty: programOperator }\n }\n action cancel { allowZero: true,\n from: pending, to: cancelled, actor: { party: payer }\n moves self.held.balance from self.held to payer economics { purpose: principal, sourceParty: programOperator }\n }\n}\n"],
|
|
7
|
-
["financing.hsx", "header financing\n\n// Economics: Principal advances and repayments are excluded from earnings. Claims, waivers,\n// write-offs and allocations are internal. Paid profit and company charges are\n// earnings; receipt refunds reverse captured cash. Outside recovery recipients\n// receive payouts from held company cash, or pass-through direct customer cash.\n\n// Expose create and sign on installments, then collect_down_payment as checkout\n// for disburse_to: funds. Checkout requires a signed plan and pending escrow;\n// it tops up only the missing down payment, without advancing lender principal.\n// Disburse still collects any missing down payment, activates slices, and confirms\n// the fully funded hold. Existing escrow credit counts once toward the down payment.\n// Borrower-directed disbursement excludes collect_down_payment. A down_payment\n// there reduces principal but does not collect cash. Price is subject metadata,\n// not the borrower limit. The escrow payer and price must match the plan.\n// Expose escrow cancel to return checkout cash if financing is abandoned; plan\n// void alone cancels the agreement and does not refund its separate escrow.\n// Approve borrower and portfolio limits before disbursement. Create builds the\n// dated slice records; payments need a separate payment record and pay action.\n// Expose parent payoff separately and create a current, unexpired payoff_quote.\n// Expose late_charge.create as propose_assessment before the clock can assess;\n// provide matching plan, slice and borrower. Fine is fixed money, not a percentage.\n// Collection uses the minimum of payment cash and outstanding fine; a partial\n// payment does not settle the remaining fine. Recovery cost needs its own record.\n// Profit share credits capital's allocatedProfitPayable, not an outside agency.\n// Credit lines need adapter binding at activation; draws are ledger advances,\n// not evidence of outside funding. Caller-authorized limit approvals and advances\n// need the Product's operation authority. No clock declaration proves retries.\n\n// Cost: installments include cash and claim moves, child-account creation and\n// bounded invocations across slices and assessments. Month and charge limits affect\n// the bound. Run hsx cost on the selected policies; profit is not a platform tariff.\n\ninstrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3, profit: percent, disburse_to: enum(funds, borrower) = funds, profit_earned: enum(on_payment, by_schedule, at_disbursement) = on_payment, apply: enum(fines_profit_principal, principal_profit, pro_rata) = fines_profit_principal, payoff_rebate: percent = 100%, write_off_after: duration = 90d, max_extension: duration = 90d, max_amendments: integer(0, 366) = 2, waiver_limit: percent = 100%, amendment_expiry: duration = 7d, payoff_quote_expiry: duration = 1h, allow_overdue: enum(allowed, blocked) = allowed, assessed_fines: enum(carry, require_waiver) = carry, down_payment: percent = 0%, funds: ref<escrow.hold>?, borrower: party = party(person), capital: party = programOperator, share: percent = 0%, limits: ref<financing.limits> = object(financing.limits), portfolio: ref<financing.portfolio_limit> = object(financing.portfolio_limit)) {\n dependencies {\n funds {\n selector: disburse_to, is: funds\n message: \"Attachment `{attachment}` disburses into a hold, but `funds` is not bound.\"\n fix: \"Bind `funds: sale` to an escrow attachment. Choose `disburse_to: borrower` only if the borrower should receive the money directly.\"\n }\n }\n revisioned: true\n familyRevision: 1\n summary: \"Funding, profit recognition and payment order chosen by the program.\"\n fields {\n funds: ref<funds>?, borrower: account of borrower, settlementIdentity: text, borrowerLimit: ref<limits>, portfolioLimit: ref<portfolio>\n months: integer = months, dates: list(date, months)\n allocatedPayable: account(capital, cash, \"allocatedProfitPayable\"), capital: account(capital, cash, \"capital\"), profitIncome: account(capital, cash, \"profitIncome\"), loss: account(capital, claim, \"loss\")\n downPaymentRemaining: money?, downPaymentCredit: money?, principalReturned: money?, profitReturned: money?, lossRecorded: money?\n price: money = subject.price\n downPayment: money = rate(self.price, down_payment)\n principal: money = subtract(self.price, self.downPayment)\n profit: money = rate(self.principal, profit)\n total: money = sum(self.principal, self.profit)\n }\n lifecycle { states: [quoted, signed, active, paid, written_off, cancelled], initial: quoted }\n invariants count of { instrument: all(financing.installments), reference: \"borrowerLimit\", anchor: self.borrowerLimit, states: [active], limit: 366 } <= self.borrowerLimit.activePlans\n invariants sum \"principalReceivable.balance\" of { instrument: all(financing.installments.slice), reference: \"borrowerLimit\", anchor: self.borrowerLimit, states: [pending, due, paid], limit: 366 } <= self.borrowerLimit.limit\n invariants sum \"principalReceivable.balance\" of { instrument: all(financing.installments.slice), reference: \"portfolioLimit\", anchor: self.portfolioLimit, states: [pending, due, paid], limit: 366 } <= self.portfolioLimit.limit\n action create {\n subject { price: money }\n requires self.borrowerLimit.borrower == self.borrower\n when disburse_to is funds { requires self.borrower == self.funds.payer; requires self.price == self.funds.price }\n invoke: [{ range: { count: { literal: months }, maximum: months, bind: position }, instrument: slice, action: create, input: { plan: { field: self.id }, borrowerLimit: { field: self.borrowerLimit }, portfolioLimit: { field: self.portfolioLimit }, position: { field: position } } }]\n }\n action sign {\n from: quoted, to: signed, actor: { party: borrower }, input { signedOffer: text, affordabilityReference: text }\n requires count of { instrument: slice, reference: \"plan\", anchor: self.id, states: [draft], limit: 366 } == self.months\n }\n action collect_down_payment { allowZero: true,\n from: signed, to: signed, actor: { party: borrower }\n when disburse_to is borrower { requires true == false }\n when disburse_to is funds {\n requires self.funds in [pending]\n calculate: [{ target: downPaymentCredit, op: minimum, values: [{ field: self.funds.held.balance }, { field: self.downPayment }] }, { target: downPaymentRemaining, op: subtract, base: { field: self.downPayment }, subtract: [{ field: self.downPaymentCredit }] }]\n moves self.downPaymentRemaining from self.borrower to self.funds.held economics { purpose: principal, sourceParty: borrower }\n }\n }\n action disburse { allowZero: true,\n from: signed, to: active, actor: { party: capital }\n requires self.borrowerLimit in [approved]\n requires self.portfolioLimit in [approved]\n when disburse_to is funds {\n requires self.funds in [pending]\n invoke: [{ reference: self.id, action: fund_down_payment, input: {} }]\n }\n when disburse_to is borrower { moves self.principal from self.capital to self.borrower economics { purpose: principal, sourceParty: capital } }\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.id, states: [draft], limit: 366, order: [position] }, action: activate, input: {} }]\n when disburse_to is funds { invoke: [{ reference: self.funds, action: confirm, input: {} }] }\n }\n action fund_down_payment { allowZero: true,\n from: active, to: active, actor: { parent: current() }\n when disburse_to is funds {\n calculate: [{ target: downPaymentCredit, op: minimum, values: [{ field: self.funds.held.balance }, { field: self.downPayment }] }, { target: downPaymentRemaining, op: subtract, base: { field: self.downPayment }, subtract: [{ field: self.downPaymentCredit }] }]\n moves self.downPaymentRemaining from self.funds.payer to self.funds.held economics { purpose: principal, sourceParty: borrower }\n moves self.principal from self.capital to self.funds.held economics { purpose: principal, sourceParty: capital }\n }\n }\n action complete {\n from: active, to: paid\n requires count of { instrument: slice, reference: \"plan\", anchor: self.id, states: [pending, due], limit: 366 } == 0\n requires sum \"receivable.balance\" of { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.id, states: [assessed, collected], limit: 366 } == \"0\"\n requires sum \"receivable.balance\" of { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.id, states: [assessed, collected], limit: 366 } == \"0\"\n }\n action restore { from: [active, paid], to: active, actor: { parent: payment } }\n action payoff {\n from: active, to: paid, actor: { party: borrower }\n input { quote: ref<payoff_quote> }\n requires input.quote.plan == self.id; requires input.quote.revision == self.productRevision\n deadline: { at: input.quote.expiresAt }\n calculate: [\n { target: \"principalReturned\", op: \"aggregate\", selection: { instrument: slice, reference: \"plan\", anchor: self.id, states: [pending, due], limit: 366 }, measure: { sum: \"principalReceivable.balance\" } }\n ]\n invoke: [{ selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.id, states: [assessed, collected], limit: 366, order: [overdueAt] }, action: payoff, input: {} }, { selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.id, states: [assessed, collected], limit: 366, order: [overdueAt] }, action: payoff, input: {} }]\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.id, states: [pending, due], limit: 366, order: [position] }, action: payoff, input: { identity: { field: self.settlementIdentity } } }, { reference: self.id, action: record_payoff, input: {} }]\n }\n action record_payoff {\n from: paid, to: paid, actor: { parent: current() }\n calculate: [{ target: profitReturned, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.id, states: [paid], limit: 366, where: { payoffIdentity: { field: self.settlementIdentity } } }, measure: { sum: \"payoffProfit\" } }]\n invoke: [{ instrument: settlement, action: create, input: { plan: { field: self.id }, identity: { field: self.settlementIdentity }, principal: { field: self.principalReturned }, profit: { field: self.profitReturned }, loss: { literal: \"0\" }, kind: { literal: \"cash\" } } }]\n }\n action write_off {\n from: active, to: written_off, actor: { parent: write_off_request }\n input { overdueSlice: ref<slice> }\n calculate: [{ target: \"lossRecorded\", op: \"aggregate\", selection: { instrument: slice, reference: \"plan\", anchor: self.id, states: [pending, due], limit: 366 }, measure: { sum: \"principalReceivable.balance\" } }]\n due: { at: input.overdueSlice.lossEligibleAt }\n requires input.overdueSlice.plan == self.id; requires input.overdueSlice.principalReceivable.balance > \"0\"\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.id, states: [pending, due], limit: 366, order: [position] }, action: write_off, input: {} }, { instrument: settlement, action: create, input: { plan: { field: self.id }, identity: { field: self.settlementIdentity }, principal: { literal: \"0\" }, profit: { literal: \"0\" }, loss: { field: self.lossRecorded }, kind: { literal: \"loss\" } } }]\n }\n action record_payment {\n from: active, to: active, actor: { parent: payment }\n input { identity: text, principal: money, profit: money }\n invoke: [{ instrument: settlement, action: create, input: { plan: { field: self.id }, identity: { field: input.identity }, principal: { field: input.principal }, profit: { field: input.profit }, loss: { literal: \"0\" }, kind: { literal: \"cash\" } } }]\n }\n action cancel { from: quoted, to: cancelled }\n action void { from: signed, to: cancelled, actor: { party: borrower } }\n records {\n write_off_request: {\n fields { plan: ref<parent>, overdueSlice: ref<slice> }\n lifecycle { states: [requested, applied, cancelled], initial: requested }\n action create { requires self.overdueSlice.plan == self.plan; requires self.plan in [active] }\n action apply {\n from: requested, to: applied, actor: { party: capital }\n invoke: [{ reference: self.plan, action: write_off, input: { overdueSlice: { field: self.overdueSlice } } }]\n }\n action cancel { from: requested, to: cancelled }\n }\n payoff_quote: {\n fields {\n plan: ref<parent>, revision: text?, effectiveAt: date?, expiresAt: date = after(self.createdAt, payoff_quote_expiry)\n principal: money?, earnedProfit: money?, unearnedProfit: money?, rebate: money?, fines: money?, costs: money?, gross: money?, amount: money?\n }\n lifecycle { states: [quoted], initial: quoted }\n action create {\n requires self.plan in [active]\n set: { revision: { field: self.productRevision }, effectiveAt: { field: self.now } }\n invoke: [\n { selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending], limit: 366 }, action: quote_pending, input: { quote: { field: self.id } } }\n { selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [due], limit: 366 }, action: quote_due, input: { quote: { field: self.id } } }\n { reference: self.id, action: record, input: {} }\n ]\n }\n action record {\n from: quoted, to: quoted, actor: { parent: current() }\n calculate: [\n { target: principal, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, measure: { sum: \"principalReceivable.balance\" } }\n { target: earnedProfit, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, measure: { sum: \"profitEarned.balance\" } }\n { target: unearnedProfit, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, measure: { sum: \"profitReceivable.balance\" } }\n { target: rebate, op: aggregate, selection: { instrument: quote_piece, reference: \"quote\", anchor: self.id, states: [recorded], limit: 366 }, measure: { sum: \"rebate\" } }\n { target: fines, op: aggregate, selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366 }, measure: { sum: \"receivable.balance\" } }\n { target: costs, op: aggregate, selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366 }, measure: { sum: \"receivable.balance\" } }\n { target: gross, op: sum, values: [{ field: self.principal }, { field: self.earnedProfit }, { field: self.unearnedProfit }, { field: self.fines }, { field: self.costs }] }\n { target: amount, op: subtract, base: { field: self.gross }, subtract: [{ field: self.rebate }] }\n ]\n }\n }\n quote_piece: {\n fields { quote: ref<payoff_quote>, slice: ref<slice>, rebate: money = rate(self.slice.profitReceivable.balance, payoff_rebate) }\n lifecycle { states: [recorded], initial: recorded }\n action create { actor: { parent: slice }, input { quote: ref<payoff_quote>, slice: ref<slice> }, requires unique \"payoff_slice_quote\" on [self.quote, self.slice] }\n }\n amendment: {\n fields {\n plan: ref<parent>, dates: list(date, months), agreement: text, waiverPercent: percent, waiverEvidence: text, maximumWaiver: percent = waiver_limit\n revision: text?, acceptedAt: date?, staleReason: text?, expiresAt: date = after(self.createdAt, amendment_expiry)\n fineDisposition: enum(carry, require_waiver) = assessed_fines, addedProfit: money = 0 SAR\n principalSnapshot: money?, earnedProfitSnapshot: money?, unearnedProfitSnapshot: money?, finesSnapshot: money?, costsSnapshot: money?\n extension: duration = max_extension, maximum: integer = max_amendments\n }\n lifecycle { states: [proposed, applied, declined, withdrawn, expired, superseded], initial: proposed }\n action create {\n actor: { party: capital }\n requires self.plan in [active]; requires self.waiverPercent <= self.maximumWaiver\n set: { revision: { field: self.productRevision } }\n calculate: [\n { target: principalSnapshot, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, measure: { sum: \"principalReceivable.balance\" } }\n { target: earnedProfitSnapshot, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, measure: { sum: \"profitEarned.balance\" } }\n { target: unearnedProfitSnapshot, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, measure: { sum: \"profitReceivable.balance\" } }\n { target: finesSnapshot, op: aggregate, selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366 }, measure: { sum: \"receivable.balance\" } }\n { target: costsSnapshot, op: aggregate, selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366 }, measure: { sum: \"receivable.balance\" } }\n ]\n requires count of { instrument: current(), reference: \"plan\", anchor: self.plan, states: [applied], limit: 366 } < self.maximum\n invoke: [{ range: { count: { literal: months }, maximum: months, bind: position }, instrument: proposed_date, action: create, input: { amendment: { field: self.id }, position: { field: position } } }, { selection: { instrument: proposed_date, reference: \"amendment\", anchor: self.id, states: [recorded], limit: 366, where: { first: { literal: 0 } } }, action: check_order, input: {} }]\n }\n action accept {\n from: proposed, to: applied, actor: { party: borrower }, deadline: { at: self.expiresAt }\n requires self.plan in [active]; requires self.revision == self.productRevision\n requires count of { instrument: current(), reference: \"plan\", anchor: self.plan, states: [applied], limit: 366 } < self.maximum\n set: { acceptedAt: { field: self.now } }\n when assessed_fines is require_waiver { requires self.waiverPercent == 10000 }\n invoke: [{ selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366 }, action: waive_for_amendment, input: { amendment: { field: self.id } } }, { selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366 }, action: waive_for_amendment, input: { amendment: { field: self.id } } }]\n invoke: [{ selection: { instrument: all(collections.case), reference: \"plan\", anchor: self.plan, states: [opened, assigned], limit: 366 }, action: recall, input: {} }, { selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [proposed], limit: 366 }, action: cancel, input: {} }, { selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.plan, states: [proposed], limit: 366 }, action: cancel, input: {} }]\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 366, order: [position] }, action: amend, input: { amendment: { field: self.id } } }]\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [paid], limit: 366 }, action: verify_fixed_date, input: { amendment: { field: self.id } } }]\n }\n action withdraw { from: proposed, to: withdrawn, actor: { party: capital } }\n action decline { from: proposed, to: declined, actor: { party: borrower } }\n action expire { from: proposed, to: expired, actor: clock, due: { at: self.expiresAt } }\n action supersede { from: proposed, to: superseded, requires self.revision != self.productRevision, set: { staleReason: { literal: \"economic_revision_changed\" } } }\n }\n proposed_date: {\n fields { amendment: ref<amendment>, position: integer(1, months), date: date = at(self.amendment.dates, self.position), first: integer = divide(1, self.position), prior: integer = subtract(self.position, 1), previousPosition: integer = sum(self.prior, self.first), previous: date = at(self.amendment.dates, self.previousPosition) }\n lifecycle { states: [recorded], initial: recorded }\n action create { actor: { parent: amendment }, input { amendment: ref<amendment>, position: integer(1, months) }, requires self.date >= self.previous }\n action check_order { from: recorded, to: recorded, actor: { parent: amendment }, requires self.date > self.previous }\n }\n date_change: {\n fields { amendment: ref<amendment>, slice: ref<slice>, oldDate: date, newDate: date }\n lifecycle { states: [recorded], initial: recorded }\n action create { actor: { parent: slice }, input { amendment: ref<amendment>, slice: ref<slice>, oldDate: date, newDate: date }, requires unique \"amended_slice\" on [self.amendment, self.slice] }\n }\n settlement: {\n fields { plan: ref<parent>, identity: text, principal: money, profit: money, loss: money, kind: enum(cash, loss), share: money?, retainedProfit: money?\n allocatedPayable: account(capital, cash, \"allocatedProfitPayable\"), capital: account(capital, cash, \"capital\"), profitIncome: account(capital, cash, \"profitIncome\"), lossAccount: account(capital, claim, \"loss\") }\n lifecycle { states: [recorded, refunded], initial: recorded }\n action create { allowZero: true,\n actor: { parent: parent }\n input { plan: ref<parent>, identity: text, principal: money, profit: money, loss: money, kind: enum(cash, loss) }\n requires unique \"settlement_identity\" on [self.plan, self.identity]\n calculate: [{ target: \"share\", op: \"rate\", base: { field: self.profit }, bps: { literal: share }, rounding: \"floor\" }, { target: retainedProfit, op: \"subtract\", base: { field: self.profit }, subtract: [{ field: self.share }] }]\n moves self.share from self.profitIncome to self.allocatedPayable economics { purpose: internal, sourceParty: capital }\n }\n action refund { allowZero: true,\n from: recorded, to: refunded, actor: { parent: payment }\n moves self.share from self.allocatedPayable to self.profitIncome economics { purpose: internal, sourceParty: capital }\n }\n }\n slice: {\n revisioned: true\n fields {\n plan: ref<parent>, borrowerLimit: ref<limits>, portfolioLimit: ref<portfolio>, position: integer(1, months)\n originalDueAt: date = at(self.plan.dates, self.position), dueAt: date?, nextDueAt: date?, previousDueAt: date?, previousPosition: integer?, previousDate: date?, extensionLimit: date = after(self.originalDueAt, max_extension), lossEligibleAt: date?\n principalBase: money = divide(self.plan.principal, months)\n principalAllocated: money = multiply(self.principalBase, months)\n principalRemainder: money = subtract(self.plan.principal, self.principalAllocated)\n profitBase: money = divide(self.plan.profit, months)\n profitAllocated: money = multiply(self.profitBase, months)\n profitRemainder: money = subtract(self.plan.profit, self.profitAllocated)\n first: integer = divide(1, self.position)\n principalAdjustment: money = multiply(self.principalRemainder, self.first)\n profitAdjustment: money = multiply(self.profitRemainder, self.first)\n principal: money = sum(self.principalBase, self.principalAdjustment)\n profit: money = sum(self.profitBase, self.profitAdjustment)\n principalReceivable: account(self, claim), profitReceivable: account(self, claim), profitEarned: account(self, claim)\n payoffIdentity: text?, payoffRebate: money?, payoffProfitTotal: money?, payoffProfit: money?\n paymentBudget: money?, principalPayment: money?, principalBasePayment: money?, principalRatio: money?, profitPayment: money?, profitBudget: money?, collectibleProfit: money?, collectibleTotal: money?, ratioDenominator: integer = sum(10000, profit)\n debt: account(borrower, claim, contra, \"debt\"), loss: account(capital, claim, \"loss\")\n }\n lifecycle { states: [draft, pending, due, paid, written_off], initial: draft }\n action create {\n actor: { parent: parent }\n input { plan: ref<parent>, borrowerLimit: ref<limits>, portfolioLimit: ref<portfolio>, position: integer(1, months) }\n set: { dueAt: { field: self.originalDueAt } }\n invoke: [{ reference: self.id, action: refresh_loss_date, input: {} }]\n requires self.plan in [quoted]; requires unique \"signed_position\" on [self.plan, self.position]; requires self.borrowerLimit == self.plan.borrowerLimit; requires self.portfolioLimit == self.plan.portfolioLimit\n }\n action quote_pending {\n from: pending, to: pending, actor: { parent: payoff_quote }, input { quote: ref<payoff_quote> }\n requires input.quote.plan == self.plan\n invoke: [{ instrument: quote_piece, action: create, input: { quote: { field: input.quote }, slice: { field: self.id } } }]\n }\n action quote_due {\n from: due, to: due, actor: { parent: payoff_quote }, input { quote: ref<payoff_quote> }\n requires input.quote.plan == self.plan\n invoke: [{ instrument: quote_piece, action: create, input: { quote: { field: input.quote }, slice: { field: self.id } } }]\n }\n action refresh_loss_date {\n from: [draft, pending, due], to: draft, actor: { parent: current() }\n calculate: [{ target: lossEligibleAt, op: shift, date: { field: self.dueAt }, milliseconds: { literal: write_off_after }, direction: after }]\n }\n action amend {\n from: [pending, due], to: pending, actor: { parent: amendment }, input { amendment: ref<amendment> }\n requires input.amendment.plan == self.plan\n when allow_overdue is blocked { requires self.dueAt > self.now }\n calculate: [\n { target: nextDueAt, op: at, list: input.amendment.dates, position: { field: self.position } }\n { target: lossEligibleAt, op: shift, date: { field: self.nextDueAt }, milliseconds: { literal: write_off_after }, direction: after }\n ]\n requires self.nextDueAt > self.now; requires self.nextDueAt >= self.dueAt; requires self.nextDueAt <= self.extensionLimit\n set: { previousDueAt: { field: self.dueAt }, dueAt: { field: self.nextDueAt } }\n invoke: [{ instrument: date_change, action: create, input: { amendment: { field: input.amendment }, slice: { field: self.id }, oldDate: { field: self.previousDueAt }, newDate: { field: self.nextDueAt } } }]\n when profit_earned is by_schedule { invoke: [{ selection: { instrument: recognition, reference: \"slice\", anchor: self.id, states: [pending], limit: 1 }, action: reschedule, input: {} }] }\n }\n action verify_fixed_date {\n from: paid, to: paid, actor: { parent: amendment }, input { amendment: ref<amendment> }\n calculate: [{ target: nextDueAt, op: at, list: input.amendment.dates, position: { field: self.position } }]\n requires self.nextDueAt == self.dueAt\n }\n action activate { allowZero: true,\n from: draft, to: pending, actor: { parent: parent }\n moves self.principal from self.debt to self.principalReceivable economics { purpose: internal, sourceParty: borrower }\n moves self.profit from self.debt to self.profitReceivable economics { purpose: internal, sourceParty: borrower }\n when profit_earned is at_disbursement { moves self.profit from self.profitReceivable to self.profitEarned economics { purpose: internal, sourceParty: programOperator } }\n when profit_earned is by_schedule { invoke: [{ instrument: recognition, action: create, input: { slice: { field: self.id } } }] }\n }\n action mature {\n from: pending, to: due, actor: clock, due: { at: self.dueAt }\n }\n action collect {\n from: [pending, due], to: preserve, actor: { parent: payment }\n input { payment: ref<payment> }\n requires input.payment.plan == self.plan\n when profit_earned is on_payment { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitReceivable.balance }] }] }\n when profit_earned is by_schedule { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitEarned.balance }] }] }\n when profit_earned is at_disbursement { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitEarned.balance }] }] }\n when apply is principal_profit {\n invoke: [\n { instrument: principal_piece, action: create, input: { slice: { field: self.id }, payment: { field: input.payment }, limit: { field: self.principalReceivable.balance } } }\n { instrument: profit_piece, action: create, input: { slice: { field: self.id }, payment: { field: input.payment }, limit: { field: self.collectibleProfit } } }\n { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 1, where: { id: { field: self.id }, principalReceivable.balance: { literal: \"0\" }, profitReceivable.balance: { literal: \"0\" }, profitEarned.balance: { literal: \"0\" } } }, action: complete, input: {} }\n ]\n }\n }\n action collect_waterfall {\n from: [pending, due], to: preserve, actor: { parent: payment }, input { payment: ref<payment> }\n requires input.payment.plan == self.plan\n when profit_earned is on_payment { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitReceivable.balance }] }] }\n when profit_earned is by_schedule { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitEarned.balance }] }] }\n when profit_earned is at_disbursement { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitEarned.balance }] }] }\n invoke: [\n { selection: { instrument: all(financing.late_charge), reference: \"slice\", anchor: self.id, states: [assessed], limit: charge_limit, order: [overdueAt] }, action: collect, input: { payment: { field: input.payment } } }\n { selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [assessed], limit: charge_limit, order: [overdueAt], where: { assessment.slice: { field: self.id } } }, action: collect, input: { payment: { field: input.payment } } }\n { instrument: profit_piece, action: create, input: { slice: { field: self.id }, payment: { field: input.payment }, limit: { field: self.collectibleProfit } } }\n { instrument: principal_piece, action: create, input: { slice: { field: self.id }, payment: { field: input.payment }, limit: { field: self.principalReceivable.balance } } }\n { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 1, where: { id: { field: self.id }, principalReceivable.balance: { literal: \"0\" }, profitReceivable.balance: { literal: \"0\" }, profitEarned.balance: { literal: \"0\" } } }, action: complete, input: {} }\n ]\n }\n action collect_pro_rata {\n from: [pending, due], to: preserve, actor: { parent: payment }, input { payment: ref<payment> }\n requires input.payment.plan == self.plan\n when profit_earned is on_payment { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitReceivable.balance }] }] }\n when profit_earned is by_schedule { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitEarned.balance }] }] }\n when profit_earned is at_disbursement { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitEarned.balance }] }] }\n calculate: [\n { target: collectibleTotal, op: sum, values: [{ field: self.principalReceivable.balance }, { field: self.collectibleProfit }] }\n { target: paymentBudget, op: minimum, values: [{ field: input.payment.held.balance }, { field: self.collectibleTotal }] }\n { target: principalRatio, op: ratio, amount: { field: self.paymentBudget }, numerator: { literal: 10000 }, denominator: { field: self.ratioDenominator }, rounding: floor }\n { target: principalBasePayment, op: minimum, values: [{ field: self.principalRatio }, { field: self.principalReceivable.balance }] }\n { target: profitBudget, op: subtract, base: { field: self.paymentBudget }, subtract: [{ field: self.principalBasePayment }] }\n { target: profitPayment, op: minimum, values: [{ field: self.profitBudget }, { field: self.collectibleProfit }] }\n { target: principalPayment, op: subtract, base: { field: self.paymentBudget }, subtract: [{ field: self.profitPayment }] }\n ]\n invoke: [\n { instrument: principal_piece, action: create, input: { slice: { field: self.id }, payment: { field: input.payment }, limit: { field: self.principalPayment } } }\n { instrument: profit_piece, action: create, input: { slice: { field: self.id }, payment: { field: input.payment }, limit: { field: self.profitPayment } } }\n { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 1, where: { id: { field: self.id }, principalReceivable.balance: { literal: \"0\" }, profitReceivable.balance: { literal: \"0\" }, profitEarned.balance: { literal: \"0\" } } }, action: complete, input: {} }\n ]\n }\n action complete {\n from: [pending, due], to: paid\n requires self.principalReceivable.balance == \"0\"; requires self.profitReceivable.balance == \"0\"; requires self.profitEarned.balance == \"0\"\n }\n action restore { from: [pending, due, paid], to: pending, actor: { parent: payment } }\n action payoff { allowZero: true,\n from: [pending, due], to: paid, actor: { parent: parent }, input { identity: text }\n set: { payoffIdentity: { field: input.identity } }\n calculate: [{ target: payoffRebate, op: rate, base: { field: self.profitReceivable.balance }, bps: { literal: payoff_rebate }, rounding: floor }, { target: payoffProfitTotal, op: sum, values: [{ field: self.profitReceivable.balance }, { field: self.profitEarned.balance }] }, { target: payoffProfit, op: subtract, base: { field: self.payoffProfitTotal }, subtract: [{ field: self.payoffRebate }] }]\n moves self.principalReceivable.balance from self.plan.borrower to self.plan.capital economics { purpose: principal, sourceParty: borrower }\n moves self.payoffProfit from self.plan.borrower to self.plan.profitIncome economics { recipient: capital, company: { purpose: earning, sourceParty: borrower }, participant: { purpose: pass_through, sourceParty: borrower } }\n moves self.principalReceivable.balance from self.principalReceivable to self.debt economics { purpose: internal, sourceParty: programOperator }\n moves self.profitReceivable.balance from self.profitReceivable to self.debt economics { purpose: internal, sourceParty: programOperator }\n moves self.profitEarned.balance from self.profitEarned to self.debt economics { purpose: internal, sourceParty: programOperator }\n }\n action write_off { allowZero: true,\n from: [pending, due], to: written_off, actor: { parent: parent }\n moves self.principalReceivable.balance from self.principalReceivable to self.loss economics { purpose: internal, sourceParty: programOperator }; moves self.profitReceivable.balance from self.profitReceivable to self.debt economics { purpose: internal, sourceParty: programOperator }; moves self.profitEarned.balance from self.profitEarned to self.loss economics { purpose: internal, sourceParty: programOperator }\n }\n }\n recognition: {\n fields { slice: ref<slice>, dueAt: date = after(self.slice.dueAt, 0) }\n lifecycle { states: [pending, recognised], initial: pending }\n action create { actor: { parent: slice }, input { slice: ref<slice> }, requires unique \"profit_recognition\" on [self.slice] }\n action reschedule { from: pending, to: pending, actor: { parent: slice }, calculate: [{ target: dueAt, op: shift, date: { field: self.slice.dueAt }, milliseconds: { literal: 0 }, direction: after }] }\n action mature { allowZero: true, from: pending, to: recognised, actor: clock, due: { at: self.dueAt }, moves self.slice.profitReceivable.balance from self.slice.profitReceivable to self.slice.profitEarned economics { purpose: internal, sourceParty: programOperator } }\n }\n payment: {\n revisioned: true\n fields { plan: ref<parent>, amount: money, paymentIdentity: text, held: account of self\n outstandingPrincipal: money?, outstandingProfit: money?, outstandingFines: money?, outstandingCosts: money?, outstandingTotal: money?, principalReturned: money?, profitReturned: money?, lossRecorded: money? }\n\n lifecycle { states: [pending, paid, refunded], initial: pending }\n action create { input { plan: ref<parent>, amount: money, paymentIdentity: text } requires self.plan in [active]; requires unique \"payment_identity\" on [self.plan, self.paymentIdentity] }\n action pay {\n expansionLimit: 8192\n from: pending, to: paid, actor: { party: borrower }\n calculate: [{ target: outstandingPrincipal, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366, order: [position] }, measure: { sum: \"principalReceivable.balance\" } }]\n when profit_earned is on_payment { calculate: [{ target: outstandingProfit, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366, order: [position] }, measure: { sum: \"profitReceivable.balance\" } }] }\n when profit_earned is by_schedule { calculate: [{ target: outstandingProfit, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366, order: [position] }, measure: { sum: \"profitEarned.balance\" } }] }\n when profit_earned is at_disbursement { calculate: [{ target: outstandingProfit, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366, order: [position] }, measure: { sum: \"profitEarned.balance\" } }] }\n when apply is fines_profit_principal {\n calculate: [{ target: outstandingFines, op: aggregate, selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366, order: [overdueAt] }, measure: { sum: \"receivable.balance\" } }, { target: outstandingCosts, op: aggregate, selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366, order: [overdueAt] }, measure: { sum: \"receivable.balance\" } }, { target: outstandingTotal, op: sum, values: [{ field: self.outstandingPrincipal }, { field: self.outstandingProfit }, { field: self.outstandingFines }, { field: self.outstandingCosts }] }]\n }\n when apply is principal_profit { calculate: [{ target: outstandingTotal, op: sum, values: [{ field: self.outstandingPrincipal }, { field: self.outstandingProfit }] }] }\n when apply is pro_rata { calculate: [{ target: outstandingTotal, op: sum, values: [{ field: self.outstandingPrincipal }, { field: self.outstandingProfit }] }] }\n requires self.plan in [active]; requires self.amount <= self.outstandingTotal\n moves self.amount from self.plan.borrower to self.held economics { purpose: principal, sourceParty: borrower }\n when apply is principal_profit {\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 366, order: [position] }, action: collect, guard: { kind: compare, left: { field: self.held.balance }, operator: \">\", right: { literal: \"0\" } }, input: { payment: { field: self.id } } }]\n }\n when apply is fines_profit_principal {\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 366, order: [position] }, action: collect_waterfall, guard: { kind: compare, left: { field: self.held.balance }, operator: \">\", right: { literal: \"0\" } }, input: { payment: { field: self.id } } }]\n }\n when apply is pro_rata {\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 366, order: [position] }, action: collect_pro_rata, guard: { kind: compare, left: { field: self.held.balance }, operator: \">\", right: { literal: \"0\" } }, input: { payment: { field: self.id } } }]\n }\n invoke: [{ reference: self.id, action: record, input: {} }]\n }\n action record {\n from: paid, to: paid, actor: { parent: current() }\n requires self.held.balance == \"0\"\n calculate: [{ target: principalReturned, op: aggregate, selection: { instrument: principal_piece, reference: \"payment\", anchor: self.id, states: [paid], limit: 366 }, measure: { sum: \"amount\" } }, { target: profitReturned, op: aggregate, selection: { instrument: profit_piece, reference: \"payment\", anchor: self.id, states: [paid], limit: 366 }, measure: { sum: \"amount\" } }]\n invoke: [{ reference: self.plan, action: record_payment, input: { identity: { field: self.paymentIdentity }, principal: { field: self.principalReturned }, profit: { field: self.profitReturned } } }]\n }\n action refund {\n from: paid, to: refunded, actor: { party: capital }\n requires unique \"settlement_consumption\" on [self.plan, self.paymentIdentity]; requires self.plan in [active, paid]\n requires count of { instrument: settlement, reference: \"plan\", anchor: self.plan, states: [recorded], limit: 366, where: { identity: { field: self.paymentIdentity } } } == 1\n invoke: [{ selection: { instrument: settlement, reference: \"plan\", anchor: self.plan, states: [recorded], limit: 366, where: { identity: { field: self.paymentIdentity } } }, action: refund, input: {} }]\n when apply is fines_profit_principal {\n invoke: [{ selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366, order: [overdueAt] }, action: refund, input: { payment: { field: self.id } } }, { selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366, order: [overdueAt] }, action: refund, input: { payment: { field: self.id } } }]\n }\n invoke: [{ reference: self.plan, action: restore, input: {} }, { selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, action: restore, input: {} }, { selection: { instrument: principal_piece, reference: \"payment\", anchor: self.id, states: [paid], limit: 366 }, action: refund, input: {} }, { selection: { instrument: profit_piece, reference: \"payment\", anchor: self.id, states: [paid], limit: 366 }, action: refund, input: {} }]\n }\n }\n principal_piece: {\n fields { slice: ref<slice>, payment: ref<payment>, limit: money, amount: money? }\n lifecycle { states: [paid, refunded], initial: paid }\n action create { allowZero: true,\n calculate: [{ target: amount, op: minimum, values: [{ field: self.payment.held.balance }, { field: self.slice.principalReceivable.balance }, { field: self.limit }] }]\n actor: { parent: slice }\n input { slice: ref<slice>, payment: ref<payment>, limit: money }\n requires unique \"principal_receipt\" on [self.slice, self.payment]\n moves self.amount from self.payment.held to self.slice.plan.capital economics { purpose: principal, sourceParty: programOperator }; moves self.amount from self.slice.principalReceivable to self.slice.debt economics { purpose: internal, sourceParty: programOperator }\n }\n action refund { allowZero: true,\n from: paid, to: refunded, actor: { parent: payment }\n moves self.amount from self.slice.plan.capital to self.slice.plan.borrower economics { purpose: principal, sourceParty: capital }; moves self.amount from self.slice.debt to self.slice.principalReceivable economics { purpose: internal, sourceParty: borrower }\n }\n }\n profit_piece: {\n fields { cashReceipt: text?, slice: ref<slice>, payment: ref<payment>, limit: money, amount: money? }\n lifecycle { states: [paid, refunded], initial: paid }\n action create { allowZero: true,\n calculate: [{ target: amount, op: minimum, values: [{ field: self.payment.held.balance }, { field: self.limit }] }]\n actor: { parent: slice }\n input { slice: ref<slice>, payment: ref<payment>, limit: money }\n requires unique \"profit_receipt\" on [self.slice, self.payment]\n moves self.amount from self.payment.held to self.slice.plan.profitIncome capture \"cashReceipt\" economics { recipient: capital, company: { purpose: earning, sourceParty: borrower }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n when profit_earned is on_payment { moves self.amount from self.slice.profitReceivable to self.slice.debt economics { purpose: internal, sourceParty: programOperator } }\n when profit_earned is by_schedule { moves self.amount from self.slice.profitEarned to self.slice.debt economics { purpose: internal, sourceParty: programOperator } }\n when profit_earned is at_disbursement { moves self.amount from self.slice.profitEarned to self.slice.debt economics { purpose: internal, sourceParty: programOperator } }\n }\n action refund { allowZero: true,\n from: paid, to: refunded, actor: { parent: payment }\n moves self.amount from self.slice.plan.profitIncome to self.slice.plan.borrower economics { recipient: capital, company: { purpose: earning, sourceParty: capital, reversalOf: self.cashReceipt }, participant: unclassified }\n when profit_earned is on_payment { moves self.amount from self.slice.debt to self.slice.profitReceivable economics { purpose: internal, sourceParty: borrower } }\n when profit_earned is by_schedule { moves self.amount from self.slice.debt to self.slice.profitEarned economics { purpose: internal, sourceParty: borrower } }\n when profit_earned is at_disbursement { moves self.amount from self.slice.debt to self.slice.profitEarned economics { purpose: internal, sourceParty: borrower } }\n }\n }\n }\n}\n\ninstrument late_charge(on: ref<financing.installments>[], grace: duration = 3d, fine: money = 50 SAR, cap: money = 25 SAR, fines_to: party = programOperator, costs_to: party = programOperator, borrower: party = party(person)) {\n parameterDiagnostics {\n fine {\n accepts: \"a fixed amount\"\n percentage: \"a percentage of overdue debt\"\n fix: \"Use a fixed amount only if that is the intended policy. A percentage charge needs an authored rate calculation; do not approximate it with a cash amount.\"\n }\n }\n revisioned: true\n familyRevision: 1\n summary: \"Separate fine and evidenced recovery claims on an overdue installment.\"\n fields {\n plan: ref<on>, slice: ref<on.slice>, borrower: account of borrower, fine: money = fine, overdueAt: date?\n receivable: account(self, claim), debt: account(borrower, claim, contra, \"debt\")\n }\n lifecycle { states: [proposed, assessed, collected, waived], initial: proposed }\n action create { calculate: [{ target: overdueAt, op: shift, date: { field: self.slice.dueAt }, milliseconds: { literal: grace }, direction: after }], requires unique \"late_assessment\" on [self.slice, self.overdueAt]; requires self.borrower == self.slice.plan.borrower; requires self.plan == self.slice.plan }\n action assess { allowZero: true,\n from: proposed, to: assessed, actor: clock, due: { at: self.overdueAt }\n requires self.slice.principalReceivable.balance > \"0\"\n moves self.fine from self.debt to self.receivable economics { purpose: internal, sourceParty: borrower }\n }\n action collect {\n from: [assessed, collected], to: assessed, actor: { parent: child(on, slice) }, input { payment: ref<on.payment> }\n requires input.payment in [paid]\n requires input.payment.plan == self.plan\n invoke: [{ instrument: receipt, action: create, input: { assessment: { field: self.id }, payment: { field: input.payment } } }, { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [assessed], limit: 1, where: { id: { field: self.id }, receivable.balance: { literal: \"0\" } } }, action: finish, input: {} }]\n }\n action payoff { allowZero: true,\n from: [assessed, collected], to: collected, actor: { parent: on }\n requires self.plan in [paid]\n moves self.receivable.balance from self.plan.borrower to fines_to economics { recipient: fines_to, company: { purpose: earning, sourceParty: borrower }, participant: { purpose: pass_through, sourceParty: borrower } }\n moves self.receivable.balance from self.receivable to self.debt economics { purpose: internal, sourceParty: programOperator }\n }\n action finish { from: assessed, to: collected, actor: { parent: current() }, requires self.receivable.balance == \"0\" }\n action cancel { from: proposed, to: waived }\n action waive_for_amendment {\n from: [assessed, collected], to: assessed, actor: { parent: child(on, amendment) }, input { amendment: ref<on.amendment> }\n requires input.amendment.plan == self.plan; requires input.amendment in [applied]\n invoke: [{ instrument: waiver, action: create, input: { assessment: { field: self.id }, amendment: { field: input.amendment } } }]\n }\n action waive { allowZero: true, from: [assessed, collected], to: waived, actor: { parent: waiver_request }, input { reason: text, evidence: text }, moves self.receivable.balance from self.receivable to self.debt economics { purpose: internal, sourceParty: programOperator } }\n action refund {\n from: [assessed, collected], to: assessed, actor: { party: fines_to }, input { payment: ref<on.payment> }\n requires input.payment in [paid, refunded]\n requires input.payment.plan == self.plan\n invoke: [{ selection: { instrument: receipt, reference: \"payment\", anchor: input.payment, states: [paid], limit: 1, where: { assessment: { field: self.id } } }, action: refund, input: {} }, { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [assessed], limit: 1, where: { id: { field: self.id }, receivable.balance: { literal: \"0\" } } }, action: finish, input: {} }]\n }\n records {\n waiver_request: {\n fields { assessment: ref<parent>, reason: text, evidence: text }\n lifecycle { states: [requested, applied, cancelled], initial: requested }\n action create { requires self.assessment in [assessed, collected] }\n action apply {\n from: requested, to: applied, actor: { party: fines_to }, input { reason: text, evidence: text }\n invoke: [{ reference: self.assessment, action: waive, input: { reason: { field: input.reason }, evidence: { field: input.evidence } } }]\n }\n action cancel { from: requested, to: cancelled }\n }\n waiver: {\n fields { assessment: ref<parent>, amendment: ref<on.amendment>, amount: money? }\n lifecycle { states: [recorded], initial: recorded }\n action create { allowZero: true,\n actor: { parent: parent }, input { assessment: ref<parent>, amendment: ref<on.amendment> }\n calculate: [{ target: amount, op: rate, base: { field: self.assessment.receivable.balance }, bps: { field: self.amendment.waiverPercent }, rounding: floor }]\n requires unique \"amendment_waiver\" on [self.assessment, self.amendment]\n moves self.amount from self.assessment.receivable to self.assessment.debt economics { purpose: internal, sourceParty: programOperator }\n }\n }\n receipt: {\n fields { cashReceipt: text?, assessment: ref<parent>, payment: ref<on.payment>, amount: money? }\n lifecycle { states: [paid, refunded], initial: paid }\n action create { allowZero: true, calculate: [{ target: amount, op: minimum, values: [{ field: self.payment.held.balance }, { field: self.assessment.receivable.balance }] }], actor: { parent: parent }, input { assessment: ref<parent>, payment: ref<on.payment> }, requires input.payment.plan == self.assessment.plan; requires unique \"fine_receipt\" on [self.assessment, self.payment]; moves self.amount from self.payment.held to fines_to capture \"cashReceipt\" economics { recipient: fines_to, company: { purpose: earning, sourceParty: borrower }, participant: { purpose: participant_payout, sourceParty: programOperator } }; moves self.amount from self.assessment.receivable to self.assessment.debt economics { purpose: internal, sourceParty: programOperator } }\n action refund { allowZero: true, from: paid, to: refunded, actor: { parent: parent }, moves self.amount from fines_to to self.payment.plan.borrower economics { recipient: fines_to, company: { purpose: earning, sourceParty: fines_to, reversalOf: self.cashReceipt }, participant: unclassified }; moves self.amount from self.assessment.debt to self.assessment.receivable economics { purpose: internal, sourceParty: borrower } }\n }\n\n cost: {\n revisioned: true\n fields {\n plan: ref<on>, assessment: ref<parent>, overdueAt: date?, evidence: text, evidencedCost: money, amount: money = minimum(self.evidencedCost, cap)\n receivable: account(self, claim), debt: account(borrower, claim, contra, \"debt\")\n }\n lifecycle { states: [proposed, assessed, collected, waived], initial: proposed }\n action create { calculate: [{ target: overdueAt, op: shift, date: { field: self.assessment.overdueAt }, milliseconds: { literal: 0 }, direction: after }], requires unique \"recovery_assessment\" on [self.assessment]; requires self.plan == self.assessment.plan }\n action assess { allowZero: true,\n from: proposed, to: assessed, actor: clock, due: { at: self.assessment.overdueAt }\n requires self.assessment.slice.principalReceivable.balance > \"0\"\n moves self.amount from self.debt to self.receivable economics { purpose: internal, sourceParty: borrower }\n }\n action collect {\n from: [assessed, collected], to: assessed, actor: { parent: child(on, slice) }, input { payment: ref<on.payment> }\n requires input.payment in [paid]\n requires input.payment.plan == self.plan\n invoke: [{ instrument: receipt, action: create, input: { assessment: { field: self.id }, payment: { field: input.payment } } }, { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [assessed], limit: 1, where: { id: { field: self.id }, receivable.balance: { literal: \"0\" } } }, action: finish, input: {} }]\n }\n action payoff { allowZero: true,\n from: [assessed, collected], to: collected, actor: { parent: on }\n requires self.plan in [paid]\n moves self.receivable.balance from self.plan.borrower to costs_to economics { recipient: costs_to, company: { purpose: earning, sourceParty: borrower }, participant: { purpose: pass_through, sourceParty: borrower } }\n moves self.receivable.balance from self.receivable to self.debt economics { purpose: internal, sourceParty: programOperator }\n }\n action finish { from: assessed, to: collected, actor: { parent: current() }, requires self.receivable.balance == \"0\" }\n action cancel { from: proposed, to: waived }\n action waive_for_amendment {\n from: [assessed, collected], to: assessed, actor: { parent: child(on, amendment) }, input { amendment: ref<on.amendment> }\n requires input.amendment.plan == self.plan; requires input.amendment in [applied]\n invoke: [{ instrument: waiver, action: create, input: { assessment: { field: self.id }, amendment: { field: input.amendment } } }]\n }\n action waive { allowZero: true, from: [assessed, collected], to: waived, actor: { parent: waiver_request }, input { reason: text, evidence: text }, moves self.receivable.balance from self.receivable to self.debt economics { purpose: internal, sourceParty: programOperator } }\n action refund {\n from: [assessed, collected], to: assessed, actor: { party: costs_to }, input { payment: ref<on.payment> }\n requires input.payment in [paid, refunded]\n requires input.payment.plan == self.plan\n invoke: [{ selection: { instrument: receipt, reference: \"payment\", anchor: input.payment, states: [paid], limit: 1, where: { assessment: { field: self.id } } }, action: refund, input: {} }, { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [assessed], limit: 1, where: { id: { field: self.id }, receivable.balance: { literal: \"0\" } } }, action: finish, input: {} }]\n }\n records {\n waiver_request: {\n fields { assessment: ref<parent>, reason: text, evidence: text }\n lifecycle { states: [requested, applied, cancelled], initial: requested }\n action create { requires self.assessment in [assessed, collected] }\n action apply {\n from: requested, to: applied, actor: { party: costs_to }, input { reason: text, evidence: text }\n invoke: [{ reference: self.assessment, action: waive, input: { reason: { field: input.reason }, evidence: { field: input.evidence } } }]\n }\n action cancel { from: requested, to: cancelled }\n }\n waiver: {\n fields { assessment: ref<parent>, amendment: ref<on.amendment>, amount: money? }\n lifecycle { states: [recorded], initial: recorded }\n action create { allowZero: true,\n actor: { parent: parent }, input { assessment: ref<parent>, amendment: ref<on.amendment> }\n calculate: [{ target: amount, op: rate, base: { field: self.assessment.receivable.balance }, bps: { field: self.amendment.waiverPercent }, rounding: floor }]\n requires unique \"amendment_waiver\" on [self.assessment, self.amendment]\n moves self.amount from self.assessment.receivable to self.assessment.debt economics { purpose: internal, sourceParty: programOperator }\n }\n }\n receipt: {\n fields { cashReceipt: text?, assessment: ref<parent>, payment: ref<on.payment>, amount: money? }\n lifecycle { states: [paid, refunded], initial: paid }\n action create { allowZero: true, calculate: [{ target: amount, op: minimum, values: [{ field: self.payment.held.balance }, { field: self.assessment.receivable.balance }] }], actor: { parent: parent }, input { assessment: ref<parent>, payment: ref<on.payment> }, requires input.payment.plan == self.assessment.plan; requires unique \"cost_receipt\" on [self.assessment, self.payment]; moves self.amount from self.payment.held to costs_to capture \"cashReceipt\" economics { recipient: costs_to, company: { purpose: earning, sourceParty: borrower }, participant: { purpose: participant_payout, sourceParty: programOperator } }; moves self.amount from self.assessment.receivable to self.assessment.debt economics { purpose: internal, sourceParty: programOperator } }\n action refund { allowZero: true, from: paid, to: refunded, actor: { parent: parent }, moves self.amount from costs_to to self.payment.plan.borrower economics { recipient: costs_to, company: { purpose: earning, sourceParty: costs_to, reversalOf: self.cashReceipt }, participant: unclassified }; moves self.amount from self.assessment.debt to self.assessment.receivable economics { purpose: internal, sourceParty: borrower } }\n }\n }\n }\n }\n}\n\ninstrument limits(per_borrower: money, borrower: party = party(person), active_plans: integer = 1) {\n familyRevision: 1\n summary: \"One outstanding balance ceiling per borrower.\"\n fields { borrower: account of borrower, limit: money = per_borrower, activePlans: integer = active_plans }\n lifecycle { states: [pending, approved], initial: pending }\n action create { requires unique \"borrower_limit\" on [self.borrower] }\n action approve { from: pending, to: approved }\n}\n\ninstrument portfolio_limit(limit: money) {\n familyRevision: 1\n summary: \"One shared ceiling on the principal the product may hold.\"\n fields { key: text = \"portfolio\", limit: money = limit }\n lifecycle { states: [pending, approved], initial: pending }\n action create { requires unique \"portfolio_limit\" on [self.key] }\n action approve { from: pending, to: approved }\n}\n\ninstrument credit_line(borrower: party = programOperator, adapter: text, limit: money, expires: date) {\n familyRevision: 1\n summary: \"A revolving facility from an outside lender; each draw is a separate immutable advance.\"\n fields { borrower: account of borrower, facility: account(borrower, cash, \"facility\"), debt: account(borrower, claim, contra, \"debt\"), limit: money = limit, expiresAt: date = expires }\n lifecycle { states: [pending, active, suspended, closed], initial: pending }\n action create {}\n action activate {\n from: pending, to: active, actor: { party: borrower }\n subject { adapter: adapter }\n }\n action suspend { from: active, to: suspended, actor: { party: borrower } }\n action resume { from: suspended, to: active, actor: { party: borrower } }\n action close { from: [active, suspended], to: closed, due: { at: self.expiresAt }, requires count of { instrument: all(financing.advance), reference: \"line\", anchor: self.id, states: [drawn], limit: 366 } == 0 }\n}\n\ninstrument advance(line: ref<financing.credit_line>, amount: money = runtime) {\n familyRevision: 1\n summary: \"A single facility draw with an immutable principal and full repayment.\"\n fields { line: ref<line>, amount: money = amount, principalReceivable: account(self, claim) }\n lifecycle { states: [pending, drawn, repaid, cancelled], initial: pending }\n action create { requires self.amount <= self.line.limit }\n invariants sum \"principalReceivable.balance\" of { instrument: all(financing.advance), reference: \"line\", anchor: self.line, states: [drawn], limit: 366 } <= self.line.limit\n action draw {\n from: pending, to: drawn\n requires self.line in [active]\n deadline: { at: self.line.expiresAt }\n moves self.amount from self.line.facility to self.line.borrower; moves self.amount from self.line.debt to self.principalReceivable\n }\n action repay { from: drawn, to: repaid, moves self.amount from self.line.borrower to self.line.facility; moves self.amount from self.principalReceivable to self.line.debt }\n action cancel { from: pending, to: cancelled }\n}\n"],
|
|
7
|
+
["financing.hsx", "header financing\n\n// Economics: Principal advances and repayments are excluded from earnings. Claims, waivers,\n// write-offs and allocations are internal. Paid profit and company charges are\n// earnings; receipt refunds reverse captured cash. Outside recovery recipients\n// receive payouts from held company cash, or pass-through direct customer cash.\n\n// Expose create and sign on installments, then collect_down_payment as checkout\n// for disburse_to: funds. Checkout requires a signed plan and pending escrow;\n// it tops up only the missing down payment, without advancing lender principal.\n// Disburse still collects any missing down payment, activates slices, and confirms\n// the fully funded hold. Existing escrow credit counts once toward the down payment.\n// Borrower-directed disbursement excludes collect_down_payment. A down_payment\n// there reduces principal but does not collect cash. Price is subject metadata,\n// not the borrower limit. The escrow payer and price must match the plan.\n// Expose escrow cancel to return checkout cash if financing is abandoned; plan\n// void alone cancels the agreement and does not refund its separate escrow.\n// Approve borrower and portfolio limits before disbursement. Create builds the\n// dated slice records; payments need a separate payment record and pay action.\n// Expose parent payoff separately and create a current, unexpired payoff_quote.\n// Expose late_charge.create as propose_assessment before the clock can assess;\n// provide matching plan, slice and borrower. Fine is fixed money, not a percentage.\n// Collection uses the minimum of payment cash and outstanding fine; a partial\n// payment does not settle the remaining fine. Recovery cost needs its own record.\n// Profit share credits capital's allocatedProfitPayable, not an outside agency.\n// Credit lines need adapter binding at activation; draws are ledger advances,\n// not evidence of outside funding. Caller-authorized limit approvals and advances\n// need the Product's operation authority. No clock declaration proves retries.\n\n// Cost: installments include cash and claim moves, child-account creation and\n// bounded invocations across slices and assessments. Month and charge limits affect\n// the bound. Run hsx cost on the selected policies; profit is not a platform tariff.\n\ninstrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3, profit: percent, disburse_to: enum(funds, borrower) = funds, profit_earned: enum(on_payment, by_schedule, at_disbursement) = on_payment, apply: enum(fines_profit_principal, principal_profit, pro_rata) = fines_profit_principal, payoff_rebate: percent = 100%, write_off_after: duration = 90d, max_extension: duration = 90d, max_amendments: integer(0, 366) = 2, waiver_limit: percent = 100%, amendment_expiry: duration = 7d, payoff_quote_expiry: duration = 1h, allow_overdue: enum(allowed, blocked) = allowed, assessed_fines: enum(carry, require_waiver) = carry, down_payment: percent = 0%, funds: ref<escrow.hold>?, borrower: party = party(person), capital: party = programOperator, share: percent = 0%, limits: ref<financing.limits> = object(financing.limits), portfolio: ref<financing.portfolio_limit> = object(financing.portfolio_limit)) {\n dependencies {\n funds {\n selector: disburse_to, is: funds\n message: \"Attachment `{attachment}` disburses into a hold, but `funds` is not bound.\"\n fix: \"Bind `funds: sale` to an escrow attachment. Choose `disburse_to: borrower` only if the borrower should receive the money directly.\"\n }\n }\n revisioned: true\n familyRevision: 1\n summary: \"Funding, profit recognition and payment order chosen by the program.\"\n fields {\n funds: ref<funds>?, borrower: account of borrower, settlementIdentity: text, borrowerLimit: ref<limits>, portfolioLimit: ref<portfolio>\n months: integer = months, dates: list(date, months)\n allocatedPayable: account(capital, cash, \"allocatedProfitPayable\"), capital: account(capital, cash, \"capital\"), profitIncome: account(capital, cash, \"profitIncome\"), loss: account(capital, claim, \"loss\")\n downPaymentRemaining: money?, downPaymentCredit: money?, principalReturned: money?, profitReturned: money?, lossRecorded: money?\n price: money = subject.price\n downPayment: money = rate(self.price, down_payment)\n principal: money = subtract(self.price, self.downPayment)\n profit: money = rate(self.principal, profit)\n total: money = sum(self.principal, self.profit)\n }\n lifecycle { states: [quoted, signed, active, paid, written_off, cancelled], initial: quoted }\n invariants count of { instrument: all(financing.installments), reference: \"borrowerLimit\", anchor: self.borrowerLimit, states: [active], limit: 366 } <= self.borrowerLimit.activePlans\n invariants sum \"principalReceivable.balance\" of { instrument: all(financing.installments.slice), reference: \"borrowerLimit\", anchor: self.borrowerLimit, states: [pending, due, paid], limit: 366 } <= self.borrowerLimit.limit\n invariants sum \"principalReceivable.balance\" of { instrument: all(financing.installments.slice), reference: \"portfolioLimit\", anchor: self.portfolioLimit, states: [pending, due, paid], limit: 366 } <= self.portfolioLimit.limit\n action create {\n subject { price: money }\n requires self.borrowerLimit.borrower == self.borrower\n when disburse_to is funds { requires self.borrower == self.funds.payer; requires self.price == self.funds.price }\n invoke: [{ range: { count: { literal: months }, maximum: months, bind: position }, instrument: slice, action: create, input: { plan: { field: self.id }, borrowerLimit: { field: self.borrowerLimit }, portfolioLimit: { field: self.portfolioLimit }, position: { field: position } } }]\n }\n action sign {\n from: quoted, to: signed, actor: { party: borrower }, input { signedOffer: text, affordabilityReference: text }\n requires count of { instrument: slice, reference: \"plan\", anchor: self.id, states: [draft], limit: 366 } == self.months\n }\n action collect_down_payment { allowZero: true,\n from: signed, to: signed, actor: { party: borrower }\n when disburse_to is borrower { requires true == false }\n when disburse_to is funds {\n requires self.funds in [pending]\n calculate: [{ target: downPaymentCredit, op: minimum, values: [{ field: self.funds.held.balance }, { field: self.downPayment }] }, { target: downPaymentRemaining, op: subtract, base: { field: self.downPayment }, subtract: [{ field: self.downPaymentCredit }] }]\n moves self.downPaymentRemaining from self.borrower to self.funds.held economics { purpose: principal, sourceParty: borrower }\n }\n }\n action disburse { allowZero: true,\n from: signed, to: active, actor: { party: capital }\n requires self.borrowerLimit in [approved]\n requires self.portfolioLimit in [approved]\n when disburse_to is funds {\n requires self.funds in [pending]\n invoke: [{ reference: self.id, action: fund_down_payment, input: {} }]\n }\n when disburse_to is borrower { moves self.principal from self.capital to self.borrower economics { purpose: principal, sourceParty: capital } }\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.id, states: [draft], limit: 366, order: [position] }, action: activate, input: {} }]\n when disburse_to is funds { invoke: [{ reference: self.funds, action: confirm, input: {} }] }\n }\n action fund_down_payment { allowZero: true,\n from: active, to: active, actor: { parent: current() }\n when disburse_to is funds {\n calculate: [{ target: downPaymentCredit, op: minimum, values: [{ field: self.funds.held.balance }, { field: self.downPayment }] }, { target: downPaymentRemaining, op: subtract, base: { field: self.downPayment }, subtract: [{ field: self.downPaymentCredit }] }]\n moves self.downPaymentRemaining from self.funds.payer to self.funds.held economics { purpose: principal, sourceParty: borrower }\n moves self.principal from self.capital to self.funds.held economics { purpose: principal, sourceParty: capital }\n }\n }\n action complete {\n from: active, to: paid\n requires count of { instrument: slice, reference: \"plan\", anchor: self.id, states: [pending, due], limit: 366 } == 0\n requires sum \"receivable.balance\" of { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.id, states: [assessed, collected], limit: 366 } == \"0\"\n requires sum \"receivable.balance\" of { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.id, states: [assessed, collected], limit: 366 } == \"0\"\n }\n action restore { from: [active, paid], to: active, actor: { parent: payment } }\n action payoff {\n from: active, to: paid, actor: { party: borrower }\n input { quote: ref<payoff_quote> }\n requires input.quote.plan == self.id; requires input.quote.revision == self.productRevision\n deadline: { at: input.quote.expiresAt }\n calculate: [\n { target: \"principalReturned\", op: \"aggregate\", selection: { instrument: slice, reference: \"plan\", anchor: self.id, states: [pending, due], limit: 366 }, measure: { sum: \"principalReceivable.balance\" } }\n ]\n invoke: [{ selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.id, states: [assessed, collected], limit: 366, order: [overdueAt] }, action: payoff, input: {} }, { selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.id, states: [assessed, collected], limit: 366, order: [overdueAt] }, action: payoff, input: {} }]\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.id, states: [pending, due], limit: 366, order: [position] }, action: payoff, input: { identity: { field: self.settlementIdentity } } }, { reference: self.id, action: record_payoff, input: {} }]\n }\n action record_payoff {\n from: paid, to: paid, actor: { parent: current() }\n calculate: [{ target: profitReturned, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.id, states: [paid], limit: 366, where: { payoffIdentity: { field: self.settlementIdentity } } }, measure: { sum: \"payoffProfit\" } }]\n invoke: [{ instrument: settlement, action: create, input: { plan: { field: self.id }, identity: { field: self.settlementIdentity }, principal: { field: self.principalReturned }, profit: { field: self.profitReturned }, loss: { literal: \"0\" }, kind: { literal: \"cash\" } } }]\n }\n action write_off {\n from: active, to: written_off, actor: { parent: write_off_request }\n input { overdueSlice: ref<slice> }\n calculate: [{ target: \"lossRecorded\", op: \"aggregate\", selection: { instrument: slice, reference: \"plan\", anchor: self.id, states: [pending, due], limit: 366 }, measure: { sum: \"principalReceivable.balance\" } }]\n due: { at: input.overdueSlice.lossEligibleAt }\n requires input.overdueSlice.plan == self.id; requires input.overdueSlice.principalReceivable.balance > \"0\"\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.id, states: [pending, due], limit: 366, order: [position] }, action: write_off, input: {} }, { instrument: settlement, action: create, input: { plan: { field: self.id }, identity: { field: self.settlementIdentity }, principal: { literal: \"0\" }, profit: { literal: \"0\" }, loss: { field: self.lossRecorded }, kind: { literal: \"loss\" } } }]\n }\n action record_payment {\n from: active, to: active, actor: { parent: payment }\n input { identity: text, principal: money, profit: money }\n invoke: [{ instrument: settlement, action: create, input: { plan: { field: self.id }, identity: { field: input.identity }, principal: { field: input.principal }, profit: { field: input.profit }, loss: { literal: \"0\" }, kind: { literal: \"cash\" } } }]\n }\n action cancel { from: quoted, to: cancelled }\n action void { from: signed, to: cancelled, actor: { party: borrower } }\n records {\n write_off_request: {\n fields { plan: ref<parent>, overdueSlice: ref<slice> }\n lifecycle { states: [requested, applied, cancelled], initial: requested }\n action create { requires self.overdueSlice.plan == self.plan; requires self.plan in [active] }\n action apply {\n from: requested, to: applied, actor: { party: capital }\n invoke: [{ reference: self.plan, action: write_off, input: { overdueSlice: { field: self.overdueSlice } } }]\n }\n action cancel { from: requested, to: cancelled }\n }\n payoff_quote: {\n fields {\n plan: ref<parent>, revision: text?, effectiveAt: date?, expiresAt: date = after(self.createdAt, payoff_quote_expiry)\n principal: money?, earnedProfit: money?, unearnedProfit: money?, rebate: money?, fines: money?, costs: money?, gross: money?, amount: money?\n }\n lifecycle { states: [quoted], initial: quoted }\n action create {\n requires self.plan in [active]\n set: { revision: { field: self.productRevision }, effectiveAt: { field: self.now } }\n invoke: [\n { selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending], limit: 366 }, action: quote_pending, input: { quote: { field: self.id } } }\n { selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [due], limit: 366 }, action: quote_due, input: { quote: { field: self.id } } }\n { reference: self.id, action: record, input: {} }\n ]\n }\n action record {\n from: quoted, to: quoted, actor: { parent: current() }\n calculate: [\n { target: principal, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, measure: { sum: \"principalReceivable.balance\" } }\n { target: earnedProfit, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, measure: { sum: \"profitEarned.balance\" } }\n { target: unearnedProfit, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, measure: { sum: \"profitReceivable.balance\" } }\n { target: rebate, op: aggregate, selection: { instrument: quote_piece, reference: \"quote\", anchor: self.id, states: [recorded], limit: 366 }, measure: { sum: \"rebate\" } }\n { target: fines, op: aggregate, selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366 }, measure: { sum: \"receivable.balance\" } }\n { target: costs, op: aggregate, selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366 }, measure: { sum: \"receivable.balance\" } }\n { target: gross, op: sum, values: [{ field: self.principal }, { field: self.earnedProfit }, { field: self.unearnedProfit }, { field: self.fines }, { field: self.costs }] }\n { target: amount, op: subtract, base: { field: self.gross }, subtract: [{ field: self.rebate }] }\n ]\n }\n }\n quote_piece: {\n fields { quote: ref<payoff_quote>, slice: ref<slice>, rebate: money = rate(self.slice.profitReceivable.balance, payoff_rebate) }\n lifecycle { states: [recorded], initial: recorded }\n action create { actor: { parent: slice }, input { quote: ref<payoff_quote>, slice: ref<slice> }, requires unique \"payoff_slice_quote\" on [self.quote, self.slice] }\n }\n amendment: {\n fields {\n plan: ref<parent>, dates: list(date, months), agreement: text, waiverPercent: percent, waiverEvidence: text, maximumWaiver: percent = waiver_limit\n revision: text?, acceptedAt: date?, staleReason: text?, expiresAt: date = after(self.createdAt, amendment_expiry)\n fineDisposition: enum(carry, require_waiver) = assessed_fines, addedProfit: money = 0 SAR\n principalSnapshot: money?, earnedProfitSnapshot: money?, unearnedProfitSnapshot: money?, finesSnapshot: money?, costsSnapshot: money?\n extension: duration = max_extension, maximum: integer = max_amendments\n }\n lifecycle { states: [proposed, applied, declined, withdrawn, expired, superseded], initial: proposed }\n action create {\n actor: { party: capital }\n requires self.plan in [active]; requires self.waiverPercent <= self.maximumWaiver\n set: { revision: { field: self.productRevision } }\n calculate: [\n { target: principalSnapshot, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, measure: { sum: \"principalReceivable.balance\" } }\n { target: earnedProfitSnapshot, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, measure: { sum: \"profitEarned.balance\" } }\n { target: unearnedProfitSnapshot, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, measure: { sum: \"profitReceivable.balance\" } }\n { target: finesSnapshot, op: aggregate, selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366 }, measure: { sum: \"receivable.balance\" } }\n { target: costsSnapshot, op: aggregate, selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366 }, measure: { sum: \"receivable.balance\" } }\n ]\n requires count of { instrument: current(), reference: \"plan\", anchor: self.plan, states: [applied], limit: 366 } < self.maximum\n invoke: [{ range: { count: { literal: months }, maximum: months, bind: position }, instrument: proposed_date, action: create, input: { amendment: { field: self.id }, position: { field: position } } }, { selection: { instrument: proposed_date, reference: \"amendment\", anchor: self.id, states: [recorded], limit: 366, where: { first: { literal: 0 } } }, action: check_order, input: {} }]\n }\n action accept {\n from: proposed, to: applied, actor: { party: borrower }, deadline: { at: self.expiresAt }\n requires self.plan in [active]; requires self.revision == self.productRevision\n requires count of { instrument: current(), reference: \"plan\", anchor: self.plan, states: [applied], limit: 366 } < self.maximum\n set: { acceptedAt: { field: self.now } }\n when assessed_fines is require_waiver { requires self.waiverPercent == 10000 }\n invoke: [{ selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366 }, action: waive_for_amendment, input: { amendment: { field: self.id } } }, { selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366 }, action: waive_for_amendment, input: { amendment: { field: self.id } } }]\n invoke: [{ selection: { instrument: all(collections.case), reference: \"plan\", anchor: self.plan, states: [opened, assigned], limit: 366 }, action: recall, input: {} }, { selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [proposed], limit: 366 }, action: cancel, input: {} }, { selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.plan, states: [proposed], limit: 366 }, action: cancel, input: {} }]\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 366, order: [position] }, action: amend, input: { amendment: { field: self.id } } }]\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [paid], limit: 366 }, action: verify_fixed_date, input: { amendment: { field: self.id } } }]\n }\n action withdraw { from: proposed, to: withdrawn, actor: { party: capital } }\n action decline { from: proposed, to: declined, actor: { party: borrower } }\n action expire { from: proposed, to: expired, actor: clock, due: { at: self.expiresAt } }\n action supersede { from: proposed, to: superseded, requires self.revision != self.productRevision, set: { staleReason: { literal: \"economic_revision_changed\" } } }\n }\n proposed_date: {\n fields { amendment: ref<amendment>, position: integer(1, months), date: date = at(self.amendment.dates, self.position), first: integer = divide(1, self.position), prior: integer = subtract(self.position, 1), previousPosition: integer = sum(self.prior, self.first), previous: date = at(self.amendment.dates, self.previousPosition) }\n lifecycle { states: [recorded], initial: recorded }\n action create { actor: { parent: amendment }, input { amendment: ref<amendment>, position: integer(1, months) }, requires self.date >= self.previous }\n action check_order { from: recorded, to: recorded, actor: { parent: amendment }, requires self.date > self.previous }\n }\n date_change: {\n fields { amendment: ref<amendment>, slice: ref<slice>, oldDate: date, newDate: date }\n lifecycle { states: [recorded], initial: recorded }\n action create { actor: { parent: slice }, input { amendment: ref<amendment>, slice: ref<slice>, oldDate: date, newDate: date }, requires unique \"amended_slice\" on [self.amendment, self.slice] }\n }\n settlement: {\n fields { plan: ref<parent>, identity: text, principal: money, profit: money, loss: money, kind: enum(cash, loss), share: money?, retainedProfit: money?\n allocatedPayable: account(capital, cash, \"allocatedProfitPayable\"), capital: account(capital, cash, \"capital\"), profitIncome: account(capital, cash, \"profitIncome\"), lossAccount: account(capital, claim, \"loss\") }\n lifecycle { states: [recorded, refunded], initial: recorded }\n action create { allowZero: true,\n actor: { parent: parent }\n input { plan: ref<parent>, identity: text, principal: money, profit: money, loss: money, kind: enum(cash, loss) }\n requires unique \"settlement_identity\" on [self.plan, self.identity]\n calculate: [{ target: \"share\", op: \"rate\", base: { field: self.profit }, bps: { literal: share }, rounding: \"floor\" }, { target: retainedProfit, op: \"subtract\", base: { field: self.profit }, subtract: [{ field: self.share }] }]\n moves self.share from self.profitIncome to self.allocatedPayable economics { purpose: internal, sourceParty: capital }\n }\n action refund { allowZero: true,\n from: recorded, to: refunded, actor: { parent: payment }\n moves self.share from self.allocatedPayable to self.profitIncome economics { purpose: internal, sourceParty: capital }\n }\n }\n slice: {\n revisioned: true\n fields {\n plan: ref<parent>, borrowerLimit: ref<limits>, portfolioLimit: ref<portfolio>, position: integer(1, months)\n originalDueAt: date = at(self.plan.dates, self.position), dueAt: date?, nextDueAt: date?, previousDueAt: date?, previousPosition: integer?, previousDate: date?, extensionLimit: date = after(self.originalDueAt, max_extension), lossEligibleAt: date?\n principalBase: money = divide(self.plan.principal, months)\n principalAllocated: money = multiply(self.principalBase, months)\n principalRemainder: money = subtract(self.plan.principal, self.principalAllocated)\n profitBase: money = divide(self.plan.profit, months)\n profitAllocated: money = multiply(self.profitBase, months)\n profitRemainder: money = subtract(self.plan.profit, self.profitAllocated)\n first: integer = divide(1, self.position)\n principalAdjustment: money = multiply(self.principalRemainder, self.first)\n profitAdjustment: money = multiply(self.profitRemainder, self.first)\n principal: money = sum(self.principalBase, self.principalAdjustment)\n profit: money = sum(self.profitBase, self.profitAdjustment)\n principalReceivable: account(self, claim), profitReceivable: account(self, claim), profitEarned: account(self, claim)\n payoffIdentity: text?, payoffRebate: money?, payoffProfitTotal: money?, payoffProfit: money?\n paymentBudget: money?, principalPayment: money?, principalBasePayment: money?, principalRatio: money?, profitPayment: money?, profitBudget: money?, collectibleProfit: money?, collectibleTotal: money?, ratioDenominator: integer = sum(10000, profit)\n debt: account(borrower, claim, contra, \"debt\"), loss: account(capital, claim, \"loss\")\n }\n lifecycle { states: [draft, pending, due, paid, written_off], initial: draft }\n action create {\n actor: { parent: parent }\n input { plan: ref<parent>, borrowerLimit: ref<limits>, portfolioLimit: ref<portfolio>, position: integer(1, months) }\n set: { dueAt: { field: self.originalDueAt } }\n invoke: [{ reference: self.id, action: refresh_loss_date, input: {} }]\n requires self.plan in [quoted]; requires unique \"signed_position\" on [self.plan, self.position]; requires self.borrowerLimit == self.plan.borrowerLimit; requires self.portfolioLimit == self.plan.portfolioLimit\n }\n action quote_pending {\n from: pending, to: pending, actor: { parent: payoff_quote }, input { quote: ref<payoff_quote> }\n requires input.quote.plan == self.plan\n invoke: [{ instrument: quote_piece, action: create, input: { quote: { field: input.quote }, slice: { field: self.id } } }]\n }\n action quote_due {\n from: due, to: due, actor: { parent: payoff_quote }, input { quote: ref<payoff_quote> }\n requires input.quote.plan == self.plan\n invoke: [{ instrument: quote_piece, action: create, input: { quote: { field: input.quote }, slice: { field: self.id } } }]\n }\n action refresh_loss_date {\n from: [draft, pending, due], to: draft, actor: { parent: current() }\n calculate: [{ target: lossEligibleAt, op: shift, date: { field: self.dueAt }, milliseconds: { literal: write_off_after }, direction: after }]\n }\n action amend {\n from: [pending, due], to: pending, actor: { parent: amendment }, input { amendment: ref<amendment> }\n requires input.amendment.plan == self.plan\n when allow_overdue is blocked { requires self.dueAt > self.now }\n calculate: [\n { target: nextDueAt, op: at, list: input.amendment.dates, position: { field: self.position } }\n { target: lossEligibleAt, op: shift, date: { field: self.nextDueAt }, milliseconds: { literal: write_off_after }, direction: after }\n ]\n requires self.nextDueAt > self.now; requires self.nextDueAt >= self.dueAt; requires self.nextDueAt <= self.extensionLimit\n set: { previousDueAt: { field: self.dueAt }, dueAt: { field: self.nextDueAt } }\n invoke: [{ instrument: date_change, action: create, input: { amendment: { field: input.amendment }, slice: { field: self.id }, oldDate: { field: self.previousDueAt }, newDate: { field: self.nextDueAt } } }]\n when profit_earned is by_schedule { invoke: [{ selection: { instrument: recognition, reference: \"slice\", anchor: self.id, states: [pending], limit: 1 }, action: reschedule, input: {} }] }\n }\n action verify_fixed_date {\n from: paid, to: paid, actor: { parent: amendment }, input { amendment: ref<amendment> }\n calculate: [{ target: nextDueAt, op: at, list: input.amendment.dates, position: { field: self.position } }]\n requires self.nextDueAt == self.dueAt\n }\n action activate { allowZero: true,\n from: draft, to: pending, actor: { parent: parent }\n moves self.principal from self.debt to self.principalReceivable economics { purpose: internal, sourceParty: borrower }\n moves self.profit from self.debt to self.profitReceivable economics { purpose: internal, sourceParty: borrower }\n when profit_earned is at_disbursement { moves self.profit from self.profitReceivable to self.profitEarned economics { purpose: internal, sourceParty: programOperator } }\n when profit_earned is by_schedule { invoke: [{ instrument: recognition, action: create, input: { slice: { field: self.id } } }] }\n }\n action mature {\n from: pending, to: due, actor: clock, due: { at: self.dueAt }\n }\n action collect {\n from: [pending, due], to: preserve, actor: { parent: payment }\n input { payment: ref<payment> }\n requires input.payment.plan == self.plan\n when profit_earned is on_payment { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitReceivable.balance }] }] }\n when profit_earned is by_schedule { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitEarned.balance }] }] }\n when profit_earned is at_disbursement { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitEarned.balance }] }] }\n when apply is principal_profit {\n invoke: [\n { instrument: principal_piece, action: create, input: { slice: { field: self.id }, payment: { field: input.payment }, limit: { field: self.principalReceivable.balance } } }\n { instrument: profit_piece, action: create, input: { slice: { field: self.id }, payment: { field: input.payment }, limit: { field: self.collectibleProfit } } }\n { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 1, where: { id: { field: self.id }, principalReceivable.balance: { literal: \"0\" }, profitReceivable.balance: { literal: \"0\" }, profitEarned.balance: { literal: \"0\" } } }, action: complete, input: {} }\n ]\n }\n }\n action collect_waterfall {\n from: [pending, due], to: preserve, actor: { parent: payment }, input { payment: ref<payment> }\n requires input.payment.plan == self.plan\n when profit_earned is on_payment { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitReceivable.balance }] }] }\n when profit_earned is by_schedule { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitEarned.balance }] }] }\n when profit_earned is at_disbursement { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitEarned.balance }] }] }\n invoke: [\n { selection: { instrument: all(financing.late_charge), reference: \"slice\", anchor: self.id, states: [assessed], limit: charge_limit, order: [overdueAt] }, action: collect, input: { payment: { field: input.payment } } }\n { selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [assessed], limit: charge_limit, order: [overdueAt], where: { assessment.slice: { field: self.id } } }, action: collect, input: { payment: { field: input.payment } } }\n { instrument: profit_piece, action: create, input: { slice: { field: self.id }, payment: { field: input.payment }, limit: { field: self.collectibleProfit } } }\n { instrument: principal_piece, action: create, input: { slice: { field: self.id }, payment: { field: input.payment }, limit: { field: self.principalReceivable.balance } } }\n { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 1, where: { id: { field: self.id }, principalReceivable.balance: { literal: \"0\" }, profitReceivable.balance: { literal: \"0\" }, profitEarned.balance: { literal: \"0\" } } }, action: complete, input: {} }\n ]\n }\n action collect_pro_rata {\n from: [pending, due], to: preserve, actor: { parent: payment }, input { payment: ref<payment> }\n requires input.payment.plan == self.plan\n when profit_earned is on_payment { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitReceivable.balance }] }] }\n when profit_earned is by_schedule { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitEarned.balance }] }] }\n when profit_earned is at_disbursement { calculate: [{ target: collectibleProfit, op: sum, values: [{ field: self.profitEarned.balance }] }] }\n calculate: [\n { target: collectibleTotal, op: sum, values: [{ field: self.principalReceivable.balance }, { field: self.collectibleProfit }] }\n { target: paymentBudget, op: minimum, values: [{ field: input.payment.held.balance }, { field: self.collectibleTotal }] }\n { target: principalRatio, op: ratio, amount: { field: self.paymentBudget }, numerator: { literal: 10000 }, denominator: { field: self.ratioDenominator }, rounding: floor }\n { target: principalBasePayment, op: minimum, values: [{ field: self.principalRatio }, { field: self.principalReceivable.balance }] }\n { target: profitBudget, op: subtract, base: { field: self.paymentBudget }, subtract: [{ field: self.principalBasePayment }] }\n { target: profitPayment, op: minimum, values: [{ field: self.profitBudget }, { field: self.collectibleProfit }] }\n { target: principalPayment, op: subtract, base: { field: self.paymentBudget }, subtract: [{ field: self.profitPayment }] }\n ]\n invoke: [\n { instrument: principal_piece, action: create, input: { slice: { field: self.id }, payment: { field: input.payment }, limit: { field: self.principalPayment } } }\n { instrument: profit_piece, action: create, input: { slice: { field: self.id }, payment: { field: input.payment }, limit: { field: self.profitPayment } } }\n { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 1, where: { id: { field: self.id }, principalReceivable.balance: { literal: \"0\" }, profitReceivable.balance: { literal: \"0\" }, profitEarned.balance: { literal: \"0\" } } }, action: complete, input: {} }\n ]\n }\n action complete {\n from: [pending, due], to: paid\n requires self.principalReceivable.balance == \"0\"; requires self.profitReceivable.balance == \"0\"; requires self.profitEarned.balance == \"0\"\n }\n action restore { from: [pending, due, paid], to: pending, actor: { parent: payment } }\n action payoff { allowZero: true,\n from: [pending, due], to: paid, actor: { parent: parent }, input { identity: text }\n set: { payoffIdentity: { field: input.identity } }\n calculate: [{ target: payoffRebate, op: rate, base: { field: self.profitReceivable.balance }, bps: { literal: payoff_rebate }, rounding: floor }, { target: payoffProfitTotal, op: sum, values: [{ field: self.profitReceivable.balance }, { field: self.profitEarned.balance }] }, { target: payoffProfit, op: subtract, base: { field: self.payoffProfitTotal }, subtract: [{ field: self.payoffRebate }] }]\n moves self.principalReceivable.balance from self.plan.borrower to self.plan.capital economics { purpose: principal, sourceParty: borrower }\n moves self.payoffProfit from self.plan.borrower to self.plan.profitIncome economics { recipient: capital, company: { purpose: earning, sourceParty: borrower }, participant: { purpose: pass_through, sourceParty: borrower } }\n moves self.principalReceivable.balance from self.principalReceivable to self.debt economics { purpose: internal, sourceParty: programOperator }\n moves self.profitReceivable.balance from self.profitReceivable to self.debt economics { purpose: internal, sourceParty: programOperator }\n moves self.profitEarned.balance from self.profitEarned to self.debt economics { purpose: internal, sourceParty: programOperator }\n }\n action write_off { allowZero: true,\n from: [pending, due], to: written_off, actor: { parent: parent }\n moves self.principalReceivable.balance from self.principalReceivable to self.loss economics { purpose: internal, sourceParty: programOperator }; moves self.profitReceivable.balance from self.profitReceivable to self.debt economics { purpose: internal, sourceParty: programOperator }; moves self.profitEarned.balance from self.profitEarned to self.loss economics { purpose: internal, sourceParty: programOperator }\n }\n }\n recognition: {\n fields { slice: ref<slice>, dueAt: date = after(self.slice.dueAt, 0) }\n lifecycle { states: [pending, recognised], initial: pending }\n action create { actor: { parent: slice }, input { slice: ref<slice> }, requires unique \"profit_recognition\" on [self.slice] }\n action reschedule { from: pending, to: pending, actor: { parent: slice }, calculate: [{ target: dueAt, op: shift, date: { field: self.slice.dueAt }, milliseconds: { literal: 0 }, direction: after }] }\n action mature { allowZero: true, from: pending, to: recognised, actor: clock, due: { at: self.dueAt }, moves self.slice.profitReceivable.balance from self.slice.profitReceivable to self.slice.profitEarned economics { purpose: internal, sourceParty: programOperator } }\n }\n payment: {\n revisioned: true\n fields { plan: ref<parent>, amount: money, paymentIdentity: text, held: account of self\n outstandingPrincipal: money?, outstandingProfit: money?, outstandingFines: money?, outstandingCosts: money?, outstandingTotal: money?, principalReturned: money?, profitReturned: money?, lossRecorded: money? }\n\n lifecycle { states: [pending, paid, refunded], initial: pending }\n action create { input { plan: ref<parent>, amount: money, paymentIdentity: text } requires self.plan in [active]; requires unique \"payment_identity\" on [self.plan, self.paymentIdentity] }\n action pay {\n expansionLimit: 8192\n from: pending, to: paid, actor: { party: borrower }\n calculate: [{ target: outstandingPrincipal, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366, order: [position] }, measure: { sum: \"principalReceivable.balance\" } }]\n when profit_earned is on_payment { calculate: [{ target: outstandingProfit, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366, order: [position] }, measure: { sum: \"profitReceivable.balance\" } }] }\n when profit_earned is by_schedule { calculate: [{ target: outstandingProfit, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366, order: [position] }, measure: { sum: \"profitEarned.balance\" } }] }\n when profit_earned is at_disbursement { calculate: [{ target: outstandingProfit, op: aggregate, selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366, order: [position] }, measure: { sum: \"profitEarned.balance\" } }] }\n when apply is fines_profit_principal {\n calculate: [{ target: outstandingFines, op: aggregate, selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366, order: [overdueAt] }, measure: { sum: \"receivable.balance\" } }, { target: outstandingCosts, op: aggregate, selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366, order: [overdueAt] }, measure: { sum: \"receivable.balance\" } }, { target: outstandingTotal, op: sum, values: [{ field: self.outstandingPrincipal }, { field: self.outstandingProfit }, { field: self.outstandingFines }, { field: self.outstandingCosts }] }]\n }\n when apply is principal_profit { calculate: [{ target: outstandingTotal, op: sum, values: [{ field: self.outstandingPrincipal }, { field: self.outstandingProfit }] }] }\n when apply is pro_rata { calculate: [{ target: outstandingTotal, op: sum, values: [{ field: self.outstandingPrincipal }, { field: self.outstandingProfit }] }] }\n requires self.plan in [active]; requires self.amount <= self.outstandingTotal\n moves self.amount from self.plan.borrower to self.held economics { purpose: principal, sourceParty: borrower }\n when apply is principal_profit {\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 366, order: [position] }, action: collect, guard: { kind: compare, left: { field: self.held.balance }, operator: \">\", right: { literal: \"0\" } }, input: { payment: { field: self.id } } }]\n }\n when apply is fines_profit_principal {\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 366, order: [position] }, action: collect_waterfall, guard: { kind: compare, left: { field: self.held.balance }, operator: \">\", right: { literal: \"0\" } }, input: { payment: { field: self.id } } }]\n }\n when apply is pro_rata {\n invoke: [{ selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due], limit: 366, order: [position] }, action: collect_pro_rata, guard: { kind: compare, left: { field: self.held.balance }, operator: \">\", right: { literal: \"0\" } }, input: { payment: { field: self.id } } }]\n }\n invoke: [{ reference: self.id, action: record, input: {} }]\n }\n action record {\n from: paid, to: paid, actor: { parent: current() }\n requires self.held.balance == \"0\"\n calculate: [{ target: principalReturned, op: aggregate, selection: { instrument: principal_piece, reference: \"payment\", anchor: self.id, states: [paid], limit: 366 }, measure: { sum: \"amount\" } }, { target: profitReturned, op: aggregate, selection: { instrument: profit_piece, reference: \"payment\", anchor: self.id, states: [paid], limit: 366 }, measure: { sum: \"amount\" } }]\n invoke: [{ reference: self.plan, action: record_payment, input: { identity: { field: self.paymentIdentity }, principal: { field: self.principalReturned }, profit: { field: self.profitReturned } } }]\n }\n action refund {\n from: paid, to: refunded, actor: { party: capital }\n requires unique \"settlement_consumption\" on [self.plan, self.paymentIdentity]; requires self.plan in [active, paid]\n requires count of { instrument: settlement, reference: \"plan\", anchor: self.plan, states: [recorded], limit: 366, where: { identity: { field: self.paymentIdentity } } } == 1\n invoke: [{ selection: { instrument: settlement, reference: \"plan\", anchor: self.plan, states: [recorded], limit: 366, where: { identity: { field: self.paymentIdentity } } }, action: refund, input: {} }]\n when apply is fines_profit_principal {\n invoke: [{ selection: { instrument: all(financing.late_charge), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366, order: [overdueAt] }, action: refund, input: { payment: { field: self.id } } }, { selection: { instrument: all(financing.late_charge.cost), reference: \"plan\", anchor: self.plan, states: [assessed, collected], limit: 366, order: [overdueAt] }, action: refund, input: { payment: { field: self.id } } }]\n }\n invoke: [{ reference: self.plan, action: restore, input: {} }, { selection: { instrument: slice, reference: \"plan\", anchor: self.plan, states: [pending, due, paid], limit: 366 }, action: restore, input: {} }, { selection: { instrument: principal_piece, reference: \"payment\", anchor: self.id, states: [paid], limit: 366 }, action: refund, input: {} }, { selection: { instrument: profit_piece, reference: \"payment\", anchor: self.id, states: [paid], limit: 366 }, action: refund, input: {} }]\n }\n }\n principal_piece: {\n fields { slice: ref<slice>, payment: ref<payment>, limit: money, amount: money? }\n lifecycle { states: [paid, refunded], initial: paid }\n action create { allowZero: true,\n calculate: [{ target: amount, op: minimum, values: [{ field: self.payment.held.balance }, { field: self.slice.principalReceivable.balance }, { field: self.limit }] }]\n actor: { parent: slice }\n input { slice: ref<slice>, payment: ref<payment>, limit: money }\n requires unique \"principal_receipt\" on [self.slice, self.payment]\n moves self.amount from self.payment.held to self.slice.plan.capital economics { purpose: principal, sourceParty: programOperator }; moves self.amount from self.slice.principalReceivable to self.slice.debt economics { purpose: internal, sourceParty: programOperator }\n }\n action refund { allowZero: true,\n from: paid, to: refunded, actor: { parent: payment }\n moves self.amount from self.slice.plan.capital to self.slice.plan.borrower economics { purpose: principal, sourceParty: capital }; moves self.amount from self.slice.debt to self.slice.principalReceivable economics { purpose: internal, sourceParty: borrower }\n }\n }\n profit_piece: {\n fields { cashReceipt: text?, slice: ref<slice>, payment: ref<payment>, limit: money, amount: money? }\n lifecycle { states: [paid, refunded], initial: paid }\n action create { allowZero: true,\n calculate: [{ target: amount, op: minimum, values: [{ field: self.payment.held.balance }, { field: self.limit }] }]\n actor: { parent: slice }\n input { slice: ref<slice>, payment: ref<payment>, limit: money }\n requires unique \"profit_receipt\" on [self.slice, self.payment]\n moves self.amount from self.payment.held to self.slice.plan.profitIncome capture \"cashReceipt\" economics { recipient: capital, company: { purpose: earning, sourceParty: borrower }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n when profit_earned is on_payment { moves self.amount from self.slice.profitReceivable to self.slice.debt economics { purpose: internal, sourceParty: programOperator } }\n when profit_earned is by_schedule { moves self.amount from self.slice.profitEarned to self.slice.debt economics { purpose: internal, sourceParty: programOperator } }\n when profit_earned is at_disbursement { moves self.amount from self.slice.profitEarned to self.slice.debt economics { purpose: internal, sourceParty: programOperator } }\n }\n action refund { allowZero: true,\n from: paid, to: refunded, actor: { parent: payment }\n moves self.amount from self.slice.plan.profitIncome to self.slice.plan.borrower economics { recipient: capital, company: { purpose: earning, sourceParty: capital, reversalOf: self.cashReceipt }, participant: unclassified }\n when profit_earned is on_payment { moves self.amount from self.slice.debt to self.slice.profitReceivable economics { purpose: internal, sourceParty: borrower } }\n when profit_earned is by_schedule { moves self.amount from self.slice.debt to self.slice.profitEarned economics { purpose: internal, sourceParty: borrower } }\n when profit_earned is at_disbursement { moves self.amount from self.slice.debt to self.slice.profitEarned economics { purpose: internal, sourceParty: borrower } }\n }\n }\n }\n}\n\ninstrument late_charge(on: ref<financing.installments>[], grace: duration = 3d, fine: money = 50 SAR, cap: money = 25 SAR, fines_to: party = programOperator, costs_to: party = programOperator, borrower: party = party(person)) {\n parameterDiagnostics {\n fine {\n accepts: \"a fixed amount\"\n percentage: \"a percentage of overdue debt\"\n fix: \"Use a fixed amount only if that is the intended policy. A percentage charge needs an authored rate calculation; do not approximate it with a cash amount.\"\n }\n }\n revisioned: true\n familyRevision: 1\n summary: \"Separate fine and evidenced recovery claims on an overdue installment.\"\n fields {\n plan: ref<on>, slice: ref<on.slice>, borrower: account of borrower, fine: money = fine, overdueAt: date?\n receivable: account(self, claim), debt: account(borrower, claim, contra, \"debt\")\n }\n lifecycle { states: [proposed, assessed, collected, waived], initial: proposed }\n action create { input { slice: ref<on.slice>? }, calculate: [{ target: overdueAt, op: shift, date: { field: self.slice.dueAt }, milliseconds: { literal: grace }, direction: after }], requires unique \"late_assessment\" on [self.slice, self.overdueAt]; requires self.borrower == self.slice.plan.borrower; requires self.plan == self.slice.plan }\n action assess { allowZero: true,\n from: proposed, to: assessed, actor: clock, due: { at: self.overdueAt }\n requires self.slice.principalReceivable.balance > \"0\"\n moves self.fine from self.debt to self.receivable economics { purpose: internal, sourceParty: borrower }\n }\n action collect {\n from: [assessed, collected], to: assessed, actor: { parent: child(on, slice) }, input { payment: ref<on.payment> }\n requires input.payment in [paid]\n requires input.payment.plan == self.plan\n invoke: [{ instrument: receipt, action: create, input: { assessment: { field: self.id }, payment: { field: input.payment } } }, { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [assessed], limit: 1, where: { id: { field: self.id }, receivable.balance: { literal: \"0\" } } }, action: finish, input: {} }]\n }\n action payoff { allowZero: true,\n from: [assessed, collected], to: collected, actor: { parent: on }\n requires self.plan in [paid]\n moves self.receivable.balance from self.plan.borrower to fines_to economics { recipient: fines_to, company: { purpose: earning, sourceParty: borrower }, participant: { purpose: pass_through, sourceParty: borrower } }\n moves self.receivable.balance from self.receivable to self.debt economics { purpose: internal, sourceParty: programOperator }\n }\n action finish { from: assessed, to: collected, actor: { parent: current() }, requires self.receivable.balance == \"0\" }\n action cancel { from: proposed, to: waived }\n action waive_for_amendment {\n from: [assessed, collected], to: assessed, actor: { parent: child(on, amendment) }, input { amendment: ref<on.amendment> }\n requires input.amendment.plan == self.plan; requires input.amendment in [applied]\n invoke: [{ instrument: waiver, action: create, input: { assessment: { field: self.id }, amendment: { field: input.amendment } } }]\n }\n action waive { allowZero: true, from: [assessed, collected], to: waived, actor: { parent: waiver_request }, input { reason: text, evidence: text }, moves self.receivable.balance from self.receivable to self.debt economics { purpose: internal, sourceParty: programOperator } }\n action refund {\n from: [assessed, collected], to: assessed, actor: { party: fines_to }, input { payment: ref<on.payment> }\n requires input.payment in [paid, refunded]\n requires input.payment.plan == self.plan\n invoke: [{ selection: { instrument: receipt, reference: \"payment\", anchor: input.payment, states: [paid], limit: 1, where: { assessment: { field: self.id } } }, action: refund, input: {} }, { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [assessed], limit: 1, where: { id: { field: self.id }, receivable.balance: { literal: \"0\" } } }, action: finish, input: {} }]\n }\n records {\n waiver_request: {\n fields { assessment: ref<parent>, reason: text, evidence: text }\n lifecycle { states: [requested, applied, cancelled], initial: requested }\n action create { requires self.assessment in [assessed, collected] }\n action apply {\n from: requested, to: applied, actor: { party: fines_to }, input { reason: text, evidence: text }\n invoke: [{ reference: self.assessment, action: waive, input: { reason: { field: input.reason }, evidence: { field: input.evidence } } }]\n }\n action cancel { from: requested, to: cancelled }\n }\n waiver: {\n fields { assessment: ref<parent>, amendment: ref<on.amendment>, amount: money? }\n lifecycle { states: [recorded], initial: recorded }\n action create { allowZero: true,\n actor: { parent: parent }, input { assessment: ref<parent>, amendment: ref<on.amendment> }\n calculate: [{ target: amount, op: rate, base: { field: self.assessment.receivable.balance }, bps: { field: self.amendment.waiverPercent }, rounding: floor }]\n requires unique \"amendment_waiver\" on [self.assessment, self.amendment]\n moves self.amount from self.assessment.receivable to self.assessment.debt economics { purpose: internal, sourceParty: programOperator }\n }\n }\n receipt: {\n fields { cashReceipt: text?, assessment: ref<parent>, payment: ref<on.payment>, amount: money? }\n lifecycle { states: [paid, refunded], initial: paid }\n action create { allowZero: true, calculate: [{ target: amount, op: minimum, values: [{ field: self.payment.held.balance }, { field: self.assessment.receivable.balance }] }], actor: { parent: parent }, input { assessment: ref<parent>, payment: ref<on.payment> }, requires input.payment.plan == self.assessment.plan; requires unique \"fine_receipt\" on [self.assessment, self.payment]; moves self.amount from self.payment.held to fines_to capture \"cashReceipt\" economics { recipient: fines_to, company: { purpose: earning, sourceParty: borrower }, participant: { purpose: participant_payout, sourceParty: programOperator } }; moves self.amount from self.assessment.receivable to self.assessment.debt economics { purpose: internal, sourceParty: programOperator } }\n action refund { allowZero: true, from: paid, to: refunded, actor: { parent: parent }, moves self.amount from fines_to to self.payment.plan.borrower economics { recipient: fines_to, company: { purpose: earning, sourceParty: fines_to, reversalOf: self.cashReceipt }, participant: unclassified }; moves self.amount from self.assessment.debt to self.assessment.receivable economics { purpose: internal, sourceParty: borrower } }\n }\n\n cost: {\n revisioned: true\n fields {\n plan: ref<on>, assessment: ref<parent>, overdueAt: date?, evidence: text, evidencedCost: money, amount: money = minimum(self.evidencedCost, cap)\n receivable: account(self, claim), debt: account(borrower, claim, contra, \"debt\")\n }\n lifecycle { states: [proposed, assessed, collected, waived], initial: proposed }\n action create { calculate: [{ target: overdueAt, op: shift, date: { field: self.assessment.overdueAt }, milliseconds: { literal: 0 }, direction: after }], requires unique \"recovery_assessment\" on [self.assessment]; requires self.plan == self.assessment.plan }\n action assess { allowZero: true,\n from: proposed, to: assessed, actor: clock, due: { at: self.assessment.overdueAt }\n requires self.assessment.slice.principalReceivable.balance > \"0\"\n moves self.amount from self.debt to self.receivable economics { purpose: internal, sourceParty: borrower }\n }\n action collect {\n from: [assessed, collected], to: assessed, actor: { parent: child(on, slice) }, input { payment: ref<on.payment> }\n requires input.payment in [paid]\n requires input.payment.plan == self.plan\n invoke: [{ instrument: receipt, action: create, input: { assessment: { field: self.id }, payment: { field: input.payment } } }, { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [assessed], limit: 1, where: { id: { field: self.id }, receivable.balance: { literal: \"0\" } } }, action: finish, input: {} }]\n }\n action payoff { allowZero: true,\n from: [assessed, collected], to: collected, actor: { parent: on }\n requires self.plan in [paid]\n moves self.receivable.balance from self.plan.borrower to costs_to economics { recipient: costs_to, company: { purpose: earning, sourceParty: borrower }, participant: { purpose: pass_through, sourceParty: borrower } }\n moves self.receivable.balance from self.receivable to self.debt economics { purpose: internal, sourceParty: programOperator }\n }\n action finish { from: assessed, to: collected, actor: { parent: current() }, requires self.receivable.balance == \"0\" }\n action cancel { from: proposed, to: waived }\n action waive_for_amendment {\n from: [assessed, collected], to: assessed, actor: { parent: child(on, amendment) }, input { amendment: ref<on.amendment> }\n requires input.amendment.plan == self.plan; requires input.amendment in [applied]\n invoke: [{ instrument: waiver, action: create, input: { assessment: { field: self.id }, amendment: { field: input.amendment } } }]\n }\n action waive { allowZero: true, from: [assessed, collected], to: waived, actor: { parent: waiver_request }, input { reason: text, evidence: text }, moves self.receivable.balance from self.receivable to self.debt economics { purpose: internal, sourceParty: programOperator } }\n action refund {\n from: [assessed, collected], to: assessed, actor: { party: costs_to }, input { payment: ref<on.payment> }\n requires input.payment in [paid, refunded]\n requires input.payment.plan == self.plan\n invoke: [{ selection: { instrument: receipt, reference: \"payment\", anchor: input.payment, states: [paid], limit: 1, where: { assessment: { field: self.id } } }, action: refund, input: {} }, { selection: { instrument: current(), reference: \"plan\", anchor: self.plan, states: [assessed], limit: 1, where: { id: { field: self.id }, receivable.balance: { literal: \"0\" } } }, action: finish, input: {} }]\n }\n records {\n waiver_request: {\n fields { assessment: ref<parent>, reason: text, evidence: text }\n lifecycle { states: [requested, applied, cancelled], initial: requested }\n action create { requires self.assessment in [assessed, collected] }\n action apply {\n from: requested, to: applied, actor: { party: costs_to }, input { reason: text, evidence: text }\n invoke: [{ reference: self.assessment, action: waive, input: { reason: { field: input.reason }, evidence: { field: input.evidence } } }]\n }\n action cancel { from: requested, to: cancelled }\n }\n waiver: {\n fields { assessment: ref<parent>, amendment: ref<on.amendment>, amount: money? }\n lifecycle { states: [recorded], initial: recorded }\n action create { allowZero: true,\n actor: { parent: parent }, input { assessment: ref<parent>, amendment: ref<on.amendment> }\n calculate: [{ target: amount, op: rate, base: { field: self.assessment.receivable.balance }, bps: { field: self.amendment.waiverPercent }, rounding: floor }]\n requires unique \"amendment_waiver\" on [self.assessment, self.amendment]\n moves self.amount from self.assessment.receivable to self.assessment.debt economics { purpose: internal, sourceParty: programOperator }\n }\n }\n receipt: {\n fields { cashReceipt: text?, assessment: ref<parent>, payment: ref<on.payment>, amount: money? }\n lifecycle { states: [paid, refunded], initial: paid }\n action create { allowZero: true, calculate: [{ target: amount, op: minimum, values: [{ field: self.payment.held.balance }, { field: self.assessment.receivable.balance }] }], actor: { parent: parent }, input { assessment: ref<parent>, payment: ref<on.payment> }, requires input.payment.plan == self.assessment.plan; requires unique \"cost_receipt\" on [self.assessment, self.payment]; moves self.amount from self.payment.held to costs_to capture \"cashReceipt\" economics { recipient: costs_to, company: { purpose: earning, sourceParty: borrower }, participant: { purpose: participant_payout, sourceParty: programOperator } }; moves self.amount from self.assessment.receivable to self.assessment.debt economics { purpose: internal, sourceParty: programOperator } }\n action refund { allowZero: true, from: paid, to: refunded, actor: { parent: parent }, moves self.amount from costs_to to self.payment.plan.borrower economics { recipient: costs_to, company: { purpose: earning, sourceParty: costs_to, reversalOf: self.cashReceipt }, participant: unclassified }; moves self.amount from self.assessment.debt to self.assessment.receivable economics { purpose: internal, sourceParty: borrower } }\n }\n }\n }\n }\n}\n\ninstrument limits(per_borrower: money, borrower: party = party(person), active_plans: integer = 1) {\n familyRevision: 1\n scope: product\n summary: \"One outstanding balance ceiling per borrower.\"\n fields { borrower: account of borrower, limit: money = per_borrower, activePlans: integer = active_plans }\n lifecycle { states: [pending, approved], initial: pending }\n action create { requires unique \"borrower_limit\" on [self.borrower] }\n action approve { from: pending, to: approved }\n}\n\ninstrument portfolio_limit(limit: money) {\n familyRevision: 1\n scope: product\n summary: \"One shared ceiling on the principal the product may hold.\"\n fields { key: text = \"portfolio\", limit: money = limit }\n lifecycle { states: [pending, approved], initial: pending }\n action create { requires unique \"portfolio_limit\" on [self.key] }\n action approve { from: pending, to: approved }\n}\n\ninstrument credit_line(borrower: party = programOperator, adapter: text, limit: money, expires: date) {\n familyRevision: 1\n summary: \"A revolving facility from an outside lender; each draw is a separate immutable advance.\"\n fields { borrower: account of borrower, facility: account(borrower, cash, \"facility\"), debt: account(borrower, claim, contra, \"debt\"), limit: money = limit, expiresAt: date = expires }\n lifecycle { states: [pending, active, suspended, closed], initial: pending }\n action create {}\n action activate {\n from: pending, to: active, actor: { party: borrower }\n subject { adapter: adapter }\n }\n action suspend { from: active, to: suspended, actor: { party: borrower } }\n action resume { from: suspended, to: active, actor: { party: borrower } }\n action close { from: [active, suspended], to: closed, due: { at: self.expiresAt }, requires count of { instrument: all(financing.advance), reference: \"line\", anchor: self.id, states: [drawn], limit: 366 } == 0 }\n}\n\ninstrument advance(line: ref<financing.credit_line>, amount: money = runtime) {\n familyRevision: 1\n summary: \"A single facility draw with an immutable principal and full repayment.\"\n fields { line: ref<line>, amount: money = amount, principalReceivable: account(self, claim) }\n lifecycle { states: [pending, drawn, repaid, cancelled], initial: pending }\n action create { requires self.amount <= self.line.limit }\n invariants sum \"principalReceivable.balance\" of { instrument: all(financing.advance), reference: \"line\", anchor: self.line, states: [drawn], limit: 366 } <= self.line.limit\n action draw {\n from: pending, to: drawn\n requires self.line in [active]\n deadline: { at: self.line.expiresAt }\n moves self.amount from self.line.facility to self.line.borrower; moves self.amount from self.line.debt to self.principalReceivable\n }\n action repay { from: drawn, to: repaid, moves self.amount from self.line.borrower to self.line.facility; moves self.amount from self.principalReceivable to self.line.debt }\n action cancel { from: pending, to: cancelled }\n}\n"],
|
|
8
8
|
["insurance.hsx", "header insurance\n\n// Economics: Company commission is earning; refunds reverse its captured transfer.\n// Outside broker commissions are pass-through. Adapter-owned premium and claim\n// accounts lack an authored source party, so their moves remain unclassified.\n\n// Expose cover.create, activate and cancel separately. Activation binds adapter;\n// each slice needs a separately created unique period and an active cover to collect.\n// Collection debits holder for insurerPremium to the insurer and commission to\n// broker as two moves. Broker defaults to programOperator; bind a declared business\n// for a distinct agency. The two amounts sum to premium. Zero portions are allowed.\n// Cover.cancel invokes refund only on paid slices, before each startsAt. It returns\n// insurerPremium from insurer and commission from broker to holder. Active or\n// expired periods are excluded; insufficient recipient funds refuse the reversal.\n// Slice refund is parent-owned, not a public alias. Expose cover.cancel instead.\n// Claims require active cover. Expose claim.create, approve, deny and pay as needed.\n// Inspector approves OR denies from submitted. After approval only pay or clock\n// expiry can consume the reservation; deny is never available after approval.\n// Inspector is a bound party, not necessarily staff. These are ledger transfers;\n// outside settlement needs the boundary protocol, not a claim of provider success.\n\n// Cost: each slice collection or refund declares two transfers. Claim approval\n// reserves once; pay posts once and expiry voids once. Cover cancellation adds\n// bounded slice invocations. Run hsx cost for composed counts, not provider prices.\n\ninstrument cover(holder: party, adapter: text, commission: percent = 0%, broker: party = programOperator, covers: ref, premium: money = runtime) {\n summary: \"Recurring cover bound to an outside insurer across an ADL boundary.\"\n fields { covers: ref<covers>, holder: account of holder, insurer: account(adapter(adapter), cash, \"premium\"), expiresAt: date }\n lifecycle { states: [pending, active, cancelled, expired], initial: pending }\n action create {}\n action activate {\n from: pending, to: active, actor: { party: programOperator }\n subject { adapter: adapter }\n }\n action cancel {\n from: active, to: cancelled, actor: { party: holder }\n invoke: [{ selection: { instrument: slice, reference: \"cover\", anchor: self.id, states: [paid], limit: 366 }, action: refund, input: {} }]\n }\n action expire { from: active, to: expired, actor: clock, due: { at: self.expiresAt } }\n records {\n slice: {\n summary: \"A whole premium period, collected once and refundable only before it starts.\"\n fields {\n cover: ref<parent>, covers: ref<covers>, premium: money = premium, startsAt: date, endsAt: date\n commission: money = rate(self.premium, commission)\n insurerPremium: money = subtract(self.premium, self.commission), commissionReceipt: text?\n }\n lifecycle { states: [pending, paid, active, expired, refunded], initial: pending }\n action create {\n requires self.covers == self.cover.covers\n requires self.startsAt < self.endsAt\n requires unique \"premium_period\" on [self.cover, self.startsAt, self.endsAt]\n }\n action collect {\n allowZero: true\n requires self.premium > \"0\"\n from: pending, to: paid, actor: { party: holder }\n requires self.cover in [active]\n moves self.insurerPremium from holder to self.cover.insurer\n moves self.commission from holder to broker capture \"commissionReceipt\" economics { recipient: broker, company: { purpose: earning, sourceParty: holder }, participant: { purpose: pass_through, sourceParty: holder } }\n }\n action start { from: paid, to: active, actor: clock, due: { at: self.startsAt } }\n action expire { from: active, to: expired, actor: clock, due: { at: self.endsAt } }\n action refund {\n allowZero: true\n requires self.premium > \"0\"\n from: paid, to: refunded, actor: { parent: parent }, deadline: { at: self.startsAt }\n moves self.insurerPremium from self.cover.insurer to holder\n moves self.commission from broker to holder economics { recipient: broker, company: { purpose: earning, sourceParty: broker, reversalOf: self.commissionReceipt }, participant: { purpose: pass_through, sourceParty: broker } }\n }\n }\n }\n}\n\ninstrument claim(cover: ref<insurance.cover>, inspector: party) {\n summary: \"A claim decision reserves one claim payment before settlement.\"\n fields { cover: ref<cover>, amount: money, expiresAt: date, evidence: text, reservation: text? }\n lifecycle { states: [submitted, approved, paid, denied, expired], initial: submitted }\n action create { requires self.cover in [active] }\n action approve {\n from: submitted, to: approved\n actor: { party: inspector }\n deadline: { at: self.expiresAt }\n moves reserve self.amount from self.cover.insurer to self.cover.holder capture \"reservation\"\n }\n action pay { from: approved, to: paid, actor: { party: inspector }, deadline: { at: self.expiresAt }, moves post self.reservation }\n action deny { from: submitted, to: denied, actor: { party: inspector } }\n action expire { from: approved, to: expired, actor: clock, due: { at: self.expiresAt }, moves void self.reservation }\n}\n"],
|
|
9
9
|
["lending.hsx", "header lending\n\n// Economics: Funding and commitment returns are principal. Distribution tax is\n// pass-through; own-account fee and claim allocations are internal. Mixed\n// principal/profit distributions and unbound source owners remain unclassified.\n\n// Round target is plan.principal from runtime subject.price, not its credit limit.\n// Expose round.create and close plus commitment.create and withdraw. A commitment\n// debits the bound investor's original active wallet before closesAt. Investor cap\n// aggregates by investor across wallets. Failure refunds those original wallets.\n// Closing needs the exact target; it funds plan.capital and does not disburse the\n// loan. Expose plan.disburse separately after signing and limit approval.\n// Distribution.create needs a recorded, unconsumed settlement matching the plan.\n// Prepare cash or loss first, then create shares against funded commitments of\n// that round. Distribution needs pending share weights equal to the round target.\n// Cash fee is a percentage of retained profit, VAT a percentage of that fee.\n// Principal plus retained profit less fee and VAT goes to weighted wallets;\n// floored residual goes to residual_to. Loss mode moves claim balances, not cash.\n// Child share execution is parent-owned. No report or clock proves outside payout.\n\n// Cost: round.create declares one owned account. Close transfers its balance\n// and invokes commitments; failure invokes their refunds. Distribution adds moves\n// and bounded share invocations. Run hsx cost for counts after policy selection.\n\ninstrument round(borrower: party, plan: ref<financing.installments> = object(financing.installments), operator: party = programOperator, minimum_ticket: money = 100 SAR, investor_cap: percent = 20%, commitments: ref<lending.commitment> = object(lending.commitment)) {\n summary: \"A threshold funding round; failed rounds return each original wallet contribution.\"\n fields {\n borrower: account of borrower, plan: ref<plan>, price: money = self.plan.principal, closesAt: date\n minimumTicket: money = minimum_ticket, maximumTicket: money = rate(self.price, investor_cap)\n held: account of self\n }\n lifecycle { states: [open, funded, failed], initial: open }\n action create { requires unique \"funding_plan\" on [self.plan]; requires self.borrower == self.plan.borrower }\n action close {\n from: open, to: funded, actor: { party: operator }\n requires sum \"amount\" of { instrument: commitments, reference: \"round\", anchor: self.id, states: [committed], limit: 366 } == self.price\n requires self.held.balance == self.price\n moves self.price from self.held to self.plan.capital economics { purpose: principal, sourceParty: programOperator }\n invoke: [{ selection: { instrument: commitments, reference: \"round\", anchor: self.id, states: [committed], limit: 366 }, action: fund, input: {} }]\n }\n action fail {\n from: open, to: failed, actor: clock, due: { at: self.closesAt }\n requires self.held.balance < self.price\n invoke: [{ selection: { instrument: commitments, reference: \"round\", anchor: self.id, states: [committed], limit: 366 }, action: refund, input: {} }]\n }\n}\n\ninstrument commitment(round: ref<lending.round>, wallet: ref<wallet.balance>, investor: party = party(person)) {\n summary: \"One investor's original-wallet contribution, capped cumulatively within the round.\"\n fields { round: ref<round>, wallet: ref<wallet>, investor: account of investor, amount: money, loss: account(investor, claim, \"loss\") }\n lifecycle { states: [committed, funded, withdrawn, refunded], initial: committed }\n invariants sum \"amount\" of { instrument: all(lending.commitment), reference: \"round\", anchor: self.round, states: [committed, funded], limit: 366, where: { investor: { field: self.investor } } } <= self.round.maximumTicket\n invariants sum \"amount\" of { instrument: all(lending.commitment), reference: \"round\", anchor: self.round, states: [committed, funded], limit: 366 } <= self.round.price\n action create {\n actor: { party: investor }\n requires self.round in [open]\n requires self.wallet in [active]\n requires self.wallet.holder == self.investor\n requires self.amount >= self.round.minimumTicket\n deadline: { at: self.round.closesAt }\n moves self.amount from self.wallet.held to self.round.held economics { purpose: principal, sourceParty: programOperator }\n }\n action fund { from: committed, to: funded, actor: { parent: round } }\n action withdraw {\n from: committed, to: withdrawn, actor: { party: investor }\n requires self.round in [open]\n deadline: { at: self.round.closesAt }\n moves self.amount from self.round.held to self.wallet.held economics { purpose: principal, sourceParty: programOperator }\n }\n action refund {\n from: committed, to: refunded, actor: { parent: round }\n moves self.amount from self.round.held to self.wallet.held economics { purpose: principal, sourceParty: programOperator }\n }\n}\n\ninstrument distribution(round: ref<lending.round>, receipt: ref, commitments: ref<lending.commitment> = object(lending.commitment), mode: enum(cash, loss) = cash, residual_to: party = programOperator, operator: party = programOperator, fee: percent = 1%, tax: percent = 15%) {\n summary: \"Frozen weighted shares, floored once, with residual assigned to the chosen party.\"\n fields {\n round: ref<round>, source: ref<receipt>, mode: enum(cash, loss) = mode\n principal: money?, profit: money?, grossTotal: money?, charge: money?, vat: money?, net: money?\n held: account of self, losses: account(self, claim), residualLoss: account(residual_to, claim, \"loss\")\n }\n lifecycle { states: [pending, cash_ready, loss_ready, distributed], initial: pending }\n action create { requires self.round in [funded]; requires self.source in [recorded]; requires self.source.plan == self.round.plan; requires unique \"settlement_consumption\" on [self.source.plan, self.source.identity] }\n action prepare_cash {\n from: pending, to: cash_ready\n requires self.mode == \"cash\"; requires self.source.kind == \"cash\"; requires self.source in [recorded]\n calculate: [\n { target: \"principal\", op: \"sum\", values: [{ field: self.source.principal }] }\n { target: \"profit\", op: \"sum\", values: [{ field: self.source.retainedProfit }] }\n { target: \"charge\", op: \"rate\", base: { field: self.profit }, bps: { literal: fee }, rounding: \"floor\" }\n { target: \"vat\", op: \"rate\", base: { field: self.charge }, bps: { literal: tax }, rounding: \"floor\" }\n { target: \"grossTotal\", op: \"sum\", values: [{ field: self.principal }, { field: self.profit }] }\n { target: \"net\", op: \"subtract\", base: { field: self.grossTotal }, subtract: [{ field: self.charge }, { field: self.vat }] }\n ]\n }\n action prepare_loss {\n from: pending, to: loss_ready\n requires self.mode == \"loss\"; requires self.source.kind == \"loss\"; requires self.source in [recorded]\n calculate: [{ target: \"net\", op: \"sum\", values: [{ field: self.source.loss }] }]\n }\n action distribute_cash { allowZero: true,\n from: cash_ready, to: distributed, actor: { party: operator }\n requires sum \"weight\" of { instrument: share, reference: \"distribution\", anchor: self.id, states: [pending], limit: 366 } == self.round.price\n moves self.principal from self.source.capital to self.held; moves self.profit from self.source.profitIncome to self.held; moves self.charge from self.held to programOperator economics { purpose: internal, sourceParty: programOperator }; moves self.vat from self.held to programTax economics { purpose: pass_through, sourceParty: programOperator }\n invoke: [{ selection: { instrument: share, reference: \"distribution\", anchor: self.id, states: [pending], limit: 366 }, action: cash, input: {} }, { reference: self.id, action: residual_cash, input: {} }]\n }\n action residual_cash { allowZero: true,\n from: distributed, to: distributed, actor: { parent: current() }\n moves self.held.balance from self.held to residual_to\n }\n action distribute_loss { allowZero: true,\n from: loss_ready, to: distributed, actor: { party: operator }\n requires sum \"weight\" of { instrument: share, reference: \"distribution\", anchor: self.id, states: [pending], limit: 366 } == self.round.price\n moves self.net from self.source.lossAccount to self.losses\n invoke: [{ selection: { instrument: share, reference: \"distribution\", anchor: self.id, states: [pending], limit: 366 }, action: loss, input: {} }, { reference: self.id, action: residual_loss, input: {} }]\n }\n action residual_loss { allowZero: true,\n from: distributed, to: distributed, actor: { parent: current() }\n moves self.losses.balance from self.losses to self.residualLoss economics { purpose: internal, sourceParty: programOperator }\n }\n records {\n share: {\n fields {\n distribution: ref<parent>, commitment: ref<commitments>\n weight: money = self.commitment.amount\n gross: money = ratio(self.distribution.net, self.weight, self.distribution.round.price)\n }\n lifecycle { states: [pending, paid], initial: pending }\n action create { requires self.distribution in [cash_ready, loss_ready]; requires self.commitment in [funded]; requires unique \"distribution_weight\" on [self.distribution, self.commitment]; requires self.commitment.round == self.distribution.round }\n action cash { allowZero: true,\n from: pending, to: paid, actor: { parent: parent }\n moves self.gross from self.distribution.held to self.commitment.wallet.held\n }\n action loss { allowZero: true, from: pending, to: paid, actor: { parent: parent }, moves self.gross from self.distribution.losses to self.commitment.loss economics { purpose: internal, sourceParty: programOperator } }\n }\n }\n}\n"],
|
|
10
10
|
["marketplace.hsx", "header marketplace\n\n// Economics: Deposit funding, escrow credit and returns are principal. Retention is\n// earning for the company or a payout to a bound outside recipient.\n\n// Listing, order and reservation are separate agreements. Expose their create\n// and decision actions individually. Order fulfillment does not move escrow cash.\n// Pair an order with escrow.hold and expose its fund, deliver, accept, dispute,\n// verify_return and refund aliases. Refund needs disputed -> return_verified,\n// with payee evidence, then returns the full price to payer; accept pays payee.\n// A reservation holds its own deposit. Activate requires an active listing and\n// no placed order. Convert must wire the declared converters to invoke credit;\n// naming a converter alone does not add that invocation. Credit consumes the\n// deposit once, credits at most the contribution, and returns excess to buyer.\n// Expose cancel, seller_cancel or operator_cancel for the intended actors.\n// Buyer cancel and expiry use configured refund percentages; seller/operator\n// cancellation return the whole reservation balance. Converted money is in escrow,\n// so subsequent return verification and refund use the escrow aliases.\n\n// Cost: listing and order actions declare no transfers. Reservation.create\n// declares one owned account; activate declares one deposit transfer. Cancellation\n// and credit split that balance into moves. Run hsx cost for the composed counts.\n\ninstrument listing(seller: party) {\n revisioned: true\n summary: \"A seller's offer and its asking price.\"\n fields { seller: account of seller, title: text, price: money }\n lifecycle { states: [draft, active, withdrawn, sold], initial: draft }\n action create { actor: { party: seller } }\n action publish {\n from: draft, to: active, actor: { party: seller }\n }\n action withdraw { from: active, to: withdrawn, actor: { party: seller }, requires count of { instrument: all(marketplace.reservation), reference: \"listing\", anchor: self.id, states: [active], limit: 366 } == 0 }\n action sell { from: active, to: sold, actor: { party: seller }, requires count of { instrument: all(marketplace.reservation), reference: \"listing\", anchor: self.id, states: [active], limit: 366 } == 0 }\n}\n\ninstrument order(listing: ref<marketplace.listing>, buyer: party) {\n revisioned: true\n summary: \"A buyer's order for one listing at its declared price.\"\n fields { listing: ref<listing>, buyer: account of buyer, price: money, reservations: integer?, ownReservations: integer?, blockingQuotes: integer?, ownBlockingQuotes: integer? }\n lifecycle { states: [quoted, placed, fulfilled, cancelled], initial: quoted }\n action create {\n actor: { party: buyer }\n requires self.listing in [active]\n calculate: [\n { target: blockingQuotes, op: aggregate, selection: { instrument: all(marketplace.reservation), reference: \"listing\", anchor: self.listing, states: [active], limit: 366, where: { quotePolicy: { literal: \"blocked\" } } }, measure: count }\n { target: ownBlockingQuotes, op: aggregate, selection: { instrument: all(marketplace.reservation), reference: \"listing\", anchor: self.listing, states: [active], limit: 366, where: { quotePolicy: { literal: \"blocked\" }, buyer: { field: self.buyer } } }, measure: count }\n ]\n requires self.blockingQuotes == self.ownBlockingQuotes\n requires self.price == self.listing.price\n }\n action commit {\n from: [quoted, placed], to: placed\n requires self.listing in [active]\n calculate: [\n { target: reservations, op: aggregate, selection: { instrument: all(marketplace.reservation), reference: \"listing\", anchor: self.listing, states: [active], limit: 366 }, measure: count }\n { target: ownReservations, op: aggregate, selection: { instrument: all(marketplace.reservation), reference: \"listing\", anchor: self.listing, states: [active], limit: 366, where: { buyer: { field: self.buyer } } }, measure: count }\n ]\n requires self.reservations == self.ownReservations\n requires count of { instrument: current(), reference: \"listing\", anchor: self.listing, states: [placed, fulfilled], limit: 366 } <= 1\n }\n invariants count of { instrument: current(), reference: \"listing\", anchor: self.listing, states: [placed, fulfilled], limit: 366 } <= 1\n action fulfill { from: placed, to: fulfilled }\n action cancel { from: [quoted, placed], to: cancelled, actor: { party: buyer } }\n}\n\ninstrument reservation(listing: ref<marketplace.listing>, funds: ref<escrow.hold>, plans: ref<financing.installments>[], converters: ref[], buyer: party, seller: party, expires_after: duration = 48h, deposit: money = 1000 SAR, cancellation_refund: percent = 100%, expiry_refund: percent = 100%, retained_to: party = programOperator, operator: party = programOperator, competing_quotes: enum(allowed, blocked) = allowed) {\n revisioned: true\n summary: \"Exclusive timed listing hold with explicit deposit credit and refund.\"\n fields {\n listing: ref<listing>, funds: ref<funds>, buyer: account of buyer, seller: account of seller, price: money, terms: text\n held: account of self, quotePolicy: enum(allowed, blocked) = competing_quotes, deposit: money = deposit, proposalExpiresAt: date = after(self.createdAt, expires_after), expiresAt: date?\n credit: money?, refund: money?, retained: money?, dispositionAt: date?, reason: text?\n }\n lifecycle { states: [proposed, active, converted, cancelled, expired], initial: proposed }\n invariants count of { instrument: current(), reference: \"listing\", anchor: self.listing, states: [active], limit: 366 } <= 1\n action create { actor: { party: buyer }, requires self.listing in [active]; requires self.seller == self.listing.seller; requires self.price == self.listing.price }\n action activate {\n from: proposed, to: active, actor: { party: buyer }, deadline: { at: self.proposalExpiresAt }\n calculate: [{ target: expiresAt, op: shift, date: { field: self.now }, milliseconds: { literal: expires_after }, direction: after }]\n requires self.listing in [active]; requires self.price == self.listing.price\n requires count of { instrument: all(marketplace.order), reference: \"listing\", anchor: self.listing, states: [placed, fulfilled], limit: 366 } == 0\n moves self.deposit from self.buyer to self.held economics { purpose: principal, sourceParty: buyer }\n }\n action convert_financed {\n from: active, to: active, actor: { party: buyer }, deadline: { at: self.expiresAt }\n input { plan: ref<plans> }\n requires input.plan.funds == self.funds; requires input.plan.borrower == self.buyer\n invoke: [{ reference: input.plan, action: disburse, input: {} }]\n }\n action convert_cash {\n from: active, to: active, actor: { party: buyer }, deadline: { at: self.expiresAt }\n invoke: [{ reference: self.funds, action: fund, input: {} }]\n }\n action credit { allowZero: true,\n from: active, to: converted, actor: { parent: converters }, deadline: { at: self.expiresAt }\n input { funds: ref<funds>, contribution: money }\n requires input.funds == self.funds; requires input.funds in [pending, funded]; requires input.funds.payer == self.buyer; requires input.funds.price == self.price\n requires input.contribution <= self.price\n calculate: [{ target: credit, op: minimum, values: [{ field: self.held.balance }, { field: input.contribution }] }, { target: refund, op: subtract, base: { field: self.held.balance }, subtract: [{ field: self.credit }] }]\n set: { dispositionAt: { field: self.now } }\n moves self.credit from self.held to input.funds.held economics { purpose: principal, sourceParty: programOperator }\n moves self.refund from self.held to self.buyer economics { purpose: principal, sourceParty: programOperator }\n }\n action cancel { allowZero: true,\n from: active, to: cancelled, actor: { party: buyer }, input { reason: text }\n calculate: [{ target: refund, op: rate, base: { field: self.held.balance }, bps: { literal: cancellation_refund }, rounding: floor }, { target: retained, op: subtract, base: { field: self.held.balance }, subtract: [{ field: self.refund }] }]\n set: { reason: { field: input.reason }, dispositionAt: { field: self.now } }\n moves self.refund from self.held to self.buyer economics { purpose: principal, sourceParty: programOperator }; moves self.retained from self.held to retained_to economics { recipient: retained_to, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action seller_cancel {\n from: active, to: cancelled, actor: { party: seller }, input { reason: text }\n set: { reason: { field: input.reason }, dispositionAt: { field: self.now } }\n moves self.held.balance from self.held to self.buyer economics { purpose: principal, sourceParty: programOperator }\n }\n action operator_cancel {\n from: active, to: cancelled, actor: { party: operator }, input { reason: text }\n set: { reason: { field: input.reason }, dispositionAt: { field: self.now } }\n moves self.held.balance from self.held to self.buyer economics { purpose: principal, sourceParty: programOperator }\n }\n action withdraw { from: proposed, to: cancelled, actor: { party: buyer } }\n action expire { allowZero: true,\n from: active, to: expired, actor: clock, due: { at: self.expiresAt }\n calculate: [{ target: refund, op: rate, base: { field: self.held.balance }, bps: { literal: expiry_refund }, rounding: floor }, { target: retained, op: subtract, base: { field: self.held.balance }, subtract: [{ field: self.refund }] }]\n set: { dispositionAt: { field: self.now } }\n moves self.refund from self.held to self.buyer economics { purpose: principal, sourceParty: programOperator }; moves self.retained from self.held to retained_to economics { recipient: retained_to, company: { purpose: earning, sourceParty: buyer }, participant: { purpose: participant_payout, sourceParty: programOperator } }\n }\n action expire_proposal { from: proposed, to: expired, actor: clock, due: { at: self.proposalExpiresAt } }\n}\n"],
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const HSX_VERSION = "5.
|
|
1
|
+
export const HSX_VERSION = "5.7.0";
|
package/std/financing.hsx
CHANGED
|
@@ -497,7 +497,7 @@ instrument late_charge(on: ref<financing.installments>[], grace: duration = 3d,
|
|
|
497
497
|
receivable: account(self, claim), debt: account(borrower, claim, contra, "debt")
|
|
498
498
|
}
|
|
499
499
|
lifecycle { states: [proposed, assessed, collected, waived], initial: proposed }
|
|
500
|
-
action create { calculate: [{ target: overdueAt, op: shift, date: { field: self.slice.dueAt }, milliseconds: { literal: grace }, direction: after }], requires unique "late_assessment" on [self.slice, self.overdueAt]; requires self.borrower == self.slice.plan.borrower; requires self.plan == self.slice.plan }
|
|
500
|
+
action create { input { slice: ref<on.slice>? }, calculate: [{ target: overdueAt, op: shift, date: { field: self.slice.dueAt }, milliseconds: { literal: grace }, direction: after }], requires unique "late_assessment" on [self.slice, self.overdueAt]; requires self.borrower == self.slice.plan.borrower; requires self.plan == self.slice.plan }
|
|
501
501
|
action assess { allowZero: true,
|
|
502
502
|
from: proposed, to: assessed, actor: clock, due: { at: self.overdueAt }
|
|
503
503
|
requires self.slice.principalReceivable.balance > "0"
|
|
@@ -630,6 +630,7 @@ instrument late_charge(on: ref<financing.installments>[], grace: duration = 3d,
|
|
|
630
630
|
|
|
631
631
|
instrument limits(per_borrower: money, borrower: party = party(person), active_plans: integer = 1) {
|
|
632
632
|
familyRevision: 1
|
|
633
|
+
scope: product
|
|
633
634
|
summary: "One outstanding balance ceiling per borrower."
|
|
634
635
|
fields { borrower: account of borrower, limit: money = per_borrower, activePlans: integer = active_plans }
|
|
635
636
|
lifecycle { states: [pending, approved], initial: pending }
|
|
@@ -639,6 +640,7 @@ instrument limits(per_borrower: money, borrower: party = party(person), active_p
|
|
|
639
640
|
|
|
640
641
|
instrument portfolio_limit(limit: money) {
|
|
641
642
|
familyRevision: 1
|
|
643
|
+
scope: product
|
|
642
644
|
summary: "One shared ceiling on the principal the product may hold."
|
|
643
645
|
fields { key: text = "portfolio", limit: money = limit }
|
|
644
646
|
lifecycle { states: [pending, approved], initial: pending }
|