@@ -323,60 +323,76 @@ public boolean deathExists(String id)
323323 return false ;
324324 }
325325
326- public void upsertWeightRecord (Map <String , Object > row ) throws QueryUpdateServiceException , DuplicateKeyException , SQLException , BatchValidationException , InvalidKeyException
326+ public boolean upsertWeightRecord (Map <String , Object > row ) throws QueryUpdateServiceException , DuplicateKeyException , SQLException , BatchValidationException , InvalidKeyException
327327 {
328- upsertWeightRecord (row , true );
328+ return upsertWeightRecord (row , true );
329329 }
330330
331331 /**
332332 * When announceChanges is false, the nested weight trigger will not announce the modified id
333333 * (skipAnnounceChangedParticipants). Callers must mark study.weight as modified on the outer helper
334334 * (addTableModified) so the single announcement at trigger completion covers it.
335+ *
336+ * @return whether a weight record was written; false when there was nothing to record
335337 */
336- public void upsertWeightRecord (Map <String , Object > row , boolean announceChanges ) throws QueryUpdateServiceException , DuplicateKeyException , SQLException , BatchValidationException , InvalidKeyException
338+ public boolean upsertWeightRecord (Map <String , Object > row , boolean announceChanges ) throws QueryUpdateServiceException , DuplicateKeyException , SQLException , BatchValidationException , InvalidKeyException
337339 {
338340 BatchValidationException errors = new BatchValidationException ();
339341 Date date = ConvertHelper .convert (row .get ("date" ), Date .class );
340342 String taskId = ConvertHelper .convert (row .get ("taskid" ), String .class );
341343
342344 TableInfo ti = getTableInfo ("study" , "weight" );
343345
344- // If there is already a weight record for this task, update that record
345- SimpleFilter filter = new SimpleFilter (FieldKey .fromString ("Id" ), row .get ("Id" ));
346- filter .addCondition (FieldKey .fromString ("taskid" ), taskId );
347- TableSelector ts = new TableSelector (ti , PageFlowUtil .set ("lsid" , "objectid" ), filter , null );
348- boolean updateRecord = ts .exists ();
349-
350- Map <String , Object > saveRow = new CaseInsensitiveHashMap <>();
351- saveRow .put ("Id" , row .get ("Id" ));
352- saveRow .put ("date" , date );
353- saveRow .put ("taskid" , taskId );
354- saveRow .put ("qcstate" , row .get ("qcstate" ));
355- saveRow .put ("performedby" , row .get ("performedby" ));
356- if (updateRecord )
346+ // If there is already a weight record for this task, update that record. A null taskid filter flips to
347+ // "taskid IS NULL" and would match unrelated historical weights, so task-less entry (e.g. a non-EHR bulk
348+ // import form) is insert-only.
349+ Map <String , Object > existingRecord = null ;
350+ if (taskId != null )
357351 {
358- saveRow .put ("objectid" , ts .getMap ().get ("objectid" ));
359- }
360- else
361- {
362- saveRow .put ("objectid" , new GUID ().toString ());
352+ SimpleFilter filter = new SimpleFilter (FieldKey .fromString ("Id" ), row .get ("Id" ));
353+ filter .addCondition (FieldKey .fromString ("taskid" ), taskId );
354+ TableSelector ts = new TableSelector (ti , PageFlowUtil .set ("lsid" , "objectid" ), filter , null );
355+ existingRecord = ts .getMap ();
363356 }
364357
365358 Double weight = null ;
366359 if (row .get ("weight" ) != null )
367360 {
368361 weight = ConvertHelper .convert (row .get ("weight" ), Double .class );
369362 }
370- saveRow .put ("weight" , weight );
371-
372- List <Map <String , Object >> rows = new ArrayList <>();
373- rows .add (saveRow );
374363
375364 Map <String , Object > context = getExtraContext ();
376365 if (!announceChanges )
377366 context .put ("skipAnnounceChangedParticipants" , true );
378367
379- if (updateRecord )
368+ // Weight is optional, so with none entered there is nothing to record. Delete any record left by an earlier
369+ // save rather than blanking it: the weight trigger only WARNs on a null weight and the default threshold
370+ // filters that out, so the emptied record would survive the save.
371+ if (weight == null )
372+ {
373+ if (existingRecord == null )
374+ return false ;
375+
376+ Map <String , Object > keyRow = new CaseInsensitiveHashMap <>();
377+ keyRow .put ("lsid" , existingRecord .get ("lsid" ));
378+ ti .getUpdateService ().deleteRows (_user , _container , List .of (keyRow ), null , context );
379+
380+ return true ;
381+ }
382+
383+ Map <String , Object > saveRow = new CaseInsensitiveHashMap <>();
384+ saveRow .put ("Id" , row .get ("Id" ));
385+ saveRow .put ("date" , date );
386+ saveRow .put ("taskid" , taskId );
387+ saveRow .put ("qcstate" , row .get ("qcstate" ));
388+ saveRow .put ("performedby" , row .get ("performedby" ));
389+ saveRow .put ("objectid" , existingRecord != null ? existingRecord .get ("objectid" ) : new GUID ().toString ());
390+ saveRow .put ("weight" , weight );
391+
392+ List <Map <String , Object >> rows = new ArrayList <>();
393+ rows .add (saveRow );
394+
395+ if (existingRecord != null )
380396 {
381397 ti .getUpdateService ().updateRows (_user , _container , rows , null , null , context );
382398 }
@@ -387,6 +403,8 @@ public void upsertWeightRecord(Map<String, Object> row, boolean announceChanges)
387403
388404 if (errors .hasErrors ())
389405 throw errors ;
406+
407+ return true ;
390408 }
391409
392410 public void clinicalMoveNotification (final String animalId , final String date )
0 commit comments