Allow independent dates while ARR field reviews are pending

This commit is contained in:
Wyndham ARR committed 2026-10-08 17:27:56 +08:00
1 parent fe8735aac2
commit fb07580c0c
15 files changed
+316 -16

No files matched your search

+98 -6
View File
@@ -7,20 +7,112 @@ const item=(extra={})=>({item_id:'1:BLOCK_CODE',source_sequence:1,confirmation_n
const review=(items,revision=1)=>({request_id:requestId,report_date:task.report_date,status:'editing',revision,items,pending_count:items.filter(x=>!x.confirmed).length,total_count:items.length,can_finalize:items.every(x=>x.confirmed)});
const plain=value=>JSON.parse(JSON.stringify(value));
test('source review opens before a job exists and choosing another date retains the original request',async()=>{
const h=harness(()=>response(200,review([item()])));
test('source review opens before a job exists and another date can start its own download',async()=>{
const h=harness((url,options)=>options.method==='POST'
? response(202,{...JSON.parse(options.body),status:'queued',job_id:null,can_retry:false})
: response(200,review([item()])));
await h.acceptARRDownloadTask(task,{sync:false});
assert.equal(h.element('#arr-download-data-review').hidden,false);
assert.equal(h.element('#arr-data-review-panel').hidden,false);
assert.equal(h.element('#arr-download-review').hidden,true);
assert.equal(h.element('#arr-data-review-finalize').disabled,true);
h.element('#arr-download-date').value='2026-10-08';
h.element('#arr-download-date').value='2026-09-17';
h.handleARRDownloadDateChange();
assert.equal(h.state.arrDownloadIntent.request_id,requestId,'choosing a date alone keeps the earlier task');
assert.equal(h.element('#arr-download-button').textContent,'arr_download.start');
assert.equal(h.element('#arr-download-button').disabled,false);
await h.submit();
assert.notEqual(h.state.arrDownloadIntent.request_id,requestId);
assert.equal(h.state.arrDownloadTask.report_date,'2026-09-17');
assert.equal(h.element('#arr-download-date').value,'2026-09-17');
const post=h.calls.find(call=>call.method==='POST');
assert.equal(post.url,'/api/arr-downloads');
assert.equal(JSON.parse(post.body).report_date,'2026-09-17');
assert.equal(h.state.arrDownloadPendingReviews[0].request_id,requestId);
assert.equal(h.element('#arr-data-review-panel').hidden,true);
});
test('submitting the pending review date only opens that review without another download',async()=>{
const h=harness(()=>response(200,review([item()])));
await h.acceptARRDownloadTask(task,{sync:false});
assert.equal(h.element('#arr-download-button').textContent,'arr_download.complete_data');
await h.submit();
assert.equal(h.state.arrDownloadIntent.request_id,requestId);
assert.equal(h.state.arrDownloadTask.report_date,'2026-10-07');
assert.equal(h.element('#arr-download-date').value,'2026-10-08');
assert.equal(h.calls.every(call=>call.method==='GET'),true,'review never creates a replacement download');
assert.equal(h.calls.every(call=>call.method==='GET'),true);
});
test('pending dates and unsaved drafts remain separate when moving between two field reviews',async()=>{
const otherId='b'.repeat(32);
const otherTask={...task,request_id:otherId,report_date:'2026-09-17'};
const h=harness(url=>url.endsWith('/data-review')
? response(200,{...review([item()]),request_id:url.includes(otherId)?otherId:requestId})
: response(200,url.endsWith(otherId)?otherTask:task));
await h.acceptARRDownloadTask(task,{sync:false});
h.trackARRDataReviewDraft(h.row('1:BLOCK_CODE','OCTOBER-DRAFT').input);
await h.acceptARRDownloadTask(otherTask,{sync:false});
assert.equal(h.state.arrDownloadPendingReviews.length,2);
assert.equal(h.state.arrDataReviewDrafts['1:BLOCK_CODE'],undefined);
h.trackARRDataReviewDraft(h.row('1:BLOCK_CODE','SEPTEMBER-DRAFT').input);
await h.selectARRPendingReview(requestId);
assert.equal(h.state.arrDownloadTask.request_id,requestId);
assert.equal(h.element('#arr-download-date').value,'2026-10-07');
assert.equal(h.state.arrDataReviewDrafts['1:BLOCK_CODE'],'OCTOBER-DRAFT');
await h.selectARRPendingReview(otherId);
assert.equal(h.state.arrDataReviewDrafts['1:BLOCK_CODE'],'SEPTEMBER-DRAFT');
assert.equal(h.calls.every(call=>call.method==='GET'),true,'returning to a review never re-fetches Oracle');
});
test('pending dates restore from the server even when the latest task is no longer a review',async()=>{
const h=harness(url=>url==='/api/arr-downloads'
? response(200,{context_id:'production',ready:true,default_date:'2026-10-07',
pending_data_reviews:[task],latest_task:{...task,request_id:'b'.repeat(32),report_date:'2026-09-17',status:'failed'}})
: response(200,url.endsWith('/data-review')?review([item()]):task));
await h.initARRDownload();
assert.equal(h.state.arrDownloadTask,null);
assert.equal(h.element('#arr-download-pending').hidden,false);
assert.match(h.element('#arr-download-pending-list').innerHTML,/2026-10-07/);
await h.selectARRPendingReview(requestId);
assert.equal(h.state.arrDownloadTask.request_id,requestId);
assert.equal(h.state.arrDataReview.pending_count,1);
});
test('an uncertain new date cannot be abandoned by opening an earlier field review',async()=>{
const h=harness(()=>{throw new Error('unexpected request');});
h.state.arrDownloadPendingReviews=[task];
h.rememberARRIntent({request_id:'b'.repeat(32),report_date:'2026-09-17'});
h.state.arrDownloadDisconnected=true;
await h.selectARRPendingReview(requestId);
assert.equal(h.calls.length,0);
assert.equal(h.state.arrDownloadIntent.report_date,'2026-09-17');
});
test('a completed pending review can still be finalized after reopening it',async()=>{
const h=harness(url=>response(200,url.endsWith('/data-review')
? review([item({confirmed:true,value:'VERIFIED'})]) : task));
h.state.arrDownloadPendingReviews=[task];
await h.selectARRPendingReview(requestId);
assert.equal(h.state.arrDownloadBusy,false);
assert.equal(h.arrDataReviewCanFinalize(),true);
assert.equal(h.element('#arr-data-review-finalize').disabled,false);
});
test('lost submission for another date retains both its uncertain intent and the earlier pending review',async()=>{
const h=harness((url,options)=>{
if(options.method==='POST') throw new TypeError('lost response');
if(url.endsWith('/data-review')) return response(200,review([item()]));
return response(404,null,'ARR_DOWNLOAD_NOT_FOUND');
});
await h.acceptARRDownloadTask(task,{sync:false});
h.element('#arr-download-date').value='2026-09-17';
h.handleARRDownloadDateChange();
await h.submit();
const intent=plain(h.state.arrDownloadIntent);
assert.equal(intent.report_date,'2026-09-17');
assert.notEqual(intent.request_id,requestId);
assert.equal(h.state.arrDownloadTask.status,'not_received');
assert.equal(h.state.arrDownloadPendingReviews[0].request_id,requestId);
await h.selectARRPendingReview(requestId);
assert.deepEqual(plain(h.state.arrDownloadIntent),intent);
});
test('incomplete review cannot finalize even when server flag says it can',async()=>{
+1 -1
View File
@@ -22,7 +22,7 @@ function harness(respond) {
localStorage:{setItem:(k,v)=>storage.set(k,v),getItem:k=>{storageReads.push(k);return storage.get(k);},removeItem:k=>storage.delete(k)},
fetch:async (url, options) => {calls.push({url,method:options.method||'GET',body:options.body});return respond(url,options,calls);},
});
const exports='state, submitARRDownload, rememberARRIntent, acceptARRDownloadTask, handleARRDownloadDateChange, initARRDownload, loadARRDownloadTask, loadARRDataReview, renderARRDataReview, arrDataReviewCanFinalize, saveARRDataReviewItem, finalizeARRDataReview, trackARRDataReviewDraft, parseARRDataReviewValue';
const exports='state, submitARRDownload, rememberARRIntent, acceptARRDownloadTask, handleARRDownloadDateChange, initARRDownload, loadARRDownloadTask, loadARRDataReview, renderARRDataReview, arrDataReviewCanFinalize, saveARRDataReviewItem, finalizeARRDataReview, trackARRDataReviewDraft, parseARRDataReviewValue, selectARRPendingReview';
vm.runInContext(source.replace(boot,` globalThis.subject = {${exports}};\n})();`),context);
const subject=context.subject;
Object.assign(subject.state,{arrDownloadReady:true,arrDownloadLoaded:true,arrDownloadStorageKey:'test',arrDownloadUsername:'operator',csrf:'fixture'});