autopilot-core-sandbox 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (822) hide show
  1. package/README.md +53 -0
  2. package/dist/Provider.d.ts +21 -0
  3. package/dist/Provider.d.ts.map +1 -0
  4. package/dist/Provider.js +61 -0
  5. package/dist/Provider.js.map +1 -0
  6. package/dist/dist/Provider.d.ts +21 -0
  7. package/dist/dist/Provider.d.ts.map +1 -0
  8. package/dist/dist/Provider.js +61 -0
  9. package/dist/dist/Provider.js.map +1 -0
  10. package/dist/dist/index.d.ts +45 -0
  11. package/dist/dist/index.d.ts.map +1 -0
  12. package/dist/dist/index.js +61 -0
  13. package/dist/dist/index.js.map +1 -0
  14. package/dist/dist/interfaces/index.d.ts +1238 -0
  15. package/dist/dist/interfaces/index.d.ts.map +1 -0
  16. package/dist/dist/interfaces/index.js +3 -0
  17. package/dist/dist/interfaces/index.js.map +1 -0
  18. package/dist/dist/migrations/20260608222757_remote_schema.sql +5666 -0
  19. package/dist/dist/migrations/20260611174826_add_job_item_recurring_id_to_job_item.sql +7 -0
  20. package/dist/dist/migrations/20260625224612_add_dashboard_guided_tour_dismissed_to_settings_user.sql +5 -0
  21. package/dist/dist/migrations/20260627031433_support_chat_tables.sql +115 -0
  22. package/dist/dist/migrations/20260627031434_support_chat_rls.sql +37 -0
  23. package/dist/dist/migrations/20260704170209_add_estimate_scheduling.sql +121 -0
  24. package/dist/dist/migrations/20260704170210_add_estimate_scheduling_rls.sql +42 -0
  25. package/dist/dist/migrations/20260704235034_add_estimate_reminder_settings.sql +11 -0
  26. package/dist/dist/migrations/20260707003825_blocked_number_table.sql +32 -0
  27. package/dist/dist/migrations/20260707003826_blocked_number_rls.sql +22 -0
  28. package/dist/dist/migrations/20260709191055_sms_opt_out_table.sql +38 -0
  29. package/dist/dist/migrations/20260709191056_sms_opt_out_rls.sql +21 -0
  30. package/dist/dist/migrations/20260709214507_job_time_entry_table.sql +70 -0
  31. package/dist/dist/migrations/20260709214508_job_time_entry_rls.sql +21 -0
  32. package/dist/dist/migrations/20260711185956_phone_call_table.sql +99 -0
  33. package/dist/dist/migrations/20260711185957_phone_call_rls.sql +25 -0
  34. package/dist/dist/migrations/20260712014705_ai_voice_assistant_settings.sql +71 -0
  35. package/dist/dist/migrations/20260712014706_ai_voice_assistant_settings_rls.sql +14 -0
  36. package/dist/dist/migrations/20260712014707_ai_prompt_templates.sql +28 -0
  37. package/dist/dist/migrations/20260712014708_ai_prompt_templates_rls.sql +5 -0
  38. package/dist/dist/migrations/20260712014709_ai_prompt_templates_seed.sql +77 -0
  39. package/dist/dist/migrations/20260715011550_reminder_dispatch_table.sql +47 -0
  40. package/dist/dist/migrations/20260715011551_reminder_dispatch_rls.sql +22 -0
  41. package/dist/dist/migrations/20260715192923_dedup_sequence_contact_add_unique_constraint.sql +27 -0
  42. package/dist/dist/migrations/20260716194420_add_employee_location_tracking.sql +146 -0
  43. package/dist/dist/migrations/20260716194421_add_employee_location_tracking_rls.sql +154 -0
  44. package/dist/dist/migrations/20260716194422_get_client_map_last_completed_jobs.sql +28 -0
  45. package/dist/dist/migrations/20260717144535_add_blast_email_invalid_skipped_count.sql +2 -0
  46. package/dist/dist/migrations/20260717162900_create_blast_email_chunk.sql +36 -0
  47. package/dist/dist/migrations/20260717162901_add_blast_email_chunk_rls.sql +5 -0
  48. package/dist/dist/migrations/20260717162902_add_blast_email_chunk_progress_columns.sql +3 -0
  49. package/dist/dist/migrations/20260717162903_add_blast_email_bounce_tracking_columns.sql +4 -0
  50. package/dist/dist/migrations/20260717162904_create_email_hard_bounced.sql +23 -0
  51. package/dist/dist/migrations/20260717162905_add_email_hard_bounced_rls.sql +5 -0
  52. package/dist/dist/migrations/20260717164837_add_sequence_contact_sent_at.sql +19 -0
  53. package/dist/dist/migrations/20260717170920_add_sequence_contact_claim_index.sql +12 -0
  54. package/dist/dist/migrations/20260719215139_create_outbound_event.sql +59 -0
  55. package/dist/dist/migrations/20260719215140_create_outbound_event_rls.sql +16 -0
  56. package/dist/dist/migrations/20260719215141_create_webhook_delivery.sql +99 -0
  57. package/dist/dist/migrations/20260719215142_create_webhook_delivery_rls.sql +11 -0
  58. package/dist/dist/migrations/20260719215143_outbound_event_triggers.sql +219 -0
  59. package/dist/dist/migrations/20260719215144_create_api_key.sql +34 -0
  60. package/dist/dist/migrations/20260719215146_create_api_key_rls.sql +12 -0
  61. package/dist/dist/migrations/20260719215147_webhook_subscription_add_secret_active.sql +28 -0
  62. package/dist/dist/migrations/20260719215148_api_aggregate_create_functions.sql +479 -0
  63. package/dist/dist/migrations/20260721174837_webhook_subscription_generic_endpoints.sql +41 -0
  64. package/dist/dist/migrations/20260721185631_webhook_outbox_retention.sql +87 -0
  65. package/dist/dist/migrations/20260721190304_create_qb_sync_task.sql +120 -0
  66. package/dist/dist/migrations/20260721190306_qb_sync_task_rls.sql +8 -0
  67. package/dist/dist/migrations/20260721190307_qb_mapping_orphan_fks.sql +29 -0
  68. package/dist/dist/migrations/20260721190308_qb_task_retention.sql +90 -0
  69. package/dist/dist/migrations/20260721234401_create_permission_role.sql +83 -0
  70. package/dist/dist/migrations/20260721234402_permission_role_rls.sql +22 -0
  71. package/dist/dist/migrations/20260721234403_user_role_add_permission_role_id.sql +12 -0
  72. package/dist/dist/migrations/20260721234404_seed_permission_roles.sql +100 -0
  73. package/dist/dist/migrations/20260721234405_backfill_user_role_permission_role_id.sql +20 -0
  74. package/dist/dist/migrations/20260722193800_permission_role_add_manage_employees.sql +56 -0
  75. package/dist/dist/migrations/20260723025606_staging_new_employee_company_read_rls.sql +10 -0
  76. package/dist/dist/migrations/20260723134328_create_google_lsa_integration.sql +1016 -0
  77. package/dist/dist/migrations/20260723134329_google_lsa_integration_rls.sql +205 -0
  78. package/dist/dist/migrations/20260723150640_google_lsa_hardening.sql +169 -0
  79. package/dist/dist/migrations/20260723150641_google_lsa_hardening_rls.sql +12 -0
  80. package/dist/dist/migrations/20260724230721_google_lsa_facebook_exclusivity_attach.sql +104 -0
  81. package/dist/dist/migrations/20260724230722_google_lsa_facebook_exclusivity_attach_rls.sql +20 -0
  82. package/dist/dist/migrations/20260725172630_add_message_pagination_and_search.sql +265 -0
  83. package/dist/dist/migrations/20260725172631_add_message_pagination_and_search_rls.sql +72 -0
  84. package/dist/dist/migrations/20260725172632_optimize_message_thread_pagination_search.sql +245 -0
  85. package/dist/dist/migrations/20260725172633_harden_message_search_and_photo_pagination.sql +256 -0
  86. package/dist/dist/migrations/20260725172634_fix_message_thread_line_filter.sql +250 -0
  87. package/dist/dist/migrations/20260725174948_google_lsa_attach_bing_exclusivity_guard.sql +23 -0
  88. package/dist/dist/migrations/20260725200430_client_portal_settings.sql +41 -0
  89. package/dist/dist/migrations/20260725200431_client_portal_settings_rls.sql +21 -0
  90. package/dist/dist/migrations/20260725200433_client_portal_auth_tables.sql +81 -0
  91. package/dist/dist/migrations/20260725200434_client_portal_auth_rls.sql +18 -0
  92. package/dist/dist/migrations/20260725200435_portal_claim_login_attempt.sql +36 -0
  93. package/dist/dist/migrations/20260725200436_portal_appointment_request.sql +39 -0
  94. package/dist/dist/migrations/20260725200437_portal_appointment_request_rls.sql +10 -0
  95. package/dist/dist/migrations/20260725210000_google_reserve_integration.sql +85 -0
  96. package/dist/dist/migrations/20260725210001_google_reserve_integration_rls.sql +10 -0
  97. package/dist/dist/migrations/20260725220000_add_analytics_query_indexes.sql +47 -0
  98. package/dist/dist/migrations/20260725230000_onboarding_preload_data.sql +1074 -0
  99. package/dist/dist/migrations/20260725230001_onboarding_preload_data_rls.sql +40 -0
  100. package/dist/dist/migrations/20260725230002_add_pricebook_query_indexes.sql +13 -0
  101. package/dist/dist/migrations/20260726000000_facebook_ads_integration.sql +1538 -0
  102. package/dist/dist/migrations/20260726000001_facebook_ads_integration_rls.sql +356 -0
  103. package/dist/dist/migrations/20260726000002_facebook_ads_attach_lsa_exclusivity_guard.sql +25 -0
  104. package/dist/dist/migrations/20260726000003_facebook_ads_attach_bing_exclusivity_guard.sql +22 -0
  105. package/dist/dist/migrations/20260726010000_create_bing_ads_integration.sql +1112 -0
  106. package/dist/dist/migrations/20260726010001_bing_ads_integration_rls.sql +227 -0
  107. package/dist/dist/migrations/20260726220000_add_document_theme_settings.sql +11 -0
  108. package/dist/dist/migrations/20260726220001_update_document_theme_comments.sql +7 -0
  109. package/dist/dist/migrations/20260727210319_evolve_tier_for_pricing.sql +68 -0
  110. package/dist/dist/migrations/20260727210320_create_billing_addon.sql +85 -0
  111. package/dist/dist/migrations/20260727210321_create_billing_addon_rls.sql +21 -0
  112. package/dist/dist/migrations/20260728213930_create_usage_metering.sql +189 -0
  113. package/dist/dist/migrations/20260728213931_create_usage_metering_rls.sql +32 -0
  114. package/dist/dist/migrations/20260729004305_marketing_charge_txn_functions.sql +242 -0
  115. package/dist/dist/migrations/20260729004306_marketing_charge_txn_functions_rls.sql +37 -0
  116. package/dist/dist/migrations/20260729005524_update_deduct_from_balance_errcode.sql +42 -0
  117. package/dist/dist/migrations/20260730193601_fix_deduct_from_balance_lost_update.sql +46 -0
  118. package/dist/dist/migrations/20260730193602_add_blast_sms_chunk_reaper_columns.sql +27 -0
  119. package/dist/dist/migrations/20260731011415_create_google_calendar_connection.sql +84 -0
  120. package/dist/dist/migrations/20260731011416_google_calendar_connection_rls.sql +23 -0
  121. package/dist/dist/migrations/20260731011417_create_google_calendar_sync.sql +157 -0
  122. package/dist/dist/migrations/20260731011418_google_calendar_sync_rls.sql +26 -0
  123. package/dist/dist/migrations/20260731011419_event_outbound_triggers.sql +28 -0
  124. package/dist/dist/migrations/20260731011420_add_google_calendar_addon_key.sql +24 -0
  125. package/dist/dist/migrations/20260731011421_gcal_task_retention.sql +109 -0
  126. package/dist/dist/migrations/20260731234245_create_estimate_proposal.sql +157 -0
  127. package/dist/dist/migrations/20260731234247_estimate_proposal_rls.sql +46 -0
  128. package/dist/dist/migrations/20260731234248_add_proposal_estimate_settings.sql +17 -0
  129. package/dist/dist/migrations/20260731234249_add_estimate_proposals_addon_key.sql +25 -0
  130. package/dist/dist/migrations/20260731234250_approve_estimate_proposal_function.sql +133 -0
  131. package/dist/dist/migrations/20260801010609_save_estimate_proposal_function.sql +154 -0
  132. package/dist/dist/migrations/20260801173554_add_hide_autopilot_branding_setting.sql +6 -0
  133. package/dist/dist/migrations/20260806230917_add_client_billing_address_columns.sql +9 -0
  134. package/dist/dist/migrations/20260806230944_api_create_client_billing_address.sql +93 -0
  135. package/dist/dist/migrations/20260807014702_create_parent_id_company_id_keys.sql +20 -0
  136. package/dist/dist/migrations/20260807014703_create_contract_template.sql +30 -0
  137. package/dist/dist/migrations/20260807014704_create_contract.sql +233 -0
  138. package/dist/dist/migrations/20260807014705_create_contract_signature.sql +39 -0
  139. package/dist/dist/migrations/20260807014706_create_item_contract_requirement.sql +38 -0
  140. package/dist/dist/migrations/20260807014707_create_settings_contract.sql +23 -0
  141. package/dist/dist/migrations/20260807014708_contract_rls.sql +74 -0
  142. package/dist/dist/migrations/20260807014709_sign_contract_function.sql +92 -0
  143. package/dist/dist/migrations/20260807014710_create_settings_rental.sql +34 -0
  144. package/dist/dist/migrations/20260807014711_create_saved_location.sql +56 -0
  145. package/dist/dist/migrations/20260807014712_create_rental_task_option.sql +52 -0
  146. package/dist/dist/migrations/20260807014713_create_asset.sql +90 -0
  147. package/dist/dist/migrations/20260807014714_add_job_schedule_asset_fkeys.sql +39 -0
  148. package/dist/dist/migrations/20260807014715_rental_rls.sql +48 -0
  149. package/dist/dist/migrations/20260807014716_add_job_schedule_any_time.sql +7 -0
  150. package/dist/dist/migrations/20260807014717_add_job_schedule_target_location.sql +48 -0
  151. package/dist/dist/migrations/20260807014718_job_schedule_completion_guard.sql +53 -0
  152. package/dist/dist/migrations/20260807014719_add_job_schedule_list_sort_key.sql +7 -0
  153. package/dist/dist/migrations/20260807014720_add_item_duration.sql +11 -0
  154. package/dist/dist/migrations/20260807014721_add_settings_booking_enforce_rental_availability.sql +9 -0
  155. package/dist/dist/migrations/20260807014722_add_job_unsigned_rental_agreement.sql +10 -0
  156. package/dist/dist/migrations/20260807014723_add_item_size.sql +12 -0
  157. package/dist/dist/migrations/20260809193533_add_booking_path_button_labels.sql +11 -0
  158. package/dist/dist/migrations/20260809231721_add_route_distance_cache.sql +37 -0
  159. package/dist/dist/migrations/20260809231722_route_distance_cache_rls.sql +15 -0
  160. package/dist/dist/migrations/20260809231723_apply_rental_route_plan_function.sql +275 -0
  161. package/dist/dist/migrations/20260810171550_add_settings_job_default_job_types.sql +9 -0
  162. package/dist/dist/migrations/20260810212430_backfill_rental_task_option_sort_order.sql +61 -0
  163. package/dist/dist/migrations/20260811224317_add_settings_user_dnd_hint_dismissed.sql +9 -0
  164. package/dist/dist/migrations/20260813174503_repair_user_role_email_drift.sql +59 -0
  165. package/dist/dist/migrations/20260813174504_sync_user_role_email_trigger.sql +30 -0
  166. package/dist/dist/migrations/20260813175210_add_event_list_sort_key.sql +5 -0
  167. package/dist/dist/migrations/20260814172222_add_client_auto_bill_on_completion.sql +6 -0
  168. package/dist/dist/migrations/20260816160252_create_automation_rule.sql +99 -0
  169. package/dist/dist/migrations/20260816160253_automation_rule_rls.sql +19 -0
  170. package/dist/dist/migrations/20260816160254_create_settings_automation.sql +36 -0
  171. package/dist/dist/migrations/20260816160255_settings_automation_rls.sql +18 -0
  172. package/dist/dist/migrations/20260816160256_create_automation_event.sql +71 -0
  173. package/dist/dist/migrations/20260816160257_automation_event_rls.sql +12 -0
  174. package/dist/dist/migrations/20260816160258_create_automation_run.sql +129 -0
  175. package/dist/dist/migrations/20260816160259_automation_run_rls.sql +19 -0
  176. package/dist/dist/migrations/20260816160300_add_client_created_via.sql +25 -0
  177. package/dist/dist/migrations/20260816160301_add_estimate_sent_at.sql +39 -0
  178. package/dist/dist/migrations/20260816160302_add_message_automation_ref.sql +10 -0
  179. package/dist/dist/migrations/20260816160303_automation_event_triggers.sql +236 -0
  180. package/dist/dist/migrations/20260816160304_automation_retention.sql +142 -0
  181. package/dist/dist/migrations/20260816202404_add_automation_center_addon_key.sql +26 -0
  182. package/dist/dist/migrations/20260816225501_widen_automation_rule_trigger_action_checks.sql +25 -0
  183. package/dist/dist/migrations/20260816225502_widen_automation_event_type_check.sql +18 -0
  184. package/dist/dist/migrations/20260816225503_add_invoice_id_to_automation_tables.sql +18 -0
  185. package/dist/dist/migrations/20260816225504_add_job_rescheduled_capture_trigger.sql +51 -0
  186. package/dist/dist/migrations/20260816225505_add_lead_converted_capture_trigger.sql +26 -0
  187. package/dist/dist/migrations/20260816225506_fix_booking_request_import_guard.sql +27 -0
  188. package/dist/dist/migrations/20260816225507_widen_outbound_event_for_automation.sql +38 -0
  189. package/dist/dist/migrations/20260817002626_add_user_last_login_platform_columns.sql +14 -0
  190. package/dist/dist/migrations/20260817221703_create_deletion.sql +34 -0
  191. package/dist/dist/migrations/20260817221707_deletion_rls.sql +21 -0
  192. package/dist/dist/migrations/20260817221708_add_soft_delete_columns.sql +82 -0
  193. package/dist/dist/migrations/20260817221709_trash_functions.sql +434 -0
  194. package/dist/dist/migrations/20260817221710_outbound_event_soft_delete.sql +55 -0
  195. package/dist/dist/migrations/20260817221711_automation_soft_delete_events.sql +77 -0
  196. package/dist/dist/migrations/20260817221712_fix_estimate_address_cascade.sql +14 -0
  197. package/dist/dist/migrations/20260817232630_trash_batch_function.sql +67 -0
  198. package/dist/dist/migrations/20260819170204_create_email_spam_complaint.sql +23 -0
  199. package/dist/dist/migrations/20260819170205_add_email_spam_complaint_rls.sql +5 -0
  200. package/dist/dist/migrations/20260819170206_email_unsubscribed_upsert_constraints.sql +14 -0
  201. package/dist/dist/migrations/20260819180151_get_suppressed_emails_function.sql +23 -0
  202. package/dist/dist/migrations/20260819191143_is_deleted_backfill_guard.sql +29 -0
  203. package/dist/dist/migrations/20260819191144_trash_functions_no_dual_write.sql +319 -0
  204. package/dist/dist/migrations/20260819191145_client_map_jobs_deleted_at.sql +33 -0
  205. package/dist/dist/migrations/20260819191147_booking_declined_deleted_at.sql +28 -0
  206. package/dist/dist/migrations/20260819191148_onboarding_preload_no_address_is_deleted.sql +1019 -0
  207. package/dist/dist/migrations/20260820222756_add_settings_job_hide_task_timer.sql +2 -0
  208. package/dist/dist/migrations/20260824234151_add_blast_chunk_recipients.sql +13 -0
  209. package/dist/dist/migrations/20260824234152_add_blast_pause_cancel_columns.sql +10 -0
  210. package/dist/dist/migrations/20260825014725_get_job_ids_in_range.sql +42 -0
  211. package/dist/dist/migrations/20260825194452_add_failed_job_status.sql +15 -0
  212. package/dist/dist/migrations/20260825194457_remove_take_to_rental_task_options.sql +24 -0
  213. package/dist/dist/migrations/20260825194458_remove_take_to_job_schedules.sql +12 -0
  214. package/dist/dist/migrations/20260825194459_rework_apply_rental_route_plan_no_take_to.sql +168 -0
  215. package/dist/dist/migrations/20260825194500_drop_job_schedule_target_location.sql +24 -0
  216. package/dist/dist/migrations/20260825194501_add_job_schedule_size.sql +17 -0
  217. package/dist/dist/migrations/20260825233001_add_job_schedule_id_company_id_key.sql +11 -0
  218. package/dist/dist/migrations/20260825233002_create_route_plan.sql +52 -0
  219. package/dist/dist/migrations/20260825233003_create_route_plan_stop.sql +159 -0
  220. package/dist/dist/migrations/20260825233004_route_plan_rls.sql +32 -0
  221. package/dist/dist/migrations/20260825233005_apply_rental_route_plan_v2.sql +351 -0
  222. package/dist/dist/migrations/20260826150934_facebook_ads_lead_ingestion.sql +1711 -0
  223. package/dist/dist/migrations/20260826151141_facebook_ads_lead_ingestion_rls_v2.sql +43 -0
  224. package/dist/dist/migrations/20260826234722_facebook_messenger_ingestion.sql +703 -0
  225. package/dist/dist/migrations/20260826234723_facebook_messenger_ingestion_rls.sql +80 -0
  226. package/dist/dist/migrations/20260826234724_widen_automations_messenger.sql +46 -0
  227. package/dist/dist/migrations/20260827100001_add_route_plan_minutes.sql +10 -0
  228. package/dist/dist/migrations/20260827100002_add_route_plan_stop_leg_minutes.sql +9 -0
  229. package/dist/dist/migrations/20260827100003_apply_rental_route_plan_v3.sql +341 -0
  230. package/dist/dist/migrations/20260827230346_apply_rental_route_plan_v4.sql +366 -0
  231. package/dist/dist/migrations/20260829090911_create_fleet_schema.sql +3698 -0
  232. package/dist/dist/migrations/20260829090912_fleet_rls.sql +1011 -0
  233. package/dist/dist/migrations/20260831102212_add_online_booking_address_display.sql +8 -0
  234. package/dist/dist/providers/AddressProvider.d.ts +9 -0
  235. package/dist/dist/providers/AddressProvider.d.ts.map +1 -0
  236. package/dist/dist/providers/AddressProvider.js +207 -0
  237. package/dist/dist/providers/AddressProvider.js.map +1 -0
  238. package/dist/dist/providers/AutomationsProvider.d.ts +11 -0
  239. package/dist/dist/providers/AutomationsProvider.d.ts.map +1 -0
  240. package/dist/dist/providers/AutomationsProvider.js +170 -0
  241. package/dist/dist/providers/AutomationsProvider.js.map +1 -0
  242. package/dist/dist/providers/BlockedNumbersProvider.d.ts +13 -0
  243. package/dist/dist/providers/BlockedNumbersProvider.d.ts.map +1 -0
  244. package/dist/dist/providers/BlockedNumbersProvider.js +71 -0
  245. package/dist/dist/providers/BlockedNumbersProvider.js.map +1 -0
  246. package/dist/dist/providers/CategoryProvider.d.ts +8 -0
  247. package/dist/dist/providers/CategoryProvider.d.ts.map +1 -0
  248. package/dist/dist/providers/CategoryProvider.js +95 -0
  249. package/dist/dist/providers/CategoryProvider.js.map +1 -0
  250. package/dist/dist/providers/ClientProvider.d.ts +39 -0
  251. package/dist/dist/providers/ClientProvider.d.ts.map +1 -0
  252. package/dist/dist/providers/ClientProvider.js +253 -0
  253. package/dist/dist/providers/ClientProvider.js.map +1 -0
  254. package/dist/dist/providers/CompanyProvider.d.ts +7 -0
  255. package/dist/dist/providers/CompanyProvider.d.ts.map +1 -0
  256. package/dist/dist/providers/CompanyProvider.js +114 -0
  257. package/dist/dist/providers/CompanyProvider.js.map +1 -0
  258. package/dist/dist/providers/DashboardProvider.d.ts +78 -0
  259. package/dist/dist/providers/DashboardProvider.d.ts.map +1 -0
  260. package/dist/dist/providers/DashboardProvider.js +568 -0
  261. package/dist/dist/providers/DashboardProvider.js.map +1 -0
  262. package/dist/dist/providers/DiscountProvider.d.ts +8 -0
  263. package/dist/dist/providers/DiscountProvider.d.ts.map +1 -0
  264. package/dist/dist/providers/DiscountProvider.js +92 -0
  265. package/dist/dist/providers/DiscountProvider.js.map +1 -0
  266. package/dist/dist/providers/EmployeesProvider.d.ts +6 -0
  267. package/dist/dist/providers/EmployeesProvider.d.ts.map +1 -0
  268. package/dist/dist/providers/EmployeesProvider.js +185 -0
  269. package/dist/dist/providers/EmployeesProvider.js.map +1 -0
  270. package/dist/dist/providers/EstimatesProvider.d.ts +16 -0
  271. package/dist/dist/providers/EstimatesProvider.d.ts.map +1 -0
  272. package/dist/dist/providers/EstimatesProvider.js +251 -0
  273. package/dist/dist/providers/EstimatesProvider.js.map +1 -0
  274. package/dist/dist/providers/EventsProvider.d.ts +4 -0
  275. package/dist/dist/providers/EventsProvider.d.ts.map +1 -0
  276. package/dist/dist/providers/EventsProvider.js +24 -0
  277. package/dist/dist/providers/EventsProvider.js.map +1 -0
  278. package/dist/dist/providers/FilesProvider.d.ts +17 -0
  279. package/dist/dist/providers/FilesProvider.d.ts.map +1 -0
  280. package/dist/dist/providers/FilesProvider.js +201 -0
  281. package/dist/dist/providers/FilesProvider.js.map +1 -0
  282. package/dist/dist/providers/InvoicesProvider.d.ts +13 -0
  283. package/dist/dist/providers/InvoicesProvider.d.ts.map +1 -0
  284. package/dist/dist/providers/InvoicesProvider.js +207 -0
  285. package/dist/dist/providers/InvoicesProvider.js.map +1 -0
  286. package/dist/dist/providers/ItemProvider.d.ts +9 -0
  287. package/dist/dist/providers/ItemProvider.d.ts.map +1 -0
  288. package/dist/dist/providers/ItemProvider.js +201 -0
  289. package/dist/dist/providers/ItemProvider.js.map +1 -0
  290. package/dist/dist/providers/JobSourceProvider.d.ts +8 -0
  291. package/dist/dist/providers/JobSourceProvider.d.ts.map +1 -0
  292. package/dist/dist/providers/JobSourceProvider.js +75 -0
  293. package/dist/dist/providers/JobSourceProvider.js.map +1 -0
  294. package/dist/dist/providers/JobTypeProvider.d.ts +8 -0
  295. package/dist/dist/providers/JobTypeProvider.d.ts.map +1 -0
  296. package/dist/dist/providers/JobTypeProvider.js +75 -0
  297. package/dist/dist/providers/JobTypeProvider.js.map +1 -0
  298. package/dist/dist/providers/JobsProvider.d.ts +35 -0
  299. package/dist/dist/providers/JobsProvider.d.ts.map +1 -0
  300. package/dist/dist/providers/JobsProvider.js +863 -0
  301. package/dist/dist/providers/JobsProvider.js.map +1 -0
  302. package/dist/dist/providers/MessagesProvider.d.ts +33 -0
  303. package/dist/dist/providers/MessagesProvider.d.ts.map +1 -0
  304. package/dist/dist/providers/MessagesProvider.js +415 -0
  305. package/dist/dist/providers/MessagesProvider.js.map +1 -0
  306. package/dist/dist/providers/PaymentProvider.d.ts +9 -0
  307. package/dist/dist/providers/PaymentProvider.d.ts.map +1 -0
  308. package/dist/dist/providers/PaymentProvider.js +48 -0
  309. package/dist/dist/providers/PaymentProvider.js.map +1 -0
  310. package/dist/dist/providers/PermissionRolesProvider.d.ts +5 -0
  311. package/dist/dist/providers/PermissionRolesProvider.d.ts.map +1 -0
  312. package/dist/dist/providers/PermissionRolesProvider.js +30 -0
  313. package/dist/dist/providers/PermissionRolesProvider.js.map +1 -0
  314. package/dist/dist/providers/PhoneNumberProvider.d.ts +12 -0
  315. package/dist/dist/providers/PhoneNumberProvider.d.ts.map +1 -0
  316. package/dist/dist/providers/PhoneNumberProvider.js +184 -0
  317. package/dist/dist/providers/PhoneNumberProvider.js.map +1 -0
  318. package/dist/dist/providers/ProfileProvider.d.ts +6 -0
  319. package/dist/dist/providers/ProfileProvider.d.ts.map +1 -0
  320. package/dist/dist/providers/ProfileProvider.js +71 -0
  321. package/dist/dist/providers/ProfileProvider.js.map +1 -0
  322. package/dist/dist/providers/RentalsProvider.d.ts +28 -0
  323. package/dist/dist/providers/RentalsProvider.d.ts.map +1 -0
  324. package/dist/dist/providers/RentalsProvider.js +438 -0
  325. package/dist/dist/providers/RentalsProvider.js.map +1 -0
  326. package/dist/dist/providers/SettingsBookingProvider.d.ts +9 -0
  327. package/dist/dist/providers/SettingsBookingProvider.d.ts.map +1 -0
  328. package/dist/dist/providers/SettingsBookingProvider.js +163 -0
  329. package/dist/dist/providers/SettingsBookingProvider.js.map +1 -0
  330. package/dist/dist/providers/SettingsProvider.d.ts +8 -0
  331. package/dist/dist/providers/SettingsProvider.d.ts.map +1 -0
  332. package/dist/dist/providers/SettingsProvider.js +86 -0
  333. package/dist/dist/providers/SettingsProvider.js.map +1 -0
  334. package/dist/dist/providers/TagsProvider.d.ts +12 -0
  335. package/dist/dist/providers/TagsProvider.d.ts.map +1 -0
  336. package/dist/dist/providers/TagsProvider.js +210 -0
  337. package/dist/dist/providers/TagsProvider.js.map +1 -0
  338. package/dist/dist/providers/TimeCardProvider.d.ts +8 -0
  339. package/dist/dist/providers/TimeCardProvider.d.ts.map +1 -0
  340. package/dist/dist/providers/TimeCardProvider.js +93 -0
  341. package/dist/dist/providers/TimeCardProvider.js.map +1 -0
  342. package/dist/dist/providers/TrashProvider.d.ts +13 -0
  343. package/dist/dist/providers/TrashProvider.d.ts.map +1 -0
  344. package/dist/dist/providers/TrashProvider.js +98 -0
  345. package/dist/dist/providers/TrashProvider.js.map +1 -0
  346. package/dist/dist/providers/dashboardAnalytics.d.ts +9 -0
  347. package/dist/dist/providers/dashboardAnalytics.d.ts.map +1 -0
  348. package/dist/dist/providers/dashboardAnalytics.js +41 -0
  349. package/dist/dist/providers/dashboardAnalytics.js.map +1 -0
  350. package/dist/dist/providers/dashboardAnalytics.test.d.ts +2 -0
  351. package/dist/dist/providers/dashboardAnalytics.test.d.ts.map +1 -0
  352. package/dist/dist/providers/dashboardAnalytics.test.js +111 -0
  353. package/dist/dist/providers/dashboardAnalytics.test.js.map +1 -0
  354. package/dist/dist/server-safe/BlockedNumberFunctions.d.ts +11 -0
  355. package/dist/dist/server-safe/BlockedNumberFunctions.d.ts.map +1 -0
  356. package/dist/dist/server-safe/BlockedNumberFunctions.js +16 -0
  357. package/dist/dist/server-safe/BlockedNumberFunctions.js.map +1 -0
  358. package/dist/dist/server-safe/EmployeeFunctions.d.ts +14 -0
  359. package/dist/dist/server-safe/EmployeeFunctions.d.ts.map +1 -0
  360. package/dist/dist/server-safe/EmployeeFunctions.js +70 -0
  361. package/dist/dist/server-safe/EmployeeFunctions.js.map +1 -0
  362. package/dist/dist/server-safe/EmployeeLocationFunctions.d.ts +7 -0
  363. package/dist/dist/server-safe/EmployeeLocationFunctions.d.ts.map +1 -0
  364. package/dist/dist/server-safe/EmployeeLocationFunctions.js +47 -0
  365. package/dist/dist/server-safe/EmployeeLocationFunctions.js.map +1 -0
  366. package/dist/dist/server-safe/EstimateFunctions.d.ts +15 -0
  367. package/dist/dist/server-safe/EstimateFunctions.d.ts.map +1 -0
  368. package/dist/dist/server-safe/EstimateFunctions.js +34 -0
  369. package/dist/dist/server-safe/EstimateFunctions.js.map +1 -0
  370. package/dist/dist/server-safe/InvoiceFunctions.d.ts +21 -0
  371. package/dist/dist/server-safe/InvoiceFunctions.d.ts.map +1 -0
  372. package/dist/dist/server-safe/InvoiceFunctions.js +124 -0
  373. package/dist/dist/server-safe/InvoiceFunctions.js.map +1 -0
  374. package/dist/dist/server-safe/JobFunctions.d.ts +15 -0
  375. package/dist/dist/server-safe/JobFunctions.d.ts.map +1 -0
  376. package/dist/dist/server-safe/JobFunctions.js +56 -0
  377. package/dist/dist/server-safe/JobFunctions.js.map +1 -0
  378. package/dist/dist/server-safe/PaymentFunctions.d.ts +16 -0
  379. package/dist/dist/server-safe/PaymentFunctions.d.ts.map +1 -0
  380. package/dist/dist/server-safe/PaymentFunctions.js +80 -0
  381. package/dist/dist/server-safe/PaymentFunctions.js.map +1 -0
  382. package/dist/dist/server-safe/PermissionFunctions.d.ts +7 -0
  383. package/dist/dist/server-safe/PermissionFunctions.d.ts.map +1 -0
  384. package/dist/dist/server-safe/PermissionFunctions.js +39 -0
  385. package/dist/dist/server-safe/PermissionFunctions.js.map +1 -0
  386. package/dist/dist/server-safe/TagFunctions.d.ts +18 -0
  387. package/dist/dist/server-safe/TagFunctions.d.ts.map +1 -0
  388. package/dist/dist/server-safe/TagFunctions.js +52 -0
  389. package/dist/dist/server-safe/TagFunctions.js.map +1 -0
  390. package/dist/dist/server-safe/autoJobType.d.ts +16 -0
  391. package/dist/dist/server-safe/autoJobType.d.ts.map +1 -0
  392. package/dist/dist/server-safe/autoJobType.js +39 -0
  393. package/dist/dist/server-safe/autoJobType.js.map +1 -0
  394. package/dist/dist/server-safe/autoJobType.test.d.ts +2 -0
  395. package/dist/dist/server-safe/autoJobType.test.d.ts.map +1 -0
  396. package/dist/dist/server-safe/autoJobType.test.js +83 -0
  397. package/dist/dist/server-safe/autoJobType.test.js.map +1 -0
  398. package/dist/dist/server-safe/automations.d.ts +197 -0
  399. package/dist/dist/server-safe/automations.d.ts.map +1 -0
  400. package/dist/dist/server-safe/automations.js +757 -0
  401. package/dist/dist/server-safe/automations.js.map +1 -0
  402. package/dist/dist/server-safe/automations.test.d.ts +2 -0
  403. package/dist/dist/server-safe/automations.test.d.ts.map +1 -0
  404. package/dist/dist/server-safe/automations.test.js +441 -0
  405. package/dist/dist/server-safe/automations.test.js.map +1 -0
  406. package/dist/dist/server-safe/constants.d.ts +156 -0
  407. package/dist/dist/server-safe/constants.d.ts.map +1 -0
  408. package/dist/dist/server-safe/constants.js +186 -0
  409. package/dist/dist/server-safe/constants.js.map +1 -0
  410. package/dist/dist/server-safe/contracts.d.ts +3 -0
  411. package/dist/dist/server-safe/contracts.d.ts.map +1 -0
  412. package/dist/dist/server-safe/contracts.js +15 -0
  413. package/dist/dist/server-safe/contracts.js.map +1 -0
  414. package/dist/dist/server-safe/database.types.d.ts +9510 -0
  415. package/dist/dist/server-safe/database.types.d.ts.map +1 -0
  416. package/dist/dist/server-safe/database.types.js +40 -0
  417. package/dist/dist/server-safe/database.types.js.map +1 -0
  418. package/dist/dist/server-safe/entitlements.d.ts +99 -0
  419. package/dist/dist/server-safe/entitlements.d.ts.map +1 -0
  420. package/dist/dist/server-safe/entitlements.js +487 -0
  421. package/dist/dist/server-safe/entitlements.js.map +1 -0
  422. package/dist/dist/server-safe/facebookAdsLeads.d.ts +225 -0
  423. package/dist/dist/server-safe/facebookAdsLeads.d.ts.map +1 -0
  424. package/dist/dist/server-safe/facebookAdsLeads.js +376 -0
  425. package/dist/dist/server-safe/facebookAdsLeads.js.map +1 -0
  426. package/dist/dist/server-safe/facebookAdsLeads.test.d.ts +2 -0
  427. package/dist/dist/server-safe/facebookAdsLeads.test.d.ts.map +1 -0
  428. package/dist/dist/server-safe/facebookAdsLeads.test.js +189 -0
  429. package/dist/dist/server-safe/facebookAdsLeads.test.js.map +1 -0
  430. package/dist/dist/server-safe/facebookAdsLeadsSql.test.d.ts +2 -0
  431. package/dist/dist/server-safe/facebookAdsLeadsSql.test.d.ts.map +1 -0
  432. package/dist/dist/server-safe/facebookAdsLeadsSql.test.js +32 -0
  433. package/dist/dist/server-safe/facebookAdsLeadsSql.test.js.map +1 -0
  434. package/dist/dist/server-safe/facebookMessenger.d.ts +20 -0
  435. package/dist/dist/server-safe/facebookMessenger.d.ts.map +1 -0
  436. package/dist/dist/server-safe/facebookMessenger.js +63 -0
  437. package/dist/dist/server-safe/facebookMessenger.js.map +1 -0
  438. package/dist/dist/server-safe/facebookMessenger.test.d.ts +2 -0
  439. package/dist/dist/server-safe/facebookMessenger.test.d.ts.map +1 -0
  440. package/dist/dist/server-safe/facebookMessenger.test.js +51 -0
  441. package/dist/dist/server-safe/facebookMessenger.test.js.map +1 -0
  442. package/dist/dist/server-safe/helpers.d.ts +78 -0
  443. package/dist/dist/server-safe/helpers.d.ts.map +1 -0
  444. package/dist/dist/server-safe/helpers.js +569 -0
  445. package/dist/dist/server-safe/helpers.js.map +1 -0
  446. package/dist/dist/server-safe/index.d.ts +30 -0
  447. package/dist/dist/server-safe/index.d.ts.map +1 -0
  448. package/dist/dist/server-safe/index.js +46 -0
  449. package/dist/dist/server-safe/index.js.map +1 -0
  450. package/dist/dist/server-safe/permissions.d.ts +29 -0
  451. package/dist/dist/server-safe/permissions.d.ts.map +1 -0
  452. package/dist/dist/server-safe/permissions.js +180 -0
  453. package/dist/dist/server-safe/permissions.js.map +1 -0
  454. package/dist/dist/server-safe/proposals.d.ts +6 -0
  455. package/dist/dist/server-safe/proposals.d.ts.map +1 -0
  456. package/dist/dist/server-safe/proposals.js +58 -0
  457. package/dist/dist/server-safe/proposals.js.map +1 -0
  458. package/dist/dist/server-safe/rentalAvailability.d.ts +56 -0
  459. package/dist/dist/server-safe/rentalAvailability.d.ts.map +1 -0
  460. package/dist/dist/server-safe/rentalAvailability.js +124 -0
  461. package/dist/dist/server-safe/rentalAvailability.js.map +1 -0
  462. package/dist/dist/server-safe/rentalAvailability.test.d.ts +2 -0
  463. package/dist/dist/server-safe/rentalAvailability.test.d.ts.map +1 -0
  464. package/dist/dist/server-safe/rentalAvailability.test.js +290 -0
  465. package/dist/dist/server-safe/rentalAvailability.test.js.map +1 -0
  466. package/dist/dist/server-safe/rentals.d.ts +95 -0
  467. package/dist/dist/server-safe/rentals.d.ts.map +1 -0
  468. package/dist/dist/server-safe/rentals.js +432 -0
  469. package/dist/dist/server-safe/rentals.js.map +1 -0
  470. package/dist/dist/server-safe/rentals.test.d.ts +2 -0
  471. package/dist/dist/server-safe/rentals.test.d.ts.map +1 -0
  472. package/dist/dist/server-safe/rentals.test.js +1034 -0
  473. package/dist/dist/server-safe/rentals.test.js.map +1 -0
  474. package/dist/dist/server-safe/routeOptimization.d.ts +155 -0
  475. package/dist/dist/server-safe/routeOptimization.d.ts.map +1 -0
  476. package/dist/dist/server-safe/routeOptimization.js +120 -0
  477. package/dist/dist/server-safe/routeOptimization.js.map +1 -0
  478. package/dist/dist/server-safe/routeOptimization.test.d.ts +2 -0
  479. package/dist/dist/server-safe/routeOptimization.test.d.ts.map +1 -0
  480. package/dist/dist/server-safe/routeOptimization.test.js +234 -0
  481. package/dist/dist/server-safe/routeOptimization.test.js.map +1 -0
  482. package/dist/dist/server-safe/routePlanFingerprint.d.ts +13 -0
  483. package/dist/dist/server-safe/routePlanFingerprint.d.ts.map +1 -0
  484. package/dist/dist/server-safe/routePlanFingerprint.js +49 -0
  485. package/dist/dist/server-safe/routePlanFingerprint.js.map +1 -0
  486. package/dist/dist/server-safe/routePlanFingerprint.test.d.ts +2 -0
  487. package/dist/dist/server-safe/routePlanFingerprint.test.d.ts.map +1 -0
  488. package/dist/dist/server-safe/routePlanFingerprint.test.js +68 -0
  489. package/dist/dist/server-safe/routePlanFingerprint.test.js.map +1 -0
  490. package/dist/dist/server-safe/scheduleListOrder.d.ts +18 -0
  491. package/dist/dist/server-safe/scheduleListOrder.d.ts.map +1 -0
  492. package/dist/dist/server-safe/scheduleListOrder.js +92 -0
  493. package/dist/dist/server-safe/scheduleListOrder.js.map +1 -0
  494. package/dist/dist/server-safe/scheduleListOrder.test.d.ts +2 -0
  495. package/dist/dist/server-safe/scheduleListOrder.test.d.ts.map +1 -0
  496. package/dist/dist/server-safe/scheduleListOrder.test.js +260 -0
  497. package/dist/dist/server-safe/scheduleListOrder.test.js.map +1 -0
  498. package/dist/dist/server-safe/serviceMinutes.d.ts +13 -0
  499. package/dist/dist/server-safe/serviceMinutes.d.ts.map +1 -0
  500. package/dist/dist/server-safe/serviceMinutes.js +38 -0
  501. package/dist/dist/server-safe/serviceMinutes.js.map +1 -0
  502. package/dist/dist/server-safe/serviceMinutes.test.d.ts +2 -0
  503. package/dist/dist/server-safe/serviceMinutes.test.d.ts.map +1 -0
  504. package/dist/dist/server-safe/serviceMinutes.test.js +86 -0
  505. package/dist/dist/server-safe/serviceMinutes.test.js.map +1 -0
  506. package/dist/dist/server-safe/settingsSearch.d.ts +24 -0
  507. package/dist/dist/server-safe/settingsSearch.d.ts.map +1 -0
  508. package/dist/dist/server-safe/settingsSearch.js +8 -0
  509. package/dist/dist/server-safe/settingsSearch.js.map +1 -0
  510. package/dist/dist/server-safe/supportChat.d.ts +59 -0
  511. package/dist/dist/server-safe/supportChat.d.ts.map +1 -0
  512. package/dist/dist/server-safe/supportChat.js +56 -0
  513. package/dist/dist/server-safe/supportChat.js.map +1 -0
  514. package/dist/dist/server-safe/templates.d.ts +15 -0
  515. package/dist/dist/server-safe/templates.d.ts.map +1 -0
  516. package/dist/dist/server-safe/templates.js +91 -0
  517. package/dist/dist/server-safe/templates.js.map +1 -0
  518. package/dist/dist/server-safe/templates.test.d.ts +2 -0
  519. package/dist/dist/server-safe/templates.test.d.ts.map +1 -0
  520. package/dist/dist/server-safe/templates.test.js +62 -0
  521. package/dist/dist/server-safe/templates.test.js.map +1 -0
  522. package/dist/dist/server-safe/trash.d.ts +50 -0
  523. package/dist/dist/server-safe/trash.d.ts.map +1 -0
  524. package/dist/dist/server-safe/trash.js +100 -0
  525. package/dist/dist/server-safe/trash.js.map +1 -0
  526. package/dist/dist/utils/LogHandler.d.ts +3 -0
  527. package/dist/dist/utils/LogHandler.d.ts.map +1 -0
  528. package/dist/dist/utils/LogHandler.js +16 -0
  529. package/dist/dist/utils/LogHandler.js.map +1 -0
  530. package/dist/dist/utils/convertSupabaseImagesToAssets.d.ts +28 -0
  531. package/dist/dist/utils/convertSupabaseImagesToAssets.d.ts.map +1 -0
  532. package/dist/dist/utils/convertSupabaseImagesToAssets.js +14 -0
  533. package/dist/dist/utils/convertSupabaseImagesToAssets.js.map +1 -0
  534. package/dist/index.d.ts +45 -0
  535. package/dist/index.d.ts.map +1 -0
  536. package/dist/index.js +61 -0
  537. package/dist/index.js.map +1 -0
  538. package/dist/interfaces/index.d.ts +1238 -0
  539. package/dist/interfaces/index.d.ts.map +1 -0
  540. package/dist/interfaces/index.js +3 -0
  541. package/dist/interfaces/index.js.map +1 -0
  542. package/dist/providers/AddressProvider.d.ts +9 -0
  543. package/dist/providers/AddressProvider.d.ts.map +1 -0
  544. package/dist/providers/AddressProvider.js +207 -0
  545. package/dist/providers/AddressProvider.js.map +1 -0
  546. package/dist/providers/AutomationsProvider.d.ts +11 -0
  547. package/dist/providers/AutomationsProvider.d.ts.map +1 -0
  548. package/dist/providers/AutomationsProvider.js +170 -0
  549. package/dist/providers/AutomationsProvider.js.map +1 -0
  550. package/dist/providers/BlockedNumbersProvider.d.ts +7 -0
  551. package/dist/providers/BlockedNumbersProvider.d.ts.map +1 -0
  552. package/dist/providers/BlockedNumbersProvider.js +71 -0
  553. package/dist/providers/BlockedNumbersProvider.js.map +1 -0
  554. package/dist/providers/CategoryProvider.d.ts +8 -0
  555. package/dist/providers/CategoryProvider.d.ts.map +1 -0
  556. package/dist/providers/CategoryProvider.js +95 -0
  557. package/dist/providers/CategoryProvider.js.map +1 -0
  558. package/dist/providers/ClientProvider.d.ts +39 -0
  559. package/dist/providers/ClientProvider.d.ts.map +1 -0
  560. package/dist/providers/ClientProvider.js +253 -0
  561. package/dist/providers/ClientProvider.js.map +1 -0
  562. package/dist/providers/CompanyProvider.d.ts +7 -0
  563. package/dist/providers/CompanyProvider.d.ts.map +1 -0
  564. package/dist/providers/CompanyProvider.js +114 -0
  565. package/dist/providers/CompanyProvider.js.map +1 -0
  566. package/dist/providers/DashboardProvider.d.ts +78 -0
  567. package/dist/providers/DashboardProvider.d.ts.map +1 -0
  568. package/dist/providers/DashboardProvider.js +568 -0
  569. package/dist/providers/DashboardProvider.js.map +1 -0
  570. package/dist/providers/DiscountProvider.d.ts +8 -0
  571. package/dist/providers/DiscountProvider.d.ts.map +1 -0
  572. package/dist/providers/DiscountProvider.js +92 -0
  573. package/dist/providers/DiscountProvider.js.map +1 -0
  574. package/dist/providers/EmployeesProvider.d.ts +6 -0
  575. package/dist/providers/EmployeesProvider.d.ts.map +1 -0
  576. package/dist/providers/EmployeesProvider.js +185 -0
  577. package/dist/providers/EmployeesProvider.js.map +1 -0
  578. package/dist/providers/EstimatesProvider.d.ts +16 -0
  579. package/dist/providers/EstimatesProvider.d.ts.map +1 -0
  580. package/dist/providers/EstimatesProvider.js +251 -0
  581. package/dist/providers/EstimatesProvider.js.map +1 -0
  582. package/dist/providers/EventsProvider.d.ts +4 -0
  583. package/dist/providers/EventsProvider.d.ts.map +1 -0
  584. package/dist/providers/EventsProvider.js +24 -0
  585. package/dist/providers/EventsProvider.js.map +1 -0
  586. package/dist/providers/FilesProvider.d.ts +17 -0
  587. package/dist/providers/FilesProvider.d.ts.map +1 -0
  588. package/dist/providers/FilesProvider.js +201 -0
  589. package/dist/providers/FilesProvider.js.map +1 -0
  590. package/dist/providers/InvoicesProvider.d.ts +13 -0
  591. package/dist/providers/InvoicesProvider.d.ts.map +1 -0
  592. package/dist/providers/InvoicesProvider.js +207 -0
  593. package/dist/providers/InvoicesProvider.js.map +1 -0
  594. package/dist/providers/ItemProvider.d.ts +9 -0
  595. package/dist/providers/ItemProvider.d.ts.map +1 -0
  596. package/dist/providers/ItemProvider.js +201 -0
  597. package/dist/providers/ItemProvider.js.map +1 -0
  598. package/dist/providers/JobSourceProvider.d.ts +8 -0
  599. package/dist/providers/JobSourceProvider.d.ts.map +1 -0
  600. package/dist/providers/JobSourceProvider.js +75 -0
  601. package/dist/providers/JobSourceProvider.js.map +1 -0
  602. package/dist/providers/JobTypeProvider.d.ts +8 -0
  603. package/dist/providers/JobTypeProvider.d.ts.map +1 -0
  604. package/dist/providers/JobTypeProvider.js +75 -0
  605. package/dist/providers/JobTypeProvider.js.map +1 -0
  606. package/dist/providers/JobsProvider.d.ts +20 -0
  607. package/dist/providers/JobsProvider.d.ts.map +1 -0
  608. package/dist/providers/JobsProvider.js +863 -0
  609. package/dist/providers/JobsProvider.js.map +1 -0
  610. package/dist/providers/MessagesProvider.d.ts +14 -0
  611. package/dist/providers/MessagesProvider.d.ts.map +1 -0
  612. package/dist/providers/MessagesProvider.js +415 -0
  613. package/dist/providers/MessagesProvider.js.map +1 -0
  614. package/dist/providers/PaymentProvider.d.ts +9 -0
  615. package/dist/providers/PaymentProvider.d.ts.map +1 -0
  616. package/dist/providers/PaymentProvider.js +48 -0
  617. package/dist/providers/PaymentProvider.js.map +1 -0
  618. package/dist/providers/PermissionRolesProvider.d.ts +5 -0
  619. package/dist/providers/PermissionRolesProvider.d.ts.map +1 -0
  620. package/dist/providers/PermissionRolesProvider.js +30 -0
  621. package/dist/providers/PermissionRolesProvider.js.map +1 -0
  622. package/dist/providers/PhoneNumberProvider.d.ts +12 -0
  623. package/dist/providers/PhoneNumberProvider.d.ts.map +1 -0
  624. package/dist/providers/PhoneNumberProvider.js +184 -0
  625. package/dist/providers/PhoneNumberProvider.js.map +1 -0
  626. package/dist/providers/ProfileProvider.d.ts +6 -0
  627. package/dist/providers/ProfileProvider.d.ts.map +1 -0
  628. package/dist/providers/ProfileProvider.js +71 -0
  629. package/dist/providers/ProfileProvider.js.map +1 -0
  630. package/dist/providers/RentalsProvider.d.ts +28 -0
  631. package/dist/providers/RentalsProvider.d.ts.map +1 -0
  632. package/dist/providers/RentalsProvider.js +438 -0
  633. package/dist/providers/RentalsProvider.js.map +1 -0
  634. package/dist/providers/SettingsBookingProvider.d.ts +9 -0
  635. package/dist/providers/SettingsBookingProvider.d.ts.map +1 -0
  636. package/dist/providers/SettingsBookingProvider.js +163 -0
  637. package/dist/providers/SettingsBookingProvider.js.map +1 -0
  638. package/dist/providers/SettingsProvider.d.ts +8 -0
  639. package/dist/providers/SettingsProvider.d.ts.map +1 -0
  640. package/dist/providers/SettingsProvider.js +86 -0
  641. package/dist/providers/SettingsProvider.js.map +1 -0
  642. package/dist/providers/TagsProvider.d.ts +12 -0
  643. package/dist/providers/TagsProvider.d.ts.map +1 -0
  644. package/dist/providers/TagsProvider.js +210 -0
  645. package/dist/providers/TagsProvider.js.map +1 -0
  646. package/dist/providers/TimeCardProvider.d.ts +8 -0
  647. package/dist/providers/TimeCardProvider.d.ts.map +1 -0
  648. package/dist/providers/TimeCardProvider.js +93 -0
  649. package/dist/providers/TimeCardProvider.js.map +1 -0
  650. package/dist/providers/TrashProvider.d.ts +13 -0
  651. package/dist/providers/TrashProvider.d.ts.map +1 -0
  652. package/dist/providers/TrashProvider.js +98 -0
  653. package/dist/providers/TrashProvider.js.map +1 -0
  654. package/dist/providers/dashboardAnalytics.d.ts +9 -0
  655. package/dist/providers/dashboardAnalytics.d.ts.map +1 -0
  656. package/dist/providers/dashboardAnalytics.js +41 -0
  657. package/dist/providers/dashboardAnalytics.js.map +1 -0
  658. package/dist/providers/dashboardAnalytics.test.d.ts +2 -0
  659. package/dist/providers/dashboardAnalytics.test.d.ts.map +1 -0
  660. package/dist/providers/dashboardAnalytics.test.js +111 -0
  661. package/dist/providers/dashboardAnalytics.test.js.map +1 -0
  662. package/dist/server-safe/BlockedNumberFunctions.d.ts +11 -0
  663. package/dist/server-safe/BlockedNumberFunctions.d.ts.map +1 -0
  664. package/dist/server-safe/BlockedNumberFunctions.js +16 -0
  665. package/dist/server-safe/BlockedNumberFunctions.js.map +1 -0
  666. package/dist/server-safe/EmployeeFunctions.d.ts +14 -0
  667. package/dist/server-safe/EmployeeFunctions.d.ts.map +1 -0
  668. package/dist/server-safe/EmployeeFunctions.js +70 -0
  669. package/dist/server-safe/EmployeeFunctions.js.map +1 -0
  670. package/dist/server-safe/EmployeeLocationFunctions.d.ts +7 -0
  671. package/dist/server-safe/EmployeeLocationFunctions.d.ts.map +1 -0
  672. package/dist/server-safe/EmployeeLocationFunctions.js +47 -0
  673. package/dist/server-safe/EmployeeLocationFunctions.js.map +1 -0
  674. package/dist/server-safe/EstimateFunctions.d.ts +15 -0
  675. package/dist/server-safe/EstimateFunctions.d.ts.map +1 -0
  676. package/dist/server-safe/EstimateFunctions.js +34 -0
  677. package/dist/server-safe/EstimateFunctions.js.map +1 -0
  678. package/dist/server-safe/InvoiceFunctions.d.ts +21 -0
  679. package/dist/server-safe/InvoiceFunctions.d.ts.map +1 -0
  680. package/dist/server-safe/InvoiceFunctions.js +124 -0
  681. package/dist/server-safe/InvoiceFunctions.js.map +1 -0
  682. package/dist/server-safe/JobFunctions.d.ts +15 -0
  683. package/dist/server-safe/JobFunctions.d.ts.map +1 -0
  684. package/dist/server-safe/JobFunctions.js +56 -0
  685. package/dist/server-safe/JobFunctions.js.map +1 -0
  686. package/dist/server-safe/PaymentFunctions.d.ts +16 -0
  687. package/dist/server-safe/PaymentFunctions.d.ts.map +1 -0
  688. package/dist/server-safe/PaymentFunctions.js +80 -0
  689. package/dist/server-safe/PaymentFunctions.js.map +1 -0
  690. package/dist/server-safe/PermissionFunctions.d.ts +7 -0
  691. package/dist/server-safe/PermissionFunctions.d.ts.map +1 -0
  692. package/dist/server-safe/PermissionFunctions.js +39 -0
  693. package/dist/server-safe/PermissionFunctions.js.map +1 -0
  694. package/dist/server-safe/TagFunctions.d.ts +18 -0
  695. package/dist/server-safe/TagFunctions.d.ts.map +1 -0
  696. package/dist/server-safe/TagFunctions.js +52 -0
  697. package/dist/server-safe/TagFunctions.js.map +1 -0
  698. package/dist/server-safe/autoJobType.d.ts +16 -0
  699. package/dist/server-safe/autoJobType.d.ts.map +1 -0
  700. package/dist/server-safe/autoJobType.js +39 -0
  701. package/dist/server-safe/autoJobType.js.map +1 -0
  702. package/dist/server-safe/autoJobType.test.d.ts +2 -0
  703. package/dist/server-safe/autoJobType.test.d.ts.map +1 -0
  704. package/dist/server-safe/autoJobType.test.js +83 -0
  705. package/dist/server-safe/autoJobType.test.js.map +1 -0
  706. package/dist/server-safe/automations.d.ts +197 -0
  707. package/dist/server-safe/automations.d.ts.map +1 -0
  708. package/dist/server-safe/automations.js +757 -0
  709. package/dist/server-safe/automations.js.map +1 -0
  710. package/dist/server-safe/automations.test.d.ts +2 -0
  711. package/dist/server-safe/automations.test.d.ts.map +1 -0
  712. package/dist/server-safe/automations.test.js +441 -0
  713. package/dist/server-safe/automations.test.js.map +1 -0
  714. package/dist/server-safe/constants.d.ts +156 -0
  715. package/dist/server-safe/constants.d.ts.map +1 -0
  716. package/dist/server-safe/constants.js +186 -0
  717. package/dist/server-safe/constants.js.map +1 -0
  718. package/dist/server-safe/contracts.d.ts +3 -0
  719. package/dist/server-safe/contracts.d.ts.map +1 -0
  720. package/dist/server-safe/contracts.js +15 -0
  721. package/dist/server-safe/contracts.js.map +1 -0
  722. package/dist/server-safe/database.types.d.ts +9510 -0
  723. package/dist/server-safe/database.types.d.ts.map +1 -0
  724. package/dist/server-safe/database.types.js +40 -0
  725. package/dist/server-safe/database.types.js.map +1 -0
  726. package/dist/server-safe/entitlements.d.ts +99 -0
  727. package/dist/server-safe/entitlements.d.ts.map +1 -0
  728. package/dist/server-safe/entitlements.js +487 -0
  729. package/dist/server-safe/entitlements.js.map +1 -0
  730. package/dist/server-safe/helpers.d.ts +78 -0
  731. package/dist/server-safe/helpers.d.ts.map +1 -0
  732. package/dist/server-safe/helpers.js +569 -0
  733. package/dist/server-safe/helpers.js.map +1 -0
  734. package/dist/server-safe/index.d.ts +30 -0
  735. package/dist/server-safe/index.d.ts.map +1 -0
  736. package/dist/server-safe/index.js +46 -0
  737. package/dist/server-safe/index.js.map +1 -0
  738. package/dist/server-safe/permissions.d.ts +29 -0
  739. package/dist/server-safe/permissions.d.ts.map +1 -0
  740. package/dist/server-safe/permissions.js +180 -0
  741. package/dist/server-safe/permissions.js.map +1 -0
  742. package/dist/server-safe/proposals.d.ts +6 -0
  743. package/dist/server-safe/proposals.d.ts.map +1 -0
  744. package/dist/server-safe/proposals.js +58 -0
  745. package/dist/server-safe/proposals.js.map +1 -0
  746. package/dist/server-safe/rentalAvailability.d.ts +56 -0
  747. package/dist/server-safe/rentalAvailability.d.ts.map +1 -0
  748. package/dist/server-safe/rentalAvailability.js +124 -0
  749. package/dist/server-safe/rentalAvailability.js.map +1 -0
  750. package/dist/server-safe/rentalAvailability.test.d.ts +2 -0
  751. package/dist/server-safe/rentalAvailability.test.d.ts.map +1 -0
  752. package/dist/server-safe/rentalAvailability.test.js +290 -0
  753. package/dist/server-safe/rentalAvailability.test.js.map +1 -0
  754. package/dist/server-safe/rentals.d.ts +95 -0
  755. package/dist/server-safe/rentals.d.ts.map +1 -0
  756. package/dist/server-safe/rentals.js +432 -0
  757. package/dist/server-safe/rentals.js.map +1 -0
  758. package/dist/server-safe/rentals.test.d.ts +2 -0
  759. package/dist/server-safe/rentals.test.d.ts.map +1 -0
  760. package/dist/server-safe/rentals.test.js +1034 -0
  761. package/dist/server-safe/rentals.test.js.map +1 -0
  762. package/dist/server-safe/routeOptimization.d.ts +155 -0
  763. package/dist/server-safe/routeOptimization.d.ts.map +1 -0
  764. package/dist/server-safe/routeOptimization.js +120 -0
  765. package/dist/server-safe/routeOptimization.js.map +1 -0
  766. package/dist/server-safe/routeOptimization.test.d.ts +2 -0
  767. package/dist/server-safe/routeOptimization.test.d.ts.map +1 -0
  768. package/dist/server-safe/routeOptimization.test.js +234 -0
  769. package/dist/server-safe/routeOptimization.test.js.map +1 -0
  770. package/dist/server-safe/routePlanFingerprint.d.ts +13 -0
  771. package/dist/server-safe/routePlanFingerprint.d.ts.map +1 -0
  772. package/dist/server-safe/routePlanFingerprint.js +49 -0
  773. package/dist/server-safe/routePlanFingerprint.js.map +1 -0
  774. package/dist/server-safe/routePlanFingerprint.test.d.ts +2 -0
  775. package/dist/server-safe/routePlanFingerprint.test.d.ts.map +1 -0
  776. package/dist/server-safe/routePlanFingerprint.test.js +68 -0
  777. package/dist/server-safe/routePlanFingerprint.test.js.map +1 -0
  778. package/dist/server-safe/scheduleListOrder.d.ts +18 -0
  779. package/dist/server-safe/scheduleListOrder.d.ts.map +1 -0
  780. package/dist/server-safe/scheduleListOrder.js +92 -0
  781. package/dist/server-safe/scheduleListOrder.js.map +1 -0
  782. package/dist/server-safe/scheduleListOrder.test.d.ts +2 -0
  783. package/dist/server-safe/scheduleListOrder.test.d.ts.map +1 -0
  784. package/dist/server-safe/scheduleListOrder.test.js +260 -0
  785. package/dist/server-safe/scheduleListOrder.test.js.map +1 -0
  786. package/dist/server-safe/serviceMinutes.d.ts +13 -0
  787. package/dist/server-safe/serviceMinutes.d.ts.map +1 -0
  788. package/dist/server-safe/serviceMinutes.js +38 -0
  789. package/dist/server-safe/serviceMinutes.js.map +1 -0
  790. package/dist/server-safe/serviceMinutes.test.d.ts +2 -0
  791. package/dist/server-safe/serviceMinutes.test.d.ts.map +1 -0
  792. package/dist/server-safe/serviceMinutes.test.js +86 -0
  793. package/dist/server-safe/serviceMinutes.test.js.map +1 -0
  794. package/dist/server-safe/settingsSearch.d.ts +24 -0
  795. package/dist/server-safe/settingsSearch.d.ts.map +1 -0
  796. package/dist/server-safe/settingsSearch.js +8 -0
  797. package/dist/server-safe/settingsSearch.js.map +1 -0
  798. package/dist/server-safe/supportChat.d.ts +59 -0
  799. package/dist/server-safe/supportChat.d.ts.map +1 -0
  800. package/dist/server-safe/supportChat.js +56 -0
  801. package/dist/server-safe/supportChat.js.map +1 -0
  802. package/dist/server-safe/templates.d.ts +15 -0
  803. package/dist/server-safe/templates.d.ts.map +1 -0
  804. package/dist/server-safe/templates.js +91 -0
  805. package/dist/server-safe/templates.js.map +1 -0
  806. package/dist/server-safe/templates.test.d.ts +2 -0
  807. package/dist/server-safe/templates.test.d.ts.map +1 -0
  808. package/dist/server-safe/templates.test.js +62 -0
  809. package/dist/server-safe/templates.test.js.map +1 -0
  810. package/dist/server-safe/trash.d.ts +50 -0
  811. package/dist/server-safe/trash.d.ts.map +1 -0
  812. package/dist/server-safe/trash.js +100 -0
  813. package/dist/server-safe/trash.js.map +1 -0
  814. package/dist/utils/LogHandler.d.ts +3 -0
  815. package/dist/utils/LogHandler.d.ts.map +1 -0
  816. package/dist/utils/LogHandler.js +16 -0
  817. package/dist/utils/LogHandler.js.map +1 -0
  818. package/dist/utils/convertSupabaseImagesToAssets.d.ts +28 -0
  819. package/dist/utils/convertSupabaseImagesToAssets.d.ts.map +1 -0
  820. package/dist/utils/convertSupabaseImagesToAssets.js +14 -0
  821. package/dist/utils/convertSupabaseImagesToAssets.js.map +1 -0
  822. package/package.json +37 -0
@@ -0,0 +1,1538 @@
1
+ -- Facebook Ads integration schema: connection, settings, cached spend,
2
+ -- campaign filtering, and reporting functions. All access is server-only; the
3
+ -- companion RLS migration locks every table and function to the service role.
4
+
5
+ -- Campaign ids arrive from Meta as decimal strings. Normalized means a
6
+ -- one-dimensional array of distinct, sorted, digit-only values, which lets the
7
+ -- selection-change comparison in set_facebook_ads_campaign_selection detect
8
+ -- no-op updates without invalidating the spend cache.
9
+ create or replace function "public"."facebook_ads_campaign_ids_are_normalized"(
10
+ "p_campaign_ids" "text"[]
11
+ )
12
+ returns boolean
13
+ language sql
14
+ immutable
15
+ parallel safe
16
+ set search_path = ''
17
+ as $$
18
+ select case
19
+ when cardinality("p_campaign_ids") = 0 then true
20
+ when coalesce(array_ndims("p_campaign_ids"), 0) <> 1 then false
21
+ when exists (
22
+ select 1
23
+ from unnest("p_campaign_ids") as "campaign_id"("value")
24
+ where "campaign_id"."value" is null
25
+ or "campaign_id"."value" !~ '^[0-9]+$'
26
+ ) then false
27
+ else "p_campaign_ids" = array(
28
+ select distinct "campaign_id"."value"
29
+ from unnest("p_campaign_ids") as "campaign_id"("value")
30
+ order by "campaign_id"."value"
31
+ )
32
+ end;
33
+ $$;
34
+
35
+ alter function "public"."facebook_ads_campaign_ids_are_normalized"("text"[])
36
+ owner to "postgres";
37
+
38
+ -- OAuth authorization is persisted before the customer selects an ad account,
39
+ -- so the token and app-scoped Meta user id are required while token expiry and
40
+ -- selected-account metadata remain nullable during that staged connection.
41
+ -- Campaign filtering tracks either every campaign or an explicit normalized
42
+ -- id selection; the spend configuration version increments whenever the
43
+ -- account or campaign selection changes so in-flight syncs for a previous
44
+ -- configuration become ineligible to write cached spend.
45
+ create table if not exists "public"."facebook_ads_connection" (
46
+ "id" "uuid" default "gen_random_uuid"() not null,
47
+ "created_at" timestamp with time zone default "now"() not null,
48
+ "updated_at" timestamp with time zone default "now"() not null,
49
+ "company_id" "uuid" not null,
50
+ "meta_user_id" "text" not null,
51
+ "access_token" "text" not null,
52
+ "token_expires_at" timestamp with time zone,
53
+ "ad_account_id" "text",
54
+ "ad_account_name" "text",
55
+ "ad_account_status" integer,
56
+ "currency" "text",
57
+ "timezone_name" "text",
58
+ "timezone_offset_hours_utc" numeric(5, 2),
59
+ "campaign_selection_mode" "text" default 'all'::"text" not null,
60
+ "selected_campaign_ids" "text"[] default '{}'::"text"[] not null,
61
+ "spend_configuration_version" bigint default 0 not null,
62
+ "last_synced_at" timestamp with time zone,
63
+ "backfill_completed_at" timestamp with time zone,
64
+ "campaign_breakdown_backfill_completed_at" timestamp with time zone,
65
+ "last_sync_error" "text",
66
+ constraint "facebook_ads_connection_pkey" primary key ("id"),
67
+ constraint "facebook_ads_connection_company_id_key" unique ("company_id"),
68
+ constraint "facebook_ads_connection_company_id_id_key" unique ("company_id", "id"),
69
+ constraint "facebook_ads_connection_company_id_fkey"
70
+ foreign key ("company_id") references "public"."company"("id") on delete cascade,
71
+ constraint "facebook_ads_connection_timezone_offset_check"
72
+ check ("timezone_offset_hours_utc" between -24 and 24),
73
+ constraint "facebook_ads_connection_campaign_selection_mode_check"
74
+ check ("campaign_selection_mode" in ('all', 'selected')),
75
+ constraint "facebook_ads_connection_selected_campaign_ids_no_nulls_check"
76
+ check (array_position("selected_campaign_ids", null::"text") is null),
77
+ constraint "facebook_ads_connection_selected_campaign_ids_format_check"
78
+ check (
79
+ "public"."facebook_ads_campaign_ids_are_normalized"(
80
+ "selected_campaign_ids"
81
+ )
82
+ ),
83
+ constraint "facebook_ads_connection_campaign_selection_consistency_check"
84
+ check (
85
+ (
86
+ "campaign_selection_mode" = 'all'
87
+ and cardinality("selected_campaign_ids") = 0
88
+ )
89
+ or (
90
+ "campaign_selection_mode" = 'selected'
91
+ and cardinality("selected_campaign_ids") > 0
92
+ )
93
+ ),
94
+ constraint "facebook_ads_connection_spend_configuration_version_check"
95
+ check ("spend_configuration_version" >= 0)
96
+ );
97
+
98
+ alter table "public"."facebook_ads_connection" owner to "postgres";
99
+
100
+ -- The selected Autopilot job source is configuration, not Meta-derived data,
101
+ -- so it is kept separately from the connection and cached spend rows.
102
+ create table if not exists "public"."settings_facebook_ads" (
103
+ "id" "uuid" default "gen_random_uuid"() not null,
104
+ "created_at" timestamp with time zone default "now"() not null,
105
+ "updated_at" timestamp with time zone default "now"() not null,
106
+ "company_id" "uuid" not null,
107
+ "source_id" "uuid",
108
+ "source_names" "text"[] default '{}'::"text"[] not null,
109
+ constraint "settings_facebook_ads_pkey" primary key ("id"),
110
+ constraint "settings_facebook_ads_company_id_key" unique ("company_id"),
111
+ constraint "settings_facebook_ads_company_id_fkey"
112
+ foreign key ("company_id") references "public"."company"("id") on delete cascade,
113
+ constraint "settings_facebook_ads_source_id_fkey"
114
+ foreign key ("source_id") references "public"."job_source"("id") on delete set null,
115
+ constraint "settings_facebook_ads_source_names_no_nulls_check"
116
+ check (array_position("source_names", null::"text") is null),
117
+ constraint "settings_facebook_ads_source_names_no_empty_check"
118
+ check (array_position("source_names", ''::"text") is null)
119
+ );
120
+
121
+ alter table "public"."settings_facebook_ads" owner to "postgres";
122
+
123
+ -- Account-level daily spend powers the summary cards. The composite foreign
124
+ -- key prevents a spend row from being assigned to a connection owned by a
125
+ -- different company.
126
+ create table if not exists "public"."facebook_ads_daily_spend" (
127
+ "id" "uuid" default "gen_random_uuid"() not null,
128
+ "created_at" timestamp with time zone default "now"() not null,
129
+ "updated_at" timestamp with time zone default "now"() not null,
130
+ "company_id" "uuid" not null,
131
+ "connection_id" "uuid" not null,
132
+ "date" date not null,
133
+ "spend" numeric(18, 6) not null,
134
+ "currency" "text" not null,
135
+ constraint "facebook_ads_daily_spend_pkey" primary key ("id"),
136
+ constraint "facebook_ads_daily_spend_connection_date_key"
137
+ unique ("connection_id", "date"),
138
+ constraint "facebook_ads_daily_spend_company_connection_fkey"
139
+ foreign key ("company_id", "connection_id")
140
+ references "public"."facebook_ads_connection"("company_id", "id")
141
+ on delete cascade,
142
+ constraint "facebook_ads_daily_spend_nonnegative_check" check ("spend" >= 0)
143
+ );
144
+
145
+ alter table "public"."facebook_ads_daily_spend" owner to "postgres";
146
+
147
+ create index if not exists "facebook_ads_daily_spend_company_date_idx"
148
+ on "public"."facebook_ads_daily_spend" using "btree" ("company_id", "date");
149
+
150
+ -- Campaign-level daily spend preserves the Meta campaign rows that the
151
+ -- account-level cache collapses into daily totals, powering the report's
152
+ -- campaign breakdown.
153
+ create table if not exists "public"."facebook_ads_campaign_daily_spend" (
154
+ "id" "uuid" default "gen_random_uuid"() not null,
155
+ "created_at" timestamp with time zone default "now"() not null,
156
+ "updated_at" timestamp with time zone default "now"() not null,
157
+ "company_id" "uuid" not null,
158
+ "connection_id" "uuid" not null,
159
+ "campaign_id" "text" not null,
160
+ "campaign_name" "text" not null,
161
+ "date" date not null,
162
+ "spend" numeric(18, 6) not null,
163
+ "currency" "text" not null,
164
+ constraint "facebook_ads_campaign_daily_spend_pkey" primary key ("id"),
165
+ constraint "facebook_ads_campaign_daily_spend_connection_campaign_date_key"
166
+ unique ("connection_id", "campaign_id", "date"),
167
+ constraint "facebook_ads_campaign_daily_spend_company_connection_fkey"
168
+ foreign key ("company_id", "connection_id")
169
+ references "public"."facebook_ads_connection"("company_id", "id")
170
+ on delete cascade,
171
+ constraint "facebook_ads_campaign_daily_spend_campaign_id_check"
172
+ check ("campaign_id" ~ '^[0-9]+$'),
173
+ constraint "facebook_ads_campaign_daily_spend_campaign_name_check"
174
+ check (nullif(btrim("campaign_name"), '') is not null),
175
+ constraint "facebook_ads_campaign_daily_spend_currency_check"
176
+ check ("currency" ~ '^[A-Z]{3}$'),
177
+ constraint "facebook_ads_campaign_daily_spend_nonnegative_check"
178
+ check ("spend" >= 0)
179
+ );
180
+
181
+ alter table "public"."facebook_ads_campaign_daily_spend" owner to "postgres";
182
+
183
+ create index if not exists "facebook_ads_campaign_daily_spend_company_date_idx"
184
+ on "public"."facebook_ads_campaign_daily_spend" (
185
+ "company_id",
186
+ "date"
187
+ );
188
+
189
+ create index if not exists "facebook_ads_campaign_daily_spend_connection_campaign_idx"
190
+ on "public"."facebook_ads_campaign_daily_spend" (
191
+ "connection_id",
192
+ "campaign_id"
193
+ );
194
+
195
+ -- Selecting an account and invalidating data from the previous account must
196
+ -- be one transaction. This prevents a concurrent sync from repopulating stale
197
+ -- rows after an account switch or clear operation. Selecting another ad
198
+ -- account also resets campaign selection to its safe default; incrementing
199
+ -- the version makes every sync started for the previous account or campaign
200
+ -- selection ineligible to write cached spend.
201
+ create or replace function "public"."set_facebook_ads_selected_account"(
202
+ "p_company_id" "uuid",
203
+ "p_ad_account_id" "text",
204
+ "p_ad_account_name" "text",
205
+ "p_ad_account_status" integer,
206
+ "p_currency" "text",
207
+ "p_timezone_name" "text",
208
+ "p_timezone_offset_hours_utc" numeric
209
+ )
210
+ returns boolean
211
+ language plpgsql
212
+ security definer
213
+ set search_path = ''
214
+ as $$
215
+ declare
216
+ "v_connection_id" "uuid";
217
+ "v_previous_ad_account_id" "text";
218
+ "v_account_changed" boolean;
219
+ begin
220
+ if "p_company_id" is null then
221
+ raise exception 'company_id is required' using errcode = '22023';
222
+ end if;
223
+
224
+ if "p_ad_account_id" is null then
225
+ if "p_ad_account_name" is not null
226
+ or "p_ad_account_status" is not null
227
+ or "p_currency" is not null
228
+ or "p_timezone_name" is not null
229
+ or "p_timezone_offset_hours_utc" is not null
230
+ then
231
+ raise exception 'account metadata must be null when clearing an account'
232
+ using errcode = '22023';
233
+ end if;
234
+ elsif nullif(btrim("p_ad_account_id"), '') is null
235
+ or nullif(btrim("p_ad_account_name"), '') is null
236
+ or "p_ad_account_status" is null
237
+ or coalesce("p_currency", '') !~ '^[A-Z]{3}$'
238
+ or nullif(btrim("p_timezone_name"), '') is null
239
+ or "p_timezone_offset_hours_utc" is null
240
+ or "p_timezone_offset_hours_utc" not between -24 and 24
241
+ then
242
+ raise exception 'complete account metadata is required when selecting an account'
243
+ using errcode = '22023';
244
+ end if;
245
+
246
+ select "id", "ad_account_id"
247
+ into "v_connection_id", "v_previous_ad_account_id"
248
+ from "public"."facebook_ads_connection"
249
+ where "company_id" = "p_company_id"
250
+ for update;
251
+
252
+ if not found then
253
+ raise exception 'Facebook Ads connection does not exist'
254
+ using errcode = '23503';
255
+ end if;
256
+
257
+ "v_account_changed" :=
258
+ "v_previous_ad_account_id" is distinct from "p_ad_account_id";
259
+
260
+ update "public"."facebook_ads_connection"
261
+ set
262
+ "ad_account_id" = "p_ad_account_id",
263
+ "ad_account_name" = "p_ad_account_name",
264
+ "ad_account_status" = "p_ad_account_status",
265
+ "currency" = "p_currency",
266
+ "timezone_name" = "p_timezone_name",
267
+ "timezone_offset_hours_utc" = "p_timezone_offset_hours_utc",
268
+ "campaign_selection_mode" = case
269
+ when "v_account_changed" or "p_ad_account_id" is null then 'all'
270
+ else "campaign_selection_mode"
271
+ end,
272
+ "selected_campaign_ids" = case
273
+ when "v_account_changed" or "p_ad_account_id" is null then
274
+ '{}'::"text"[]
275
+ else "selected_campaign_ids"
276
+ end,
277
+ "spend_configuration_version" = case
278
+ when "v_account_changed" then "spend_configuration_version" + 1
279
+ else "spend_configuration_version"
280
+ end,
281
+ "last_synced_at" = case
282
+ when "v_account_changed" then null
283
+ else "last_synced_at"
284
+ end,
285
+ "backfill_completed_at" = case
286
+ when "v_account_changed" or "p_ad_account_id" is null then null
287
+ else "backfill_completed_at"
288
+ end,
289
+ "last_sync_error" = null
290
+ where "id" = "v_connection_id";
291
+
292
+ if "v_account_changed" or "p_ad_account_id" is null then
293
+ delete from "public"."facebook_ads_daily_spend"
294
+ where "connection_id" = "v_connection_id";
295
+ end if;
296
+
297
+ return "v_account_changed";
298
+ end;
299
+ $$;
300
+
301
+ alter function "public"."set_facebook_ads_selected_account"(
302
+ "uuid",
303
+ "text",
304
+ "text",
305
+ integer,
306
+ "text",
307
+ "text",
308
+ numeric
309
+ ) owner to "postgres";
310
+
311
+ -- Normalize ids before comparing them so selecting the same campaigns in a
312
+ -- different order does not invalidate and re-fetch the spend cache.
313
+ create or replace function "public"."set_facebook_ads_campaign_selection"(
314
+ "p_company_id" "uuid",
315
+ "p_ad_account_id" "text",
316
+ "p_campaign_selection_mode" "text",
317
+ "p_selected_campaign_ids" "text"[]
318
+ )
319
+ returns boolean
320
+ language plpgsql
321
+ security invoker
322
+ set search_path = ''
323
+ as $$
324
+ declare
325
+ "v_campaign_selection_mode" "text";
326
+ "v_connection_id" "uuid";
327
+ "v_current_campaign_selection_mode" "text";
328
+ "v_current_selected_campaign_ids" "text"[];
329
+ "v_normalized_campaign_ids" "text"[];
330
+ "v_selection_changed" boolean;
331
+ begin
332
+ if "p_company_id" is null
333
+ or nullif(btrim("p_ad_account_id"), '') is null
334
+ or nullif(btrim("p_campaign_selection_mode"), '') is null
335
+ then
336
+ raise exception 'company_id, ad_account_id, and campaign selection mode are required'
337
+ using errcode = '22023';
338
+ end if;
339
+
340
+ "v_campaign_selection_mode" := lower(btrim("p_campaign_selection_mode"));
341
+ if "v_campaign_selection_mode" not in ('all', 'selected') then
342
+ raise exception 'campaign selection mode must be all or selected'
343
+ using errcode = '22023';
344
+ end if;
345
+
346
+ if "v_campaign_selection_mode" = 'all' then
347
+ "v_normalized_campaign_ids" := '{}'::"text"[];
348
+ else
349
+ if exists (
350
+ select 1
351
+ from unnest(
352
+ coalesce("p_selected_campaign_ids", '{}'::"text"[])
353
+ ) as "campaign_id"("value")
354
+ where "campaign_id"."value" is null
355
+ or btrim("campaign_id"."value") !~ '^[0-9]+$'
356
+ ) then
357
+ raise exception 'selected campaign ids must contain only Meta campaign ids'
358
+ using errcode = '22023';
359
+ end if;
360
+
361
+ select coalesce(
362
+ array_agg("normalized_campaign_id"."value"
363
+ order by "normalized_campaign_id"."value"),
364
+ '{}'::"text"[]
365
+ )
366
+ into "v_normalized_campaign_ids"
367
+ from (
368
+ select distinct btrim("campaign_id"."value") as "value"
369
+ from unnest(
370
+ coalesce("p_selected_campaign_ids", '{}'::"text"[])
371
+ ) as "campaign_id"("value")
372
+ ) as "normalized_campaign_id";
373
+
374
+ if cardinality("v_normalized_campaign_ids") = 0 then
375
+ raise exception 'select at least one Facebook Ads campaign'
376
+ using errcode = '22023';
377
+ end if;
378
+ end if;
379
+
380
+ select
381
+ "id",
382
+ "campaign_selection_mode",
383
+ "selected_campaign_ids"
384
+ into
385
+ "v_connection_id",
386
+ "v_current_campaign_selection_mode",
387
+ "v_current_selected_campaign_ids"
388
+ from "public"."facebook_ads_connection"
389
+ where "company_id" = "p_company_id"
390
+ and "ad_account_id" = btrim("p_ad_account_id")
391
+ for update;
392
+
393
+ if not found then
394
+ raise exception 'Facebook Ads account selection changed'
395
+ using errcode = '23503';
396
+ end if;
397
+
398
+ "v_selection_changed" :=
399
+ "v_current_campaign_selection_mode"
400
+ is distinct from "v_campaign_selection_mode"
401
+ or "v_current_selected_campaign_ids"
402
+ is distinct from "v_normalized_campaign_ids";
403
+
404
+ if not "v_selection_changed" then
405
+ return false;
406
+ end if;
407
+
408
+ update "public"."facebook_ads_connection"
409
+ set
410
+ "campaign_selection_mode" = "v_campaign_selection_mode",
411
+ "selected_campaign_ids" = "v_normalized_campaign_ids",
412
+ "spend_configuration_version" = "spend_configuration_version" + 1,
413
+ "last_synced_at" = null,
414
+ "backfill_completed_at" = null,
415
+ "last_sync_error" = null
416
+ where "id" = "v_connection_id";
417
+
418
+ delete from "public"."facebook_ads_daily_spend"
419
+ where "connection_id" = "v_connection_id";
420
+
421
+ return true;
422
+ end;
423
+ $$;
424
+
425
+ alter function "public"."set_facebook_ads_campaign_selection"(
426
+ "uuid",
427
+ "text",
428
+ "text",
429
+ "text"[]
430
+ ) owner to "postgres";
431
+
432
+ -- Meta returns spend as a decimal string. Keeping it as text through the API
433
+ -- boundary avoids JavaScript floating-point conversion before PostgreSQL casts
434
+ -- it to the exact numeric column type. A sync captures the spend configuration
435
+ -- version before calling Meta; if the account or campaign selection changes
436
+ -- while that request is running, the stale response returns zero and cannot
437
+ -- repopulate rows deleted by the selection transaction.
438
+ create or replace function "public"."upsert_facebook_ads_daily_spend"(
439
+ "p_company_id" "uuid",
440
+ "p_connection_id" "uuid",
441
+ "p_ad_account_id" "text",
442
+ "p_spend_configuration_version" bigint,
443
+ "p_currency" "text",
444
+ "p_rows" jsonb
445
+ )
446
+ returns integer
447
+ language plpgsql
448
+ set search_path = ''
449
+ as $$
450
+ declare
451
+ "v_row" jsonb;
452
+ "v_rows_upserted" integer;
453
+ begin
454
+ if "p_company_id" is null
455
+ or "p_connection_id" is null
456
+ or nullif("p_ad_account_id", '') is null
457
+ or "p_spend_configuration_version" is null
458
+ or "p_spend_configuration_version" < 0
459
+ then
460
+ raise exception 'company_id, connection_id, ad_account_id, and spend configuration version are required'
461
+ using errcode = '22023';
462
+ end if;
463
+
464
+ if coalesce("p_currency", '') !~ '^[A-Z]{3}$' then
465
+ raise exception 'currency must be a three-letter uppercase code'
466
+ using errcode = '22023';
467
+ end if;
468
+
469
+ if "p_rows" is null or jsonb_typeof("p_rows") <> 'array' then
470
+ raise exception 'rows must be a JSON array'
471
+ using errcode = '22023';
472
+ end if;
473
+
474
+ perform 1
475
+ from "public"."facebook_ads_connection"
476
+ where "company_id" = "p_company_id"
477
+ and "id" = "p_connection_id"
478
+ and "ad_account_id" = "p_ad_account_id"
479
+ and "spend_configuration_version" = "p_spend_configuration_version"
480
+ for update;
481
+
482
+ if not found then
483
+ return 0;
484
+ end if;
485
+
486
+ for "v_row" in
487
+ select "row_value"
488
+ from jsonb_array_elements("p_rows") as "input"("row_value")
489
+ loop
490
+ if jsonb_typeof("v_row") <> 'object'
491
+ or coalesce(jsonb_typeof("v_row" -> 'date'), '') <> 'string'
492
+ or coalesce("v_row" ->> 'date', '') !~ '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'
493
+ or coalesce(jsonb_typeof("v_row" -> 'spend'), '') <> 'string'
494
+ or coalesce("v_row" ->> 'spend', '') !~ '^[0-9]{1,12}([.][0-9]{1,6})?$'
495
+ then
496
+ raise exception 'each spend row must contain a valid date and decimal-string spend'
497
+ using errcode = '22023';
498
+ end if;
499
+
500
+ -- Force date validation before the insert so impossible calendar dates
501
+ -- fail the entire atomic batch.
502
+ perform ("v_row" ->> 'date')::date;
503
+ end loop;
504
+
505
+ insert into "public"."facebook_ads_daily_spend" (
506
+ "company_id",
507
+ "connection_id",
508
+ "date",
509
+ "spend",
510
+ "currency"
511
+ )
512
+ select
513
+ "p_company_id",
514
+ "p_connection_id",
515
+ ("row_value" ->> 'date')::date,
516
+ ("row_value" ->> 'spend')::numeric(18, 6),
517
+ "p_currency"
518
+ from jsonb_array_elements("p_rows") as "input"("row_value")
519
+ on conflict ("connection_id", "date") do update
520
+ set
521
+ "company_id" = excluded."company_id",
522
+ "spend" = excluded."spend",
523
+ "currency" = excluded."currency";
524
+
525
+ get diagnostics "v_rows_upserted" = row_count;
526
+ return "v_rows_upserted";
527
+ end;
528
+ $$;
529
+
530
+ alter function "public"."upsert_facebook_ads_daily_spend"(
531
+ "uuid",
532
+ "uuid",
533
+ "text",
534
+ bigint,
535
+ "text",
536
+ jsonb
537
+ ) owner to "postgres";
538
+
539
+ -- Replace one synchronized date window atomically. Campaign rows are retained
540
+ -- for the breakdown while account-level zero-filled daily totals continue to
541
+ -- power the existing summary report.
542
+ create or replace function "public"."replace_facebook_ads_campaign_daily_spend"(
543
+ "p_company_id" "uuid",
544
+ "p_connection_id" "uuid",
545
+ "p_ad_account_id" "text",
546
+ "p_spend_configuration_version" bigint,
547
+ "p_currency" "text",
548
+ "p_date_from" date,
549
+ "p_date_to" date,
550
+ "p_rows" jsonb
551
+ )
552
+ returns boolean
553
+ language plpgsql
554
+ set search_path = ''
555
+ as $$
556
+ declare
557
+ "v_row" jsonb;
558
+ begin
559
+ if "p_company_id" is null
560
+ or "p_connection_id" is null
561
+ or nullif(btrim("p_ad_account_id"), '') is null
562
+ or "p_spend_configuration_version" is null
563
+ or "p_spend_configuration_version" < 0
564
+ or "p_date_from" is null
565
+ or "p_date_to" is null
566
+ or "p_date_from" > "p_date_to"
567
+ then
568
+ raise exception 'valid connection and date range are required'
569
+ using errcode = '22023';
570
+ end if;
571
+
572
+ if "p_date_to" - "p_date_from" > 89 then
573
+ raise exception 'campaign spend windows cannot exceed 90 days'
574
+ using errcode = '22023';
575
+ end if;
576
+
577
+ if coalesce("p_currency", '') !~ '^[A-Z]{3}$' then
578
+ raise exception 'currency must be a three-letter uppercase code'
579
+ using errcode = '22023';
580
+ end if;
581
+
582
+ if "p_rows" is null or jsonb_typeof("p_rows") <> 'array' then
583
+ raise exception 'rows must be a JSON array' using errcode = '22023';
584
+ end if;
585
+
586
+ perform 1
587
+ from "public"."facebook_ads_connection"
588
+ where "company_id" = "p_company_id"
589
+ and "id" = "p_connection_id"
590
+ and "ad_account_id" = "p_ad_account_id"
591
+ and "spend_configuration_version" = "p_spend_configuration_version"
592
+ for update;
593
+
594
+ if not found then
595
+ return false;
596
+ end if;
597
+
598
+ for "v_row" in
599
+ select "row_value"
600
+ from jsonb_array_elements("p_rows") as "input"("row_value")
601
+ loop
602
+ if jsonb_typeof("v_row") <> 'object'
603
+ or coalesce(jsonb_typeof("v_row" -> 'campaign_id'), '') <> 'string'
604
+ or coalesce("v_row" ->> 'campaign_id', '') !~ '^[0-9]+$'
605
+ or coalesce(jsonb_typeof("v_row" -> 'campaign_name'), '') <> 'string'
606
+ or nullif(btrim("v_row" ->> 'campaign_name'), '') is null
607
+ or coalesce(jsonb_typeof("v_row" -> 'date'), '') <> 'string'
608
+ or coalesce("v_row" ->> 'date', '') !~ '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'
609
+ or coalesce(jsonb_typeof("v_row" -> 'spend'), '') <> 'string'
610
+ or coalesce("v_row" ->> 'spend', '')
611
+ !~ '^[0-9]{1,12}([.][0-9]{1,6})?$'
612
+ then
613
+ raise exception 'each row must contain a valid campaign, date, and spend'
614
+ using errcode = '22023';
615
+ end if;
616
+
617
+ if ("v_row" ->> 'date')::date
618
+ not between "p_date_from" and "p_date_to"
619
+ then
620
+ raise exception 'campaign spend row is outside the requested range'
621
+ using errcode = '22023';
622
+ end if;
623
+ end loop;
624
+
625
+ if exists (
626
+ select 1
627
+ from jsonb_array_elements("p_rows") as "input"("row_value")
628
+ group by
629
+ "row_value" ->> 'campaign_id',
630
+ "row_value" ->> 'date'
631
+ having count(*) > 1
632
+ ) then
633
+ raise exception 'campaign spend rows must be unique by campaign and date'
634
+ using errcode = '22023';
635
+ end if;
636
+
637
+ delete from "public"."facebook_ads_campaign_daily_spend"
638
+ where "connection_id" = "p_connection_id"
639
+ and "date" between "p_date_from" and "p_date_to";
640
+
641
+ insert into "public"."facebook_ads_campaign_daily_spend" (
642
+ "company_id",
643
+ "connection_id",
644
+ "campaign_id",
645
+ "campaign_name",
646
+ "date",
647
+ "spend",
648
+ "currency"
649
+ )
650
+ select
651
+ "p_company_id",
652
+ "p_connection_id",
653
+ "row_value" ->> 'campaign_id',
654
+ btrim("row_value" ->> 'campaign_name'),
655
+ ("row_value" ->> 'date')::date,
656
+ ("row_value" ->> 'spend')::numeric(18, 6),
657
+ "p_currency"
658
+ from jsonb_array_elements("p_rows") as "input"("row_value");
659
+
660
+ insert into "public"."facebook_ads_daily_spend" (
661
+ "company_id",
662
+ "connection_id",
663
+ "date",
664
+ "spend",
665
+ "currency"
666
+ )
667
+ select
668
+ "p_company_id",
669
+ "p_connection_id",
670
+ "date_row"."value"::date,
671
+ coalesce(sum("campaign_spend"."spend"), 0::numeric),
672
+ "p_currency"
673
+ from generate_series(
674
+ "p_date_from"::timestamp without time zone,
675
+ "p_date_to"::timestamp without time zone,
676
+ interval '1 day'
677
+ ) as "date_row"("value")
678
+ left join "public"."facebook_ads_campaign_daily_spend" as "campaign_spend"
679
+ on "campaign_spend"."connection_id" = "p_connection_id"
680
+ and "campaign_spend"."date" = "date_row"."value"::date
681
+ group by "date_row"."value"
682
+ on conflict ("connection_id", "date") do update
683
+ set
684
+ "company_id" = excluded."company_id",
685
+ "spend" = excluded."spend",
686
+ "currency" = excluded."currency";
687
+
688
+ return true;
689
+ end;
690
+ $$;
691
+
692
+ alter function "public"."replace_facebook_ads_campaign_daily_spend"(
693
+ "uuid",
694
+ "uuid",
695
+ "text",
696
+ bigint,
697
+ "text",
698
+ date,
699
+ date,
700
+ jsonb
701
+ ) owner to "postgres";
702
+
703
+ -- Save the selected lead source and its initial attribution name together.
704
+ -- Historical names are reset when the selected source changes so one source
705
+ -- can never inherit aliases belonging to another source.
706
+ create or replace function "public"."set_facebook_ads_source"(
707
+ "p_company_id" "uuid",
708
+ "p_source_id" "uuid"
709
+ )
710
+ returns void
711
+ language plpgsql
712
+ security definer
713
+ set search_path = ''
714
+ as $$
715
+ declare
716
+ "v_source_name" "text";
717
+ begin
718
+ if "p_company_id" is null then
719
+ raise exception 'company_id is required' using errcode = '22023';
720
+ end if;
721
+
722
+ perform pg_advisory_xact_lock(
723
+ hashtextextended("p_company_id"::text || ':facebook-source-name', 0)
724
+ );
725
+
726
+ if "p_source_id" is null then
727
+ insert into "public"."settings_facebook_ads" (
728
+ "company_id",
729
+ "source_id",
730
+ "source_names"
731
+ )
732
+ values ("p_company_id", null, '{}'::"text"[])
733
+ on conflict ("company_id") do update
734
+ set
735
+ "source_id" = null,
736
+ "source_names" = '{}'::"text"[];
737
+ return;
738
+ end if;
739
+
740
+ select "name"
741
+ into "v_source_name"
742
+ from "public"."job_source"
743
+ where "company_id" = "p_company_id"
744
+ and "id" = "p_source_id";
745
+
746
+ if not found then
747
+ raise exception 'Lead source does not belong to this company'
748
+ using errcode = '23503';
749
+ end if;
750
+
751
+ if nullif(btrim("v_source_name"), '') is null then
752
+ raise exception 'Lead source name cannot be blank'
753
+ using errcode = '22023';
754
+ end if;
755
+
756
+ if exists (
757
+ select 1
758
+ from "public"."job_source" as "other_source"
759
+ where "other_source"."company_id" = "p_company_id"
760
+ and "other_source"."id" <> "p_source_id"
761
+ and "other_source"."name" = "v_source_name"
762
+ ) then
763
+ raise exception 'Lead source name is not unique within this company'
764
+ using
765
+ errcode = '23505',
766
+ constraint = 'facebook_ads_source_name_unambiguous';
767
+ end if;
768
+
769
+ insert into "public"."settings_facebook_ads" (
770
+ "company_id",
771
+ "source_id",
772
+ "source_names"
773
+ )
774
+ values ("p_company_id", "p_source_id", array["v_source_name"])
775
+ on conflict ("company_id") do update
776
+ set
777
+ "source_id" = excluded."source_id",
778
+ "source_names" = case
779
+ when "settings_facebook_ads"."source_id" = excluded."source_id" then
780
+ array(
781
+ select distinct "candidate"."value"
782
+ from unnest(
783
+ "settings_facebook_ads"."source_names"
784
+ || excluded."source_names"
785
+ ) as "candidate"("value")
786
+ where nullif(btrim("candidate"."value"), '') is not null
787
+ order by "candidate"."value"
788
+ )
789
+ else excluded."source_names"
790
+ end;
791
+ end;
792
+ $$;
793
+
794
+ alter function "public"."set_facebook_ads_source"("uuid", "uuid")
795
+ owner to "postgres";
796
+
797
+ -- Supabase's generated TypeScript types cannot represent nullable RPC
798
+ -- arguments. Expose explicit clear operations so callers remain fully typed
799
+ -- while the existing transactional account and lead-source logic is reused.
800
+ create or replace function "public"."clear_facebook_ads_selected_account"(
801
+ "p_company_id" "uuid"
802
+ )
803
+ returns boolean
804
+ language plpgsql
805
+ security definer
806
+ set search_path = ''
807
+ as $$
808
+ begin
809
+ return "public"."set_facebook_ads_selected_account"(
810
+ "p_company_id",
811
+ null,
812
+ null,
813
+ null,
814
+ null,
815
+ null,
816
+ null
817
+ );
818
+ end;
819
+ $$;
820
+
821
+ alter function "public"."clear_facebook_ads_selected_account"("uuid")
822
+ owner to "postgres";
823
+
824
+ create or replace function "public"."clear_facebook_ads_source"(
825
+ "p_company_id" "uuid"
826
+ )
827
+ returns void
828
+ language plpgsql
829
+ security definer
830
+ set search_path = ''
831
+ as $$
832
+ begin
833
+ perform "public"."set_facebook_ads_source"(
834
+ "p_company_id",
835
+ null
836
+ );
837
+ end;
838
+ $$;
839
+
840
+ alter function "public"."clear_facebook_ads_source"("uuid")
841
+ owner to "postgres";
842
+
843
+ -- Protect historical source-name attribution at mutation time. The advisory
844
+ -- lock matches the selector RPC so source selection and source creation or
845
+ -- renaming cannot race one another.
846
+ create or replace function "public"."prevent_facebook_ads_source_name_collision"()
847
+ returns trigger
848
+ language plpgsql
849
+ security definer
850
+ set search_path = ''
851
+ as $$
852
+ declare
853
+ "v_selected_source_id" "uuid";
854
+ "v_selected_source_names" "text"[];
855
+ "v_selected_current_name" "text";
856
+ begin
857
+ perform pg_advisory_xact_lock(
858
+ hashtextextended(new."company_id"::text || ':facebook-source-name', 0)
859
+ );
860
+
861
+ select
862
+ "settings"."source_id",
863
+ "settings"."source_names",
864
+ "selected_source"."name"
865
+ into
866
+ "v_selected_source_id",
867
+ "v_selected_source_names",
868
+ "v_selected_current_name"
869
+ from "public"."settings_facebook_ads" as "settings"
870
+ left join "public"."job_source" as "selected_source"
871
+ on "selected_source"."company_id" = "settings"."company_id"
872
+ and "selected_source"."id" = "settings"."source_id"
873
+ where "settings"."company_id" = new."company_id";
874
+
875
+ if "v_selected_source_id" is null then
876
+ return new;
877
+ end if;
878
+
879
+ "v_selected_source_names" :=
880
+ coalesce("v_selected_source_names", '{}'::"text"[])
881
+ || array["v_selected_current_name"];
882
+
883
+ if new."id" = "v_selected_source_id" then
884
+ if nullif(btrim(new."name"), '') is null then
885
+ raise exception 'Selected Facebook Ads lead source name cannot be blank'
886
+ using errcode = '22023';
887
+ end if;
888
+
889
+ if exists (
890
+ select 1
891
+ from "public"."job_source" as "other_source"
892
+ where "other_source"."company_id" = new."company_id"
893
+ and "other_source"."id" <> new."id"
894
+ and "other_source"."name" = new."name"
895
+ ) then
896
+ raise exception 'Lead source name conflicts with Facebook Ads attribution'
897
+ using
898
+ errcode = '23505',
899
+ constraint = 'facebook_ads_source_name_unambiguous';
900
+ end if;
901
+ elsif new."name" = any("v_selected_source_names") then
902
+ raise exception 'Lead source name conflicts with Facebook Ads attribution'
903
+ using
904
+ errcode = '23505',
905
+ constraint = 'facebook_ads_source_name_unambiguous';
906
+ end if;
907
+
908
+ return new;
909
+ end;
910
+ $$;
911
+
912
+ alter function "public"."prevent_facebook_ads_source_name_collision"()
913
+ owner to "postgres";
914
+
915
+ create or replace trigger "prevent_facebook_ads_source_name_collision_trigger"
916
+ before insert or update of "name" on "public"."job_source"
917
+ for each row
918
+ execute function "public"."prevent_facebook_ads_source_name_collision"();
919
+
920
+ -- Preserve exact historical names for the currently selected source. Jobs
921
+ -- store the source name rather than source id, so this keeps older jobs
922
+ -- attributable after a source rename.
923
+ create or replace function "public"."append_facebook_ads_source_name_on_rename"()
924
+ returns trigger
925
+ language plpgsql
926
+ security definer
927
+ set search_path = ''
928
+ as $$
929
+ begin
930
+ update "public"."settings_facebook_ads" as "settings"
931
+ set "source_names" = array(
932
+ select distinct "candidate"."value"
933
+ from unnest(
934
+ coalesce("settings"."source_names", '{}'::"text"[])
935
+ || array[old."name", new."name"]
936
+ ) as "candidate"("value")
937
+ where nullif(btrim("candidate"."value"), '') is not null
938
+ order by "candidate"."value"
939
+ )
940
+ where "settings"."company_id" = new."company_id"
941
+ and "settings"."source_id" = new."id";
942
+
943
+ return new;
944
+ end;
945
+ $$;
946
+
947
+ alter function "public"."append_facebook_ads_source_name_on_rename"()
948
+ owner to "postgres";
949
+
950
+ create or replace trigger "append_facebook_ads_source_name_on_rename_trigger"
951
+ after update of "name" on "public"."job_source"
952
+ for each row
953
+ when (old."name" is distinct from new."name")
954
+ execute function "public"."append_facebook_ads_source_name_on_rename"();
955
+
956
+ -- Build all dashboard aggregates in PostgreSQL. This avoids PostgREST row
957
+ -- limits and guarantees each job is counted once by its earliest non-canceled
958
+ -- schedule in the company's local calendar range.
959
+ create or replace function "public"."get_facebook_ads_report"(
960
+ "p_company_id" "uuid",
961
+ "p_date_from" date,
962
+ "p_date_to" date
963
+ )
964
+ returns table(
965
+ "currency" "text",
966
+ "total_ad_spend" numeric,
967
+ "total_sales" numeric,
968
+ "client_count" bigint,
969
+ "source_attribution_ambiguous" boolean
970
+ )
971
+ language plpgsql
972
+ stable
973
+ security definer
974
+ set search_path = ''
975
+ as $$
976
+ declare
977
+ "v_timezone_name" "text";
978
+ "v_date_from_utc" timestamp with time zone;
979
+ "v_date_to_utc" timestamp with time zone;
980
+ "v_source_id" "uuid";
981
+ "v_source_names" "text"[];
982
+ "v_current_source_name" "text";
983
+ "v_attribution_names" "text"[];
984
+ begin
985
+ if "p_company_id" is null
986
+ or "p_date_from" is null
987
+ or "p_date_to" is null
988
+ or "p_date_from" > "p_date_to"
989
+ then
990
+ raise exception 'company_id and a valid date range are required'
991
+ using errcode = '22023';
992
+ end if;
993
+
994
+ select coalesce(nullif("company_row"."time_zone", ''), 'America/Chicago')
995
+ into "v_timezone_name"
996
+ from "public"."company" as "company_row"
997
+ where "company_row"."id" = "p_company_id";
998
+
999
+ if not found then
1000
+ raise exception 'Company does not exist' using errcode = '23503';
1001
+ end if;
1002
+
1003
+ "v_date_from_utc" := timezone(
1004
+ "v_timezone_name",
1005
+ "p_date_from"::timestamp without time zone
1006
+ );
1007
+ "v_date_to_utc" := timezone(
1008
+ "v_timezone_name",
1009
+ ("p_date_to" + 1)::timestamp without time zone
1010
+ );
1011
+
1012
+ select "connection"."currency"
1013
+ into "currency"
1014
+ from "public"."facebook_ads_connection" as "connection"
1015
+ where "connection"."company_id" = "p_company_id"
1016
+ and "connection"."ad_account_id" is not null
1017
+ and "connection"."backfill_completed_at" is not null
1018
+ and upper("connection"."currency") = 'USD';
1019
+
1020
+ if not found then
1021
+ raise exception 'Facebook Ads connection is not report-ready'
1022
+ using errcode = '55000';
1023
+ end if;
1024
+
1025
+ select coalesce(sum("daily_spend"."spend"), 0::numeric)
1026
+ into "total_ad_spend"
1027
+ from "public"."facebook_ads_daily_spend" as "daily_spend"
1028
+ where "daily_spend"."company_id" = "p_company_id"
1029
+ and "daily_spend"."date" between "p_date_from" and "p_date_to";
1030
+
1031
+ "total_sales" := 0::numeric;
1032
+ "client_count" := 0::bigint;
1033
+ "source_attribution_ambiguous" := false;
1034
+
1035
+ select
1036
+ "settings"."source_id",
1037
+ "settings"."source_names",
1038
+ "source"."name"
1039
+ into
1040
+ "v_source_id",
1041
+ "v_source_names",
1042
+ "v_current_source_name"
1043
+ from "public"."settings_facebook_ads" as "settings"
1044
+ left join "public"."job_source" as "source"
1045
+ on "source"."company_id" = "settings"."company_id"
1046
+ and "source"."id" = "settings"."source_id"
1047
+ where "settings"."company_id" = "p_company_id";
1048
+
1049
+ if "v_source_id" is null then
1050
+ return next;
1051
+ return;
1052
+ end if;
1053
+
1054
+ select coalesce(array_agg("alias_row"."name" order by "alias_row"."name"), '{}'::"text"[])
1055
+ into "v_attribution_names"
1056
+ from (
1057
+ select distinct "candidate"."value" as "name"
1058
+ from unnest(
1059
+ coalesce("v_source_names", '{}'::"text"[])
1060
+ || array["v_current_source_name"]
1061
+ ) as "candidate"("value")
1062
+ where nullif(btrim("candidate"."value"), '') is not null
1063
+ ) as "alias_row";
1064
+
1065
+ if cardinality("v_attribution_names") = 0 then
1066
+ return next;
1067
+ return;
1068
+ end if;
1069
+
1070
+ select exists (
1071
+ select 1
1072
+ from "public"."job_source" as "other_source"
1073
+ where "other_source"."company_id" = "p_company_id"
1074
+ and "other_source"."id" <> "v_source_id"
1075
+ and "other_source"."name" = any("v_attribution_names")
1076
+ )
1077
+ into "source_attribution_ambiguous";
1078
+
1079
+ if "source_attribution_ambiguous" then
1080
+ return next;
1081
+ return;
1082
+ end if;
1083
+
1084
+ with "earliest_schedule" as (
1085
+ select
1086
+ "schedule"."job_id",
1087
+ min("schedule"."start_time") as "start_time"
1088
+ from "public"."job_schedule" as "schedule"
1089
+ where "schedule"."company_id" = "p_company_id"
1090
+ and "schedule"."status" <> 'Canceled'::"public"."job_status_enum"
1091
+ group by "schedule"."job_id"
1092
+ ),
1093
+ "eligible_job" as (
1094
+ select "job_row"."id"
1095
+ from "public"."job" as "job_row"
1096
+ inner join "earliest_schedule"
1097
+ on "earliest_schedule"."job_id" = "job_row"."id"
1098
+ where "job_row"."company_id" = "p_company_id"
1099
+ and "earliest_schedule"."start_time" >= "v_date_from_utc"
1100
+ and "earliest_schedule"."start_time" < "v_date_to_utc"
1101
+ and "job_row"."job_source" = any("v_attribution_names")
1102
+ )
1103
+ select coalesce(sum("job_item"."item_price" * "job_item"."quantity"), 0::numeric)
1104
+ into "total_sales"
1105
+ from "eligible_job"
1106
+ inner join "public"."job_item" as "job_item"
1107
+ on "job_item"."company_id" = "p_company_id"
1108
+ and "job_item"."job_id" = "eligible_job"."id";
1109
+
1110
+ select count(*)
1111
+ into "client_count"
1112
+ from "public"."client" as "client_row"
1113
+ where "client_row"."company_id" = "p_company_id"
1114
+ and "client_row"."source_id" = "v_source_id"
1115
+ and "client_row"."client_or_lead" = 'client'::"public"."client_or_lead_enum"
1116
+ and "client_row"."created_at" >= "v_date_from_utc"
1117
+ and "client_row"."created_at" < "v_date_to_utc";
1118
+
1119
+ return next;
1120
+ end;
1121
+ $$;
1122
+
1123
+ alter function "public"."get_facebook_ads_report"("uuid", date, date)
1124
+ owner to "postgres";
1125
+
1126
+ -- These indexes support the report's company-scoped earliest-schedule, item,
1127
+ -- and client attribution scans. They are added once with the feature schema.
1128
+ create index if not exists "facebook_ads_job_schedule_report_idx"
1129
+ on "public"."job_schedule" ("company_id", "job_id", "start_time")
1130
+ where "status" <> 'Canceled'::"public"."job_status_enum";
1131
+
1132
+ create index if not exists "facebook_ads_job_item_report_idx"
1133
+ on "public"."job_item" ("company_id", "job_id");
1134
+
1135
+ create index if not exists "facebook_ads_client_report_idx"
1136
+ on "public"."client" (
1137
+ "company_id",
1138
+ "source_id",
1139
+ "client_or_lead",
1140
+ "created_at"
1141
+ );
1142
+
1143
+ create or replace function "public"."get_facebook_ads_campaign_spend_breakdown"(
1144
+ "p_company_id" "uuid",
1145
+ "p_date_from" date,
1146
+ "p_date_to" date
1147
+ )
1148
+ returns table (
1149
+ "campaign_id" "text",
1150
+ "campaign_name" "text",
1151
+ "total_spend" numeric
1152
+ )
1153
+ language sql
1154
+ stable
1155
+ security definer
1156
+ set search_path = ''
1157
+ as $$
1158
+ select
1159
+ "campaign_spend"."campaign_id",
1160
+ (array_agg(
1161
+ "campaign_spend"."campaign_name"
1162
+ order by
1163
+ "campaign_spend"."date" desc,
1164
+ "campaign_spend"."updated_at" desc
1165
+ ))[1] as "campaign_name",
1166
+ coalesce(sum("campaign_spend"."spend"), 0::numeric) as "total_spend"
1167
+ from "public"."facebook_ads_campaign_daily_spend" as "campaign_spend"
1168
+ where "campaign_spend"."company_id" = "p_company_id"
1169
+ and "campaign_spend"."date" between "p_date_from" and "p_date_to"
1170
+ group by "campaign_spend"."campaign_id"
1171
+ order by "total_spend" desc, "campaign_name", "campaign_id";
1172
+ $$;
1173
+
1174
+ alter function "public"."get_facebook_ads_campaign_spend_breakdown"(
1175
+ "uuid",
1176
+ date,
1177
+ date
1178
+ ) owner to "postgres";
1179
+
1180
+ create or replace function "public"."get_facebook_ads_job_sales_breakdown"(
1181
+ "p_company_id" "uuid",
1182
+ "p_date_from" date,
1183
+ "p_date_to" date,
1184
+ "p_limit" integer default 25,
1185
+ "p_offset" integer default 0
1186
+ )
1187
+ returns table (
1188
+ "job_id" "uuid",
1189
+ "job_number" integer,
1190
+ "scheduled_at" timestamp with time zone,
1191
+ "client_id" "uuid",
1192
+ "client_name" "text",
1193
+ "lead_source" "text",
1194
+ "sales" numeric,
1195
+ "total_count" bigint
1196
+ )
1197
+ language plpgsql
1198
+ stable
1199
+ security definer
1200
+ set search_path = ''
1201
+ as $$
1202
+ declare
1203
+ "v_timezone_name" "text";
1204
+ "v_date_from_utc" timestamp with time zone;
1205
+ "v_date_to_utc" timestamp with time zone;
1206
+ "v_source_id" "uuid";
1207
+ "v_source_names" "text"[];
1208
+ "v_current_source_name" "text";
1209
+ "v_attribution_names" "text"[];
1210
+ begin
1211
+ if "p_company_id" is null
1212
+ or "p_date_from" is null
1213
+ or "p_date_to" is null
1214
+ or "p_date_from" > "p_date_to"
1215
+ or "p_limit" not between 1 and 100
1216
+ or "p_offset" < 0
1217
+ then
1218
+ raise exception 'company, date range, and pagination are invalid'
1219
+ using errcode = '22023';
1220
+ end if;
1221
+
1222
+ select coalesce(nullif("company_row"."time_zone", ''), 'America/Chicago')
1223
+ into "v_timezone_name"
1224
+ from "public"."company" as "company_row"
1225
+ where "company_row"."id" = "p_company_id";
1226
+
1227
+ if not found then
1228
+ raise exception 'Company does not exist' using errcode = '23503';
1229
+ end if;
1230
+
1231
+ "v_date_from_utc" := timezone(
1232
+ "v_timezone_name",
1233
+ "p_date_from"::timestamp without time zone
1234
+ );
1235
+ "v_date_to_utc" := timezone(
1236
+ "v_timezone_name",
1237
+ ("p_date_to" + 1)::timestamp without time zone
1238
+ );
1239
+
1240
+ select
1241
+ "settings"."source_id",
1242
+ "settings"."source_names",
1243
+ "source"."name"
1244
+ into
1245
+ "v_source_id",
1246
+ "v_source_names",
1247
+ "v_current_source_name"
1248
+ from "public"."settings_facebook_ads" as "settings"
1249
+ left join "public"."job_source" as "source"
1250
+ on "source"."company_id" = "settings"."company_id"
1251
+ and "source"."id" = "settings"."source_id"
1252
+ where "settings"."company_id" = "p_company_id";
1253
+
1254
+ if "v_source_id" is null then
1255
+ return;
1256
+ end if;
1257
+
1258
+ select coalesce(array_agg("alias_row"."name" order by "alias_row"."name"), '{}'::"text"[])
1259
+ into "v_attribution_names"
1260
+ from (
1261
+ select distinct "candidate"."value" as "name"
1262
+ from unnest(
1263
+ coalesce("v_source_names", '{}'::"text"[])
1264
+ || array["v_current_source_name"]
1265
+ ) as "candidate"("value")
1266
+ where nullif(btrim("candidate"."value"), '') is not null
1267
+ ) as "alias_row";
1268
+
1269
+ return query
1270
+ with "earliest_schedule" as (
1271
+ select
1272
+ "schedule"."job_id",
1273
+ min("schedule"."start_time") as "start_time"
1274
+ from "public"."job_schedule" as "schedule"
1275
+ where "schedule"."company_id" = "p_company_id"
1276
+ and "schedule"."status" <> 'Canceled'::"public"."job_status_enum"
1277
+ group by "schedule"."job_id"
1278
+ ),
1279
+ "job_sales" as (
1280
+ select
1281
+ "job_row"."id" as "job_id",
1282
+ "job_row"."job_number",
1283
+ "earliest_schedule"."start_time" as "scheduled_at",
1284
+ "client_row"."id" as "client_id",
1285
+ coalesce(
1286
+ nullif(btrim("client_row"."client_company_name"), ''),
1287
+ nullif(btrim(concat_ws(
1288
+ ' ',
1289
+ "client_row"."first_name",
1290
+ "client_row"."last_name"
1291
+ )), ''),
1292
+ 'Unknown client'
1293
+ ) as "client_name",
1294
+ "job_row"."job_source" as "lead_source",
1295
+ coalesce(sum(
1296
+ "job_item"."item_price" * "job_item"."quantity"
1297
+ ), 0::numeric) as "sales"
1298
+ from "public"."job" as "job_row"
1299
+ inner join "earliest_schedule"
1300
+ on "earliest_schedule"."job_id" = "job_row"."id"
1301
+ inner join "public"."client" as "client_row"
1302
+ on "client_row"."company_id" = "p_company_id"
1303
+ and "client_row"."id" = "job_row"."client_id"
1304
+ left join "public"."job_item" as "job_item"
1305
+ on "job_item"."company_id" = "p_company_id"
1306
+ and "job_item"."job_id" = "job_row"."id"
1307
+ where "job_row"."company_id" = "p_company_id"
1308
+ and "earliest_schedule"."start_time" >= "v_date_from_utc"
1309
+ and "earliest_schedule"."start_time" < "v_date_to_utc"
1310
+ and "job_row"."job_source" = any("v_attribution_names")
1311
+ group by
1312
+ "job_row"."id",
1313
+ "job_row"."job_number",
1314
+ "earliest_schedule"."start_time",
1315
+ "client_row"."id",
1316
+ "client_row"."client_company_name",
1317
+ "client_row"."first_name",
1318
+ "client_row"."last_name",
1319
+ "job_row"."job_source"
1320
+ )
1321
+ select
1322
+ "job_sales"."job_id",
1323
+ "job_sales"."job_number",
1324
+ "job_sales"."scheduled_at",
1325
+ "job_sales"."client_id",
1326
+ "job_sales"."client_name",
1327
+ "job_sales"."lead_source",
1328
+ "job_sales"."sales",
1329
+ count(*) over() as "total_count"
1330
+ from "job_sales"
1331
+ order by "job_sales"."scheduled_at" desc, "job_sales"."job_number" desc
1332
+ limit "p_limit"
1333
+ offset "p_offset";
1334
+ end;
1335
+ $$;
1336
+
1337
+ alter function "public"."get_facebook_ads_job_sales_breakdown"(
1338
+ "uuid",
1339
+ date,
1340
+ date,
1341
+ integer,
1342
+ integer
1343
+ ) owner to "postgres";
1344
+
1345
+ -- Issuing the report, campaign, and job queries as three separate RPC calls
1346
+ -- would let a sync commit between them and mix database snapshots. Because
1347
+ -- this function is STABLE, every query it runs — including the STABLE report
1348
+ -- functions it calls — uses the single snapshot of the calling statement, so
1349
+ -- the aggregate totals, campaign rows, and attributed jobs are always
1350
+ -- mutually consistent.
1351
+ create or replace function "public"."get_facebook_ads_breakdown"(
1352
+ "p_company_id" "uuid",
1353
+ "p_date_from" date,
1354
+ "p_date_to" date,
1355
+ "p_limit" integer default 25,
1356
+ "p_offset" integer default 0
1357
+ )
1358
+ returns jsonb
1359
+ language plpgsql
1360
+ stable
1361
+ security definer
1362
+ set search_path = ''
1363
+ as $$
1364
+ declare
1365
+ "v_report" jsonb;
1366
+ "v_campaigns" jsonb;
1367
+ "v_jobs" jsonb;
1368
+ begin
1369
+ select to_jsonb("report_row")
1370
+ into "v_report"
1371
+ from "public"."get_facebook_ads_report"(
1372
+ "p_company_id",
1373
+ "p_date_from",
1374
+ "p_date_to"
1375
+ ) as "report_row";
1376
+
1377
+ select coalesce(jsonb_agg(to_jsonb("campaign_row")), '[]'::jsonb)
1378
+ into "v_campaigns"
1379
+ from "public"."get_facebook_ads_campaign_spend_breakdown"(
1380
+ "p_company_id",
1381
+ "p_date_from",
1382
+ "p_date_to"
1383
+ ) as "campaign_row";
1384
+
1385
+ select coalesce(jsonb_agg(to_jsonb("job_row")), '[]'::jsonb)
1386
+ into "v_jobs"
1387
+ from "public"."get_facebook_ads_job_sales_breakdown"(
1388
+ "p_company_id",
1389
+ "p_date_from",
1390
+ "p_date_to",
1391
+ "p_limit",
1392
+ "p_offset"
1393
+ ) as "job_row";
1394
+
1395
+ return jsonb_build_object(
1396
+ 'report', "v_report",
1397
+ 'campaigns', "v_campaigns",
1398
+ 'jobs', "v_jobs"
1399
+ );
1400
+ end;
1401
+ $$;
1402
+
1403
+ alter function "public"."get_facebook_ads_breakdown"(
1404
+ "uuid",
1405
+ date,
1406
+ date,
1407
+ integer,
1408
+ integer
1409
+ ) owner to "postgres";
1410
+
1411
+ -- A lead source can represent one ad platform at a time. The advisory lock
1412
+ -- closes the cross-table race where Google and Facebook settings are updated
1413
+ -- concurrently for the same company and source.
1414
+ create or replace function "public"."prevent_duplicate_ads_source_assignment"()
1415
+ returns trigger
1416
+ language plpgsql
1417
+ security definer
1418
+ set search_path = ''
1419
+ as $$
1420
+ begin
1421
+ if new."source_id" is null then
1422
+ return new;
1423
+ end if;
1424
+
1425
+ perform pg_advisory_xact_lock(
1426
+ hashtextextended(
1427
+ new."company_id"::text || ':' || new."source_id"::text,
1428
+ 0
1429
+ )
1430
+ );
1431
+
1432
+ if tg_table_name = 'settings_facebook_ads' then
1433
+ if exists (
1434
+ select 1
1435
+ from "public"."settings_google_ads"
1436
+ where "company_id" = new."company_id"
1437
+ and "source_id" = new."source_id"
1438
+ ) then
1439
+ raise exception 'Lead source is already assigned to Google Ads'
1440
+ using
1441
+ errcode = '23505',
1442
+ constraint = 'ads_source_platform_unique';
1443
+ end if;
1444
+ elsif tg_table_name = 'settings_google_ads' then
1445
+ if exists (
1446
+ select 1
1447
+ from "public"."settings_facebook_ads"
1448
+ where "company_id" = new."company_id"
1449
+ and "source_id" = new."source_id"
1450
+ ) then
1451
+ raise exception 'Lead source is already assigned to Facebook Ads'
1452
+ using
1453
+ errcode = '23505',
1454
+ constraint = 'ads_source_platform_unique';
1455
+ end if;
1456
+ else
1457
+ raise exception 'Unsupported ads settings table'
1458
+ using errcode = '55000';
1459
+ end if;
1460
+
1461
+ return new;
1462
+ end;
1463
+ $$;
1464
+
1465
+ alter function "public"."prevent_duplicate_ads_source_assignment"()
1466
+ owner to "postgres";
1467
+
1468
+ create or replace trigger "prevent_duplicate_facebook_ads_source_trigger"
1469
+ before insert or update of "source_id" on "public"."settings_facebook_ads"
1470
+ for each row
1471
+ execute function "public"."prevent_duplicate_ads_source_assignment"();
1472
+
1473
+ create or replace trigger "prevent_duplicate_google_ads_source_trigger"
1474
+ before insert or update of "source_id" on "public"."settings_google_ads"
1475
+ for each row
1476
+ execute function "public"."prevent_duplicate_ads_source_assignment"();
1477
+
1478
+ -- Account changes and campaign-selection changes increment the spend
1479
+ -- configuration version. Clear the campaign cache in the same transaction and
1480
+ -- mark its historical import incomplete whenever that version changes.
1481
+ create or replace function "public"."reset_facebook_ads_campaign_breakdown"()
1482
+ returns trigger
1483
+ language plpgsql
1484
+ security definer
1485
+ set search_path = ''
1486
+ as $$
1487
+ begin
1488
+ if "old"."ad_account_id" is distinct from "new"."ad_account_id"
1489
+ or "old"."spend_configuration_version"
1490
+ is distinct from "new"."spend_configuration_version"
1491
+ then
1492
+ delete from "public"."facebook_ads_campaign_daily_spend"
1493
+ where "connection_id" = "old"."id";
1494
+ "new"."campaign_breakdown_backfill_completed_at" := null;
1495
+ end if;
1496
+
1497
+ return "new";
1498
+ end;
1499
+ $$;
1500
+
1501
+ alter function "public"."reset_facebook_ads_campaign_breakdown"()
1502
+ owner to "postgres";
1503
+
1504
+ create or replace trigger "reset_facebook_ads_campaign_breakdown_trigger"
1505
+ before update of "ad_account_id", "spend_configuration_version"
1506
+ on "public"."facebook_ads_connection"
1507
+ for each row execute function "public"."reset_facebook_ads_campaign_breakdown"();
1508
+
1509
+ create or replace function "public"."set_facebook_ads_updated_at"()
1510
+ returns trigger
1511
+ language plpgsql
1512
+ as $$
1513
+ begin
1514
+ new."updated_at" = "now"();
1515
+ return new;
1516
+ end;
1517
+ $$;
1518
+
1519
+ alter function "public"."set_facebook_ads_updated_at"() owner to "postgres";
1520
+
1521
+ create or replace trigger "set_facebook_ads_connection_updated_at_trigger"
1522
+ before update on "public"."facebook_ads_connection"
1523
+ for each row
1524
+ execute function "public"."set_facebook_ads_updated_at"();
1525
+
1526
+ create or replace trigger "set_settings_facebook_ads_updated_at_trigger"
1527
+ before update on "public"."settings_facebook_ads"
1528
+ for each row
1529
+ execute function "public"."set_facebook_ads_updated_at"();
1530
+
1531
+ create or replace trigger "set_facebook_ads_daily_spend_updated_at_trigger"
1532
+ before update on "public"."facebook_ads_daily_spend"
1533
+ for each row
1534
+ execute function "public"."set_facebook_ads_updated_at"();
1535
+
1536
+ create or replace trigger "set_facebook_ads_campaign_daily_spend_updated_at_trigger"
1537
+ before update on "public"."facebook_ads_campaign_daily_spend"
1538
+ for each row execute function "public"."set_facebook_ads_updated_at"();