feat(so-sync): bidirectional round-trip for company data established [lessons-learned]
This commit is contained in:
@@ -133,10 +133,13 @@ Folgende IDs werden in den Skripten als Referenz genutzt. Diese müssen für PRO
|
||||
| `26` | Leisure - Indoor Active |
|
||||
| `...` | *tbd* |
|
||||
|
||||
## 5. "Gotchas" & Lessons Learned (POC)
|
||||
## 5. "Gotchas" & Lessons Learned (Update Feb 16, 2026)
|
||||
|
||||
* **API-URL:** Der `sod` Tenant `Cust55774` ist nur über `https://app-sod.superoffice.com` erreichbar, nicht `sod.superoffice.com`.
|
||||
* **API-URL:** Der `sod` Tenant `Cust55774` ist nur über `https://app-sod.superoffice.com` erreichbar.
|
||||
* **Listen-IDs:** Die API gibt IDs von Listenfeldern im Format `[I:26]` zurück. Der String muss vor der DB-Abfrage auf den Integer `26` geparst werden.
|
||||
* **Dev-System Limits:** Die Textfelder im DEV-System sind auf 40 Zeichen limitiert. Die generierten Texte müssen vor dem Senden gekürzt werden.
|
||||
* **Y-Tabellen:** Der direkte API-Zugriff auf Zusatz-Tabellen ist in diesem Mandanten blockiert (`403 Forbidden`). Daher der Workaround mit UDFs.
|
||||
* **CRMScript Trigger:** Die Erstellung von Triggern ist im DEV-System nicht möglich. Daher die Umstellung auf den externen Polling-Daemon.
|
||||
* **Write-Back (Stammfelder):**
|
||||
* **UrlAddress & Phones:** Das einfache Root-Feld `UrlAddress` ist beim `PUT` oft schreibgeschützt. Um die Website oder Telefonnummern zu setzen, muss die entsprechende Liste (`Urls` oder `Phones`) als Array von Objekten gesendet werden (z.B. `{"Value": "...", "Description": "..."}`).
|
||||
* **Mandatory Fields:** Beim Update eines `Contact` Objekts müssen Pflichtfelder wie `Name` und `Number2` (oder `Number1`) zwingend im Payload enthalten sein, sonst schlägt die Validierung serverseitig fehl.
|
||||
* **Full Object PUT:** SuperOffice REST überschreibt das gesamte Objekt. Felder, die im `PUT`-Payload fehlen, werden im CRM geleert. Es empfiehlt sich, das Objekt erst per `GET` zu laden, die Änderungen vorzunehmen und dann das gesamte Objekt zurückzusenden.
|
||||
* **Dev-System Limits:** Die Textfelder im DEV-System sind auf 40 Zeichen limitiert.
|
||||
* **Y-Tabellen & Trigger:** Direkter Zugriff auf Zusatz-Tabellen und CRMScript-Trigger sind im SOD-DEV Mandanten blockiert.
|
||||
|
||||
@@ -9,37 +9,17 @@ logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def discover_contact_structure():
|
||||
load_dotenv(dotenv_path="../.env")
|
||||
auth = AuthHandler()
|
||||
client = SuperOfficeClient(auth)
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
client = SuperOfficeClient()
|
||||
|
||||
logger.info("Fetching a single contact to inspect structure...")
|
||||
logger.info("Fetching contact ID 2 to inspect structure...")
|
||||
|
||||
# Try to get the first contact (usually ID 1 exists or can be found)
|
||||
# If not, we try to create a dummy and then inspect it.
|
||||
url = client._get_url("v1/Contact/1")
|
||||
try:
|
||||
resp = client.session.get(url, headers=client._get_headers())
|
||||
if resp.status_code == 200:
|
||||
contact = resp.json()
|
||||
print("\n--- CONTACT STRUCTURE ---")
|
||||
print(json.dumps(contact, indent=2))
|
||||
else:
|
||||
logger.warning(f"Contact 1 not found (Status {resp.status_code}). Trying to list contacts...")
|
||||
url = client._get_url("v1/Contact?$top=1")
|
||||
resp = client.session.get(url, headers=client._get_headers())
|
||||
resp.raise_for_status()
|
||||
contacts = resp.json().get("value", [])
|
||||
if contacts:
|
||||
print("\n--- CONTACT STRUCTURE (from list) ---")
|
||||
print(json.dumps(contacts[0], indent=2))
|
||||
else:
|
||||
print("\nNo contacts found in tenant. Please create one manually in the UI or stay tuned.")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to fetch contact: {e}")
|
||||
if hasattr(e, 'response') and e.response is not None:
|
||||
print(f"Details: {e.response.text}")
|
||||
contact = client._get("Contact/2")
|
||||
if contact:
|
||||
print("\n--- CONTACT STRUCTURE ---")
|
||||
print(json.dumps(contact, indent=2))
|
||||
else:
|
||||
logger.error("Failed to fetch contact.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
discover_contact_structure()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from dotenv import load_dotenv
|
||||
import json
|
||||
from config import Config
|
||||
from logging_config import setup_logging
|
||||
@@ -7,18 +8,15 @@ from superoffice_client import SuperOfficeClient
|
||||
logger = setup_logging("inspector")
|
||||
|
||||
def inspect_person(person_id):
|
||||
auth = AuthHandler()
|
||||
client = SuperOfficeClient(auth)
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
client = SuperOfficeClient()
|
||||
logger.info(f"Fetching Person with ID {person_id} to inspect structure...")
|
||||
url = client._get_url(f"v1/Person/{person_id}")
|
||||
try:
|
||||
resp = client.session.get(url, headers=client._get_headers())
|
||||
resp.raise_for_status()
|
||||
person_data = resp.json()
|
||||
person_data = client._get(f"Person/{person_id}")
|
||||
if person_data:
|
||||
print(f"\n--- PERSON STRUCTURE (ID: {person_id}) ---")
|
||||
print(json.dumps(person_data, indent=2))
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to fetch person data: {e}")
|
||||
else:
|
||||
logger.error(f"Failed to fetch person data.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
target_person_id = 9
|
||||
|
||||
Reference in New Issue
Block a user