From 26449801f88f099aac1963e9b03d8830bc687668 Mon Sep 17 00:00:00 2001 From: MuchQuak Date: Tue, 9 Jul 2024 14:12:45 -0700 Subject: [PATCH 1/5] add conditional check for if there are any determinations to downgrade before trying closes #1451 --- classes/OccurrenceEditorManager.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/classes/OccurrenceEditorManager.php b/classes/OccurrenceEditorManager.php index e43d5f97cb..7ec9bdd699 100644 --- a/classes/OccurrenceEditorManager.php +++ b/classes/OccurrenceEditorManager.php @@ -1589,15 +1589,16 @@ 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 + 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)); + } //Remap images $sql = <<<'SQL' UPDATE images SET occid = ? WHERE occid = ?; From da96a3a84ee11aa7ad4e9d357d506d5d2208a45b Mon Sep 17 00:00:00 2001 From: MuchQuak Date: Mon, 15 Jul 2024 17:42:20 -0700 Subject: [PATCH 2/5] 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 --- classes/OccurrenceEditorManager.php | 114 ++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 5 deletions(-) diff --git a/classes/OccurrenceEditorManager.php b/classes/OccurrenceEditorManager.php index 527eb55c1c..8e9d3d7023 100644 --- a/classes/OccurrenceEditorManager.php +++ b/classes/OccurrenceEditorManager.php @@ -1161,6 +1161,91 @@ 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()); + } + //$tidToAdd = $detArr['tidtoadd']; + //if($tidToAdd && !is_numeric($tidToAdd)) $tidToAdd = 0; + //$this->updateBaseOccurrence($detId); + + //Add identification confidence + /* + if(isset($detArr['confidenceranking'])){ + $idStatus = $this->editIdentificationRanking($detArr['confidenceranking'],''); + if($idStatus) $status .= '; '.$idStatus; + }*/ + } + + // 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 = ""'; + $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']; @@ -1186,6 +1271,7 @@ public function addOccurrence($postArr){ } else $sql .= ', NULL'; } + $sql .= ')'; if($this->conn->query($sql)){ $this->occid = $this->conn->insert_id; @@ -1268,6 +1354,9 @@ public function addOccurrence($postArr){ $status = $LANG['FAILED_ADD_OCC'].": ".$this->conn->error.'
SQL: '.$sql; } } + + $this->addLatestIdentToDetermination($this->occid); + return $status; } @@ -1514,6 +1603,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; @@ -1529,6 +1619,8 @@ public function mergeRecords($targetOccid,$sourceOccid){ /* Start transaction */ // This will autocommit if not rollback explicitly $this->conn->begin_transaction(); + $this->addLatestIdentToDetermination($targetOccid); + $this->addLatestIdentToDetermination($sourceOccid); $stage = ''; try { $oArr = array(); @@ -1561,12 +1653,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' @@ -1603,6 +1700,13 @@ public function mergeRecords($targetOccid,$sourceOccid){ SQL; $this->conn->execute_query($sql, array_merge([$targetOccid], $currentDeterminations, [$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' UPDATE images SET occid = ? WHERE occid = ?; From 2bbb3da85f867903c1cbbecba85588987725bf41 Mon Sep 17 00:00:00 2001 From: MuchQuak Date: Tue, 16 Jul 2024 15:06:13 -0700 Subject: [PATCH 3/5] removing dead code comments --- classes/OccurrenceEditorManager.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/classes/OccurrenceEditorManager.php b/classes/OccurrenceEditorManager.php index 8e9d3d7023..f5e980d438 100644 --- a/classes/OccurrenceEditorManager.php +++ b/classes/OccurrenceEditorManager.php @@ -1175,16 +1175,6 @@ private function addLatestIdentToDetermination($occid) : void { echo 'Duplicate: '.$this->conn->error; error_log('Error Duplicate determination from latest identification:' . $e->getMessage()); } - //$tidToAdd = $detArr['tidtoadd']; - //if($tidToAdd && !is_numeric($tidToAdd)) $tidToAdd = 0; - //$this->updateBaseOccurrence($detId); - - //Add identification confidence - /* - if(isset($detArr['confidenceranking'])){ - $idStatus = $this->editIdentificationRanking($detArr['confidenceranking'],''); - if($idStatus) $status .= '; '.$idStatus; - }*/ } // Copy of updateBaseOccurrence in OccurrenceEditorDeterminations for temporary utility till 3.2 From bdf0c6e4c07625ee7c4fdb5bec83770c8a9a2435 Mon Sep 17 00:00:00 2001 From: MuchQuak Date: Fri, 26 Jul 2024 11:28:07 -0700 Subject: [PATCH 4/5] fix determination merging priority to favor the lasting record --- classes/OccurrenceEditorManager.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/classes/OccurrenceEditorManager.php b/classes/OccurrenceEditorManager.php index f5e980d438..ecc8ea2003 100644 --- a/classes/OccurrenceEditorManager.php +++ b/classes/OccurrenceEditorManager.php @@ -1681,14 +1681,14 @@ public function mergeRecords($targetOccid,$sourceOccid){ //Downgrade old determinations if new determinations have a current determination if(count($currentDeterminations) > 0) { + $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); + WHERE occid = ? AND isCurrent = 1 AND detid NOT IN ($parameters); SQL; - $this->conn->execute_query($sql, array_merge([$targetOccid], $currentDeterminations, [$targetOccid], $currentDeterminations)); + $this->conn->execute_query($sql, array_merge([$targetOccid], $currentDeterminations)); } // Get New Current determination and updateBaseOccurrence to match From 2d8ed20bf214694191af6573e6dcc629df04088d Mon Sep 17 00:00:00 2001 From: MuchQuak Date: Fri, 26 Jul 2024 14:31:27 -0700 Subject: [PATCH 5/5] adds temp function to transfer attributes over to omoccuridentifers if none are present before record merge takes place --- classes/OccurrenceEditorManager.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/classes/OccurrenceEditorManager.php b/classes/OccurrenceEditorManager.php index ecc8ea2003..15ae2b1106 100644 --- a/classes/OccurrenceEditorManager.php +++ b/classes/OccurrenceEditorManager.php @@ -1177,6 +1177,22 @@ private function addLatestIdentToDetermination($occid) : void { } } + // 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){ @@ -1609,8 +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();