where('ContactID', $ContactID) ->where('SiteID', $detail['SiteID']) ->first(); if ($existing) { $this->update($existing[$this->primaryKey], $detail); } else { $this->insert($detail); } $keptSiteIDs[] = $detail['SiteID']; } // Delete missing rows if (!empty($keptSiteIDs)) { $this->where('ContactID', $ContactID) ->whereNotIn('SiteID', $keptSiteIDs) ->delete(); } else { $this->where('ContactID', $ContactID)->delete(); } return [ 'status' => 'success', 'inserted' => count($contactDetails) - count($keptSiteIDs), 'kept' => count($keptSiteIDs), ]; } catch (\Throwable $e) { log_message('error', 'syncDetails error: ' . $e->getMessage()); return [ 'status' => 'error', 'message' => $e->getMessage(), ]; } } public function applyDetailOperations(int $contactID, array $operations): array { try { if (!empty($operations['edited']) && !$this->updateDetails($contactID, $operations['edited'])) { return ['status' => 'error', 'message' => 'Failed to update contact details']; } if (!empty($operations['deleted']) && !$this->softDeleteDetails($contactID, $operations['deleted'])) { return ['status' => 'error', 'message' => 'Failed to delete contact details']; } if (!empty($operations['created']) && !$this->insertDetailRows($contactID, $operations['created'])) { return ['status' => 'error', 'message' => 'Failed to create contact details']; } return ['status' => 'success']; } catch (\Throwable $e) { log_message('error', 'applyDetailOperations error: ' . $e->getMessage()); return [ 'status' => 'error', 'message' => $e->getMessage(), ]; } } private function insertDetailRows(int $contactID, array $items): bool { foreach ($items as $item) { if (!is_array($item)) { return false; } $item['ContactID'] = $contactID; $this->insert($item); } return true; } private function updateDetails(int $contactID, array $items): bool { foreach ($items as $detail) { $detailID = $detail['ContactDetID'] ?? null; if (!$detailID || !ctype_digit((string) $detailID)) { return false; } $existing = $this->where('ContactDetID', (int) $detailID) ->where('ContactID', $contactID) ->where('ContactEndDate', null) ->first(); if (empty($existing)) { return false; } $updateData = array_intersect_key($detail, array_flip($this->allowedFields)); unset($updateData['ContactID']); if ($updateData !== [] && !$this->update((int) $detailID, $updateData)) { return false; } } return true; } private function softDeleteDetails(int $contactID, array $ids): bool { $ids = array_values(array_unique(array_map('intval', $ids))); if ($ids === []) { return true; } $existing = $this->select('ContactDetID') ->whereIn('ContactDetID', $ids) ->where('ContactID', $contactID) ->findAll(); if (count($existing) !== count($ids)) { return false; } $this->whereIn('ContactDetID', $ids) ->where('ContactID', $contactID) ->delete(); return true; } }