niwayandm commited on
Commit
45e05b6
·
1 Parent(s): d415fe9

Add recurring charges on billing and company associations to invoice

Browse files
python/hubspot_billing.py CHANGED
@@ -81,7 +81,9 @@ BILLING_PROPERTIES = [
81
  "hs_created_by_user_id",
82
  "hs_createdate",
83
  "connection_date",
84
- "disconnect_date"
 
 
85
  ]
86
 
87
  PROPERTY_RENAME = {
@@ -289,6 +291,8 @@ def read_billing_by_ids(
289
  "hubspot_created_at": parse_ts(p.get("hs_createdate")),
290
  "connection_date": parse_ts(p.get("connection_date")),
291
  "disconnect_date": parse_ts(p.get("disconnect_date")),
 
 
292
  }
293
  services.append(row)
294
 
 
81
  "hs_created_by_user_id",
82
  "hs_createdate",
83
  "connection_date",
84
+ "disconnect_date",
85
+ "recurring_charges__value_",
86
+ "recurring_charges__daily_",
87
  ]
88
 
89
  PROPERTY_RENAME = {
 
291
  "hubspot_created_at": parse_ts(p.get("hs_createdate")),
292
  "connection_date": parse_ts(p.get("connection_date")),
293
  "disconnect_date": parse_ts(p.get("disconnect_date")),
294
+ "recurring_charges_value": p.get("recurring_charges__value"),
295
+ "recurring_charges_daily": p.get("recurring_charges__daily"),
296
  }
297
  services.append(row)
298
 
python/hubspot_invoices.py CHANGED
@@ -203,7 +203,7 @@ def search_invoice_ids_after_ms(since_ms: int) -> Tuple[List[str], str]:
203
  def read_invoice_by_ids(
204
  invoice_ids: List[str],
205
  cursor_prop: str,
206
- ) -> Tuple[List[Dict], List[Dict], Optional[int]]:
207
  """
208
  Read invoices by ID including deal associations.
209
  Returns: (all_invoices, max_ts_ms_for_cursor_prop)
@@ -213,8 +213,9 @@ def read_invoice_by_ids(
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
 
@@ -244,6 +245,17 @@ def read_invoice_by_ids(
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")
249
 
@@ -273,12 +285,12 @@ def read_invoice_by_ids(
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.")
@@ -292,6 +304,16 @@ def upsert_invoices(invoices: List[Dict], invoice_contact_links: List[Dict]) ->
292
  on_conflict=["invoice_id", "contact_id"],
293
  )
294
  print(f"Upserted {len(invoice_contact_links)} invoice-contact associations.")
 
 
 
 
 
 
 
 
 
 
295
 
296
 
297
  # -----------------------------------------------------------------------------
@@ -329,10 +351,10 @@ def main(since_ms: Optional[int] = None):
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
 
203
  def read_invoice_by_ids(
204
  invoice_ids: List[str],
205
  cursor_prop: str,
206
+ ) -> Tuple[List[Dict], List[Dict], List[Dict], Optional[int]]:
207
  """
208
  Read invoices by ID including deal associations.
209
  Returns: (all_invoices, max_ts_ms_for_cursor_prop)
 
213
 
214
  all_invoices: List[Dict] = []
215
  invoice_contact_links: List[Dict] = []
216
+ invoice_company_links: List[Dict] = []
217
 
218
+ assoc_types = ["contacts", "companies"]
219
 
220
  max_ts_ms: Optional[int] = None
221
 
 
245
  "contact_id": try_parse_int(a.id),
246
  })
247
 
248
+ # Companies
249
+ if getattr(record, "associations", None) and record.associations.get("companies"):
250
+ bucket = record.associations["companies"]
251
+ if getattr(bucket, "results", None):
252
+ for a in bucket.results:
253
+ if a.id and a.id.isdigit():
254
+ invoice_company_links.append({
255
+ "invoice_id": try_parse_int(record.id),
256
+ "company_id": try_parse_int(a.id),
257
+ })
258
+
259
  # Created date: accept either createdate or hs_createdate
260
  created_iso = p.get("createdate") or p.get("hs_createdate")
261
 
 
285
  except (ObjectsApiException, httpx.HTTPError) as e:
286
  logging.error("Error reading invoice %s: %s", did, e)
287
 
288
+ return all_invoices, invoice_contact_links, invoice_company_links, max_ts_ms
289
 
290
  # -----------------------------------------------------------------------------
291
  # Upsert
292
  # -----------------------------------------------------------------------------
293
+ def upsert_invoices(invoices: List[Dict], invoice_contact_links: List[Dict], invoice_company_links: List[Dict]) -> None:
294
  if invoices:
295
  insert_into_supabase_table(supabase_client, "hubspot_invoices", invoices)
296
  print(f"Upserted {len(invoices)} invoices.")
 
304
  on_conflict=["invoice_id", "contact_id"],
305
  )
306
  print(f"Upserted {len(invoice_contact_links)} invoice-contact associations.")
307
+
308
+ if invoice_company_links:
309
+ invoice_company_links = deduplicate_by_key(invoice_company_links, key=("invoice_id", "company_id"))
310
+ insert_into_supabase_table(
311
+ supabase_client,
312
+ "hubspot_invoice_companies",
313
+ invoice_company_links,
314
+ on_conflict=["invoice_id", "company_id"],
315
+ )
316
+ print(f"Upserted {len(invoice_company_links)} invoice-company associations.")
317
 
318
 
319
  # -----------------------------------------------------------------------------
 
351
  return
352
 
353
  print("Reading invoices (with associations)...")
354
+ invoices, invoice_contact_links, invoice_company_links, max_ts_ms = read_invoice_by_ids(ids, cursor_prop)
355
 
356
  print("Upserting into Supabase...")
357
+ upsert_invoices(invoices, invoice_contact_links, invoice_company_links)
358
 
359
  # Advance cursor to max timestamp we actually ingested for the chosen property
360
  new_cursor_ms = max_ts_ms if max_ts_ms is not None else since_ms