@@ -114,14 +114,15 @@ const refusalOf = async (p: Promise<unknown>): Promise<Thrown> => p.then(() => n
114114const SYS = { context : { isSystem : true } } as const ;
115115const BATCH : EngineUpdateOptions = { where : { title : 'batch' } , multi : true } ;
116116
117- async function boot ( object = invoice ( ) , home : string | undefined = 'CNY' ) {
117+ /** `home: null` composes no home-currency resolver at all (no settings service). */
118+ async function boot ( object = invoice ( ) , home : string | null = 'CNY' ) {
118119 const engine = new ObjectQL ( ) ;
119120 const d = makeDriver ( ) ;
120121 engine . registerDriver ( d . driver , true ) ;
121122 await engine . init ( ) ;
122123 engine . registry . registerObject ( RATE_OBJECT as any ) ;
123124 engine . registry . registerObject ( object as any ) ;
124- if ( home !== undefined ) engine . setHomeCurrencyResolver ( async ( ) => home ) ;
125+ if ( home !== null ) engine . setHomeCurrencyResolver ( async ( ) => home ) ;
125126 const rate = ( currency : string , effective_date : string , value : number ) =>
126127 d . storeFor ( 'sys_exchange_rate' ) . set ( `${ currency } _${ effective_date } ` , { id : `${ currency } _${ effective_date } ` , currency, effective_date, rate : value } ) ;
127128 return { engine, ...d , rate } ;
@@ -200,15 +201,15 @@ describe('insert: the home amount is the amount divided by the rate in force on
200201
201202describe ( 'the home currency is the organization\'s setting, never a default' , ( ) => {
202203 it ( 'no resolver (no settings service) refuses ERR_HOME_CURRENCY_UNSET' , async ( ) => {
203- const t = await boot ( invoice ( ) , undefined ) ;
204+ const t = await boot ( invoice ( ) , null ) ;
204205 const err = await refusalOf ( t . engine . insert ( 'fx_invoice' , { title : 'i1' , currency_code : 'USD' , invoice_date : '2026-03-15' , amount : 1 } ) ) ;
205206 expect ( { code : err ?. code , status : err ?. status } ) . toEqual ( { code : 'ERR_HOME_CURRENCY_UNSET' , status : 400 } ) ;
206207 expect ( err ?. message ) . toContain ( 'localization.currency' ) ;
207208 expect ( t . storeFor ( 'fx_invoice' ) . size ) . toBe ( 0 ) ;
208209 } ) ;
209210
210211 it ( 'the resolver is asked for the row\'s organization' , async ( ) => {
211- const t = await boot ( invoice ( ) , undefined ) ;
212+ const t = await boot ( invoice ( ) , null ) ;
212213 const asked : Array < string | undefined > = [ ] ;
213214 t . engine . setHomeCurrencyResolver ( async ( org ) => { asked . push ( org ) ; return 'CNY' ; } ) ;
214215 await t . engine . insert ( 'fx_invoice' , { title : 'i1' , currency_code : 'CNY' , amount : 1 } , { context : { isSystem : true , tenantId : 'org_a' } } as any ) ;
@@ -260,16 +261,16 @@ describe('only the engine writes the home and rate fields', () => {
260261 expect ( t . storeFor ( 'fx_invoice' ) . get ( blank . id ) ) . toMatchObject ( { amount_home : null , amount_rate : null } ) ;
261262 } ) ;
262263
263- it ( 'a rate field whose scale keeps fewer decimals than the rate refuses max_scale — the rate is never rounded' , async ( ) => {
264+ it ( 'a rate field declaring a scale below the rate\'s decimals stores the rate unrounded, and converts with all of it' , async ( ) => {
265+ // `readonly` values are judged for SHAPE only (`ReadonlyValueScope`), so a
266+ // declared `scale` is no write constraint on the rate field, and every
267+ // numeric column is the same exact decimal: the stored rate is the rate
268+ // row's own value, and the stored home amount reproduces from it.
264269 const t = await boot ( invoice ( { rate : { scale : 4 } } ) ) ;
265- t . rate ( 'USD' , '2026-01-01' , 0.1389 ) ;
266- t . rate ( 'USD' , '2026-02-01' , 0.138912 ) ;
267- const fits = await t . engine . insert ( 'fx_invoice' , { title : 'i1' , currency_code : 'USD' , invoice_date : '2026-01-15' , amount : 10000 } ) ;
268- expect ( t . storeFor ( 'fx_invoice' ) . get ( fits . id ) ) . toMatchObject ( { amount_rate : 0.1389 } ) ;
269- const err = await refusalOf ( t . engine . insert ( 'fx_invoice' , { title : 'i2' , currency_code : 'USD' , invoice_date : '2026-02-15' , amount : 10000 } ) ) ;
270- expect ( err ?. code ) . toBe ( 'VALIDATION_FAILED' ) ;
271- expect ( err ?. fields ?. map ( ( f ) => [ f . field , f . code ] ) ) . toEqual ( [ [ 'amount_rate' , 'max_scale' ] ] ) ;
272- expect ( t . storeFor ( 'fx_invoice' ) . size ) . toBe ( 1 ) ;
270+ t . rate ( 'USD' , '2026-02-01' , 0.138912345678 ) ;
271+ const row = await t . engine . insert ( 'fx_invoice' , { title : 'i1' , currency_code : 'USD' , invoice_date : '2026-02-15' , amount : 10000 } ) ;
272+ // 10000 ÷ 0.138912345678 = 71987.84…; at the rounded 0.1389 it would be 71994.24.
273+ expect ( t . storeFor ( 'fx_invoice' ) . get ( row . id ) ) . toMatchObject ( { amount_home : 71987.84 , amount_rate : 0.138912345678 } ) ;
273274 } ) ;
274275} ) ;
275276
0 commit comments