@hyperscale0/hsx 4.3.0 → 5.0.1
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 +23 -0
- package/README.md +5 -4
- package/dist/src/binding-contract.d.ts +22 -0
- package/dist/src/binding-contract.d.ts.map +1 -0
- package/dist/src/binding-contract.js +74 -0
- package/dist/src/binding-contract.js.map +1 -0
- package/dist/src/compile.d.ts.map +1 -1
- package/dist/src/compile.js +340 -112
- package/dist/src/compile.js.map +1 -1
- package/dist/src/examples-bundle.d.ts.map +1 -1
- package/dist/src/examples-bundle.js +2 -1
- package/dist/src/examples-bundle.js.map +1 -1
- package/dist/src/headers.d.ts +13 -0
- package/dist/src/headers.d.ts.map +1 -1
- package/dist/src/headers.js +3 -0
- package/dist/src/headers.js.map +1 -1
- package/dist/src/std-bundle.js +8 -8
- 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 +78 -3
- package/docs/examples.md +3 -2
- package/docs/headers.md +2 -2
- package/examples/lending.hsx +14 -3
- package/examples/repair-approval.hsx +43 -0
- package/package.json +3 -3
- package/src/binding-contract.ts +104 -0
- package/src/compile.ts +476 -171
- package/src/examples-bundle.ts +2 -1
- package/src/headers.ts +8 -0
- package/src/std-bundle.ts +8 -8
- package/src/version.ts +1 -1
- package/std/collections.hsx +1 -1
- package/std/escrow.hsx +1 -1
- package/std/financing.hsx +37 -23
- package/std/lending.hsx +6 -6
- package/std/marketplace.hsx +3 -3
- package/std/money.hsx +6 -6
- package/std/savings.hsx +1 -1
- package/std/travel.hsx +7 -7
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const HSX_VERSION = "
|
|
1
|
+
export const HSX_VERSION = "5.0.1";
|
|
2
2
|
export const HSX_TARGET_UDL_VERSION = 4;
|
package/std/collections.hsx
CHANGED
|
@@ -13,7 +13,7 @@ instrument case(on: ref<financing.installments>[], agency: party, capital: party
|
|
|
13
13
|
}
|
|
14
14
|
action assign { from: opened, to: assigned, actor: { party: capital } }
|
|
15
15
|
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: {} }] }
|
|
16
|
-
action pay_fee { from: recovered, to: recovered, actor: { parent: current() }, moves self.agencyFee from self.plan.capital to agency }
|
|
16
|
+
action pay_fee { allowZero: true, from: recovered, to: recovered, actor: { parent: current() }, moves self.agencyFee from self.plan.capital to agency }
|
|
17
17
|
action recall { from: [opened, assigned], to: recalled, actor: { party: capital } }
|
|
18
18
|
action return_uncollected { from: assigned, to: returned_uncollected, actor: { party: agency } }
|
|
19
19
|
}
|
package/std/escrow.hsx
CHANGED
|
@@ -26,7 +26,7 @@ instrument hold(payer: party = party(person), payee: party = programOperator, ac
|
|
|
26
26
|
from: funded, to: delivered, actor: { party: payee }
|
|
27
27
|
set: { deliveredAt: { field: self.now } }
|
|
28
28
|
}
|
|
29
|
-
action accept {
|
|
29
|
+
action accept { allowZero: true, requires self.price > "0";
|
|
30
30
|
from: delivered, to: released, actor: { party: payer }
|
|
31
31
|
input { acceptanceReference: text }
|
|
32
32
|
deadline: { at: self.deliveredAt, offset: accept_within }
|
package/std/financing.hsx
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
header financing
|
|
2
2
|
|
|
3
3
|
instrument 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)) {
|
|
4
|
+
dependencies {
|
|
5
|
+
funds {
|
|
6
|
+
selector: disburse_to, is: funds
|
|
7
|
+
message: "Attachment `{attachment}` disburses into a hold, but `funds` is not bound."
|
|
8
|
+
fix: "Bind `funds: sale` to an escrow attachment. Choose `disburse_to: borrower` only if the borrower should receive the money directly."
|
|
9
|
+
}
|
|
10
|
+
}
|
|
4
11
|
revisioned: true
|
|
5
12
|
familyRevision: 1
|
|
6
13
|
summary: "Funding, profit recognition and payment order chosen by the program."
|
|
@@ -29,7 +36,7 @@ instrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3
|
|
|
29
36
|
from: quoted, to: signed, actor: { party: borrower }, input { signedOffer: text, affordabilityReference: text }
|
|
30
37
|
requires count of { instrument: slice, reference: "plan", anchor: self.id, states: [draft], limit: 366 } == self.months
|
|
31
38
|
}
|
|
32
|
-
action disburse {
|
|
39
|
+
action disburse { allowZero: true,
|
|
33
40
|
from: signed, to: active, actor: { party: capital }
|
|
34
41
|
requires self.borrowerLimit in [approved]
|
|
35
42
|
requires self.portfolioLimit in [approved]
|
|
@@ -41,7 +48,7 @@ instrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3
|
|
|
41
48
|
invoke: [{ selection: { instrument: slice, reference: "plan", anchor: self.id, states: [draft], limit: 366, order: [position] }, action: activate, input: {} }]
|
|
42
49
|
when disburse_to is funds { invoke: [{ reference: self.funds, action: confirm, input: {} }] }
|
|
43
50
|
}
|
|
44
|
-
action fund_down_payment {
|
|
51
|
+
action fund_down_payment { allowZero: true,
|
|
45
52
|
from: active, to: active, actor: { parent: current() }
|
|
46
53
|
when disburse_to is funds {
|
|
47
54
|
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 }] }]
|
|
@@ -186,14 +193,14 @@ instrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3
|
|
|
186
193
|
fields { plan: ref<parent>, identity: text, principal: money, profit: money, loss: money, kind: enum(cash, loss), share: money?, retainedProfit: money?
|
|
187
194
|
allocatedPayable: account(capital, cash, "allocatedProfitPayable"), capital: account(capital, cash, "capital"), profitIncome: account(capital, cash, "profitIncome"), lossAccount: account(capital, claim, "loss") }
|
|
188
195
|
lifecycle { states: [recorded, refunded], initial: recorded }
|
|
189
|
-
action create {
|
|
196
|
+
action create { allowZero: true,
|
|
190
197
|
actor: { parent: parent }
|
|
191
198
|
input { plan: ref<parent>, identity: text, principal: money, profit: money, loss: money, kind: enum(cash, loss) }
|
|
192
199
|
requires unique "settlement_identity" on [self.plan, self.identity]
|
|
193
200
|
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 }] }]
|
|
194
201
|
moves self.share from self.profitIncome to self.allocatedPayable
|
|
195
202
|
}
|
|
196
|
-
action refund {
|
|
203
|
+
action refund { allowZero: true,
|
|
197
204
|
from: recorded, to: refunded, actor: { parent: payment }
|
|
198
205
|
moves self.share from self.allocatedPayable to self.profitIncome
|
|
199
206
|
}
|
|
@@ -259,7 +266,7 @@ instrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3
|
|
|
259
266
|
calculate: [{ target: nextDueAt, op: at, list: input.amendment.dates, position: { field: self.position } }]
|
|
260
267
|
requires self.nextDueAt == self.dueAt
|
|
261
268
|
}
|
|
262
|
-
action activate {
|
|
269
|
+
action activate { allowZero: true,
|
|
263
270
|
from: draft, to: pending, actor: { parent: parent }
|
|
264
271
|
moves self.principal from self.debt to self.principalReceivable
|
|
265
272
|
moves self.profit from self.debt to self.profitReceivable
|
|
@@ -324,7 +331,7 @@ instrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3
|
|
|
324
331
|
requires self.principalReceivable.balance == "0"; requires self.profitReceivable.balance == "0"; requires self.profitEarned.balance == "0"
|
|
325
332
|
}
|
|
326
333
|
action restore { from: [pending, due, paid], to: pending, actor: { parent: payment } }
|
|
327
|
-
action payoff {
|
|
334
|
+
action payoff { allowZero: true,
|
|
328
335
|
from: [pending, due], to: paid, actor: { parent: parent }, input { identity: text }
|
|
329
336
|
set: { payoffIdentity: { field: input.identity } }
|
|
330
337
|
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 }] }]
|
|
@@ -334,7 +341,7 @@ instrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3
|
|
|
334
341
|
moves self.profitReceivable.balance from self.profitReceivable to self.debt
|
|
335
342
|
moves self.profitEarned.balance from self.profitEarned to self.debt
|
|
336
343
|
}
|
|
337
|
-
action write_off {
|
|
344
|
+
action write_off { allowZero: true,
|
|
338
345
|
from: [pending, due], to: written_off, actor: { parent: parent }
|
|
339
346
|
moves self.principalReceivable.balance from self.principalReceivable to self.loss; moves self.profitReceivable.balance from self.profitReceivable to self.debt; moves self.profitEarned.balance from self.profitEarned to self.loss
|
|
340
347
|
}
|
|
@@ -344,7 +351,7 @@ instrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3
|
|
|
344
351
|
lifecycle { states: [pending, recognised], initial: pending }
|
|
345
352
|
action create { actor: { parent: slice }, input { slice: ref<slice> }, requires unique "profit_recognition" on [self.slice] }
|
|
346
353
|
action reschedule { from: pending, to: pending, actor: { parent: slice } }
|
|
347
|
-
action mature { from: pending, to: recognised, actor: clock, due: { at: self.dueAt }, moves self.slice.profitReceivable.balance from self.slice.profitReceivable to self.slice.profitEarned }
|
|
354
|
+
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 }
|
|
348
355
|
}
|
|
349
356
|
payment: {
|
|
350
357
|
revisioned: true
|
|
@@ -398,14 +405,14 @@ instrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3
|
|
|
398
405
|
principal_piece: {
|
|
399
406
|
fields { slice: ref<slice>, payment: ref<payment>, limit: money, amount: money? }
|
|
400
407
|
lifecycle { states: [paid, refunded], initial: paid }
|
|
401
|
-
action create {
|
|
408
|
+
action create { allowZero: true,
|
|
402
409
|
calculate: [{ target: amount, op: minimum, values: [{ field: self.payment.held.balance }, { field: self.slice.principalReceivable.balance }, { field: self.limit }] }]
|
|
403
410
|
actor: { parent: slice }
|
|
404
411
|
input { slice: ref<slice>, payment: ref<payment>, limit: money }
|
|
405
412
|
requires unique "principal_receipt" on [self.slice, self.payment]
|
|
406
413
|
moves self.amount from self.payment.held to self.slice.plan.capital; moves self.amount from self.slice.principalReceivable to self.slice.debt
|
|
407
414
|
}
|
|
408
|
-
action refund {
|
|
415
|
+
action refund { allowZero: true,
|
|
409
416
|
from: paid, to: refunded, actor: { parent: payment }
|
|
410
417
|
moves self.amount from self.slice.plan.capital to self.slice.plan.borrower; moves self.amount from self.slice.debt to self.slice.principalReceivable
|
|
411
418
|
}
|
|
@@ -413,7 +420,7 @@ instrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3
|
|
|
413
420
|
profit_piece: {
|
|
414
421
|
fields { slice: ref<slice>, payment: ref<payment>, limit: money, amount: money? }
|
|
415
422
|
lifecycle { states: [paid, refunded], initial: paid }
|
|
416
|
-
action create {
|
|
423
|
+
action create { allowZero: true,
|
|
417
424
|
calculate: [{ target: amount, op: minimum, values: [{ field: self.payment.held.balance }, { field: self.limit }] }]
|
|
418
425
|
actor: { parent: slice }
|
|
419
426
|
input { slice: ref<slice>, payment: ref<payment>, limit: money }
|
|
@@ -423,7 +430,7 @@ instrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3
|
|
|
423
430
|
when profit_earned is by_schedule { moves self.amount from self.slice.profitEarned to self.slice.debt }
|
|
424
431
|
when profit_earned is at_disbursement { moves self.amount from self.slice.profitEarned to self.slice.debt }
|
|
425
432
|
}
|
|
426
|
-
action refund {
|
|
433
|
+
action refund { allowZero: true,
|
|
427
434
|
from: paid, to: refunded, actor: { parent: payment }
|
|
428
435
|
moves self.amount from self.slice.plan.profitIncome to self.slice.plan.borrower
|
|
429
436
|
when profit_earned is on_payment { moves self.amount from self.slice.debt to self.slice.profitReceivable }
|
|
@@ -435,6 +442,13 @@ instrument installments(months: integer(1, 366), charge_limit: integer(1, 3) = 3
|
|
|
435
442
|
}
|
|
436
443
|
|
|
437
444
|
instrument 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)) {
|
|
445
|
+
parameterDiagnostics {
|
|
446
|
+
fine {
|
|
447
|
+
accepts: "a fixed amount"
|
|
448
|
+
percentage: "a percentage of overdue debt"
|
|
449
|
+
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."
|
|
450
|
+
}
|
|
451
|
+
}
|
|
438
452
|
revisioned: true
|
|
439
453
|
familyRevision: 1
|
|
440
454
|
summary: "Separate approved fine and evidenced recovery claims on an overdue installment."
|
|
@@ -444,7 +458,7 @@ instrument late_charge(on: ref<financing.installments>[], grace: duration = 3d,
|
|
|
444
458
|
}
|
|
445
459
|
lifecycle { states: [proposed, assessed, collected, waived, refunded], initial: proposed }
|
|
446
460
|
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 }
|
|
447
|
-
action assess {
|
|
461
|
+
action assess { allowZero: true,
|
|
448
462
|
from: proposed, to: assessed, actor: clock, due: { at: self.overdueAt }
|
|
449
463
|
requires self.slice.principalReceivable.balance > "0"
|
|
450
464
|
moves self.fine from self.debt to self.receivable
|
|
@@ -455,7 +469,7 @@ instrument late_charge(on: ref<financing.installments>[], grace: duration = 3d,
|
|
|
455
469
|
requires input.payment.plan == self.plan
|
|
456
470
|
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: {} }]
|
|
457
471
|
}
|
|
458
|
-
action payoff {
|
|
472
|
+
action payoff { allowZero: true,
|
|
459
473
|
from: [assessed, collected], to: collected, actor: { parent: on }
|
|
460
474
|
requires self.plan in [paid]
|
|
461
475
|
moves self.receivable.balance from self.plan.borrower to fines_to
|
|
@@ -468,7 +482,7 @@ instrument late_charge(on: ref<financing.installments>[], grace: duration = 3d,
|
|
|
468
482
|
requires input.amendment.plan == self.plan; requires input.amendment in [applied]
|
|
469
483
|
invoke: [{ instrument: waiver, action: create, input: { assessment: { field: self.id }, amendment: { field: input.amendment } } }]
|
|
470
484
|
}
|
|
471
|
-
action waive { from: [assessed, collected], to: waived, actor: { parent: waiver_request }, input { reason: text, evidence: text }, moves self.receivable.balance from self.receivable to self.debt }
|
|
485
|
+
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 }
|
|
472
486
|
action refund {
|
|
473
487
|
from: [assessed, collected], to: assessed, actor: { party: fines_to }, input { payment: ref<on.payment> }
|
|
474
488
|
requires input.payment in [paid, refunded]
|
|
@@ -489,7 +503,7 @@ instrument late_charge(on: ref<financing.installments>[], grace: duration = 3d,
|
|
|
489
503
|
waiver: {
|
|
490
504
|
fields { assessment: ref<parent>, amendment: ref<on.amendment>, amount: money? }
|
|
491
505
|
lifecycle { states: [recorded], initial: recorded }
|
|
492
|
-
action create {
|
|
506
|
+
action create { allowZero: true,
|
|
493
507
|
actor: { parent: parent }, input { assessment: ref<parent>, amendment: ref<on.amendment> }
|
|
494
508
|
calculate: [{ target: amount, op: rate, base: { field: self.assessment.receivable.balance }, bps: { field: self.amendment.waiverPercent }, rounding: floor }]
|
|
495
509
|
requires unique "amendment_waiver" on [self.assessment, self.amendment]
|
|
@@ -499,8 +513,8 @@ instrument late_charge(on: ref<financing.installments>[], grace: duration = 3d,
|
|
|
499
513
|
receipt: {
|
|
500
514
|
fields { assessment: ref<parent>, payment: ref<on.payment>, amount: money? }
|
|
501
515
|
lifecycle { states: [paid, refunded], initial: paid }
|
|
502
|
-
action create { 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; moves self.amount from self.assessment.receivable to self.assessment.debt }
|
|
503
|
-
action refund { from: paid, to: refunded, actor: { parent: parent }, moves self.amount from fines_to to self.payment.plan.borrower; moves self.amount from self.assessment.debt to self.assessment.receivable }
|
|
516
|
+
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; moves self.amount from self.assessment.receivable to self.assessment.debt }
|
|
517
|
+
action refund { allowZero: true, from: paid, to: refunded, actor: { parent: parent }, moves self.amount from fines_to to self.payment.plan.borrower; moves self.amount from self.assessment.debt to self.assessment.receivable }
|
|
504
518
|
}
|
|
505
519
|
|
|
506
520
|
cost: {
|
|
@@ -522,7 +536,7 @@ instrument late_charge(on: ref<financing.installments>[], grace: duration = 3d,
|
|
|
522
536
|
requires input.payment.plan == self.plan
|
|
523
537
|
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: {} }]
|
|
524
538
|
}
|
|
525
|
-
action payoff {
|
|
539
|
+
action payoff { allowZero: true,
|
|
526
540
|
from: [assessed, collected], to: collected, actor: { parent: on }
|
|
527
541
|
requires self.plan in [paid]
|
|
528
542
|
moves self.receivable.balance from self.plan.borrower to costs_to
|
|
@@ -535,7 +549,7 @@ instrument late_charge(on: ref<financing.installments>[], grace: duration = 3d,
|
|
|
535
549
|
requires input.amendment.plan == self.plan; requires input.amendment in [applied]
|
|
536
550
|
invoke: [{ instrument: waiver, action: create, input: { assessment: { field: self.id }, amendment: { field: input.amendment } } }]
|
|
537
551
|
}
|
|
538
|
-
action waive { from: [assessed, collected], to: waived, actor: { parent: waiver_request }, input { reason: text, evidence: text }, moves self.receivable.balance from self.receivable to self.debt }
|
|
552
|
+
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 }
|
|
539
553
|
action refund {
|
|
540
554
|
from: [assessed, collected], to: assessed, actor: { party: costs_to }, input { payment: ref<on.payment> }
|
|
541
555
|
requires input.payment in [paid, refunded]
|
|
@@ -556,7 +570,7 @@ instrument late_charge(on: ref<financing.installments>[], grace: duration = 3d,
|
|
|
556
570
|
waiver: {
|
|
557
571
|
fields { assessment: ref<parent>, amendment: ref<on.amendment>, amount: money? }
|
|
558
572
|
lifecycle { states: [recorded], initial: recorded }
|
|
559
|
-
action create {
|
|
573
|
+
action create { allowZero: true,
|
|
560
574
|
actor: { parent: parent }, input { assessment: ref<parent>, amendment: ref<on.amendment> }
|
|
561
575
|
calculate: [{ target: amount, op: rate, base: { field: self.assessment.receivable.balance }, bps: { field: self.amendment.waiverPercent }, rounding: floor }]
|
|
562
576
|
requires unique "amendment_waiver" on [self.assessment, self.amendment]
|
|
@@ -566,8 +580,8 @@ instrument late_charge(on: ref<financing.installments>[], grace: duration = 3d,
|
|
|
566
580
|
receipt: {
|
|
567
581
|
fields { assessment: ref<parent>, payment: ref<on.payment>, amount: money? }
|
|
568
582
|
lifecycle { states: [paid, refunded], initial: paid }
|
|
569
|
-
action create { 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; moves self.amount from self.assessment.receivable to self.assessment.debt }
|
|
570
|
-
action refund { from: paid, to: refunded, actor: { parent: parent }, moves self.amount from costs_to to self.payment.plan.borrower; moves self.amount from self.assessment.debt to self.assessment.receivable }
|
|
583
|
+
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; moves self.amount from self.assessment.receivable to self.assessment.debt }
|
|
584
|
+
action refund { allowZero: true, from: paid, to: refunded, actor: { parent: parent }, moves self.amount from costs_to to self.payment.plan.borrower; moves self.amount from self.assessment.debt to self.assessment.receivable }
|
|
571
585
|
}
|
|
572
586
|
}
|
|
573
587
|
}
|
package/std/lending.hsx
CHANGED
|
@@ -76,23 +76,23 @@ instrument distribution(round: ref<lending.round>, receipt: ref, commitments: re
|
|
|
76
76
|
requires self.mode == "loss"; requires self.source.kind == "loss"; requires self.source in [recorded]
|
|
77
77
|
calculate: [{ target: "net", op: "sum", values: [{ field: self.source.loss }] }]
|
|
78
78
|
}
|
|
79
|
-
action distribute_cash {
|
|
79
|
+
action distribute_cash { allowZero: true,
|
|
80
80
|
from: cash_ready, to: distributed, actor: { party: operator }
|
|
81
81
|
requires sum "weight" of { instrument: share, reference: "distribution", anchor: self.id, states: [pending], limit: 366 } == self.round.price
|
|
82
82
|
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; moves self.vat from self.held to programTax
|
|
83
83
|
invoke: [{ selection: { instrument: share, reference: "distribution", anchor: self.id, states: [pending], limit: 366 }, action: cash, input: {} }, { reference: self.id, action: residual_cash, input: {} }]
|
|
84
84
|
}
|
|
85
|
-
action residual_cash {
|
|
85
|
+
action residual_cash { allowZero: true,
|
|
86
86
|
from: distributed, to: distributed, actor: { parent: current() }
|
|
87
87
|
moves self.held.balance from self.held to residual_to
|
|
88
88
|
}
|
|
89
|
-
action distribute_loss {
|
|
89
|
+
action distribute_loss { allowZero: true,
|
|
90
90
|
from: loss_ready, to: distributed, actor: { party: operator }
|
|
91
91
|
requires sum "weight" of { instrument: share, reference: "distribution", anchor: self.id, states: [pending], limit: 366 } == self.round.price
|
|
92
92
|
moves self.net from self.source.lossAccount to self.losses
|
|
93
93
|
invoke: [{ selection: { instrument: share, reference: "distribution", anchor: self.id, states: [pending], limit: 366 }, action: loss, input: {} }, { reference: self.id, action: residual_loss, input: {} }]
|
|
94
94
|
}
|
|
95
|
-
action residual_loss {
|
|
95
|
+
action residual_loss { allowZero: true,
|
|
96
96
|
from: distributed, to: distributed, actor: { parent: current() }
|
|
97
97
|
moves self.losses.balance from self.losses to self.residualLoss
|
|
98
98
|
}
|
|
@@ -105,11 +105,11 @@ instrument distribution(round: ref<lending.round>, receipt: ref, commitments: re
|
|
|
105
105
|
}
|
|
106
106
|
lifecycle { states: [pending, paid], initial: pending }
|
|
107
107
|
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 }
|
|
108
|
-
action cash {
|
|
108
|
+
action cash { allowZero: true,
|
|
109
109
|
from: pending, to: paid, actor: { parent: parent }
|
|
110
110
|
moves self.gross from self.distribution.held to self.commitment.wallet.held
|
|
111
111
|
}
|
|
112
|
-
action loss { from: pending, to: paid, actor: { parent: parent }, moves self.gross from self.distribution.losses to self.commitment.loss }
|
|
112
|
+
action loss { allowZero: true, from: pending, to: paid, actor: { parent: parent }, moves self.gross from self.distribution.losses to self.commitment.loss }
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
}
|
package/std/marketplace.hsx
CHANGED
|
@@ -71,7 +71,7 @@ instrument reservation(listing: ref<marketplace.listing>, funds: ref<escrow.hold
|
|
|
71
71
|
from: active, to: active, actor: { party: buyer }, deadline: { at: self.expiresAt }
|
|
72
72
|
invoke: [{ reference: self.funds, action: fund, input: {} }]
|
|
73
73
|
}
|
|
74
|
-
action credit {
|
|
74
|
+
action credit { allowZero: true,
|
|
75
75
|
from: active, to: converted, actor: { parent: converters }, deadline: { at: self.expiresAt }
|
|
76
76
|
input { funds: ref<funds>, contribution: money }
|
|
77
77
|
requires input.funds == self.funds; requires input.funds in [pending, funded]; requires input.funds.payer == self.buyer; requires input.funds.price == self.price
|
|
@@ -81,7 +81,7 @@ instrument reservation(listing: ref<marketplace.listing>, funds: ref<escrow.hold
|
|
|
81
81
|
moves self.credit from self.held to input.funds.held
|
|
82
82
|
moves self.refund from self.held to self.buyer
|
|
83
83
|
}
|
|
84
|
-
action cancel {
|
|
84
|
+
action cancel { allowZero: true,
|
|
85
85
|
from: active, to: cancelled, actor: { party: buyer }, input { reason: text }
|
|
86
86
|
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 }] }]
|
|
87
87
|
set: { reason: { field: input.reason }, dispositionAt: { field: self.now } }
|
|
@@ -98,7 +98,7 @@ instrument reservation(listing: ref<marketplace.listing>, funds: ref<escrow.hold
|
|
|
98
98
|
moves self.held.balance from self.held to self.buyer
|
|
99
99
|
}
|
|
100
100
|
action withdraw { from: proposed, to: cancelled, actor: { party: buyer } }
|
|
101
|
-
action expire {
|
|
101
|
+
action expire { allowZero: true,
|
|
102
102
|
from: active, to: expired, actor: clock, due: { at: self.expiresAt }
|
|
103
103
|
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 }] }]
|
|
104
104
|
set: { dispositionAt: { field: self.now } }
|
package/std/money.hsx
CHANGED
|
@@ -4,7 +4,7 @@ instrument transfer(payer: party, payee: party, amount: money = runtime) {
|
|
|
4
4
|
summary: "One transfer between the bound parties."
|
|
5
5
|
fields { amount: money = amount }
|
|
6
6
|
lifecycle { states: [pending, paid, cancelled], initial: pending }
|
|
7
|
-
action create { actor: { party: payer } }
|
|
7
|
+
action create { actor: { party: payer }, requires self.amount > "0" }
|
|
8
8
|
action pay {
|
|
9
9
|
from: pending, to: paid, actor: { party: payer }
|
|
10
10
|
moves self.amount from payer to payee
|
|
@@ -41,7 +41,7 @@ instrument split(payer: party, amount: money = runtime, shares: split = { progra
|
|
|
41
41
|
fields { amount: money = amount }
|
|
42
42
|
lifecycle { states: [pending, paid, cancelled], initial: pending }
|
|
43
43
|
action create {}
|
|
44
|
-
action pay { from: pending, to: paid, actor: { party: payer }, moves self.amount from payer shares shares }
|
|
44
|
+
action pay { allowZero: true, requires self.amount > "0"; from: pending, to: paid, actor: { party: payer }, moves self.amount from payer shares shares }
|
|
45
45
|
action cancel { from: pending, to: cancelled }
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -72,7 +72,7 @@ instrument schedule(payer: party, payee: party, amount: money = runtime, count:
|
|
|
72
72
|
}
|
|
73
73
|
lifecycle { states: [pending, paid, cancelled], initial: pending }
|
|
74
74
|
action create { requires self.schedule in [draft]; requires unique "scheduled_position" on [self.schedule, self.position] }
|
|
75
|
-
action pay { from: pending, to: paid, actor: clock, due: { at: self.dueAt }, requires self.schedule in [active], moves self.amount from payer to payee }
|
|
75
|
+
action pay { allowZero: true, from: pending, to: paid, actor: clock, due: { at: self.dueAt }, requires self.schedule in [active], moves self.amount from payer to payee }
|
|
76
76
|
action cancel { from: pending, to: cancelled, requires self.schedule in [cancelled] }
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -95,10 +95,10 @@ instrument pool(payer: party, payee: party, target: money, closes: date) {
|
|
|
95
95
|
}
|
|
96
96
|
records {
|
|
97
97
|
contribution: {
|
|
98
|
-
fields { pool: ref<parent>, payer: account of payer, amount: money }
|
|
98
|
+
fields { pool: ref<parent>, payer: account of payer, amount: money, remaining: money? }
|
|
99
99
|
lifecycle { states: [pending, paid, refunded], initial: pending }
|
|
100
100
|
action create { requires self.pool in [open] }
|
|
101
|
-
action pay { from: pending, to: paid, actor: { party: payer }, deadline: { at: self.pool.closesAt }, requires self.pool in [open], moves self.amount from self.payer to self.pool.held }
|
|
101
|
+
action pay { from: pending, to: paid, actor: { party: payer }, deadline: { at: self.pool.closesAt }, requires self.pool in [open], calculate: [{ target: remaining, op: subtract, base: { field: self.pool.target }, subtract: [{ field: self.pool.held.balance }] }], requires self.amount <= self.remaining, moves self.amount from self.payer to self.pool.held }
|
|
102
102
|
action refund { from: paid, to: refunded, actor: { parent: parent }, moves self.amount from self.pool.held to self.payer }
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -146,6 +146,6 @@ instrument metered(payer: party, payee: party, unit_price: money, units: integer
|
|
|
146
146
|
fields { usageIdentity: text, unitPrice: money = unit_price, units: integer = units, amount: money = multiply(self.unitPrice, self.units) }
|
|
147
147
|
lifecycle { states: [recorded, billed, cancelled], initial: recorded }
|
|
148
148
|
action create { requires unique "usage_event" on [self.usageIdentity] }
|
|
149
|
-
action bill { from: recorded, to: billed, actor: { party: payee }, moves self.amount from payer to payee fee fee }
|
|
149
|
+
action bill { allowZero: true, requires self.amount > "0"; from: recorded, to: billed, actor: { party: payee }, moves self.amount from payer to payee fee fee }
|
|
150
150
|
action cancel { from: recorded, to: cancelled }
|
|
151
151
|
}
|
package/std/savings.hsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
header savings
|
|
2
2
|
|
|
3
|
-
instrument circle(contribution: money, members: integer(1,
|
|
3
|
+
instrument circle(contribution: money, members: integer(1, 60), starts: date, memberships: ref<savings.membership> = object(savings.membership)) {
|
|
4
4
|
summary: "A fixed group contributes on its explicit calendar and takes the pot in order."
|
|
5
5
|
fields { contribution: money = contribution, members: integer = members, startsAt: date = starts, dates: list(date, members), pot: money = multiply(self.contribution, self.members), held: account of self }
|
|
6
6
|
lifecycle { states: [forming, active, closed, disbanded], initial: forming }
|
package/std/travel.hsx
CHANGED
|
@@ -33,17 +33,17 @@ instrument booking(package: ref<travel.package>, buyer: party, supplier: party,
|
|
|
33
33
|
action create {
|
|
34
34
|
requires self.package in [published]
|
|
35
35
|
}
|
|
36
|
-
action deposit {
|
|
36
|
+
action deposit { allowZero: true, requires self.price > "0";
|
|
37
37
|
from: created, to: deposit_paid, actor: { party: buyer }, deadline: { at: self.balanceAt }
|
|
38
38
|
requires count of { instrument: child(cover, slice), reference: "covers", anchor: self.id, states: [pending], limit: 366 } >= 1
|
|
39
39
|
moves self.deposit from buyer to self.held
|
|
40
40
|
invoke: [{ selection: { instrument: child(cover, slice), reference: "covers", anchor: self.id, states: [pending], limit: 366 }, action: collect, input: {} }]
|
|
41
41
|
}
|
|
42
|
-
action balance {
|
|
42
|
+
action balance { allowZero: true, requires self.price > "0";
|
|
43
43
|
from: deposit_paid, to: paid, actor: { party: buyer }, deadline: { at: self.balanceAt }
|
|
44
44
|
moves self.balance from buyer to self.held
|
|
45
45
|
}
|
|
46
|
-
action confirm {
|
|
46
|
+
action confirm { allowZero: true, requires self.price > "0";
|
|
47
47
|
from: paid, to: completed, actor: { party: operator }
|
|
48
48
|
due: { at: self.package.departure }, deadline: { at: self.confirmBy }
|
|
49
49
|
moves self.supplierCost from self.held to supplier
|
|
@@ -54,11 +54,11 @@ instrument booking(package: ref<travel.package>, buyer: party, supplier: party,
|
|
|
54
54
|
from: paid, to: refunded, actor: clock, due: { at: self.confirmBy }
|
|
55
55
|
moves self.price from self.held to buyer
|
|
56
56
|
}
|
|
57
|
-
action cancel_early {
|
|
57
|
+
action cancel_early { allowZero: true, requires self.price > "0";
|
|
58
58
|
from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, deadline: { at: self.earlyAt }
|
|
59
59
|
moves self.held.balance from self.held to buyer
|
|
60
60
|
}
|
|
61
|
-
action cancel_middle {
|
|
61
|
+
action cancel_middle { allowZero: true, requires self.price > "0";
|
|
62
62
|
from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, due: { at: self.earlyAt }, deadline: { at: self.lateAt }
|
|
63
63
|
calculate: [
|
|
64
64
|
{ target: refund, op: "subtract", base: { field: self.held.balance }, subtract: [{ field: self.deposit }] }
|
|
@@ -71,7 +71,7 @@ instrument booking(package: ref<travel.package>, buyer: party, supplier: party,
|
|
|
71
71
|
moves self.retainedTax from self.held to programTax
|
|
72
72
|
moves self.retainedNet from self.held to programOperator
|
|
73
73
|
}
|
|
74
|
-
action cancel_late {
|
|
74
|
+
action cancel_late { allowZero: true, requires self.price > "0";
|
|
75
75
|
from: [deposit_paid, paid], to: cancelled, actor: { party: buyer }, due: { at: self.lateAt }
|
|
76
76
|
calculate: [
|
|
77
77
|
{ target: retainedMargin, op: "subtract", base: { field: self.held.balance }, subtract: [{ field: self.latePenalty }] }
|
|
@@ -82,7 +82,7 @@ instrument booking(package: ref<travel.package>, buyer: party, supplier: party,
|
|
|
82
82
|
moves self.retainedTax from self.held to programTax
|
|
83
83
|
moves self.retainedNet from self.held to programOperator
|
|
84
84
|
}
|
|
85
|
-
action default_balance {
|
|
85
|
+
action default_balance { allowZero: true, requires self.price > "0";
|
|
86
86
|
from: deposit_paid, to: cancelled, actor: clock, due: { at: self.balanceAt }
|
|
87
87
|
calculate: [
|
|
88
88
|
{ target: retainedMargin, op: "subtract", base: { field: self.held.balance }, subtract: [{ field: self.latePenalty }] }
|