Skip to content

Commit

Permalink
Fix for Merge Duplicates Failing when no Determinations need Downgrad…
Browse files Browse the repository at this point in the history
…ing (#1484)

* add conditional check for if there are any determinations to downgrade before trying closes #1451

* adds copies of some functions from occurrenceEditorDeterminations to properly merge determinations records

copied functions have been label as such with todos to remove in 3.2
when occurrence editor work to remove latest identification section has
been done

* removing dead code comments

* fix determination merging priority to favor the lasting record

* adds temp function to transfer attributes over to omoccuridentifers if none are present before record merge takes place
  • Loading branch information
MuchQuak committed Jul 29, 2024
1 parent fadb043 commit a7afc04
Showing 1 changed file with 130 additions and 13 deletions.
143 changes: 130 additions & 13 deletions classes/OccurrenceEditorManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,97 @@ private function getIdentifiers($occidStr){
return $retArr;
}

private function addLatestIdentToDetermination($occid) : void {
//If determination is already in omoccurdeterminations, INSERT will fail
$guid = UuidFactory::getUuidV4();
$sqlInsert = 'INSERT IGNORE INTO omoccurdeterminations(occid, identifiedBy, dateIdentified, sciname, scientificNameAuthorship, '.
'identificationQualifier, identificationReferences, identificationRemarks, recordID, sortsequence, isCurrent) '.
'SELECT occid, IFNULL(identifiedby,"unknown") AS idby, IFNULL(dateidentified,"s.d.") AS di, '.
'sciname, scientificnameauthorship, identificationqualifier, identificationreferences, identificationremarks, "'.$guid.'", 10 AS sortseq, (SELECT IF(COUNT(*) > 0, 0, 1) AS isCur from omoccurdeterminations where isCurrent = 1 and occid = '. $occid . ') '.
'FROM omoccurrences WHERE (occid = ' . $occid . ') AND (identifiedBy IS NOT NULL OR dateIdentified IS NOT NULL OR sciname IS NOT NULL)';
try {
$this->conn->query($sqlInsert);
} catch (mysqli_sql_exception $e) {
echo 'Duplicate: '.$this->conn->error;
error_log('Error Duplicate determination from latest identification:' . $e->getMessage());
}
}

// Function is only exists to move otherCatalogNumber when merging records
// This should be removed when otherCatalogNumber is no longer in omoccurrences
private function addLegacyIdentifers($occid) : void {
$sql_cnt = 'SELECT COUNT(*) AS cnt FROM omoccuridentifiers oi join omoccurrences o on o.occid = oi.occid WHERE o.occid = ?';
$sql_insert = 'INSERT INTO omoccuridentifiers(occid, identifierName, identifierValue, notes, modifiedUid) select occid,"legacyOtherCatalogNumber" as identifierName, otherCatalogNumbers as identifierValue, "Auto generated during record merge" as notes, ? as modifiedUid from omoccurrences where occid = ?';
try {
$result_cnt = $this->conn->execute_query($sql_cnt, [$occid]);
$cnt = ($result_cnt->fetch_assoc())["cnt"];
if($cnt === 0) {
$this->conn->execute_query($sql_insert,[$GLOBALS['SYMB_UID'], $occid]);
}
} catch (mysqli_sql_exception $e) {
error_log('Error: Failed to add otherCatalogNumbers to omoccuridentifiers for occid '. $occid . ' :' . $e->getMessage());
}
}

// Copy of updateBaseOccurrence in OccurrenceEditorDeterminations for temporary utility till 3.2
// TODO (Logan) remove once latest Identification section in editor is removed
private function updateBaseOccurrence($detId){
if(is_numeric($detId)){
$taxonArr = $this->getTaxonVariables($detId);
$sql = 'UPDATE omoccurrences o INNER JOIN omoccurdeterminations d ON o.occid = d.occid
SET o.identifiedBy = d.identifiedBy, o.dateIdentified = d.dateIdentified, o.sciname = d.sciname, o.scientificNameAuthorship = d.scientificnameauthorship,
o.identificationQualifier = d.identificationqualifier, o.identificationReferences = d.identificationReferences, o.identificationRemarks = d.identificationRemarks,
o.taxonRemarks = d.taxonRemarks, o.genus = NULL, o.specificEpithet = NULL, o.taxonRank = NULL, o.infraspecificepithet = NULL, o.scientificname = NULL ';
if(isset($taxonArr['family']) && $taxonArr['family']) $sql .= ', o.family = "'.$this->cleanInStr($taxonArr['family']).'"';
if(isset($taxonArr['tid']) && $taxonArr['tid']) $sql .= ', o.tidinterpreted = '.$taxonArr['tid'];
if(isset($taxonArr['security']) && $taxonArr['security']) $sql .= ', o.localitysecurity = '.$taxonArr['security'].', o.localitysecurityreason = "<Security Setting Locked>"';
$sql .= ' WHERE (d.iscurrent = 1) AND (d.detid = '.$detId.')';
$updated_base = $this->conn->query($sql);

//Whenever occurrence is updated also update associated images
if($updated_base && isset($taxonArr['tid']) && $taxonArr['tid']) {
$sql = <<<'SQL'
UPDATE images i
INNER JOIN omoccurdeterminations od on od.occid = i.occid
SET tid = ? WHERE detid = ?;
SQL;
$this->conn->execute_query($sql, [$taxonArr['tid'], $detId]);
}
}
}

// Copy of getTaxonVariables in OccurrenceEditorDeterminations for temporary utility till 3.2
// TODO (Logan) remove once latest Identification section in editor is removed
private function getTaxonVariables($detId){
$retArr = array();
$sqlTid = 'SELECT t.tid, t.securitystatus, ts.family
FROM omoccurdeterminations d INNER JOIN taxa t ON d.sciname = t.sciname
INNER JOIN taxstatus ts ON t.tid = ts.tid
WHERE (d.detid = '.$detId.') AND (taxauthid = 1)';
$rs = $this->conn->query($sqlTid);
if($r = $rs->fetch_object()){
$retArr['tid'] = $r->tid;
$retArr['family'] = $r->family;
$retArr['security'] = ($r->securitystatus == 1 ? 1 : 0);
}
$rs->free();
if($retArr && !$retArr['security'] && $retArr['tid']){
$sql2 = 'SELECT c.clid
FROM fmchecklists c INNER JOIN fmchklsttaxalink cl ON c.clid = cl.clid
INNER JOIN taxstatus ts1 ON cl.tid = ts1.tid
INNER JOIN taxstatus ts2 ON ts1.tidaccepted = ts2.tidaccepted
INNER JOIN omoccurrences o ON c.locality = o.stateprovince
WHERE c.type = "rarespp" AND ts1.taxauthid = 1 AND ts2.taxauthid = 1
AND (ts2.tid = '.$retArr['tid'].') AND (o.occid = '.$this->occid.')';
$rs2 = $this->conn->query($sql2);
if($rs2->num_rows){
$retArr['security'] = 1;
}
$rs2->free();
}
return $retArr;
}

public function addOccurrence($postArr){
global $LANG;
$status = $LANG['SUCCESS_NEW_OCC_SUBMITTED'];
Expand All @@ -1186,6 +1277,7 @@ public function addOccurrence($postArr){
}
else $sql .= ', NULL';
}

$sql .= ')';
if($this->conn->query($sql)){
$this->occid = $this->conn->insert_id;
Expand Down Expand Up @@ -1268,6 +1360,9 @@ public function addOccurrence($postArr){
$status = $LANG['FAILED_ADD_OCC'].": ".$this->conn->error.'<br/>SQL: '.$sql;
}
}

$this->addLatestIdentToDetermination($this->occid);

return $status;
}

Expand Down Expand Up @@ -1514,6 +1609,7 @@ public function cloneOccurrence($postArr){
return $retArr;
}

// Note source is record that started duplicate lookup and is deleted up success
public function mergeRecords($targetOccid,$sourceOccid){
global $LANG;
$status = true;
Expand All @@ -1529,6 +1625,14 @@ public function mergeRecords($targetOccid,$sourceOccid){
/* Start transaction */
// This will autocommit if not rollback explicitly
$this->conn->begin_transaction();

//Add Latest Determination if missing
$this->addLatestIdentToDetermination($targetOccid);
$this->addLatestIdentToDetermination($sourceOccid);

//Add otherCatalogNumbers to Identifiers if missing
$this->addLegacyIdentifers($targetOccid);
$this->addLegacyIdentifers($sourceOccid);
$stage = '';
try {
$oArr = array();
Expand Down Expand Up @@ -1561,12 +1665,17 @@ public function mergeRecords($targetOccid,$sourceOccid){
$this->conn->execute_query($sqlIns, [$targetOccid]);
}

// Anon function for util of merging determinations
$get_current_determinations = function ($occid) {
$sql =<<<'SQL'
SELECT detid FROM omoccurdeterminations where occid = ? and isCurrent = 1;
SQL;
$result = $this->conn->execute_query($sql, [$occid]);
return array_map(fn($v) => $v[0], $result->fetch_all());
};

//Fetch List of Old Current Determinations
$sql =<<<'SQL'
SELECT detid FROM omoccurdeterminations where occid = ? and isCurrent = 1;
SQL;
$result = $this->conn->execute_query($sql, [$targetOccid]);
$currentDeterminations = array_map(fn($v) => $v[0], $result->fetch_all());
$currentDeterminations = $get_current_determinations($targetOccid);

//Remap determinations
$sql = <<<'SQL'
Expand All @@ -1593,14 +1702,22 @@ public function mergeRecords($targetOccid,$sourceOccid){
]);

//Downgrade old determinations if new determinations have a current determination
$parameters = str_repeat('?,', count($currentDeterminations) - 1) . '?';
$sql = <<<"SQL"
UPDATE omoccurdeterminations
JOIN (SELECT count(*) as cnt FROM omoccurdeterminations WHERE isCurrent = 1 AND occid = ? AND detid NOT IN ($parameters)) as update_flag on cnt > 0
SET isCurrent = 0
WHERE occid = ? AND isCurrent = 1 AND detid IN ($parameters);
SQL;
$this->conn->execute_query($sql, array_merge([$targetOccid], $currentDeterminations, [$targetOccid], $currentDeterminations));
if(count($currentDeterminations) > 0) {

$parameters = str_repeat('?,', count($currentDeterminations) - 1) . '?';
$sql = <<<"SQL"
UPDATE omoccurdeterminations
SET isCurrent = 0
WHERE occid = ? AND isCurrent = 1 AND detid NOT IN ($parameters);
SQL;
$this->conn->execute_query($sql, array_merge([$targetOccid], $currentDeterminations));
}

// Get New Current determination and updateBaseOccurrence to match
$currentDeterminations = $get_current_determinations($targetOccid);
if(is_array($currentDeterminations) && count($currentDeterminations) > 0) {
$this->updateBaseOccurrence($currentDeterminations[0]);
}

//Remap images
$sql = <<<'SQL'
Expand Down

0 comments on commit a7afc04

Please sign in to comment.