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.
- package/README.md +53 -0
- package/dist/Provider.d.ts +21 -0
- package/dist/Provider.d.ts.map +1 -0
- package/dist/Provider.js +61 -0
- package/dist/Provider.js.map +1 -0
- package/dist/dist/Provider.d.ts +21 -0
- package/dist/dist/Provider.d.ts.map +1 -0
- package/dist/dist/Provider.js +61 -0
- package/dist/dist/Provider.js.map +1 -0
- package/dist/dist/index.d.ts +45 -0
- package/dist/dist/index.d.ts.map +1 -0
- package/dist/dist/index.js +61 -0
- package/dist/dist/index.js.map +1 -0
- package/dist/dist/interfaces/index.d.ts +1238 -0
- package/dist/dist/interfaces/index.d.ts.map +1 -0
- package/dist/dist/interfaces/index.js +3 -0
- package/dist/dist/interfaces/index.js.map +1 -0
- package/dist/dist/migrations/20260608222757_remote_schema.sql +5666 -0
- package/dist/dist/migrations/20260611174826_add_job_item_recurring_id_to_job_item.sql +7 -0
- package/dist/dist/migrations/20260625224612_add_dashboard_guided_tour_dismissed_to_settings_user.sql +5 -0
- package/dist/dist/migrations/20260627031433_support_chat_tables.sql +115 -0
- package/dist/dist/migrations/20260627031434_support_chat_rls.sql +37 -0
- package/dist/dist/migrations/20260704170209_add_estimate_scheduling.sql +121 -0
- package/dist/dist/migrations/20260704170210_add_estimate_scheduling_rls.sql +42 -0
- package/dist/dist/migrations/20260704235034_add_estimate_reminder_settings.sql +11 -0
- package/dist/dist/migrations/20260707003825_blocked_number_table.sql +32 -0
- package/dist/dist/migrations/20260707003826_blocked_number_rls.sql +22 -0
- package/dist/dist/migrations/20260709191055_sms_opt_out_table.sql +38 -0
- package/dist/dist/migrations/20260709191056_sms_opt_out_rls.sql +21 -0
- package/dist/dist/migrations/20260709214507_job_time_entry_table.sql +70 -0
- package/dist/dist/migrations/20260709214508_job_time_entry_rls.sql +21 -0
- package/dist/dist/migrations/20260711185956_phone_call_table.sql +99 -0
- package/dist/dist/migrations/20260711185957_phone_call_rls.sql +25 -0
- package/dist/dist/migrations/20260712014705_ai_voice_assistant_settings.sql +71 -0
- package/dist/dist/migrations/20260712014706_ai_voice_assistant_settings_rls.sql +14 -0
- package/dist/dist/migrations/20260712014707_ai_prompt_templates.sql +28 -0
- package/dist/dist/migrations/20260712014708_ai_prompt_templates_rls.sql +5 -0
- package/dist/dist/migrations/20260712014709_ai_prompt_templates_seed.sql +77 -0
- package/dist/dist/migrations/20260715011550_reminder_dispatch_table.sql +47 -0
- package/dist/dist/migrations/20260715011551_reminder_dispatch_rls.sql +22 -0
- package/dist/dist/migrations/20260715192923_dedup_sequence_contact_add_unique_constraint.sql +27 -0
- package/dist/dist/migrations/20260716194420_add_employee_location_tracking.sql +146 -0
- package/dist/dist/migrations/20260716194421_add_employee_location_tracking_rls.sql +154 -0
- package/dist/dist/migrations/20260716194422_get_client_map_last_completed_jobs.sql +28 -0
- package/dist/dist/migrations/20260717144535_add_blast_email_invalid_skipped_count.sql +2 -0
- package/dist/dist/migrations/20260717162900_create_blast_email_chunk.sql +36 -0
- package/dist/dist/migrations/20260717162901_add_blast_email_chunk_rls.sql +5 -0
- package/dist/dist/migrations/20260717162902_add_blast_email_chunk_progress_columns.sql +3 -0
- package/dist/dist/migrations/20260717162903_add_blast_email_bounce_tracking_columns.sql +4 -0
- package/dist/dist/migrations/20260717162904_create_email_hard_bounced.sql +23 -0
- package/dist/dist/migrations/20260717162905_add_email_hard_bounced_rls.sql +5 -0
- package/dist/dist/migrations/20260717164837_add_sequence_contact_sent_at.sql +19 -0
- package/dist/dist/migrations/20260717170920_add_sequence_contact_claim_index.sql +12 -0
- package/dist/dist/migrations/20260719215139_create_outbound_event.sql +59 -0
- package/dist/dist/migrations/20260719215140_create_outbound_event_rls.sql +16 -0
- package/dist/dist/migrations/20260719215141_create_webhook_delivery.sql +99 -0
- package/dist/dist/migrations/20260719215142_create_webhook_delivery_rls.sql +11 -0
- package/dist/dist/migrations/20260719215143_outbound_event_triggers.sql +219 -0
- package/dist/dist/migrations/20260719215144_create_api_key.sql +34 -0
- package/dist/dist/migrations/20260719215146_create_api_key_rls.sql +12 -0
- package/dist/dist/migrations/20260719215147_webhook_subscription_add_secret_active.sql +28 -0
- package/dist/dist/migrations/20260719215148_api_aggregate_create_functions.sql +479 -0
- package/dist/dist/migrations/20260721174837_webhook_subscription_generic_endpoints.sql +41 -0
- package/dist/dist/migrations/20260721185631_webhook_outbox_retention.sql +87 -0
- package/dist/dist/migrations/20260721190304_create_qb_sync_task.sql +120 -0
- package/dist/dist/migrations/20260721190306_qb_sync_task_rls.sql +8 -0
- package/dist/dist/migrations/20260721190307_qb_mapping_orphan_fks.sql +29 -0
- package/dist/dist/migrations/20260721190308_qb_task_retention.sql +90 -0
- package/dist/dist/migrations/20260721234401_create_permission_role.sql +83 -0
- package/dist/dist/migrations/20260721234402_permission_role_rls.sql +22 -0
- package/dist/dist/migrations/20260721234403_user_role_add_permission_role_id.sql +12 -0
- package/dist/dist/migrations/20260721234404_seed_permission_roles.sql +100 -0
- package/dist/dist/migrations/20260721234405_backfill_user_role_permission_role_id.sql +20 -0
- package/dist/dist/migrations/20260722193800_permission_role_add_manage_employees.sql +56 -0
- package/dist/dist/migrations/20260723025606_staging_new_employee_company_read_rls.sql +10 -0
- package/dist/dist/migrations/20260723134328_create_google_lsa_integration.sql +1016 -0
- package/dist/dist/migrations/20260723134329_google_lsa_integration_rls.sql +205 -0
- package/dist/dist/migrations/20260723150640_google_lsa_hardening.sql +169 -0
- package/dist/dist/migrations/20260723150641_google_lsa_hardening_rls.sql +12 -0
- package/dist/dist/migrations/20260724230721_google_lsa_facebook_exclusivity_attach.sql +104 -0
- package/dist/dist/migrations/20260724230722_google_lsa_facebook_exclusivity_attach_rls.sql +20 -0
- package/dist/dist/migrations/20260725172630_add_message_pagination_and_search.sql +265 -0
- package/dist/dist/migrations/20260725172631_add_message_pagination_and_search_rls.sql +72 -0
- package/dist/dist/migrations/20260725172632_optimize_message_thread_pagination_search.sql +245 -0
- package/dist/dist/migrations/20260725172633_harden_message_search_and_photo_pagination.sql +256 -0
- package/dist/dist/migrations/20260725172634_fix_message_thread_line_filter.sql +250 -0
- package/dist/dist/migrations/20260725174948_google_lsa_attach_bing_exclusivity_guard.sql +23 -0
- package/dist/dist/migrations/20260725200430_client_portal_settings.sql +41 -0
- package/dist/dist/migrations/20260725200431_client_portal_settings_rls.sql +21 -0
- package/dist/dist/migrations/20260725200433_client_portal_auth_tables.sql +81 -0
- package/dist/dist/migrations/20260725200434_client_portal_auth_rls.sql +18 -0
- package/dist/dist/migrations/20260725200435_portal_claim_login_attempt.sql +36 -0
- package/dist/dist/migrations/20260725200436_portal_appointment_request.sql +39 -0
- package/dist/dist/migrations/20260725200437_portal_appointment_request_rls.sql +10 -0
- package/dist/dist/migrations/20260725210000_google_reserve_integration.sql +85 -0
- package/dist/dist/migrations/20260725210001_google_reserve_integration_rls.sql +10 -0
- package/dist/dist/migrations/20260725220000_add_analytics_query_indexes.sql +47 -0
- package/dist/dist/migrations/20260725230000_onboarding_preload_data.sql +1074 -0
- package/dist/dist/migrations/20260725230001_onboarding_preload_data_rls.sql +40 -0
- package/dist/dist/migrations/20260725230002_add_pricebook_query_indexes.sql +13 -0
- package/dist/dist/migrations/20260726000000_facebook_ads_integration.sql +1538 -0
- package/dist/dist/migrations/20260726000001_facebook_ads_integration_rls.sql +356 -0
- package/dist/dist/migrations/20260726000002_facebook_ads_attach_lsa_exclusivity_guard.sql +25 -0
- package/dist/dist/migrations/20260726000003_facebook_ads_attach_bing_exclusivity_guard.sql +22 -0
- package/dist/dist/migrations/20260726010000_create_bing_ads_integration.sql +1112 -0
- package/dist/dist/migrations/20260726010001_bing_ads_integration_rls.sql +227 -0
- package/dist/dist/migrations/20260726220000_add_document_theme_settings.sql +11 -0
- package/dist/dist/migrations/20260726220001_update_document_theme_comments.sql +7 -0
- package/dist/dist/migrations/20260727210319_evolve_tier_for_pricing.sql +68 -0
- package/dist/dist/migrations/20260727210320_create_billing_addon.sql +85 -0
- package/dist/dist/migrations/20260727210321_create_billing_addon_rls.sql +21 -0
- package/dist/dist/migrations/20260728213930_create_usage_metering.sql +189 -0
- package/dist/dist/migrations/20260728213931_create_usage_metering_rls.sql +32 -0
- package/dist/dist/migrations/20260729004305_marketing_charge_txn_functions.sql +242 -0
- package/dist/dist/migrations/20260729004306_marketing_charge_txn_functions_rls.sql +37 -0
- package/dist/dist/migrations/20260729005524_update_deduct_from_balance_errcode.sql +42 -0
- package/dist/dist/migrations/20260730193601_fix_deduct_from_balance_lost_update.sql +46 -0
- package/dist/dist/migrations/20260730193602_add_blast_sms_chunk_reaper_columns.sql +27 -0
- package/dist/dist/migrations/20260731011415_create_google_calendar_connection.sql +84 -0
- package/dist/dist/migrations/20260731011416_google_calendar_connection_rls.sql +23 -0
- package/dist/dist/migrations/20260731011417_create_google_calendar_sync.sql +157 -0
- package/dist/dist/migrations/20260731011418_google_calendar_sync_rls.sql +26 -0
- package/dist/dist/migrations/20260731011419_event_outbound_triggers.sql +28 -0
- package/dist/dist/migrations/20260731011420_add_google_calendar_addon_key.sql +24 -0
- package/dist/dist/migrations/20260731011421_gcal_task_retention.sql +109 -0
- package/dist/dist/migrations/20260731234245_create_estimate_proposal.sql +157 -0
- package/dist/dist/migrations/20260731234247_estimate_proposal_rls.sql +46 -0
- package/dist/dist/migrations/20260731234248_add_proposal_estimate_settings.sql +17 -0
- package/dist/dist/migrations/20260731234249_add_estimate_proposals_addon_key.sql +25 -0
- package/dist/dist/migrations/20260731234250_approve_estimate_proposal_function.sql +133 -0
- package/dist/dist/migrations/20260801010609_save_estimate_proposal_function.sql +154 -0
- package/dist/dist/migrations/20260801173554_add_hide_autopilot_branding_setting.sql +6 -0
- package/dist/dist/migrations/20260806230917_add_client_billing_address_columns.sql +9 -0
- package/dist/dist/migrations/20260806230944_api_create_client_billing_address.sql +93 -0
- package/dist/dist/migrations/20260807014702_create_parent_id_company_id_keys.sql +20 -0
- package/dist/dist/migrations/20260807014703_create_contract_template.sql +30 -0
- package/dist/dist/migrations/20260807014704_create_contract.sql +233 -0
- package/dist/dist/migrations/20260807014705_create_contract_signature.sql +39 -0
- package/dist/dist/migrations/20260807014706_create_item_contract_requirement.sql +38 -0
- package/dist/dist/migrations/20260807014707_create_settings_contract.sql +23 -0
- package/dist/dist/migrations/20260807014708_contract_rls.sql +74 -0
- package/dist/dist/migrations/20260807014709_sign_contract_function.sql +92 -0
- package/dist/dist/migrations/20260807014710_create_settings_rental.sql +34 -0
- package/dist/dist/migrations/20260807014711_create_saved_location.sql +56 -0
- package/dist/dist/migrations/20260807014712_create_rental_task_option.sql +52 -0
- package/dist/dist/migrations/20260807014713_create_asset.sql +90 -0
- package/dist/dist/migrations/20260807014714_add_job_schedule_asset_fkeys.sql +39 -0
- package/dist/dist/migrations/20260807014715_rental_rls.sql +48 -0
- package/dist/dist/migrations/20260807014716_add_job_schedule_any_time.sql +7 -0
- package/dist/dist/migrations/20260807014717_add_job_schedule_target_location.sql +48 -0
- package/dist/dist/migrations/20260807014718_job_schedule_completion_guard.sql +53 -0
- package/dist/dist/migrations/20260807014719_add_job_schedule_list_sort_key.sql +7 -0
- package/dist/dist/migrations/20260807014720_add_item_duration.sql +11 -0
- package/dist/dist/migrations/20260807014721_add_settings_booking_enforce_rental_availability.sql +9 -0
- package/dist/dist/migrations/20260807014722_add_job_unsigned_rental_agreement.sql +10 -0
- package/dist/dist/migrations/20260807014723_add_item_size.sql +12 -0
- package/dist/dist/migrations/20260809193533_add_booking_path_button_labels.sql +11 -0
- package/dist/dist/migrations/20260809231721_add_route_distance_cache.sql +37 -0
- package/dist/dist/migrations/20260809231722_route_distance_cache_rls.sql +15 -0
- package/dist/dist/migrations/20260809231723_apply_rental_route_plan_function.sql +275 -0
- package/dist/dist/migrations/20260810171550_add_settings_job_default_job_types.sql +9 -0
- package/dist/dist/migrations/20260810212430_backfill_rental_task_option_sort_order.sql +61 -0
- package/dist/dist/migrations/20260811224317_add_settings_user_dnd_hint_dismissed.sql +9 -0
- package/dist/dist/migrations/20260813174503_repair_user_role_email_drift.sql +59 -0
- package/dist/dist/migrations/20260813174504_sync_user_role_email_trigger.sql +30 -0
- package/dist/dist/migrations/20260813175210_add_event_list_sort_key.sql +5 -0
- package/dist/dist/migrations/20260814172222_add_client_auto_bill_on_completion.sql +6 -0
- package/dist/dist/migrations/20260816160252_create_automation_rule.sql +99 -0
- package/dist/dist/migrations/20260816160253_automation_rule_rls.sql +19 -0
- package/dist/dist/migrations/20260816160254_create_settings_automation.sql +36 -0
- package/dist/dist/migrations/20260816160255_settings_automation_rls.sql +18 -0
- package/dist/dist/migrations/20260816160256_create_automation_event.sql +71 -0
- package/dist/dist/migrations/20260816160257_automation_event_rls.sql +12 -0
- package/dist/dist/migrations/20260816160258_create_automation_run.sql +129 -0
- package/dist/dist/migrations/20260816160259_automation_run_rls.sql +19 -0
- package/dist/dist/migrations/20260816160300_add_client_created_via.sql +25 -0
- package/dist/dist/migrations/20260816160301_add_estimate_sent_at.sql +39 -0
- package/dist/dist/migrations/20260816160302_add_message_automation_ref.sql +10 -0
- package/dist/dist/migrations/20260816160303_automation_event_triggers.sql +236 -0
- package/dist/dist/migrations/20260816160304_automation_retention.sql +142 -0
- package/dist/dist/migrations/20260816202404_add_automation_center_addon_key.sql +26 -0
- package/dist/dist/migrations/20260816225501_widen_automation_rule_trigger_action_checks.sql +25 -0
- package/dist/dist/migrations/20260816225502_widen_automation_event_type_check.sql +18 -0
- package/dist/dist/migrations/20260816225503_add_invoice_id_to_automation_tables.sql +18 -0
- package/dist/dist/migrations/20260816225504_add_job_rescheduled_capture_trigger.sql +51 -0
- package/dist/dist/migrations/20260816225505_add_lead_converted_capture_trigger.sql +26 -0
- package/dist/dist/migrations/20260816225506_fix_booking_request_import_guard.sql +27 -0
- package/dist/dist/migrations/20260816225507_widen_outbound_event_for_automation.sql +38 -0
- package/dist/dist/migrations/20260817002626_add_user_last_login_platform_columns.sql +14 -0
- package/dist/dist/migrations/20260817221703_create_deletion.sql +34 -0
- package/dist/dist/migrations/20260817221707_deletion_rls.sql +21 -0
- package/dist/dist/migrations/20260817221708_add_soft_delete_columns.sql +82 -0
- package/dist/dist/migrations/20260817221709_trash_functions.sql +434 -0
- package/dist/dist/migrations/20260817221710_outbound_event_soft_delete.sql +55 -0
- package/dist/dist/migrations/20260817221711_automation_soft_delete_events.sql +77 -0
- package/dist/dist/migrations/20260817221712_fix_estimate_address_cascade.sql +14 -0
- package/dist/dist/migrations/20260817232630_trash_batch_function.sql +67 -0
- package/dist/dist/migrations/20260819170204_create_email_spam_complaint.sql +23 -0
- package/dist/dist/migrations/20260819170205_add_email_spam_complaint_rls.sql +5 -0
- package/dist/dist/migrations/20260819170206_email_unsubscribed_upsert_constraints.sql +14 -0
- package/dist/dist/migrations/20260819180151_get_suppressed_emails_function.sql +23 -0
- package/dist/dist/migrations/20260819191143_is_deleted_backfill_guard.sql +29 -0
- package/dist/dist/migrations/20260819191144_trash_functions_no_dual_write.sql +319 -0
- package/dist/dist/migrations/20260819191145_client_map_jobs_deleted_at.sql +33 -0
- package/dist/dist/migrations/20260819191147_booking_declined_deleted_at.sql +28 -0
- package/dist/dist/migrations/20260819191148_onboarding_preload_no_address_is_deleted.sql +1019 -0
- package/dist/dist/migrations/20260820222756_add_settings_job_hide_task_timer.sql +2 -0
- package/dist/dist/migrations/20260824234151_add_blast_chunk_recipients.sql +13 -0
- package/dist/dist/migrations/20260824234152_add_blast_pause_cancel_columns.sql +10 -0
- package/dist/dist/migrations/20260825014725_get_job_ids_in_range.sql +42 -0
- package/dist/dist/migrations/20260825194452_add_failed_job_status.sql +15 -0
- package/dist/dist/migrations/20260825194457_remove_take_to_rental_task_options.sql +24 -0
- package/dist/dist/migrations/20260825194458_remove_take_to_job_schedules.sql +12 -0
- package/dist/dist/migrations/20260825194459_rework_apply_rental_route_plan_no_take_to.sql +168 -0
- package/dist/dist/migrations/20260825194500_drop_job_schedule_target_location.sql +24 -0
- package/dist/dist/migrations/20260825194501_add_job_schedule_size.sql +17 -0
- package/dist/dist/migrations/20260825233001_add_job_schedule_id_company_id_key.sql +11 -0
- package/dist/dist/migrations/20260825233002_create_route_plan.sql +52 -0
- package/dist/dist/migrations/20260825233003_create_route_plan_stop.sql +159 -0
- package/dist/dist/migrations/20260825233004_route_plan_rls.sql +32 -0
- package/dist/dist/migrations/20260825233005_apply_rental_route_plan_v2.sql +351 -0
- package/dist/dist/migrations/20260826150934_facebook_ads_lead_ingestion.sql +1711 -0
- package/dist/dist/migrations/20260826151141_facebook_ads_lead_ingestion_rls_v2.sql +43 -0
- package/dist/dist/migrations/20260826234722_facebook_messenger_ingestion.sql +703 -0
- package/dist/dist/migrations/20260826234723_facebook_messenger_ingestion_rls.sql +80 -0
- package/dist/dist/migrations/20260826234724_widen_automations_messenger.sql +46 -0
- package/dist/dist/migrations/20260827100001_add_route_plan_minutes.sql +10 -0
- package/dist/dist/migrations/20260827100002_add_route_plan_stop_leg_minutes.sql +9 -0
- package/dist/dist/migrations/20260827100003_apply_rental_route_plan_v3.sql +341 -0
- package/dist/dist/migrations/20260827230346_apply_rental_route_plan_v4.sql +366 -0
- package/dist/dist/migrations/20260829090911_create_fleet_schema.sql +3698 -0
- package/dist/dist/migrations/20260829090912_fleet_rls.sql +1011 -0
- package/dist/dist/migrations/20260831102212_add_online_booking_address_display.sql +8 -0
- package/dist/dist/providers/AddressProvider.d.ts +9 -0
- package/dist/dist/providers/AddressProvider.d.ts.map +1 -0
- package/dist/dist/providers/AddressProvider.js +207 -0
- package/dist/dist/providers/AddressProvider.js.map +1 -0
- package/dist/dist/providers/AutomationsProvider.d.ts +11 -0
- package/dist/dist/providers/AutomationsProvider.d.ts.map +1 -0
- package/dist/dist/providers/AutomationsProvider.js +170 -0
- package/dist/dist/providers/AutomationsProvider.js.map +1 -0
- package/dist/dist/providers/BlockedNumbersProvider.d.ts +13 -0
- package/dist/dist/providers/BlockedNumbersProvider.d.ts.map +1 -0
- package/dist/dist/providers/BlockedNumbersProvider.js +71 -0
- package/dist/dist/providers/BlockedNumbersProvider.js.map +1 -0
- package/dist/dist/providers/CategoryProvider.d.ts +8 -0
- package/dist/dist/providers/CategoryProvider.d.ts.map +1 -0
- package/dist/dist/providers/CategoryProvider.js +95 -0
- package/dist/dist/providers/CategoryProvider.js.map +1 -0
- package/dist/dist/providers/ClientProvider.d.ts +39 -0
- package/dist/dist/providers/ClientProvider.d.ts.map +1 -0
- package/dist/dist/providers/ClientProvider.js +253 -0
- package/dist/dist/providers/ClientProvider.js.map +1 -0
- package/dist/dist/providers/CompanyProvider.d.ts +7 -0
- package/dist/dist/providers/CompanyProvider.d.ts.map +1 -0
- package/dist/dist/providers/CompanyProvider.js +114 -0
- package/dist/dist/providers/CompanyProvider.js.map +1 -0
- package/dist/dist/providers/DashboardProvider.d.ts +78 -0
- package/dist/dist/providers/DashboardProvider.d.ts.map +1 -0
- package/dist/dist/providers/DashboardProvider.js +568 -0
- package/dist/dist/providers/DashboardProvider.js.map +1 -0
- package/dist/dist/providers/DiscountProvider.d.ts +8 -0
- package/dist/dist/providers/DiscountProvider.d.ts.map +1 -0
- package/dist/dist/providers/DiscountProvider.js +92 -0
- package/dist/dist/providers/DiscountProvider.js.map +1 -0
- package/dist/dist/providers/EmployeesProvider.d.ts +6 -0
- package/dist/dist/providers/EmployeesProvider.d.ts.map +1 -0
- package/dist/dist/providers/EmployeesProvider.js +185 -0
- package/dist/dist/providers/EmployeesProvider.js.map +1 -0
- package/dist/dist/providers/EstimatesProvider.d.ts +16 -0
- package/dist/dist/providers/EstimatesProvider.d.ts.map +1 -0
- package/dist/dist/providers/EstimatesProvider.js +251 -0
- package/dist/dist/providers/EstimatesProvider.js.map +1 -0
- package/dist/dist/providers/EventsProvider.d.ts +4 -0
- package/dist/dist/providers/EventsProvider.d.ts.map +1 -0
- package/dist/dist/providers/EventsProvider.js +24 -0
- package/dist/dist/providers/EventsProvider.js.map +1 -0
- package/dist/dist/providers/FilesProvider.d.ts +17 -0
- package/dist/dist/providers/FilesProvider.d.ts.map +1 -0
- package/dist/dist/providers/FilesProvider.js +201 -0
- package/dist/dist/providers/FilesProvider.js.map +1 -0
- package/dist/dist/providers/InvoicesProvider.d.ts +13 -0
- package/dist/dist/providers/InvoicesProvider.d.ts.map +1 -0
- package/dist/dist/providers/InvoicesProvider.js +207 -0
- package/dist/dist/providers/InvoicesProvider.js.map +1 -0
- package/dist/dist/providers/ItemProvider.d.ts +9 -0
- package/dist/dist/providers/ItemProvider.d.ts.map +1 -0
- package/dist/dist/providers/ItemProvider.js +201 -0
- package/dist/dist/providers/ItemProvider.js.map +1 -0
- package/dist/dist/providers/JobSourceProvider.d.ts +8 -0
- package/dist/dist/providers/JobSourceProvider.d.ts.map +1 -0
- package/dist/dist/providers/JobSourceProvider.js +75 -0
- package/dist/dist/providers/JobSourceProvider.js.map +1 -0
- package/dist/dist/providers/JobTypeProvider.d.ts +8 -0
- package/dist/dist/providers/JobTypeProvider.d.ts.map +1 -0
- package/dist/dist/providers/JobTypeProvider.js +75 -0
- package/dist/dist/providers/JobTypeProvider.js.map +1 -0
- package/dist/dist/providers/JobsProvider.d.ts +35 -0
- package/dist/dist/providers/JobsProvider.d.ts.map +1 -0
- package/dist/dist/providers/JobsProvider.js +863 -0
- package/dist/dist/providers/JobsProvider.js.map +1 -0
- package/dist/dist/providers/MessagesProvider.d.ts +33 -0
- package/dist/dist/providers/MessagesProvider.d.ts.map +1 -0
- package/dist/dist/providers/MessagesProvider.js +415 -0
- package/dist/dist/providers/MessagesProvider.js.map +1 -0
- package/dist/dist/providers/PaymentProvider.d.ts +9 -0
- package/dist/dist/providers/PaymentProvider.d.ts.map +1 -0
- package/dist/dist/providers/PaymentProvider.js +48 -0
- package/dist/dist/providers/PaymentProvider.js.map +1 -0
- package/dist/dist/providers/PermissionRolesProvider.d.ts +5 -0
- package/dist/dist/providers/PermissionRolesProvider.d.ts.map +1 -0
- package/dist/dist/providers/PermissionRolesProvider.js +30 -0
- package/dist/dist/providers/PermissionRolesProvider.js.map +1 -0
- package/dist/dist/providers/PhoneNumberProvider.d.ts +12 -0
- package/dist/dist/providers/PhoneNumberProvider.d.ts.map +1 -0
- package/dist/dist/providers/PhoneNumberProvider.js +184 -0
- package/dist/dist/providers/PhoneNumberProvider.js.map +1 -0
- package/dist/dist/providers/ProfileProvider.d.ts +6 -0
- package/dist/dist/providers/ProfileProvider.d.ts.map +1 -0
- package/dist/dist/providers/ProfileProvider.js +71 -0
- package/dist/dist/providers/ProfileProvider.js.map +1 -0
- package/dist/dist/providers/RentalsProvider.d.ts +28 -0
- package/dist/dist/providers/RentalsProvider.d.ts.map +1 -0
- package/dist/dist/providers/RentalsProvider.js +438 -0
- package/dist/dist/providers/RentalsProvider.js.map +1 -0
- package/dist/dist/providers/SettingsBookingProvider.d.ts +9 -0
- package/dist/dist/providers/SettingsBookingProvider.d.ts.map +1 -0
- package/dist/dist/providers/SettingsBookingProvider.js +163 -0
- package/dist/dist/providers/SettingsBookingProvider.js.map +1 -0
- package/dist/dist/providers/SettingsProvider.d.ts +8 -0
- package/dist/dist/providers/SettingsProvider.d.ts.map +1 -0
- package/dist/dist/providers/SettingsProvider.js +86 -0
- package/dist/dist/providers/SettingsProvider.js.map +1 -0
- package/dist/dist/providers/TagsProvider.d.ts +12 -0
- package/dist/dist/providers/TagsProvider.d.ts.map +1 -0
- package/dist/dist/providers/TagsProvider.js +210 -0
- package/dist/dist/providers/TagsProvider.js.map +1 -0
- package/dist/dist/providers/TimeCardProvider.d.ts +8 -0
- package/dist/dist/providers/TimeCardProvider.d.ts.map +1 -0
- package/dist/dist/providers/TimeCardProvider.js +93 -0
- package/dist/dist/providers/TimeCardProvider.js.map +1 -0
- package/dist/dist/providers/TrashProvider.d.ts +13 -0
- package/dist/dist/providers/TrashProvider.d.ts.map +1 -0
- package/dist/dist/providers/TrashProvider.js +98 -0
- package/dist/dist/providers/TrashProvider.js.map +1 -0
- package/dist/dist/providers/dashboardAnalytics.d.ts +9 -0
- package/dist/dist/providers/dashboardAnalytics.d.ts.map +1 -0
- package/dist/dist/providers/dashboardAnalytics.js +41 -0
- package/dist/dist/providers/dashboardAnalytics.js.map +1 -0
- package/dist/dist/providers/dashboardAnalytics.test.d.ts +2 -0
- package/dist/dist/providers/dashboardAnalytics.test.d.ts.map +1 -0
- package/dist/dist/providers/dashboardAnalytics.test.js +111 -0
- package/dist/dist/providers/dashboardAnalytics.test.js.map +1 -0
- package/dist/dist/server-safe/BlockedNumberFunctions.d.ts +11 -0
- package/dist/dist/server-safe/BlockedNumberFunctions.d.ts.map +1 -0
- package/dist/dist/server-safe/BlockedNumberFunctions.js +16 -0
- package/dist/dist/server-safe/BlockedNumberFunctions.js.map +1 -0
- package/dist/dist/server-safe/EmployeeFunctions.d.ts +14 -0
- package/dist/dist/server-safe/EmployeeFunctions.d.ts.map +1 -0
- package/dist/dist/server-safe/EmployeeFunctions.js +70 -0
- package/dist/dist/server-safe/EmployeeFunctions.js.map +1 -0
- package/dist/dist/server-safe/EmployeeLocationFunctions.d.ts +7 -0
- package/dist/dist/server-safe/EmployeeLocationFunctions.d.ts.map +1 -0
- package/dist/dist/server-safe/EmployeeLocationFunctions.js +47 -0
- package/dist/dist/server-safe/EmployeeLocationFunctions.js.map +1 -0
- package/dist/dist/server-safe/EstimateFunctions.d.ts +15 -0
- package/dist/dist/server-safe/EstimateFunctions.d.ts.map +1 -0
- package/dist/dist/server-safe/EstimateFunctions.js +34 -0
- package/dist/dist/server-safe/EstimateFunctions.js.map +1 -0
- package/dist/dist/server-safe/InvoiceFunctions.d.ts +21 -0
- package/dist/dist/server-safe/InvoiceFunctions.d.ts.map +1 -0
- package/dist/dist/server-safe/InvoiceFunctions.js +124 -0
- package/dist/dist/server-safe/InvoiceFunctions.js.map +1 -0
- package/dist/dist/server-safe/JobFunctions.d.ts +15 -0
- package/dist/dist/server-safe/JobFunctions.d.ts.map +1 -0
- package/dist/dist/server-safe/JobFunctions.js +56 -0
- package/dist/dist/server-safe/JobFunctions.js.map +1 -0
- package/dist/dist/server-safe/PaymentFunctions.d.ts +16 -0
- package/dist/dist/server-safe/PaymentFunctions.d.ts.map +1 -0
- package/dist/dist/server-safe/PaymentFunctions.js +80 -0
- package/dist/dist/server-safe/PaymentFunctions.js.map +1 -0
- package/dist/dist/server-safe/PermissionFunctions.d.ts +7 -0
- package/dist/dist/server-safe/PermissionFunctions.d.ts.map +1 -0
- package/dist/dist/server-safe/PermissionFunctions.js +39 -0
- package/dist/dist/server-safe/PermissionFunctions.js.map +1 -0
- package/dist/dist/server-safe/TagFunctions.d.ts +18 -0
- package/dist/dist/server-safe/TagFunctions.d.ts.map +1 -0
- package/dist/dist/server-safe/TagFunctions.js +52 -0
- package/dist/dist/server-safe/TagFunctions.js.map +1 -0
- package/dist/dist/server-safe/autoJobType.d.ts +16 -0
- package/dist/dist/server-safe/autoJobType.d.ts.map +1 -0
- package/dist/dist/server-safe/autoJobType.js +39 -0
- package/dist/dist/server-safe/autoJobType.js.map +1 -0
- package/dist/dist/server-safe/autoJobType.test.d.ts +2 -0
- package/dist/dist/server-safe/autoJobType.test.d.ts.map +1 -0
- package/dist/dist/server-safe/autoJobType.test.js +83 -0
- package/dist/dist/server-safe/autoJobType.test.js.map +1 -0
- package/dist/dist/server-safe/automations.d.ts +197 -0
- package/dist/dist/server-safe/automations.d.ts.map +1 -0
- package/dist/dist/server-safe/automations.js +757 -0
- package/dist/dist/server-safe/automations.js.map +1 -0
- package/dist/dist/server-safe/automations.test.d.ts +2 -0
- package/dist/dist/server-safe/automations.test.d.ts.map +1 -0
- package/dist/dist/server-safe/automations.test.js +441 -0
- package/dist/dist/server-safe/automations.test.js.map +1 -0
- package/dist/dist/server-safe/constants.d.ts +156 -0
- package/dist/dist/server-safe/constants.d.ts.map +1 -0
- package/dist/dist/server-safe/constants.js +186 -0
- package/dist/dist/server-safe/constants.js.map +1 -0
- package/dist/dist/server-safe/contracts.d.ts +3 -0
- package/dist/dist/server-safe/contracts.d.ts.map +1 -0
- package/dist/dist/server-safe/contracts.js +15 -0
- package/dist/dist/server-safe/contracts.js.map +1 -0
- package/dist/dist/server-safe/database.types.d.ts +9510 -0
- package/dist/dist/server-safe/database.types.d.ts.map +1 -0
- package/dist/dist/server-safe/database.types.js +40 -0
- package/dist/dist/server-safe/database.types.js.map +1 -0
- package/dist/dist/server-safe/entitlements.d.ts +99 -0
- package/dist/dist/server-safe/entitlements.d.ts.map +1 -0
- package/dist/dist/server-safe/entitlements.js +487 -0
- package/dist/dist/server-safe/entitlements.js.map +1 -0
- package/dist/dist/server-safe/facebookAdsLeads.d.ts +225 -0
- package/dist/dist/server-safe/facebookAdsLeads.d.ts.map +1 -0
- package/dist/dist/server-safe/facebookAdsLeads.js +376 -0
- package/dist/dist/server-safe/facebookAdsLeads.js.map +1 -0
- package/dist/dist/server-safe/facebookAdsLeads.test.d.ts +2 -0
- package/dist/dist/server-safe/facebookAdsLeads.test.d.ts.map +1 -0
- package/dist/dist/server-safe/facebookAdsLeads.test.js +189 -0
- package/dist/dist/server-safe/facebookAdsLeads.test.js.map +1 -0
- package/dist/dist/server-safe/facebookAdsLeadsSql.test.d.ts +2 -0
- package/dist/dist/server-safe/facebookAdsLeadsSql.test.d.ts.map +1 -0
- package/dist/dist/server-safe/facebookAdsLeadsSql.test.js +32 -0
- package/dist/dist/server-safe/facebookAdsLeadsSql.test.js.map +1 -0
- package/dist/dist/server-safe/facebookMessenger.d.ts +20 -0
- package/dist/dist/server-safe/facebookMessenger.d.ts.map +1 -0
- package/dist/dist/server-safe/facebookMessenger.js +63 -0
- package/dist/dist/server-safe/facebookMessenger.js.map +1 -0
- package/dist/dist/server-safe/facebookMessenger.test.d.ts +2 -0
- package/dist/dist/server-safe/facebookMessenger.test.d.ts.map +1 -0
- package/dist/dist/server-safe/facebookMessenger.test.js +51 -0
- package/dist/dist/server-safe/facebookMessenger.test.js.map +1 -0
- package/dist/dist/server-safe/helpers.d.ts +78 -0
- package/dist/dist/server-safe/helpers.d.ts.map +1 -0
- package/dist/dist/server-safe/helpers.js +569 -0
- package/dist/dist/server-safe/helpers.js.map +1 -0
- package/dist/dist/server-safe/index.d.ts +30 -0
- package/dist/dist/server-safe/index.d.ts.map +1 -0
- package/dist/dist/server-safe/index.js +46 -0
- package/dist/dist/server-safe/index.js.map +1 -0
- package/dist/dist/server-safe/permissions.d.ts +29 -0
- package/dist/dist/server-safe/permissions.d.ts.map +1 -0
- package/dist/dist/server-safe/permissions.js +180 -0
- package/dist/dist/server-safe/permissions.js.map +1 -0
- package/dist/dist/server-safe/proposals.d.ts +6 -0
- package/dist/dist/server-safe/proposals.d.ts.map +1 -0
- package/dist/dist/server-safe/proposals.js +58 -0
- package/dist/dist/server-safe/proposals.js.map +1 -0
- package/dist/dist/server-safe/rentalAvailability.d.ts +56 -0
- package/dist/dist/server-safe/rentalAvailability.d.ts.map +1 -0
- package/dist/dist/server-safe/rentalAvailability.js +124 -0
- package/dist/dist/server-safe/rentalAvailability.js.map +1 -0
- package/dist/dist/server-safe/rentalAvailability.test.d.ts +2 -0
- package/dist/dist/server-safe/rentalAvailability.test.d.ts.map +1 -0
- package/dist/dist/server-safe/rentalAvailability.test.js +290 -0
- package/dist/dist/server-safe/rentalAvailability.test.js.map +1 -0
- package/dist/dist/server-safe/rentals.d.ts +95 -0
- package/dist/dist/server-safe/rentals.d.ts.map +1 -0
- package/dist/dist/server-safe/rentals.js +432 -0
- package/dist/dist/server-safe/rentals.js.map +1 -0
- package/dist/dist/server-safe/rentals.test.d.ts +2 -0
- package/dist/dist/server-safe/rentals.test.d.ts.map +1 -0
- package/dist/dist/server-safe/rentals.test.js +1034 -0
- package/dist/dist/server-safe/rentals.test.js.map +1 -0
- package/dist/dist/server-safe/routeOptimization.d.ts +155 -0
- package/dist/dist/server-safe/routeOptimization.d.ts.map +1 -0
- package/dist/dist/server-safe/routeOptimization.js +120 -0
- package/dist/dist/server-safe/routeOptimization.js.map +1 -0
- package/dist/dist/server-safe/routeOptimization.test.d.ts +2 -0
- package/dist/dist/server-safe/routeOptimization.test.d.ts.map +1 -0
- package/dist/dist/server-safe/routeOptimization.test.js +234 -0
- package/dist/dist/server-safe/routeOptimization.test.js.map +1 -0
- package/dist/dist/server-safe/routePlanFingerprint.d.ts +13 -0
- package/dist/dist/server-safe/routePlanFingerprint.d.ts.map +1 -0
- package/dist/dist/server-safe/routePlanFingerprint.js +49 -0
- package/dist/dist/server-safe/routePlanFingerprint.js.map +1 -0
- package/dist/dist/server-safe/routePlanFingerprint.test.d.ts +2 -0
- package/dist/dist/server-safe/routePlanFingerprint.test.d.ts.map +1 -0
- package/dist/dist/server-safe/routePlanFingerprint.test.js +68 -0
- package/dist/dist/server-safe/routePlanFingerprint.test.js.map +1 -0
- package/dist/dist/server-safe/scheduleListOrder.d.ts +18 -0
- package/dist/dist/server-safe/scheduleListOrder.d.ts.map +1 -0
- package/dist/dist/server-safe/scheduleListOrder.js +92 -0
- package/dist/dist/server-safe/scheduleListOrder.js.map +1 -0
- package/dist/dist/server-safe/scheduleListOrder.test.d.ts +2 -0
- package/dist/dist/server-safe/scheduleListOrder.test.d.ts.map +1 -0
- package/dist/dist/server-safe/scheduleListOrder.test.js +260 -0
- package/dist/dist/server-safe/scheduleListOrder.test.js.map +1 -0
- package/dist/dist/server-safe/serviceMinutes.d.ts +13 -0
- package/dist/dist/server-safe/serviceMinutes.d.ts.map +1 -0
- package/dist/dist/server-safe/serviceMinutes.js +38 -0
- package/dist/dist/server-safe/serviceMinutes.js.map +1 -0
- package/dist/dist/server-safe/serviceMinutes.test.d.ts +2 -0
- package/dist/dist/server-safe/serviceMinutes.test.d.ts.map +1 -0
- package/dist/dist/server-safe/serviceMinutes.test.js +86 -0
- package/dist/dist/server-safe/serviceMinutes.test.js.map +1 -0
- package/dist/dist/server-safe/settingsSearch.d.ts +24 -0
- package/dist/dist/server-safe/settingsSearch.d.ts.map +1 -0
- package/dist/dist/server-safe/settingsSearch.js +8 -0
- package/dist/dist/server-safe/settingsSearch.js.map +1 -0
- package/dist/dist/server-safe/supportChat.d.ts +59 -0
- package/dist/dist/server-safe/supportChat.d.ts.map +1 -0
- package/dist/dist/server-safe/supportChat.js +56 -0
- package/dist/dist/server-safe/supportChat.js.map +1 -0
- package/dist/dist/server-safe/templates.d.ts +15 -0
- package/dist/dist/server-safe/templates.d.ts.map +1 -0
- package/dist/dist/server-safe/templates.js +91 -0
- package/dist/dist/server-safe/templates.js.map +1 -0
- package/dist/dist/server-safe/templates.test.d.ts +2 -0
- package/dist/dist/server-safe/templates.test.d.ts.map +1 -0
- package/dist/dist/server-safe/templates.test.js +62 -0
- package/dist/dist/server-safe/templates.test.js.map +1 -0
- package/dist/dist/server-safe/trash.d.ts +50 -0
- package/dist/dist/server-safe/trash.d.ts.map +1 -0
- package/dist/dist/server-safe/trash.js +100 -0
- package/dist/dist/server-safe/trash.js.map +1 -0
- package/dist/dist/utils/LogHandler.d.ts +3 -0
- package/dist/dist/utils/LogHandler.d.ts.map +1 -0
- package/dist/dist/utils/LogHandler.js +16 -0
- package/dist/dist/utils/LogHandler.js.map +1 -0
- package/dist/dist/utils/convertSupabaseImagesToAssets.d.ts +28 -0
- package/dist/dist/utils/convertSupabaseImagesToAssets.d.ts.map +1 -0
- package/dist/dist/utils/convertSupabaseImagesToAssets.js +14 -0
- package/dist/dist/utils/convertSupabaseImagesToAssets.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/index.d.ts +1238 -0
- package/dist/interfaces/index.d.ts.map +1 -0
- package/dist/interfaces/index.js +3 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/providers/AddressProvider.d.ts +9 -0
- package/dist/providers/AddressProvider.d.ts.map +1 -0
- package/dist/providers/AddressProvider.js +207 -0
- package/dist/providers/AddressProvider.js.map +1 -0
- package/dist/providers/AutomationsProvider.d.ts +11 -0
- package/dist/providers/AutomationsProvider.d.ts.map +1 -0
- package/dist/providers/AutomationsProvider.js +170 -0
- package/dist/providers/AutomationsProvider.js.map +1 -0
- package/dist/providers/BlockedNumbersProvider.d.ts +7 -0
- package/dist/providers/BlockedNumbersProvider.d.ts.map +1 -0
- package/dist/providers/BlockedNumbersProvider.js +71 -0
- package/dist/providers/BlockedNumbersProvider.js.map +1 -0
- package/dist/providers/CategoryProvider.d.ts +8 -0
- package/dist/providers/CategoryProvider.d.ts.map +1 -0
- package/dist/providers/CategoryProvider.js +95 -0
- package/dist/providers/CategoryProvider.js.map +1 -0
- package/dist/providers/ClientProvider.d.ts +39 -0
- package/dist/providers/ClientProvider.d.ts.map +1 -0
- package/dist/providers/ClientProvider.js +253 -0
- package/dist/providers/ClientProvider.js.map +1 -0
- package/dist/providers/CompanyProvider.d.ts +7 -0
- package/dist/providers/CompanyProvider.d.ts.map +1 -0
- package/dist/providers/CompanyProvider.js +114 -0
- package/dist/providers/CompanyProvider.js.map +1 -0
- package/dist/providers/DashboardProvider.d.ts +78 -0
- package/dist/providers/DashboardProvider.d.ts.map +1 -0
- package/dist/providers/DashboardProvider.js +568 -0
- package/dist/providers/DashboardProvider.js.map +1 -0
- package/dist/providers/DiscountProvider.d.ts +8 -0
- package/dist/providers/DiscountProvider.d.ts.map +1 -0
- package/dist/providers/DiscountProvider.js +92 -0
- package/dist/providers/DiscountProvider.js.map +1 -0
- package/dist/providers/EmployeesProvider.d.ts +6 -0
- package/dist/providers/EmployeesProvider.d.ts.map +1 -0
- package/dist/providers/EmployeesProvider.js +185 -0
- package/dist/providers/EmployeesProvider.js.map +1 -0
- package/dist/providers/EstimatesProvider.d.ts +16 -0
- package/dist/providers/EstimatesProvider.d.ts.map +1 -0
- package/dist/providers/EstimatesProvider.js +251 -0
- package/dist/providers/EstimatesProvider.js.map +1 -0
- package/dist/providers/EventsProvider.d.ts +4 -0
- package/dist/providers/EventsProvider.d.ts.map +1 -0
- package/dist/providers/EventsProvider.js +24 -0
- package/dist/providers/EventsProvider.js.map +1 -0
- package/dist/providers/FilesProvider.d.ts +17 -0
- package/dist/providers/FilesProvider.d.ts.map +1 -0
- package/dist/providers/FilesProvider.js +201 -0
- package/dist/providers/FilesProvider.js.map +1 -0
- package/dist/providers/InvoicesProvider.d.ts +13 -0
- package/dist/providers/InvoicesProvider.d.ts.map +1 -0
- package/dist/providers/InvoicesProvider.js +207 -0
- package/dist/providers/InvoicesProvider.js.map +1 -0
- package/dist/providers/ItemProvider.d.ts +9 -0
- package/dist/providers/ItemProvider.d.ts.map +1 -0
- package/dist/providers/ItemProvider.js +201 -0
- package/dist/providers/ItemProvider.js.map +1 -0
- package/dist/providers/JobSourceProvider.d.ts +8 -0
- package/dist/providers/JobSourceProvider.d.ts.map +1 -0
- package/dist/providers/JobSourceProvider.js +75 -0
- package/dist/providers/JobSourceProvider.js.map +1 -0
- package/dist/providers/JobTypeProvider.d.ts +8 -0
- package/dist/providers/JobTypeProvider.d.ts.map +1 -0
- package/dist/providers/JobTypeProvider.js +75 -0
- package/dist/providers/JobTypeProvider.js.map +1 -0
- package/dist/providers/JobsProvider.d.ts +20 -0
- package/dist/providers/JobsProvider.d.ts.map +1 -0
- package/dist/providers/JobsProvider.js +863 -0
- package/dist/providers/JobsProvider.js.map +1 -0
- package/dist/providers/MessagesProvider.d.ts +14 -0
- package/dist/providers/MessagesProvider.d.ts.map +1 -0
- package/dist/providers/MessagesProvider.js +415 -0
- package/dist/providers/MessagesProvider.js.map +1 -0
- package/dist/providers/PaymentProvider.d.ts +9 -0
- package/dist/providers/PaymentProvider.d.ts.map +1 -0
- package/dist/providers/PaymentProvider.js +48 -0
- package/dist/providers/PaymentProvider.js.map +1 -0
- package/dist/providers/PermissionRolesProvider.d.ts +5 -0
- package/dist/providers/PermissionRolesProvider.d.ts.map +1 -0
- package/dist/providers/PermissionRolesProvider.js +30 -0
- package/dist/providers/PermissionRolesProvider.js.map +1 -0
- package/dist/providers/PhoneNumberProvider.d.ts +12 -0
- package/dist/providers/PhoneNumberProvider.d.ts.map +1 -0
- package/dist/providers/PhoneNumberProvider.js +184 -0
- package/dist/providers/PhoneNumberProvider.js.map +1 -0
- package/dist/providers/ProfileProvider.d.ts +6 -0
- package/dist/providers/ProfileProvider.d.ts.map +1 -0
- package/dist/providers/ProfileProvider.js +71 -0
- package/dist/providers/ProfileProvider.js.map +1 -0
- package/dist/providers/RentalsProvider.d.ts +28 -0
- package/dist/providers/RentalsProvider.d.ts.map +1 -0
- package/dist/providers/RentalsProvider.js +438 -0
- package/dist/providers/RentalsProvider.js.map +1 -0
- package/dist/providers/SettingsBookingProvider.d.ts +9 -0
- package/dist/providers/SettingsBookingProvider.d.ts.map +1 -0
- package/dist/providers/SettingsBookingProvider.js +163 -0
- package/dist/providers/SettingsBookingProvider.js.map +1 -0
- package/dist/providers/SettingsProvider.d.ts +8 -0
- package/dist/providers/SettingsProvider.d.ts.map +1 -0
- package/dist/providers/SettingsProvider.js +86 -0
- package/dist/providers/SettingsProvider.js.map +1 -0
- package/dist/providers/TagsProvider.d.ts +12 -0
- package/dist/providers/TagsProvider.d.ts.map +1 -0
- package/dist/providers/TagsProvider.js +210 -0
- package/dist/providers/TagsProvider.js.map +1 -0
- package/dist/providers/TimeCardProvider.d.ts +8 -0
- package/dist/providers/TimeCardProvider.d.ts.map +1 -0
- package/dist/providers/TimeCardProvider.js +93 -0
- package/dist/providers/TimeCardProvider.js.map +1 -0
- package/dist/providers/TrashProvider.d.ts +13 -0
- package/dist/providers/TrashProvider.d.ts.map +1 -0
- package/dist/providers/TrashProvider.js +98 -0
- package/dist/providers/TrashProvider.js.map +1 -0
- package/dist/providers/dashboardAnalytics.d.ts +9 -0
- package/dist/providers/dashboardAnalytics.d.ts.map +1 -0
- package/dist/providers/dashboardAnalytics.js +41 -0
- package/dist/providers/dashboardAnalytics.js.map +1 -0
- package/dist/providers/dashboardAnalytics.test.d.ts +2 -0
- package/dist/providers/dashboardAnalytics.test.d.ts.map +1 -0
- package/dist/providers/dashboardAnalytics.test.js +111 -0
- package/dist/providers/dashboardAnalytics.test.js.map +1 -0
- package/dist/server-safe/BlockedNumberFunctions.d.ts +11 -0
- package/dist/server-safe/BlockedNumberFunctions.d.ts.map +1 -0
- package/dist/server-safe/BlockedNumberFunctions.js +16 -0
- package/dist/server-safe/BlockedNumberFunctions.js.map +1 -0
- package/dist/server-safe/EmployeeFunctions.d.ts +14 -0
- package/dist/server-safe/EmployeeFunctions.d.ts.map +1 -0
- package/dist/server-safe/EmployeeFunctions.js +70 -0
- package/dist/server-safe/EmployeeFunctions.js.map +1 -0
- package/dist/server-safe/EmployeeLocationFunctions.d.ts +7 -0
- package/dist/server-safe/EmployeeLocationFunctions.d.ts.map +1 -0
- package/dist/server-safe/EmployeeLocationFunctions.js +47 -0
- package/dist/server-safe/EmployeeLocationFunctions.js.map +1 -0
- package/dist/server-safe/EstimateFunctions.d.ts +15 -0
- package/dist/server-safe/EstimateFunctions.d.ts.map +1 -0
- package/dist/server-safe/EstimateFunctions.js +34 -0
- package/dist/server-safe/EstimateFunctions.js.map +1 -0
- package/dist/server-safe/InvoiceFunctions.d.ts +21 -0
- package/dist/server-safe/InvoiceFunctions.d.ts.map +1 -0
- package/dist/server-safe/InvoiceFunctions.js +124 -0
- package/dist/server-safe/InvoiceFunctions.js.map +1 -0
- package/dist/server-safe/JobFunctions.d.ts +15 -0
- package/dist/server-safe/JobFunctions.d.ts.map +1 -0
- package/dist/server-safe/JobFunctions.js +56 -0
- package/dist/server-safe/JobFunctions.js.map +1 -0
- package/dist/server-safe/PaymentFunctions.d.ts +16 -0
- package/dist/server-safe/PaymentFunctions.d.ts.map +1 -0
- package/dist/server-safe/PaymentFunctions.js +80 -0
- package/dist/server-safe/PaymentFunctions.js.map +1 -0
- package/dist/server-safe/PermissionFunctions.d.ts +7 -0
- package/dist/server-safe/PermissionFunctions.d.ts.map +1 -0
- package/dist/server-safe/PermissionFunctions.js +39 -0
- package/dist/server-safe/PermissionFunctions.js.map +1 -0
- package/dist/server-safe/TagFunctions.d.ts +18 -0
- package/dist/server-safe/TagFunctions.d.ts.map +1 -0
- package/dist/server-safe/TagFunctions.js +52 -0
- package/dist/server-safe/TagFunctions.js.map +1 -0
- package/dist/server-safe/autoJobType.d.ts +16 -0
- package/dist/server-safe/autoJobType.d.ts.map +1 -0
- package/dist/server-safe/autoJobType.js +39 -0
- package/dist/server-safe/autoJobType.js.map +1 -0
- package/dist/server-safe/autoJobType.test.d.ts +2 -0
- package/dist/server-safe/autoJobType.test.d.ts.map +1 -0
- package/dist/server-safe/autoJobType.test.js +83 -0
- package/dist/server-safe/autoJobType.test.js.map +1 -0
- package/dist/server-safe/automations.d.ts +197 -0
- package/dist/server-safe/automations.d.ts.map +1 -0
- package/dist/server-safe/automations.js +757 -0
- package/dist/server-safe/automations.js.map +1 -0
- package/dist/server-safe/automations.test.d.ts +2 -0
- package/dist/server-safe/automations.test.d.ts.map +1 -0
- package/dist/server-safe/automations.test.js +441 -0
- package/dist/server-safe/automations.test.js.map +1 -0
- package/dist/server-safe/constants.d.ts +156 -0
- package/dist/server-safe/constants.d.ts.map +1 -0
- package/dist/server-safe/constants.js +186 -0
- package/dist/server-safe/constants.js.map +1 -0
- package/dist/server-safe/contracts.d.ts +3 -0
- package/dist/server-safe/contracts.d.ts.map +1 -0
- package/dist/server-safe/contracts.js +15 -0
- package/dist/server-safe/contracts.js.map +1 -0
- package/dist/server-safe/database.types.d.ts +9510 -0
- package/dist/server-safe/database.types.d.ts.map +1 -0
- package/dist/server-safe/database.types.js +40 -0
- package/dist/server-safe/database.types.js.map +1 -0
- package/dist/server-safe/entitlements.d.ts +99 -0
- package/dist/server-safe/entitlements.d.ts.map +1 -0
- package/dist/server-safe/entitlements.js +487 -0
- package/dist/server-safe/entitlements.js.map +1 -0
- package/dist/server-safe/helpers.d.ts +78 -0
- package/dist/server-safe/helpers.d.ts.map +1 -0
- package/dist/server-safe/helpers.js +569 -0
- package/dist/server-safe/helpers.js.map +1 -0
- package/dist/server-safe/index.d.ts +30 -0
- package/dist/server-safe/index.d.ts.map +1 -0
- package/dist/server-safe/index.js +46 -0
- package/dist/server-safe/index.js.map +1 -0
- package/dist/server-safe/permissions.d.ts +29 -0
- package/dist/server-safe/permissions.d.ts.map +1 -0
- package/dist/server-safe/permissions.js +180 -0
- package/dist/server-safe/permissions.js.map +1 -0
- package/dist/server-safe/proposals.d.ts +6 -0
- package/dist/server-safe/proposals.d.ts.map +1 -0
- package/dist/server-safe/proposals.js +58 -0
- package/dist/server-safe/proposals.js.map +1 -0
- package/dist/server-safe/rentalAvailability.d.ts +56 -0
- package/dist/server-safe/rentalAvailability.d.ts.map +1 -0
- package/dist/server-safe/rentalAvailability.js +124 -0
- package/dist/server-safe/rentalAvailability.js.map +1 -0
- package/dist/server-safe/rentalAvailability.test.d.ts +2 -0
- package/dist/server-safe/rentalAvailability.test.d.ts.map +1 -0
- package/dist/server-safe/rentalAvailability.test.js +290 -0
- package/dist/server-safe/rentalAvailability.test.js.map +1 -0
- package/dist/server-safe/rentals.d.ts +95 -0
- package/dist/server-safe/rentals.d.ts.map +1 -0
- package/dist/server-safe/rentals.js +432 -0
- package/dist/server-safe/rentals.js.map +1 -0
- package/dist/server-safe/rentals.test.d.ts +2 -0
- package/dist/server-safe/rentals.test.d.ts.map +1 -0
- package/dist/server-safe/rentals.test.js +1034 -0
- package/dist/server-safe/rentals.test.js.map +1 -0
- package/dist/server-safe/routeOptimization.d.ts +155 -0
- package/dist/server-safe/routeOptimization.d.ts.map +1 -0
- package/dist/server-safe/routeOptimization.js +120 -0
- package/dist/server-safe/routeOptimization.js.map +1 -0
- package/dist/server-safe/routeOptimization.test.d.ts +2 -0
- package/dist/server-safe/routeOptimization.test.d.ts.map +1 -0
- package/dist/server-safe/routeOptimization.test.js +234 -0
- package/dist/server-safe/routeOptimization.test.js.map +1 -0
- package/dist/server-safe/routePlanFingerprint.d.ts +13 -0
- package/dist/server-safe/routePlanFingerprint.d.ts.map +1 -0
- package/dist/server-safe/routePlanFingerprint.js +49 -0
- package/dist/server-safe/routePlanFingerprint.js.map +1 -0
- package/dist/server-safe/routePlanFingerprint.test.d.ts +2 -0
- package/dist/server-safe/routePlanFingerprint.test.d.ts.map +1 -0
- package/dist/server-safe/routePlanFingerprint.test.js +68 -0
- package/dist/server-safe/routePlanFingerprint.test.js.map +1 -0
- package/dist/server-safe/scheduleListOrder.d.ts +18 -0
- package/dist/server-safe/scheduleListOrder.d.ts.map +1 -0
- package/dist/server-safe/scheduleListOrder.js +92 -0
- package/dist/server-safe/scheduleListOrder.js.map +1 -0
- package/dist/server-safe/scheduleListOrder.test.d.ts +2 -0
- package/dist/server-safe/scheduleListOrder.test.d.ts.map +1 -0
- package/dist/server-safe/scheduleListOrder.test.js +260 -0
- package/dist/server-safe/scheduleListOrder.test.js.map +1 -0
- package/dist/server-safe/serviceMinutes.d.ts +13 -0
- package/dist/server-safe/serviceMinutes.d.ts.map +1 -0
- package/dist/server-safe/serviceMinutes.js +38 -0
- package/dist/server-safe/serviceMinutes.js.map +1 -0
- package/dist/server-safe/serviceMinutes.test.d.ts +2 -0
- package/dist/server-safe/serviceMinutes.test.d.ts.map +1 -0
- package/dist/server-safe/serviceMinutes.test.js +86 -0
- package/dist/server-safe/serviceMinutes.test.js.map +1 -0
- package/dist/server-safe/settingsSearch.d.ts +24 -0
- package/dist/server-safe/settingsSearch.d.ts.map +1 -0
- package/dist/server-safe/settingsSearch.js +8 -0
- package/dist/server-safe/settingsSearch.js.map +1 -0
- package/dist/server-safe/supportChat.d.ts +59 -0
- package/dist/server-safe/supportChat.d.ts.map +1 -0
- package/dist/server-safe/supportChat.js +56 -0
- package/dist/server-safe/supportChat.js.map +1 -0
- package/dist/server-safe/templates.d.ts +15 -0
- package/dist/server-safe/templates.d.ts.map +1 -0
- package/dist/server-safe/templates.js +91 -0
- package/dist/server-safe/templates.js.map +1 -0
- package/dist/server-safe/templates.test.d.ts +2 -0
- package/dist/server-safe/templates.test.d.ts.map +1 -0
- package/dist/server-safe/templates.test.js +62 -0
- package/dist/server-safe/templates.test.js.map +1 -0
- package/dist/server-safe/trash.d.ts +50 -0
- package/dist/server-safe/trash.d.ts.map +1 -0
- package/dist/server-safe/trash.js +100 -0
- package/dist/server-safe/trash.js.map +1 -0
- package/dist/utils/LogHandler.d.ts +3 -0
- package/dist/utils/LogHandler.d.ts.map +1 -0
- package/dist/utils/LogHandler.js +16 -0
- package/dist/utils/LogHandler.js.map +1 -0
- package/dist/utils/convertSupabaseImagesToAssets.d.ts +28 -0
- package/dist/utils/convertSupabaseImagesToAssets.d.ts.map +1 -0
- package/dist/utils/convertSupabaseImagesToAssets.js +14 -0
- package/dist/utils/convertSupabaseImagesToAssets.js.map +1 -0
- 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"();
|