refactor: [30388f42] Strukturiere Root-Skripte thematisch neu
- Organisiert eine Vielzahl von Skripten aus dem Root-Verzeichnis in thematische Unterordner, um die Übersichtlichkeit zu verbessern und die Migration vorzubereiten. - Verschiebt SuperOffice-bezogene Test- und Hilfsskripte in . - Verschiebt Notion-bezogene Synchronisations- und Import-Skripte in . - Archiviert eindeutig veraltete und ungenutzte Skripte in . - Die zentralen Helfer und bleiben im Root, da sie von mehreren Tools als Abhängigkeit genutzt werden.
This commit is contained in:
40
connector-superoffice/tools/cleanup_test_data.py
Normal file
40
connector-superoffice/tools/cleanup_test_data.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import sys
|
||||
import os
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Ensure we use the correct config and client
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'connector-superoffice')))
|
||||
|
||||
from superoffice_client import SuperOfficeClient
|
||||
|
||||
def cleanup():
|
||||
print("🧹 Cleaning up Test Data...")
|
||||
client = SuperOfficeClient()
|
||||
|
||||
if not client.access_token:
|
||||
print("❌ Auth failed.")
|
||||
return
|
||||
|
||||
# Objects to delete (Reverse order of dependency)
|
||||
to_delete = [
|
||||
("Sale", 342539),
|
||||
("Appointment", 993350),
|
||||
("Appointment", 993347),
|
||||
("Person", 193092),
|
||||
("Contact", 171185) # Attempting to delete the company too
|
||||
]
|
||||
|
||||
for entity_type, entity_id in to_delete:
|
||||
print(f"🗑️ Deleting {entity_type} {entity_id}...")
|
||||
try:
|
||||
# SuperOffice DELETE usually returns 204 No Content
|
||||
# Our client returns None on success if response body is empty, or the JSON if not.
|
||||
# We need to catch exceptions if it fails.
|
||||
resp = client._delete(f"{entity_type}/{entity_id}")
|
||||
print(f"✅ Deleted {entity_type} {entity_id}")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Failed to delete {entity_type} {entity_id}: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
cleanup()
|
||||
72
connector-superoffice/tools/final_mailing_test.py
Normal file
72
connector-superoffice/tools/final_mailing_test.py
Normal file
@@ -0,0 +1,72 @@
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
from datetime import datetime, timedelta
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Ensure we use the correct config and client from the connector-superoffice subdir
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'connector-superoffice')))
|
||||
|
||||
from superoffice_client import SuperOfficeClient
|
||||
|
||||
def run_final_test():
|
||||
print("🚀 Starting Final Mailing Test for floke.com@gmail.com...")
|
||||
|
||||
# 1. Initialize Client
|
||||
client = SuperOfficeClient()
|
||||
if not client.access_token:
|
||||
print("❌ Auth failed.")
|
||||
return
|
||||
|
||||
# 2. Use Target Contact (Bremer Abenteuerland)
|
||||
contact_id = 171185
|
||||
print(f"✅ Using Contact ID: {contact_id}")
|
||||
|
||||
# 3. Use Created Person
|
||||
person_id = 193092
|
||||
print(f"✅ Using Person ID: {person_id} (floke.com@gmail.com)")
|
||||
|
||||
# 4. Attempt Shipment (Mailing)
|
||||
print("📤 Attempting to create Shipment (the direct email send)...")
|
||||
shipment_payload = {
|
||||
"Name": "Gemini Diagnostics: Test Shipment",
|
||||
"Subject": "Hallo aus der Gemini GTM Engine",
|
||||
"Body": "Dies ist ein Testversuch für den direkten E-Mail-Versand via SuperOffice API.",
|
||||
"DocumentTemplateId": 157, # Outgoing Email (ID 157 is confirmed from previous runs as typical)
|
||||
"ShipmentType": "Email",
|
||||
"AssociateId": 528, # API User RCGO
|
||||
"ContactId": contact_id,
|
||||
"PersonId": person_id,
|
||||
"Status": "Ready"
|
||||
}
|
||||
|
||||
try:
|
||||
shipment_resp = client._post("Shipment", shipment_payload)
|
||||
if shipment_resp:
|
||||
print("✅ UNEXPECTED SUCCESS: Shipment created!")
|
||||
print(json.dumps(shipment_resp, indent=2))
|
||||
else:
|
||||
print("❌ Shipment creation returned empty response.")
|
||||
except Exception as e:
|
||||
print(f"❌ EXPECTED FAILURE: Shipment creation failed as predicted.")
|
||||
print(f"Error details: {e}")
|
||||
|
||||
# 5. Fallback: Create Appointment as "Proof of Work"
|
||||
print("\n📅 Running Workaround: Creating Appointment instead...")
|
||||
appt_resp = client.create_appointment(
|
||||
subject="KI: E-Mail Testversuch an floke.com@gmail.com",
|
||||
description="Hier würde der E-Mail-Text stehen, der aufgrund technischer Blockaden (Mailing-Modul/Identität) nicht direkt versendet werden konnte.",
|
||||
contact_id=contact_id,
|
||||
person_id=person_id
|
||||
)
|
||||
|
||||
if appt_resp:
|
||||
appt_id = appt_resp.get("appointmentId") or appt_resp.get("AppointmentId")
|
||||
print(f"✅ Workaround Successful: Appointment ID: {appt_id}")
|
||||
print(f"🔗 Link: https://online3.superoffice.com/Cust26720/default.aspx?appointment_id={appt_id}")
|
||||
else:
|
||||
print("❌ Workaround (Appointment) failed too.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_final_test()
|
||||
68
connector-superoffice/tools/round_trip_final.py
Normal file
68
connector-superoffice/tools/round_trip_final.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Path gymnastics
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "connector-superoffice"))
|
||||
|
||||
from company_explorer_connector import get_company_details
|
||||
from superoffice_client import SuperOfficeClient
|
||||
|
||||
# Load ENV
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
|
||||
def perform_final_round_trip(ce_id):
|
||||
client = SuperOfficeClient()
|
||||
print(f"--- Final Round-Trip: CE {ce_id} -> SuperOffice ---")
|
||||
|
||||
# 1. Get enriched data from CE
|
||||
ce_data = get_company_details(ce_id)
|
||||
if not ce_data or "error" in ce_data:
|
||||
print("❌ Could not fetch CE data.")
|
||||
return
|
||||
|
||||
so_id = ce_data.get("crm_id")
|
||||
if not so_id:
|
||||
print("❌ No SO ID found in CE.")
|
||||
return
|
||||
|
||||
# 2. Fetch current SO contact
|
||||
contact = client._get(f"Contact/{so_id}")
|
||||
if not contact:
|
||||
print(f"❌ Could not fetch SO Contact {so_id}")
|
||||
return
|
||||
|
||||
# 3. Intelligent Mapping (Full Object)
|
||||
print(f"Mapping data for {ce_data.get('name')}...")
|
||||
|
||||
# Simple Fields
|
||||
contact["UrlAddress"] = ce_data.get("website", "")
|
||||
contact["Department"] = "KI-Enriched via CE"
|
||||
|
||||
# Address Object
|
||||
if "Address" not in contact: contact["Address"] = {}
|
||||
if "Street" not in contact["Address"]: contact["Address"]["Street"] = {}
|
||||
|
||||
contact["Address"]["Street"]["Address1"] = ce_data.get("address", "")
|
||||
contact["Address"]["Street"]["City"] = ce_data.get("city", "")
|
||||
contact["Address"]["Street"]["Zipcode"] = ce_data.get("zip", "")
|
||||
|
||||
# Phones (List)
|
||||
if ce_data.get("phone"):
|
||||
contact["Phones"] = [{"Number": ce_data.get("phone"), "Description": "Main"}]
|
||||
|
||||
# 4. Write back
|
||||
print(f"Sending full update to SO Contact {so_id}...")
|
||||
result = client._put(f"Contact/{so_id}", contact)
|
||||
|
||||
if result:
|
||||
print("🚀 SUCCESS! Round-trip for Robo-Planet complete.")
|
||||
print(f"Website: {contact['UrlAddress']}")
|
||||
print(f"City: {contact['Address']['Street']['City']}")
|
||||
else:
|
||||
print("❌ Update failed.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
perform_final_round_trip(53)
|
||||
111
connector-superoffice/tools/seed_test_data.py
Normal file
111
connector-superoffice/tools/seed_test_data.py
Normal file
@@ -0,0 +1,111 @@
|
||||
import sys
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
from sqlalchemy import create_engine, select
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
# Add paths to use backend models directly for complex seeding (Matrix/Person)
|
||||
sys.path.append(os.path.join(os.getcwd(), "company-explorer"))
|
||||
from backend.database import Base, Company, Contact, Industry, JobRoleMapping, MarketingMatrix
|
||||
|
||||
# Database Connection (Direct SQL access is easier for seeding specific IDs)
|
||||
DB_PATH = "sqlite:///companies_v3_fixed_2.db" # Local relative path
|
||||
engine = create_engine(DB_PATH)
|
||||
Session = sessionmaker(bind=engine)
|
||||
session = Session()
|
||||
|
||||
def seed():
|
||||
print("--- Company Explorer Test Data Seeder ---")
|
||||
print("This script prepares the database for the SuperOffice Connector End-to-End Test.")
|
||||
|
||||
# 1. User Input
|
||||
so_contact_id = input("Enter SuperOffice Contact ID (Company) [e.g. 123]: ").strip()
|
||||
so_person_id = input("Enter SuperOffice Person ID [e.g. 456]: ").strip()
|
||||
company_name = input("Enter Company Name [e.g. Test GmbH]: ").strip() or "Test GmbH"
|
||||
person_role = "Geschäftsführer" # Fixed for test simplicity
|
||||
industry_name = "Logistik" # Fixed for test simplicity
|
||||
|
||||
if not so_contact_id or not so_person_id:
|
||||
print("Error: IDs are required!")
|
||||
return
|
||||
|
||||
print(f"\nSeeding for Company '{company_name}' (ID: {so_contact_id}) and Person (ID: {so_person_id})...")
|
||||
|
||||
# 2. Check/Create Industry
|
||||
industry = session.query(Industry).filter_by(name=industry_name).first()
|
||||
if not industry:
|
||||
industry = Industry(name=industry_name, description="Test Industry")
|
||||
session.add(industry)
|
||||
session.commit()
|
||||
print(f"✅ Created Industry '{industry_name}'")
|
||||
else:
|
||||
print(f"ℹ️ Industry '{industry_name}' exists")
|
||||
|
||||
# 3. Check/Create Job Role
|
||||
role_map = session.query(JobRoleMapping).filter_by(role=person_role).first()
|
||||
if not role_map:
|
||||
role_map = JobRoleMapping(pattern=person_role, role=person_role) # Simple mapping
|
||||
session.add(role_map)
|
||||
session.commit()
|
||||
print(f"✅ Created Role Mapping '{person_role}'")
|
||||
else:
|
||||
print(f"ℹ️ Role Mapping '{person_role}' exists")
|
||||
|
||||
# 4. Check/Create Company
|
||||
company = session.query(Company).filter_by(crm_id=str(so_contact_id)).first()
|
||||
if not company:
|
||||
company = Company(
|
||||
name=company_name,
|
||||
crm_id=str(so_contact_id),
|
||||
industry_ai=industry_name, # Link to our test industry
|
||||
status="ENRICHED"
|
||||
)
|
||||
session.add(company)
|
||||
session.commit()
|
||||
print(f"✅ Created Company '{company_name}' with CRM-ID {so_contact_id}")
|
||||
else:
|
||||
company.industry_ai = industry_name # Ensure correct industry for test
|
||||
session.commit()
|
||||
print(f"ℹ️ Company '{company_name}' exists (Updated Industry)")
|
||||
|
||||
# 5. Check/Create Person
|
||||
person = session.query(Contact).filter_by(so_person_id=int(so_person_id)).first()
|
||||
if not person:
|
||||
person = Contact(
|
||||
company_id=company.id,
|
||||
first_name="Max",
|
||||
last_name="Mustermann",
|
||||
so_person_id=int(so_person_id),
|
||||
so_contact_id=int(so_contact_id),
|
||||
role=person_role
|
||||
)
|
||||
session.add(person)
|
||||
session.commit()
|
||||
print(f"✅ Created Person with SO-ID {so_person_id}")
|
||||
else:
|
||||
person.role = person_role # Ensure role match
|
||||
session.commit()
|
||||
print(f"ℹ️ Person with SO-ID {so_person_id} exists (Updated Role)")
|
||||
|
||||
# 6. Check/Create Matrix Entry
|
||||
matrix = session.query(MarketingMatrix).filter_by(industry_id=industry.id, role_id=role_map.id).first()
|
||||
if not matrix:
|
||||
matrix = MarketingMatrix(
|
||||
industry_id=industry.id,
|
||||
role_id=role_map.id,
|
||||
subject="Test Betreff: Optimierung für {{company_name}}",
|
||||
intro="Hallo, dies ist ein generierter Test-Text aus dem Company Explorer.",
|
||||
social_proof="Wir arbeiten bereits erfolgreich mit anderen Logistikern zusammen."
|
||||
)
|
||||
session.add(matrix)
|
||||
session.commit()
|
||||
print(f"✅ Created Matrix Entry for {industry_name} x {person_role}")
|
||||
else:
|
||||
print(f"ℹ️ Matrix Entry exists")
|
||||
|
||||
print("\n🎉 Seeding Complete! The Company Explorer is ready.")
|
||||
print(f"You can now trigger the Webhook for Contact {so_contact_id} / Person {so_person_id}.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
seed()
|
||||
64
connector-superoffice/tools/so_final_correction.py
Normal file
64
connector-superoffice/tools/so_final_correction.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Path gymnastics
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "connector-superoffice"))
|
||||
|
||||
from superoffice_client import SuperOfficeClient
|
||||
from company_explorer_connector import get_company_details
|
||||
|
||||
# Load ENV
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
|
||||
def final_correction(ce_id):
|
||||
client = SuperOfficeClient()
|
||||
print(f"--- Final Correction: Applying GROUND TRUTH for CE {ce_id} ---")
|
||||
|
||||
# 1. Force fetch from CE to ensure we have REAL data
|
||||
ce_data = get_company_details(ce_id)
|
||||
if not ce_data or "error" in ce_data:
|
||||
# Fallback to manual ground truth from your message if API still flutters
|
||||
ce_address = "Schatzbogen 39"
|
||||
ce_city = "München"
|
||||
ce_zip = "81829"
|
||||
ce_name = "Robo-Planet GmbH"
|
||||
else:
|
||||
ce_address = ce_data.get("address", "Schatzbogen 39")
|
||||
ce_city = ce_data.get("city", "München")
|
||||
ce_zip = ce_data.get("zip", "81829")
|
||||
ce_name = ce_data.get("name")
|
||||
|
||||
# 2. Map correctly
|
||||
payload = {
|
||||
"contactId": 2,
|
||||
"Name": "RoboPlanet GmbH-SOD",
|
||||
"Number2": "123",
|
||||
"OrgNr": "DE343867623", # Real Robo-Planet VAT
|
||||
"Address": {
|
||||
"Postal": {
|
||||
"Address1": ce_address,
|
||||
"City": ce_city,
|
||||
"Zipcode": ce_zip
|
||||
},
|
||||
"Street": {
|
||||
"Address1": ce_address,
|
||||
"City": ce_city,
|
||||
"Zipcode": ce_zip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
url = f"{client.base_url}/Contact/2"
|
||||
resp = requests.put(url, headers=client.headers, json=payload)
|
||||
|
||||
if resp.status_code == 200:
|
||||
print(f"🚀 SUCCESS! Applied Ground Truth: {ce_address}, {ce_city}")
|
||||
else:
|
||||
print(f"❌ Error: {resp.text}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
final_correction(53)
|
||||
56
connector-superoffice/tools/so_force_write.py
Normal file
56
connector-superoffice/tools/so_force_write.py
Normal file
@@ -0,0 +1,56 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Path gymnastics
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "connector-superoffice"))
|
||||
|
||||
from superoffice_client import SuperOfficeClient
|
||||
|
||||
# Load ENV
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
|
||||
def force_write(so_id):
|
||||
client = SuperOfficeClient()
|
||||
print(f"--- Force Write-Back: Contact {so_id} ---")
|
||||
|
||||
# Using the mandatory fields you identified and the structured address
|
||||
payload = {
|
||||
"contactId": int(so_id),
|
||||
"Name": "RoboPlanet GmbH-SOD",
|
||||
"Number2": "123", # Mandatory field fix
|
||||
"OrgNr": "DE348572190",
|
||||
"Department": "Force Write 13:35",
|
||||
"Address": {
|
||||
"Postal": {
|
||||
"Address1": "Humboldtstr. 1",
|
||||
"City": "Dornstadt",
|
||||
"Zipcode": "89160"
|
||||
},
|
||||
"Street": {
|
||||
"Address1": "Humboldtstr. 1",
|
||||
"City": "Dornstadt",
|
||||
"Zipcode": "89160"
|
||||
}
|
||||
},
|
||||
"UserDefinedFields": {
|
||||
"SuperOffice:5": "[I:23]" # Vertical: Logistics
|
||||
}
|
||||
}
|
||||
|
||||
url = f"{client.base_url}/Contact/{so_id}"
|
||||
print(f"Sending Force Payload to {url}...")
|
||||
|
||||
resp = requests.put(url, headers=client.headers, json=payload)
|
||||
|
||||
print(f"Status Code: {resp.status_code}")
|
||||
if resp.status_code == 200:
|
||||
print("🚀 SUCCESS! Check Address, VAT and Vertical now.")
|
||||
else:
|
||||
print(f"❌ Error: {resp.text}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
force_write(2)
|
||||
62
connector-superoffice/tools/so_full_enrichment.py
Normal file
62
connector-superoffice/tools/so_full_enrichment.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Path gymnastics
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "connector-superoffice"))
|
||||
|
||||
from superoffice_client import SuperOfficeClient
|
||||
from company_explorer_connector import get_company_details
|
||||
|
||||
# Load ENV
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
|
||||
def full_enrichment_writeback(ce_id):
|
||||
client = SuperOfficeClient()
|
||||
print(f"--- Full Enrichment Write-Back: CE {ce_id} -> SuperOffice ---")
|
||||
|
||||
# 1. Get data from CE
|
||||
ce_data = get_company_details(ce_id)
|
||||
if not ce_data or "error" in ce_data:
|
||||
print("❌ Could not fetch CE data.")
|
||||
return
|
||||
|
||||
so_id = ce_data.get("crm_id")
|
||||
if not so_id:
|
||||
print("❌ No SO ID found in CE.")
|
||||
return
|
||||
|
||||
# 2. Build Surgical Payload (Postal Address, VAT, Vertical)
|
||||
# We use the specific sub-object structure SO expects
|
||||
payload = {
|
||||
"contactId": int(so_id),
|
||||
"OrgNr": "DE348572190", # Test VAT
|
||||
"Department": "Fully Enriched 13:25",
|
||||
"Address": {
|
||||
"Postal": {
|
||||
"Address1": ce_data.get("address", "Humboldtstr. 1"),
|
||||
"City": ce_data.get("city", "Dornstadt"),
|
||||
"Zipcode": ce_data.get("zip", "89160")
|
||||
}
|
||||
},
|
||||
"UserDefinedFields": {
|
||||
"SuperOffice:5": "[I:23]" # Vertical: Logistics - Warehouse
|
||||
}
|
||||
}
|
||||
|
||||
url = f"{client.base_url}/Contact/{so_id}"
|
||||
print(f"Sending Full Payload to {url}...")
|
||||
|
||||
resp = requests.put(url, headers=client.headers, json=payload)
|
||||
|
||||
print(f"Status Code: {resp.status_code}")
|
||||
if resp.status_code == 200:
|
||||
print("🚀 SUCCESS! Full enrichment (Address, VAT, Vertical) should be visible.")
|
||||
else:
|
||||
print(f"❌ Error: {resp.text}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
full_enrichment_writeback(53)
|
||||
66
connector-superoffice/tools/so_one_shot_fix.py
Normal file
66
connector-superoffice/tools/so_one_shot_fix.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
|
||||
def fix_all_now_v2():
|
||||
# 1. Refresh Token
|
||||
token_url = "https://sod.superoffice.com/login/common/oauth/tokens"
|
||||
token_data = {
|
||||
"grant_type": "refresh_token",
|
||||
"client_id": os.getenv("SO_CLIENT_ID"),
|
||||
"client_secret": os.getenv("SO_CLIENT_SECRET"),
|
||||
"refresh_token": os.getenv("SO_REFRESH_TOKEN"),
|
||||
"redirect_uri": "http://localhost"
|
||||
}
|
||||
t_resp = requests.post(token_url, data=token_data)
|
||||
access_token = t_resp.json().get("access_token")
|
||||
|
||||
if not access_token:
|
||||
print("❌ Token Refresh failed.")
|
||||
return
|
||||
|
||||
# 2. Dual-Url Payload (Root + Array)
|
||||
payload = {
|
||||
"contactId": 2,
|
||||
"Name": "RoboPlanet GmbH-SOD",
|
||||
"Number2": "123",
|
||||
"UrlAddress": "http://robo-planet.de",
|
||||
"Urls": [
|
||||
{
|
||||
"Value": "http://robo-planet.de",
|
||||
"Description": "Website"
|
||||
}
|
||||
],
|
||||
"OrgNr": "DE400464410",
|
||||
"Department": "Website Final Fix 13:42",
|
||||
"Address": {
|
||||
"Postal": {
|
||||
"Address1": "Schatzbogen 39",
|
||||
"City": "München",
|
||||
"Zipcode": "81829"
|
||||
}
|
||||
},
|
||||
"UserDefinedFields": {
|
||||
"SuperOffice:5": "[I:23]"
|
||||
}
|
||||
}
|
||||
|
||||
# 3. Update Call
|
||||
url = "https://app-sod.superoffice.com/Cust55774/api/v1/Contact/2"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
resp = requests.put(url, headers=headers, json=payload)
|
||||
|
||||
if resp.status_code == 200:
|
||||
print("🚀 SUCCESS! Website should now be visible via the Urls list.")
|
||||
else:
|
||||
print(f"❌ Error: {resp.text}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
fix_all_now_v2()
|
||||
57
connector-superoffice/tools/so_perfect_sync.py
Normal file
57
connector-superoffice/tools/so_perfect_sync.py
Normal file
@@ -0,0 +1,57 @@
|
||||
import os
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load ENV
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
|
||||
def perfect_sync():
|
||||
# Credentials
|
||||
base_url = "https://app-sod.superoffice.com/Cust55774/api/v1"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {os.getenv('SO_ACCESS_TOKEN')}", # Will be handled by client if needed, but here direct for speed
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
# We use the SuperOfficeClient to get a fresh token first
|
||||
from repos.brancheneinstufung2.connector_superoffice.superoffice_client import SuperOfficeClient
|
||||
client = SuperOfficeClient()
|
||||
headers["Authorization"] = f"Bearer {client.access_token}"
|
||||
|
||||
print("--- Perfect Sync: Finalizing Robo-Planet (ID 2) ---")
|
||||
|
||||
payload = {
|
||||
"contactId": 2,
|
||||
"Name": "RoboPlanet GmbH-SOD",
|
||||
"Number2": "123",
|
||||
"UrlAddress": "http://robo-planet.de",
|
||||
"OrgNr": "DE400464410",
|
||||
"Department": "Perfectly Synchronized",
|
||||
"Address": {
|
||||
"Postal": {
|
||||
"Address1": "Schatzbogen 39",
|
||||
"City": "München",
|
||||
"Zipcode": "81829"
|
||||
},
|
||||
"Street": {
|
||||
"Address1": "Schatzbogen 39",
|
||||
"City": "München",
|
||||
"Zipcode": "81829"
|
||||
}
|
||||
},
|
||||
"UserDefinedFields": {
|
||||
"SuperOffice:5": "[I:23]" # Logistics
|
||||
}
|
||||
}
|
||||
|
||||
url = f"{base_url}/Contact/2"
|
||||
resp = requests.put(url, headers=headers, json=payload)
|
||||
|
||||
if resp.status_code == 200:
|
||||
print("🚀 BOOM. Website, VAT, Address and Vertical are now 100% correct.")
|
||||
else:
|
||||
print(f"❌ Error: {resp.text}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
perfect_sync()
|
||||
38
connector-superoffice/tools/so_surgical_update.py
Normal file
38
connector-superoffice/tools/so_surgical_update.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Path gymnastics
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "connector-superoffice"))
|
||||
|
||||
from superoffice_client import SuperOfficeClient
|
||||
|
||||
# Load ENV
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
|
||||
def surgical_update(contact_id):
|
||||
client = SuperOfficeClient()
|
||||
print(f"--- Surgical Update: Contact {contact_id} ---")
|
||||
|
||||
# We use a MINIMAL payload. SuperOffice REST often prefers this for Stammfelder.
|
||||
# Note: Using 'contactId' as it appeared in your discovery log.
|
||||
payload = {
|
||||
"contactId": int(contact_id),
|
||||
"Department": "Surgical Update 13:20",
|
||||
"UrlAddress": "http://robo-planet.de"
|
||||
}
|
||||
|
||||
url = f"{client.base_url}/Contact/{contact_id}"
|
||||
print(f"Sending PUT to {url} with payload: {payload}")
|
||||
|
||||
resp = requests.put(url, headers=client.headers, json=payload)
|
||||
|
||||
print(f"Status Code: {resp.status_code}")
|
||||
print("Full Response Body:")
|
||||
print(json.dumps(resp.json() if resp.content else {}, indent=2))
|
||||
|
||||
if __name__ == "__main__":
|
||||
surgical_update(2)
|
||||
44
connector-superoffice/tools/so_surgical_update_v2.py
Normal file
44
connector-superoffice/tools/so_surgical_update_v2.py
Normal file
@@ -0,0 +1,44 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Path gymnastics
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "connector-superoffice"))
|
||||
|
||||
from superoffice_client import SuperOfficeClient
|
||||
|
||||
# Load ENV
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
|
||||
def surgical_update_v2(contact_id):
|
||||
client = SuperOfficeClient()
|
||||
print(f"--- Surgical Update V2: Contact {contact_id} ---")
|
||||
|
||||
# We now use the proper 'Urls' list format
|
||||
payload = {
|
||||
"contactId": int(contact_id),
|
||||
"Department": "Final Round-Trip 13:20",
|
||||
"Urls": [
|
||||
{
|
||||
"Value": "http://robo-planet.de",
|
||||
"Description": "Website"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
url = f"{client.base_url}/Contact/{contact_id}"
|
||||
print(f"Sending PUT to {url} with proper URL list...")
|
||||
|
||||
resp = requests.put(url, headers=client.headers, json=payload)
|
||||
|
||||
print(f"Status Code: {resp.status_code}")
|
||||
if resp.status_code == 200:
|
||||
print("✅ SUCCESS! Website should be visible now.")
|
||||
else:
|
||||
print(f"❌ Error: {resp.text}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
surgical_update_v2(2)
|
||||
44
connector-superoffice/tools/so_write_debug.py
Normal file
44
connector-superoffice/tools/so_write_debug.py
Normal file
@@ -0,0 +1,44 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Path gymnastics
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "connector-superoffice"))
|
||||
|
||||
from superoffice_client import SuperOfficeClient
|
||||
|
||||
# Load ENV
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
|
||||
def debug_update(contact_id):
|
||||
client = SuperOfficeClient()
|
||||
print(f"--- Hard-Debug: Update Contact {contact_id} ---")
|
||||
|
||||
# 1. Fetch full existing object
|
||||
contact = client._get(f"Contact/{contact_id}")
|
||||
if not contact:
|
||||
print("❌ Could not fetch contact.")
|
||||
return
|
||||
|
||||
print(f"Current Name: {contact.get('Name')}")
|
||||
print(f"Current Dept: {contact.get('Department')}")
|
||||
|
||||
# 2. Modify only one simple field
|
||||
contact["Department"] = "AI-Test 13:10"
|
||||
|
||||
# 3. PUT it back
|
||||
print("Sending full object back with modified Department...")
|
||||
result = client._put(f"Contact/{contact_id}", contact)
|
||||
|
||||
if result:
|
||||
print("✅ API accepted the update.")
|
||||
# Verify immediately
|
||||
updated = client._get(f"Contact/{contact_id}")
|
||||
print(f"New Department in SO: {updated.get('Department')}")
|
||||
else:
|
||||
print("❌ Update failed.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
debug_update(2)
|
||||
66
connector-superoffice/tools/sync_ce_to_so_test.py
Normal file
66
connector-superoffice/tools/sync_ce_to_so_test.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Path gymnastics
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "connector-superoffice"))
|
||||
|
||||
from company_explorer_connector import get_company_details
|
||||
from superoffice_client import SuperOfficeClient
|
||||
|
||||
# Load ENV
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
|
||||
def round_trip_test(ce_id):
|
||||
print(f"--- Starting Round-Trip POC: CE-ID {ce_id} -> SuperOffice ---")
|
||||
|
||||
# 1. Get enriched data from Company Explorer
|
||||
ce_data = get_company_details(ce_id)
|
||||
if not ce_data or "error" in ce_data:
|
||||
print(f"❌ ERROR: Could not fetch data from Company Explorer for ID {ce_id}")
|
||||
return
|
||||
|
||||
print(f"✅ Success: Received data from CE for '{ce_data.get('name')}'")
|
||||
|
||||
# 2. Extract CRM ID
|
||||
so_id = ce_data.get("crm_id")
|
||||
if not so_id:
|
||||
print("❌ ERROR: No crm_id found in Company Explorer for this record. Cannot sync back.")
|
||||
return
|
||||
|
||||
print(f"Targeting SuperOffice Contact ID: {so_id}")
|
||||
|
||||
# 3. Prepare SuperOffice Update Payload
|
||||
# Based on your request: Address, Website, Email, Phone
|
||||
# Note: We need to match the SO schema (Street Address vs Postal Address)
|
||||
so_payload = {
|
||||
"Name": ce_data.get("name"),
|
||||
"UrlAddress": ce_data.get("website"),
|
||||
"Address": {
|
||||
"Street": {
|
||||
"Address1": ce_data.get("address", ""), # Simplified mapping for POC
|
||||
"City": ce_data.get("city", ""),
|
||||
"Zipcode": ce_data.get("zip", "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 4. Perform Update via SuperOfficeClient
|
||||
client = SuperOfficeClient()
|
||||
print(f"Updating SuperOffice Contact {so_id}...")
|
||||
|
||||
# Using the generic PUT method from our client
|
||||
endpoint = f"Contact/{so_id}"
|
||||
result = client._put(endpoint, so_payload)
|
||||
|
||||
if result:
|
||||
print(f"🚀 SUCCESS! Round-trip complete. SuperOffice Contact {so_id} updated.")
|
||||
print(f"Updated Data: {ce_data.get('website')} | {ce_data.get('city')}")
|
||||
else:
|
||||
print("❌ ERROR: Failed to update SuperOffice.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test with the ID you manually enriched
|
||||
round_trip_test(53)
|
||||
41
connector-superoffice/tools/sync_test_roboplanet.py
Normal file
41
connector-superoffice/tools/sync_test_roboplanet.py
Normal file
@@ -0,0 +1,41 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Path gymnastics to ensure imports work from the current directory
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "connector-superoffice"))
|
||||
|
||||
from company_explorer_connector import handle_company_workflow
|
||||
from superoffice_client import SuperOfficeClient
|
||||
|
||||
# Load ENV from correct path
|
||||
load_dotenv(dotenv_path="/home/node/clawd/.env", override=True)
|
||||
|
||||
def sync_roboplanet():
|
||||
print("--- Starting Sync Test: SuperOffice -> Company Explorer ---")
|
||||
|
||||
# 1. Fetch Contact from SuperOffice
|
||||
client = SuperOfficeClient()
|
||||
contact_id = 2
|
||||
print(f"Fetching Contact ID {contact_id} from SuperOffice...")
|
||||
contact_so = client._get(f"Contact/{contact_id}")
|
||||
|
||||
if not contact_so:
|
||||
print("❌ ERROR: Could not find Contact ID 2 in SuperOffice.")
|
||||
return
|
||||
|
||||
company_name = contact_so.get("Name")
|
||||
print(f"✅ Success: Found '{company_name}' in SuperOffice.")
|
||||
|
||||
# 2. Push to Company Explorer
|
||||
print(f"\nPushing '{company_name}' to Company Explorer via Connector...")
|
||||
# Using the workflow to check existence and create if needed
|
||||
result = handle_company_workflow(company_name)
|
||||
|
||||
print("\n--- WORKFLOW RESULT ---")
|
||||
print(json.dumps(result, indent=2, ensure_ascii=False))
|
||||
|
||||
if __name__ == "__main__":
|
||||
sync_roboplanet()
|
||||
Reference in New Issue
Block a user