11// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22
33import { ObjectSchema , Field } from '@objectstack/spec/data' ;
4+ import { cel , P } from '@objectstack/spec' ;
45
56/**
67 * Product — a small price-book / catalog. The invoice line's `product` lookup
@@ -60,7 +61,7 @@ export const Invoice = ObjectSchema.create({
6061 // the same predicate over the merged record — one rule, both ends agree.
6162 issued_on : Field . date ( {
6263 label : 'Issued On' ,
63- requiredWhen : " record.status in ['sent', 'paid']" ,
64+ requiredWhen : P ` record.status in ['sent', 'paid']` ,
6465 } ) ,
6566 // Conditional rule (B2): once an invoice is Paid, its tax rate is locked.
6667 // `readonlyWhen` makes the client render the field read-only, and the
@@ -73,16 +74,16 @@ export const Invoice = ObjectSchema.create({
7374 min : 0 ,
7475 max : 100 ,
7576 defaultValue : 0 ,
76- readonlyWhen : " record.status == 'paid'" ,
77+ readonlyWhen : P ` record.status == 'paid'` ,
7778 } ) ,
7879 // Conditional rule (B2): "Paid On" is only meaningful — and only shown —
7980 // once the invoice is Paid, and then it is required. `visibleWhen` is a
8081 // pure client UX concern (the server has no visibility notion); the
8182 // `requiredWhen` half is enforced on both ends.
8283 paid_on : Field . date ( {
8384 label : 'Paid On' ,
84- visibleWhen : " record.status == 'paid'" ,
85- requiredWhen : " record.status == 'paid'" ,
85+ visibleWhen : P ` record.status == 'paid'` ,
86+ requiredWhen : P ` record.status == 'paid'` ,
8687 } ) ,
8788 // Roll-up: recomputed server-side as line items are inserted/updated/deleted
8889 // (child FK auto-detected: showcase_invoice_line.invoice). This is the line
@@ -123,7 +124,7 @@ export const InvoiceLine = ObjectSchema.create({
123124 product : Field . lookup ( 'showcase_product' , {
124125 label : 'Product' ,
125126 required : true ,
126- readonlyWhen : " parent.status == 'paid'" ,
127+ readonlyWhen : P ` parent.status == 'paid'` ,
127128 } ) ,
128129 // Conditional rule (B2 in grids): a bulk line (large quantity) must carry a
129130 // description note. `requiredWhen` here is ROW-scoped — it references the
@@ -134,20 +135,20 @@ export const InvoiceLine = ObjectSchema.create({
134135 description : Field . text ( {
135136 label : 'Description' ,
136137 maxLength : 200 ,
137- requiredWhen : ' record.quantity >= 100' ,
138+ requiredWhen : P ` record.quantity >= 100` ,
138139 } ) ,
139140 quantity : Field . number ( {
140141 label : 'Qty' ,
141142 required : true ,
142143 min : 0 ,
143144 defaultValue : 1 ,
144- readonlyWhen : " parent.status == 'paid'" ,
145+ readonlyWhen : P ` parent.status == 'paid'` ,
145146 } ) ,
146147 unit_price : Field . currency ( {
147148 label : 'Unit Price' ,
148149 scale : 2 ,
149150 min : 0 ,
150- readonlyWhen : " parent.status == 'paid'" ,
151+ readonlyWhen : P ` parent.status == 'paid'` ,
151152 } ) ,
152153 // Amount = Qty × Unit Price. Kept as a *stored* currency column (so the
153154 // parent Invoice.total summary can roll it up — summary aggregation reads
@@ -160,7 +161,7 @@ export const InvoiceLine = ObjectSchema.create({
160161 label : 'Amount' ,
161162 scale : 2 ,
162163 min : 0 ,
163- expression : ' record.quantity * record.unit_price' ,
164+ expression : cel ` record.quantity * record.unit_price` ,
164165 } ) ,
165166 } ,
166167} ) ;
0 commit comments