code wiki / _hdl_build / nx_estate.nx
nx_estate.nx source
↩ module page · 135 lines · 7972 B
1// nx_estate.nx -- LIB: renders a will's SCHEDULE OF ASSETS (a tangible-personal-property memorandum) from the
2// universal inventory's `estate` domain. Sovereign no-JS document: estate summary (net worth, item count),
3// per-beneficiary bequests with subtotals, residuary (unassigned) section, and the full asset schedule.
4// Boundary defense (rule 12): every asset name / owner is HTML-escaped. Money is integer CENTS (no float).
5// One more CONSUMER of the universal inventory (like the restaurant site is a consumer of the food engine).
6// license_tier: ORIGINAL
7import "nx_inventory.nx"
8import "nx_syscalls.nx"
9
10func er_streq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } if b[i] != (0 as u8) { return 0 } return 1 }
11
12// unassigned assets carry this explicit sentinel owner -> the residuary estate. (NishiLang gotcha: an empty
13// string literal "" aliases to another literal's bytes, so never store "" -- use a real sentinel.)
14const ER_RESID: *u8 = "(residuary)"
15func er_is_residuary(o: *u8) -> i64 { return er_streq(o, ER_RESID) }
16
17// distinct owner strings (incl. "" = residuary) into owners_out (ptrs to copies); returns count
18func er_distinct_owners(inv_prefix: *u8, domain: *u8, owners_out: *i64) -> i64 {
19 let ids: *i64 = sys_mmap(8 * 256) as *i64
20 let n: i64 = iv_list(inv_prefix, domain, ids)
21 var c: i64 = 0
22 var i: i64 = 0
23 while i < n {
24 let ow: *u8 = sys_mmap(64)
25 iv_field_of(inv_prefix, domain, ids[i] as *u8, 7, ow)
26 var seen: i64 = 0
27 var j: i64 = 0
28 while j < c { if er_streq(owners_out[j] as *u8, ow) == 1 { seen = 1 } j = j + 1 }
29 if seen == 0 { owners_out[c] = ow as i64; c = c + 1 }
30 i = i + 1
31 }
32 return c
33}
34
35// total value (cents) of items willed to `owner`
36func er_owner_total(inv_prefix: *u8, domain: *u8, owner: *u8) -> i64 {
37 let ids: *i64 = sys_mmap(8 * 256) as *i64
38 let n: i64 = iv_list(inv_prefix, domain, ids)
39 var tot: i64 = 0
40 var i: i64 = 0
41 while i < n {
42 let ow: *u8 = sys_mmap(64)
43 iv_field_of(inv_prefix, domain, ids[i] as *u8, 7, ow)
44 if er_streq(ow, owner) == 1 { tot = tot + iv_value(inv_prefix, domain, ids[i] as *u8) }
45 i = i + 1
46 }
47 return tot
48}
49
50// emit one item row "<tr>...<td>$value</td></tr>" (cols depend on with_ben); returns new off
51func er_item_row(inv_prefix: *u8, domain: *u8, id: *u8, with_ben: i64, out: *u8, off: i64) -> i64 {
52 let f: *u8 = sys_mmap(128)
53 var o: i64 = off
54 o = as_append(out, o, "<tr><td>" as *u8)
55 iv_field_of(inv_prefix, domain, id, 0, f); o = as_append_escaped(out, o, f, as_len(f)) // name
56 o = as_append(out, o, "</td><td>" as *u8)
57 iv_field_of(inv_prefix, domain, id, 1, f); o = as_append_escaped(out, o, f, as_len(f)) // category
58 o = as_append(out, o, "</td><td>" as *u8)
59 iv_field_of(inv_prefix, domain, id, 4, f); o = as_append_escaped(out, o, f, as_len(f)) // location
60 if with_ben == 1 {
61 o = as_append(out, o, "</td><td>" as *u8)
62 iv_field_of(inv_prefix, domain, id, 7, f) // beneficiary
63 if er_is_residuary(f) == 1 { o = as_append(out, o, "(residuary)" as *u8) } else { o = as_append_escaped(out, o, f, as_len(f)) }
64 }
65 o = as_append(out, o, "</td><td class='v'>" as *u8)
66 o = iv_money(out, o, iv_value(inv_prefix, domain, id))
67 o = as_append(out, o, "</td></tr>" as *u8)
68 return o
69}
70
71// render a per-beneficiary bequest section
72func er_owner_section(inv_prefix: *u8, domain: *u8, owner: *u8, out: *u8, off: i64) -> i64 {
73 var o: i64 = off
74 o = as_append(out, o, "<section class='ben'><h3>" as *u8)
75 if er_is_residuary(owner) == 1 { o = as_append(out, o, "Residuary estate (unassigned)" as *u8) } else {
76 o = as_append(out, o, "Bequeathed to " as *u8)
77 o = as_append_escaped(out, o, owner, as_len(owner))
78 }
79 o = as_append(out, o, "</h3><table><tr><th>Item</th><th>Category</th><th>Location</th><th>Value</th></tr>" as *u8)
80 let ids: *i64 = sys_mmap(8 * 256) as *i64
81 let n: i64 = iv_list(inv_prefix, domain, ids)
82 var i: i64 = 0
83 while i < n {
84 let ow: *u8 = sys_mmap(64)
85 iv_field_of(inv_prefix, domain, ids[i] as *u8, 7, ow)
86 if er_streq(ow, owner) == 1 { o = er_item_row(inv_prefix, domain, ids[i] as *u8, 0, out, o) }
87 i = i + 1
88 }
89 o = as_append(out, o, "</table><p class='sub'>Subtotal: " as *u8)
90 o = iv_money(out, o, er_owner_total(inv_prefix, domain, owner))
91 o = as_append(out, o, "</p></section>" as *u8)
92 return o
93}
94
95// render the full Schedule of Assets document (NUL-terminated); returns byte length.
96func er_render_schedule(inv_prefix: *u8, domain: *u8, estate_owner: *u8, out: *u8) -> i64 {
97 var o: i64 = 0
98 o = as_append(out, o, "<!doctype html><html lang='en'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>Schedule of Assets</title><style>body{margin:0;font-family:Georgia,'Times New Roman',serif;color:#1c1c1c;background:#f6f4ef;line-height:1.5}.doc{max-width:720px;margin:0 auto;padding:32px 28px;background:#fff;box-shadow:0 1px 4px rgba(0,0,0,.08)}h1{font-size:1.5rem;margin:0 0 2px;text-align:center}.estof{text-align:center;color:#555;margin:0 0 18px}.summary{background:#f0ece3;border:1px solid #ddd5c6;border-radius:6px;padding:12px 16px;margin:0 0 22px}h3{font-size:1.05rem;border-bottom:1px solid #c9b896;padding-bottom:4px;margin:22px 0 8px}table{border-collapse:collapse;width:100%;font-size:.95rem}th{text-align:left;border-bottom:2px solid #c9b896;padding:5px 8px;color:#555}td{padding:5px 8px;border-bottom:1px solid #ece5d8}td.v{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}.sub{text-align:right;font-weight:700;margin:6px 0 0}.tot{font-size:1.1rem;font-weight:700}.ftr{margin-top:26px;border-top:1px solid #ddd5c6;padding-top:12px;color:#777;font-size:.82rem;text-align:center}</style></head><body><div class='doc'>" as *u8)
99 o = as_append(out, o, "<h1>Schedule of Assets</h1><p class='estof'>Estate of " as *u8)
100 o = as_append_escaped(out, o, estate_owner, as_len(estate_owner))
101 o = as_append(out, o, "</p>" as *u8)
102
103 let ids: *i64 = sys_mmap(8 * 256) as *i64
104 let n: i64 = iv_list(inv_prefix, domain, ids)
105 let owners: *i64 = sys_mmap(8 * 64) as *i64
106 let no: i64 = er_distinct_owners(inv_prefix, domain, owners)
107 let total: i64 = iv_value_total(inv_prefix, domain)
108
109 o = as_append(out, o, "<div class='summary'><span class='tot'>Total estate value: " as *u8)
110 o = iv_money(out, o, total)
111 o = as_append(out, o, "</span><br>" as *u8)
112 o = iv_num(out, o, n)
113 o = as_append(out, o, " catalogued assets across " as *u8)
114 o = iv_num(out, o, no)
115 o = as_append(out, o, " distribution group(s).</div>" as *u8)
116
117 // named beneficiaries first
118 var i: i64 = 0
119 while i < no { if er_is_residuary(owners[i] as *u8) == 0 { o = er_owner_section(inv_prefix, domain, owners[i] as *u8, out, o) } i = i + 1 }
120 // residuary last
121 i = 0
122 while i < no { if er_is_residuary(owners[i] as *u8) == 1 { o = er_owner_section(inv_prefix, domain, owners[i] as *u8, out, o) } i = i + 1 }
123
124 // full schedule
125 o = as_append(out, o, "<h3>Full schedule</h3><table><tr><th>Item</th><th>Category</th><th>Location</th><th>Beneficiary</th><th>Value</th></tr>" as *u8)
126 i = 0
127 while i < n { o = er_item_row(inv_prefix, domain, ids[i] as *u8, 1, out, o); i = i + 1 }
128 o = as_append(out, o, "<tr><td colspan='4' class='tot'>Total</td><td class='v tot'>" as *u8)
129 o = iv_money(out, o, total)
130 o = as_append(out, o, "</td></tr></table>" as *u8)
131
132 o = as_append(out, o, "<p class='ftr'>Generated by the Nishi inventory engine — sovereign, no tracking. A tangible-personal-property memorandum for use with your will; review with your estate attorney.</p></div></body></html>" as *u8)
133 out[o] = 0 as u8
134 return o
135}