niwayandm commited on
Commit ·
908f282
1
Parent(s): 1fcc733
Add invoice-contact associations
Browse files- python/hubspot_invoices.py +31 -5
python/hubspot_invoices.py
CHANGED
|
@@ -212,6 +212,9 @@ def read_invoice_by_ids(
|
|
| 212 |
return [], [], None
|
| 213 |
|
| 214 |
all_invoices: List[Dict] = []
|
|
|
|
|
|
|
|
|
|
| 215 |
|
| 216 |
max_ts_ms: Optional[int] = None
|
| 217 |
|
|
@@ -219,7 +222,8 @@ def read_invoice_by_ids(
|
|
| 219 |
try:
|
| 220 |
record = hubspot_client.crm.objects.basic_api.get_by_id(
|
| 221 |
object_type="invoices",
|
| 222 |
-
object_id=did, properties=INOVICE_PROPERTIES,
|
|
|
|
| 223 |
)
|
| 224 |
p = record.properties or {}
|
| 225 |
|
|
@@ -228,6 +232,17 @@ def read_invoice_by_ids(
|
|
| 228 |
ts_ms = parse_any_ts_ms(cursor_val)
|
| 229 |
if ts_ms is not None and (max_ts_ms is None or ts_ms > max_ts_ms):
|
| 230 |
max_ts_ms = ts_ms
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 231 |
|
| 232 |
# Created date: accept either createdate or hs_createdate
|
| 233 |
created_iso = p.get("createdate") or p.get("hs_createdate")
|
|
@@ -258,16 +273,27 @@ def read_invoice_by_ids(
|
|
| 258 |
except (ObjectsApiException, httpx.HTTPError) as e:
|
| 259 |
logging.error("Error reading invoice %s: %s", did, e)
|
| 260 |
|
| 261 |
-
return all_invoices, max_ts_ms
|
| 262 |
|
| 263 |
# -----------------------------------------------------------------------------
|
| 264 |
# Upsert
|
| 265 |
# -----------------------------------------------------------------------------
|
| 266 |
-
def upsert_invoices(invoices: List[Dict]) -> None:
|
| 267 |
if invoices:
|
| 268 |
insert_into_supabase_table(supabase_client, "hubspot_invoices", invoices)
|
| 269 |
print(f"Upserted {len(invoices)} invoices.")
|
| 270 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 271 |
# -----------------------------------------------------------------------------
|
| 272 |
# Main (timestamp cursor)
|
| 273 |
# -----------------------------------------------------------------------------
|
|
@@ -303,10 +329,10 @@ def main(since_ms: Optional[int] = None):
|
|
| 303 |
return
|
| 304 |
|
| 305 |
print("Reading invoices (with associations)...")
|
| 306 |
-
invoices, max_ts_ms = read_invoice_by_ids(ids, cursor_prop)
|
| 307 |
|
| 308 |
print("Upserting into Supabase...")
|
| 309 |
-
upsert_invoices(invoices)
|
| 310 |
|
| 311 |
# Advance cursor to max timestamp we actually ingested for the chosen property
|
| 312 |
new_cursor_ms = max_ts_ms if max_ts_ms is not None else since_ms
|
|
|
|
| 212 |
return [], [], None
|
| 213 |
|
| 214 |
all_invoices: List[Dict] = []
|
| 215 |
+
invoice_contact_links: List[Dict] = []
|
| 216 |
+
|
| 217 |
+
assoc_types = ["contacts"]
|
| 218 |
|
| 219 |
max_ts_ms: Optional[int] = None
|
| 220 |
|
|
|
|
| 222 |
try:
|
| 223 |
record = hubspot_client.crm.objects.basic_api.get_by_id(
|
| 224 |
object_type="invoices",
|
| 225 |
+
object_id=did, properties=INOVICE_PROPERTIES,
|
| 226 |
+
associations=assoc_types,archived=False
|
| 227 |
)
|
| 228 |
p = record.properties or {}
|
| 229 |
|
|
|
|
| 232 |
ts_ms = parse_any_ts_ms(cursor_val)
|
| 233 |
if ts_ms is not None and (max_ts_ms is None or ts_ms > max_ts_ms):
|
| 234 |
max_ts_ms = ts_ms
|
| 235 |
+
|
| 236 |
+
# Contacts
|
| 237 |
+
if getattr(record, "associations", None) and record.associations.get("contacts"):
|
| 238 |
+
bucket = record.associations["contacts"]
|
| 239 |
+
if getattr(bucket, "results", None):
|
| 240 |
+
for a in bucket.results:
|
| 241 |
+
if a.id and a.id.isdigit():
|
| 242 |
+
invoice_contact_links.append({
|
| 243 |
+
"invoice_id": try_parse_int(record.id),
|
| 244 |
+
"contact_id": try_parse_int(a.id),
|
| 245 |
+
})
|
| 246 |
|
| 247 |
# Created date: accept either createdate or hs_createdate
|
| 248 |
created_iso = p.get("createdate") or p.get("hs_createdate")
|
|
|
|
| 273 |
except (ObjectsApiException, httpx.HTTPError) as e:
|
| 274 |
logging.error("Error reading invoice %s: %s", did, e)
|
| 275 |
|
| 276 |
+
return all_invoices, invoice_contact_links, max_ts_ms
|
| 277 |
|
| 278 |
# -----------------------------------------------------------------------------
|
| 279 |
# Upsert
|
| 280 |
# -----------------------------------------------------------------------------
|
| 281 |
+
def upsert_invoices(invoices: List[Dict], invoice_contact_links: List[Dict]) -> None:
|
| 282 |
if invoices:
|
| 283 |
insert_into_supabase_table(supabase_client, "hubspot_invoices", invoices)
|
| 284 |
print(f"Upserted {len(invoices)} invoices.")
|
| 285 |
|
| 286 |
+
if invoice_contact_links:
|
| 287 |
+
invoice_contact_links = deduplicate_by_key(invoice_contact_links, key=("invoice_id", "contact_id"))
|
| 288 |
+
insert_into_supabase_table(
|
| 289 |
+
supabase_client,
|
| 290 |
+
"hubspot_invoice_contacts",
|
| 291 |
+
invoice_contact_links,
|
| 292 |
+
on_conflict=["invoice_id", "contact_id"],
|
| 293 |
+
)
|
| 294 |
+
print(f"Upserted {len(invoice_contact_links)} invoice-contact associations.")
|
| 295 |
+
|
| 296 |
+
|
| 297 |
# -----------------------------------------------------------------------------
|
| 298 |
# Main (timestamp cursor)
|
| 299 |
# -----------------------------------------------------------------------------
|
|
|
|
| 329 |
return
|
| 330 |
|
| 331 |
print("Reading invoices (with associations)...")
|
| 332 |
+
invoices, invoice_contact_links, max_ts_ms = read_invoice_by_ids(ids, cursor_prop)
|
| 333 |
|
| 334 |
print("Upserting into Supabase...")
|
| 335 |
+
upsert_invoices(invoices, invoice_contact_links)
|
| 336 |
|
| 337 |
# Advance cursor to max timestamp we actually ingested for the chosen property
|
| 338 |
new_cursor_ms = max_ts_ms if max_ts_ms is not None else since_ms
|