fincas 0.4.1__py3-none-any.whl
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.
- accounting/__init__.py +0 -0
- accounting/admin.py +167 -0
- accounting/api.py +66 -0
- accounting/apps.py +7 -0
- accounting/erp_urls.py +46 -0
- accounting/erp_views.py +1054 -0
- accounting/forms.py +63 -0
- accounting/management/__init__.py +0 -0
- accounting/management/commands/__init__.py +0 -0
- accounting/management/commands/import_qbo_export.py +197 -0
- accounting/management/commands/posting_rules.py +206 -0
- accounting/migrations/0001_initial.py +442 -0
- accounting/migrations/0002_documentpostingrule_journalentry_posting_key_and_more.py +191 -0
- accounting/migrations/0003_paymentproviderpostingoverride.py +67 -0
- accounting/migrations/__init__.py +0 -0
- accounting/models.py +811 -0
- accounting/periods.py +83 -0
- accounting/posting.py +280 -0
- accounting/qbo/__init__.py +8 -0
- accounting/qbo/importer.py +921 -0
- accounting/qbo/mapping.py +280 -0
- accounting/qbo/readers.py +416 -0
- accounting/serializers.py +17 -0
- accounting/test_m3_upload.py +103 -0
- accounting/tests/__init__.py +0 -0
- accounting/tests/fixtures/qbo_synthetic/AMBIGUITIES.md +61 -0
- accounting/tests/fixtures/qbo_synthetic/MANIFEST.json +111 -0
- accounting/tests/fixtures/qbo_synthetic/coa_account_number_via_account_hash.csv +6 -0
- accounting/tests/fixtures/qbo_synthetic/coa_account_number_via_account_hash.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_account_number_via_account_no.csv +6 -0
- accounting/tests/fixtures/qbo_synthetic/coa_account_number_via_account_no.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_account_number_via_account_number.csv +6 -0
- accounting/tests/fixtures/qbo_synthetic/coa_account_number_via_account_number.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_account_number_via_no.csv +6 -0
- accounting/tests/fixtures/qbo_synthetic/coa_account_number_via_no.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_account_number_via_num.csv +6 -0
- accounting/tests/fixtures/qbo_synthetic/coa_account_number_via_num.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_account_number_via_number.csv +6 -0
- accounting/tests/fixtures/qbo_synthetic/coa_account_number_via_number.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_description_vs_memo.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/coa_description_vs_memo.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_duplicate_headers.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/coa_duplicate_headers.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_empty_rows_and_spacers.csv +4 -0
- accounting/tests/fixtures/qbo_synthetic/coa_empty_rows_and_spacers.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_full_with_preamble_and_extras.csv +9 -0
- accounting/tests/fixtures/qbo_synthetic/coa_full_with_preamble_and_extras.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_header_case_variants.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/coa_header_case_variants.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_header_normalization.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/coa_header_normalization.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_header_only_one_match.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/coa_header_only_one_match.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_header_punctuation.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/coa_header_punctuation.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_minimal_columns.csv +3 -0
- accounting/tests/fixtures/qbo_synthetic/coa_minimal_columns.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_name_and_account_both_present.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/coa_name_and_account_both_present.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_name_is_account.csv +3 -0
- accounting/tests/fixtures/qbo_synthetic/coa_name_is_account.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/coa_short_rows_padded.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/coa_short_rows_padded.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_dates_mixed.csv +5 -0
- accounting/tests/fixtures/qbo_synthetic/txn_dates_mixed.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_doc_number.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_doc_number.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_document_number.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_document_number.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_no.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_no.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_num.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_num.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_number.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_number.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_ref_no.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_ref_no.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_reference_number.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_doc_number_via_reference_number.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_duplicate_amount.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_duplicate_amount.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_entity_via_customer.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_entity_via_customer.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_entity_via_customer_vendor.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_entity_via_customer_vendor.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_entity_via_entity.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_entity_via_entity.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_entity_via_payee.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_entity_via_payee.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_entity_via_vendor.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_entity_via_vendor.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_full_journal_with_preamble.csv +9 -0
- accounting/tests/fixtures/qbo_synthetic/txn_full_journal_with_preamble.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_header_normalization.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_header_normalization.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_header_punctuation.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_header_punctuation.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_memo_description_ambiguous.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_memo_description_ambiguous.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_minimal_columns.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_minimal_columns.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_money_variants.csv +5 -0
- accounting/tests/fixtures/qbo_synthetic/txn_money_variants.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_name_and_account.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_name_and_account.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_name_is_entity.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_name_is_entity.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_number_header_ambiguous.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_number_header_ambiguous.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_qbo_id_via_journal_id.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_qbo_id_via_journal_id.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_qbo_id_via_qbo_txn_id.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_qbo_id_via_qbo_txn_id.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_qbo_id_via_transaction_id.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_qbo_id_via_transaction_id.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_qbo_id_via_txn_id.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_qbo_id_via_txn_id.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_transaction_type_via_transaction_type.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_transaction_type_via_transaction_type.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_transaction_type_via_txn_type.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_transaction_type_via_txn_type.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_transaction_type_via_type.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_transaction_type_via_type.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_type_header_ambiguous.csv +2 -0
- accounting/tests/fixtures/qbo_synthetic/txn_type_header_ambiguous.xlsx +0 -0
- accounting/tests/fixtures/qbo_synthetic/txn_with_extras_and_blanks.csv +4 -0
- accounting/tests/fixtures/qbo_synthetic/txn_with_extras_and_blanks.xlsx +0 -0
- accounting/tests/test_accounting_import_view.py +325 -0
- accounting/tests/test_admin.py +200 -0
- accounting/tests/test_company_scoping.py +95 -0
- accounting/tests/test_double_entry_balance.py +221 -0
- accounting/tests/test_fiscal_period_guard.py +146 -0
- accounting/tests/test_import_command.py +276 -0
- accounting/tests/test_models.py +539 -0
- accounting/tests/test_period_close.py +258 -0
- accounting/tests/test_posting.py +679 -0
- accounting/tests/test_posting_rules_command.py +137 -0
- accounting/tests/test_qbo_aliases_fuzz.py +399 -0
- accounting/tests/test_qbo_import.py +1327 -0
- accounting/tests/test_qbo_mapping.py +116 -0
- accounting/tests/test_qbo_readers.py +353 -0
- accounting/tests/test_reconciliation.py +138 -0
- accounting/tests/test_reporting_views.py +399 -0
- accounting/urls.py +8 -0
- addons/__init__.py +86 -0
- chat/__init__.py +0 -0
- chat/admin.py +40 -0
- chat/apps.py +6 -0
- chat/context_processors.py +41 -0
- chat/llm/__init__.py +67 -0
- chat/llm/anthropic.py +196 -0
- chat/llm/base.py +123 -0
- chat/llm/openai_compat.py +766 -0
- chat/llm/registry.py +398 -0
- chat/llm/tool_schema.py +71 -0
- chat/management/__init__.py +0 -0
- chat/management/commands/__init__.py +0 -0
- chat/management/commands/check_llm_models.py +191 -0
- chat/migrations/0001_initial.py +105 -0
- chat/migrations/__init__.py +0 -0
- chat/models.py +98 -0
- chat/static/chat/chat.css +281 -0
- chat/static/chat/chat.js +638 -0
- chat/templates/chat/drawer.html +127 -0
- chat/test_m3_llm_abuse.py +175 -0
- chat/tests/__init__.py +0 -0
- chat/tests/test_anthropic.py +335 -0
- chat/tests/test_openai_compat.py +734 -0
- chat/tests/test_registry.py +243 -0
- chat/tests/test_stream_view.py +468 -0
- chat/tests/test_tools.py +68 -0
- chat/tests/test_trackc.py +235 -0
- chat/tools.py +49 -0
- chat/urls.py +17 -0
- chat/views.py +656 -0
- communications/__init__.py +0 -0
- communications/admin.py +97 -0
- communications/api.py +160 -0
- communications/apps.py +33 -0
- communications/backfill.py +164 -0
- communications/email_link.py +180 -0
- communications/ingest.py +365 -0
- communications/kinds.py +206 -0
- communications/management/__init__.py +0 -0
- communications/management/commands/__init__.py +0 -0
- communications/management/commands/resolve_participants.py +26 -0
- communications/migrations/0001_initial.py +98 -0
- communications/migrations/0002_communication_schema.py +290 -0
- communications/migrations/0003_backfill_email_communications.py +31 -0
- communications/migrations/0004_us_english_choice_labels.py +28 -0
- communications/migrations/__init__.py +0 -0
- communications/models.py +271 -0
- communications/participants.py +217 -0
- communications/serializers.py +84 -0
- communications/services.py +493 -0
- communications/templates/communications/emails/invoice_email.html +37 -0
- communications/templates/communications/emails/order_confirmation.html +188 -0
- communications/templates/communications/emails/order_confirmation.txt +31 -0
- communications/templates/communications/emails/quote_email.html +44 -0
- communications/templates/communications/emails/shipping_notification.html +192 -0
- communications/templates/communications/emails/shipping_notification.txt +29 -0
- communications/tests/__init__.py +0 -0
- communications/tests/helpers.py +48 -0
- communications/tests/test_communication_models.py +168 -0
- communications/tests/test_email_backfill.py +216 -0
- communications/tests/test_email_link.py +178 -0
- communications/tests/test_email_sends.py +516 -0
- communications/tests/test_ingest.py +331 -0
- communications/tests/test_ingest_activity.py +142 -0
- communications/tests/test_kinds.py +147 -0
- communications/tests/test_merge.py +49 -0
- communications/urls.py +8 -0
- content/__init__.py +0 -0
- content/admin.py +12 -0
- content/apps.py +5 -0
- content/erp_urls.py +17 -0
- content/erp_views.py +100 -0
- content/forms.py +42 -0
- content/migrations/0001_initial.py +69 -0
- content/migrations/__init__.py +0 -0
- content/models.py +45 -0
- content/serializers.py +16 -0
- content/test_m3_xss.py +74 -0
- content/tests.py +82 -0
- content/urls.py +8 -0
- content/views.py +21 -0
- core/__init__.py +0 -0
- core/access_matrix.py +300 -0
- core/admin.py +250 -0
- core/api_exceptions.py +41 -0
- core/apps.py +62 -0
- core/auth_views.py +198 -0
- core/authentication.py +416 -0
- core/cache_guard.py +276 -0
- core/checks.py +283 -0
- core/client_ip.py +67 -0
- core/context_processors.py +97 -0
- core/csv_safety.py +46 -0
- core/demo_clock.py +376 -0
- core/erp_urls.py +127 -0
- core/error_views.py +73 -0
- core/field_registry.py +289 -0
- core/forms.py +76 -0
- core/hook_registry.py +121 -0
- core/html_safety.py +30 -0
- core/http.py +18 -0
- core/identity/__init__.py +26 -0
- core/identity/backfill.py +270 -0
- core/identity/base.py +165 -0
- core/identity/models.py +60 -0
- core/identity/oidc.py +748 -0
- core/identity/providers.py +465 -0
- core/identity/resolve.py +731 -0
- core/identity/retire.py +209 -0
- core/integration_checks.py +199 -0
- core/integration_registry.py +372 -0
- core/integrations/__init__.py +12 -0
- core/integrations/accounts.py +175 -0
- core/integrations/checks.py +51 -0
- core/integrations/erasure.py +472 -0
- core/integrations/models.py +179 -0
- core/integrations/poll.py +162 -0
- core/integrations/ratelimit.py +163 -0
- core/integrations/transport.py +153 -0
- core/integrations/views.py +301 -0
- core/integrations/webhook.py +121 -0
- core/integrity.py +686 -0
- core/label_registry.py +335 -0
- core/labels.py +145 -0
- core/list_columns.py +368 -0
- core/list_export.py +166 -0
- core/list_prefs.py +67 -0
- core/lookups.py +27 -0
- core/management/__init__.py +0 -0
- core/management/commands/__init__.py +0 -0
- core/management/commands/backfill_tenancy.py +211 -0
- core/management/commands/check_external_refs.py +63 -0
- core/management/commands/check_money.py +118 -0
- core/management/commands/check_numbering.py +84 -0
- core/management/commands/check_outbox.py +50 -0
- core/management/commands/check_schema_parity.py +168 -0
- core/management/commands/check_sidecar.py +156 -0
- core/management/commands/check_tenancy.py +107 -0
- core/management/commands/create_api_key.py +118 -0
- core/management/commands/demo_roll_dates.py +87 -0
- core/management/commands/ensure_legacy_api_user.py +24 -0
- core/management/commands/ensure_storefront_identity.py +41 -0
- core/management/commands/generate_secrets.py +51 -0
- core/management/commands/integration_connect.py +63 -0
- core/management/commands/integrations_poll.py +30 -0
- core/management/commands/integrations_sync.py +60 -0
- core/management/commands/outbox.py +65 -0
- core/management/commands/process_outbox.py +67 -0
- core/management/commands/release_notes.py +59 -0
- core/management/commands/requeue_outbox.py +24 -0
- core/management/commands/revoke_api_key.py +44 -0
- core/management/commands/rotate_secrets.py +69 -0
- core/management/commands/seed_demo_data.py +421 -0
- core/management/commands/seed_release_test.py +365 -0
- core/management/commands/seed_test_edge.py +119 -0
- core/management/commands/seed_test_minimal.py +137 -0
- core/management/commands/setup_demo_user.py +51 -0
- core/management/commands/smoke_cutover.py +257 -0
- core/management/commands/sync_roles.py +99 -0
- core/management/release_exit_codes.py +51 -0
- core/managers.py +52 -0
- core/middleware.py +218 -0
- core/migration_ops.py +82 -0
- core/migrations/0001_initial.py +168 -0
- core/migrations/0002_storefront_identity.py +33 -0
- core/migrations/0003_userprofile_user.py +27 -0
- core/migrations/0004_integrationcheck.py +62 -0
- core/migrations/0005_externalref.py +69 -0
- core/migrations/0006_identity_schema.py +82 -0
- core/migrations/0007_timezones.py +34 -0
- core/migrations/0008_apikey.py +61 -0
- core/migrations/0009_api_service_account.py +50 -0
- core/migrations/0010_userprofile_legacy_external_id.py +25 -0
- core/migrations/0011_remove_userprofile_supabase_uid.py +24 -0
- core/migrations/0012_team.py +64 -0
- core/migrations/0012_useridentity_user_provider_uniq.py +63 -0
- core/migrations/0013_merge_team_useridentity_uniq.py +19 -0
- core/migrations/0014_list_preferences_savedfilter.py +84 -0
- core/migrations/0015_outboxevent.py +136 -0
- core/migrations/0016_integration_accounts.py +190 -0
- core/migrations/0017_erpusersettings_hidden_quick_actions.py +18 -0
- core/migrations/0018_us_english_choice_labels.py +28 -0
- core/migrations/0019_labeloverride.py +52 -0
- core/migrations/__init__.py +0 -0
- core/models.py +542 -0
- core/nav_registry.py +119 -0
- core/oidc_views.py +158 -0
- core/once.py +70 -0
- core/outbox/__init__.py +709 -0
- core/outbox/testing.py +26 -0
- core/permissions.py +73 -0
- core/plugin_apps.py +180 -0
- core/plugins/__init__.py +44 -0
- core/plugins/base.py +263 -0
- core/plugins/crm_adapter.py +946 -0
- core/plugins/crm_export.py +116 -0
- core/plugins/dispatch.py +136 -0
- core/plugins/payroll.py +182 -0
- core/plugins/registry.py +590 -0
- core/plugins/signals.py +199 -0
- core/plugins/url_auth.py +100 -0
- core/portal_auth.py +57 -0
- core/portal_permissions.py +31 -0
- core/portal_urls.py +16 -0
- core/portal_views.py +270 -0
- core/provenance.py +133 -0
- core/quick_actions.py +57 -0
- core/release_notes.py +556 -0
- core/release_test.py +209 -0
- core/role_registry.py +178 -0
- core/roles.py +399 -0
- core/saved_filters.py +202 -0
- core/schema.py +51 -0
- core/schema_parity.py +612 -0
- core/secrets.py +169 -0
- core/serializers.py +149 -0
- core/service_accounts.py +577 -0
- core/sidecar.py +804 -0
- core/sidecar_api.py +193 -0
- core/sidecar_forms.py +243 -0
- core/signals.py +36 -0
- core/sso_views.py +75 -0
- core/staff.py +175 -0
- core/storefront.py +170 -0
- core/teams.py +133 -0
- core/templatetags/__init__.py +0 -0
- core/templatetags/erp_tags.py +190 -0
- core/templatetags/labels.py +105 -0
- core/testing/__init__.py +1 -0
- core/testing/integration_fixtures.py +494 -0
- core/testing/no_network.py +312 -0
- core/tests/__init__.py +0 -0
- core/tests/access_matrix_expectations.py +439 -0
- core/tests/helpers.py +83 -0
- core/tests/legacy_schema.py +104 -0
- core/tests/plugin_fixtures/__init__.py +1 -0
- core/tests/plugin_fixtures/glue.py +45 -0
- core/tests/plugin_fixtures/unimported_glue.py +19 -0
- core/tests/test_access_matrix.py +805 -0
- core/tests/test_addons_alias.py +158 -0
- core/tests/test_alert_markup.py +30 -0
- core/tests/test_api_error_envelope.py +94 -0
- core/tests/test_api_protected_delete.py +66 -0
- core/tests/test_auth_matrix.py +576 -0
- core/tests/test_authentication.py +862 -0
- core/tests/test_backfill_tenancy.py +180 -0
- core/tests/test_cache_down.py +408 -0
- core/tests/test_cancel_button_wiring.py +109 -0
- core/tests/test_check_money.py +392 -0
- core/tests/test_check_numbering.py +202 -0
- core/tests/test_check_sidecar.py +110 -0
- core/tests/test_coupon_throttle_keys.py +112 -0
- core/tests/test_csv_safety.py +129 -0
- core/tests/test_dashboard_aggregates.py +251 -0
- core/tests/test_demo_clock.py +363 -0
- core/tests/test_demo_guard.py +173 -0
- core/tests/test_deploy_secrets.py +86 -0
- core/tests/test_document_sequence.py +39 -0
- core/tests/test_erp_staff_only.py +78 -0
- core/tests/test_erp_tags.py +31 -0
- core/tests/test_error_pages.py +124 -0
- core/tests/test_external_refs.py +110 -0
- core/tests/test_field_registry.py +189 -0
- core/tests/test_findings_check.py +200 -0
- core/tests/test_forge_absent.py +111 -0
- core/tests/test_harness_settings.py +272 -0
- core/tests/test_hook_registry.py +146 -0
- core/tests/test_identity_backfill.py +514 -0
- core/tests/test_identity_providers.py +486 -0
- core/tests/test_identity_retire.py +222 -0
- core/tests/test_integration_adapter.py +330 -0
- core/tests/test_integration_no_leak.py +125 -0
- core/tests/test_integration_poll.py +223 -0
- core/tests/test_integration_registry.py +330 -0
- core/tests/test_integration_secrets.py +268 -0
- core/tests/test_integration_views.py +350 -0
- core/tests/test_integration_webhook.py +160 -0
- core/tests/test_label_overrides_screen.py +112 -0
- core/tests/test_labels.py +343 -0
- core/tests/test_labels_never_leak.py +216 -0
- core/tests/test_list_a11y.py +231 -0
- core/tests/test_list_cell_display.py +65 -0
- core/tests/test_list_export_query.py +93 -0
- core/tests/test_list_infra.py +614 -0
- core/tests/test_list_sort_headers.py +86 -0
- core/tests/test_list_sorting.py +105 -0
- core/tests/test_m2d_auth_ux.py +241 -0
- core/tests/test_m2d_form_roundtrips.py +176 -0
- core/tests/test_m2d_render_sweep.py +230 -0
- core/tests/test_m3_csrf.py +62 -0
- core/tests/test_m3_ratelimit.py +108 -0
- core/tests/test_m3_secrets_headers.py +214 -0
- core/tests/test_m3_sqli.py +108 -0
- core/tests/test_nav_registry.py +96 -0
- core/tests/test_no_network.py +226 -0
- core/tests/test_oidc.py +837 -0
- core/tests/test_one_company.py +136 -0
- core/tests/test_openapi_schema.py +32 -0
- core/tests/test_outbox.py +583 -0
- core/tests/test_payroll_slot.py +139 -0
- core/tests/test_plugin_boot.py +188 -0
- core/tests/test_plugin_signal_emission.py +359 -0
- core/tests/test_plugins.py +113 -0
- core/tests/test_portal_auth.py +735 -0
- core/tests/test_portal_invite_resend.py +242 -0
- core/tests/test_portal_party.py +446 -0
- core/tests/test_prod_compose.py +144 -0
- core/tests/test_prod_settings_db.py +26 -0
- core/tests/test_query_counts.py +62 -0
- core/tests/test_release_notes.py +341 -0
- core/tests/test_role_registry.py +646 -0
- core/tests/test_schema_parity.py +538 -0
- core/tests/test_security_auth_flows.py +250 -0
- core/tests/test_security_input.py +477 -0
- core/tests/test_security_pii.py +140 -0
- core/tests/test_security_settings.py +122 -0
- core/tests/test_seed_release_test.py +120 -0
- core/tests/test_sentry_before_send.py +271 -0
- core/tests/test_session_company_resolution.py +62 -0
- core/tests/test_sidecar.py +416 -0
- core/tests/test_sidecar_api.py +237 -0
- core/tests/test_sidecar_registry.py +127 -0
- core/tests/test_sidecar_vendors.py +256 -0
- core/tests/test_smoke_cutover.py +147 -0
- core/tests/test_sso_views.py +116 -0
- core/tests/test_storefront_identity.py +483 -0
- core/tests/test_teams_and_staff.py +281 -0
- core/tests/test_template_comment_hygiene.py +70 -0
- core/tests/test_tenancy_remainder.py +229 -0
- core/tests/test_tenant_settings_fail_closed.py +95 -0
- core/tests/test_theme_registry.py +83 -0
- core/tests/test_token_scopes.py +354 -0
- core/tests/test_trackc_plugins.py +96 -0
- core/tests/test_tripwire.py +119 -0
- core/tests/test_tz.py +150 -0
- core/tests/test_us_english_values.py +20 -0
- core/tests/test_user_create_view.py +55 -0
- core/tests/test_user_roles_screen.py +104 -0
- core/theme_registry.py +131 -0
- core/throttling.py +254 -0
- core/tripwire_patterns.py +49 -0
- core/tz.py +90 -0
- core/urls.py +20 -0
- core/user_roles.py +78 -0
- core/views/__init__.py +293 -0
- core/views/account.py +218 -0
- core/views/dashboard.py +117 -0
- core/views/form_view.py +54 -0
- core/views/integrations.py +132 -0
- core/views/labels.py +122 -0
- core/views/list_view.py +576 -0
- core/views/mixins.py +47 -0
- core/views/teams.py +155 -0
- crm/__init__.py +0 -0
- crm/activity_compat.py +358 -0
- crm/admin.py +189 -0
- crm/api.py +797 -0
- crm/api_serializers.py +573 -0
- crm/apps.py +19 -0
- crm/assist.py +305 -0
- crm/backfill.py +1430 -0
- crm/conf.py +49 -0
- crm/due.py +84 -0
- crm/engagements.py +716 -0
- crm/erp_timeline.py +232 -0
- crm/erp_urls.py +49 -0
- crm/erp_views.py +1665 -0
- crm/fields/__init__.py +6 -0
- crm/fields/counts.py +166 -0
- crm/fields/inventory.py +305 -0
- crm/forms.py +611 -0
- crm/intake.py +286 -0
- crm/lifecycle.py +121 -0
- crm/management/__init__.py +0 -0
- crm/management/commands/__init__.py +0 -0
- crm/management/commands/ads_conversions.py +71 -0
- crm/management/commands/backfill_crm.py +90 -0
- crm/management/commands/check_engagements.py +93 -0
- crm/management/commands/check_field_inventory.py +60 -0
- crm/management/commands/crm_emit_due.py +25 -0
- crm/management/commands/field_inventory.py +88 -0
- crm/management/commands/reconcile_engagements.py +263 -0
- crm/management/commands/seed_crm.py +360 -0
- crm/management/commands/seed_my_day.py +277 -0
- crm/migrations/0001_initial.py +156 -0
- crm/migrations/0002_initial.py +81 -0
- crm/migrations/0003_initial.py +38 -0
- crm/migrations/0004_activitylog_company.py +25 -0
- crm/migrations/0005_backfill_activitylog_company.py +33 -0
- crm/migrations/0006_party_links.py +27 -0
- crm/migrations/0007_engagement_schema.py +923 -0
- crm/migrations/0008_seed_default_pipelines.py +29 -0
- crm/migrations/0009_task_communication.py +26 -0
- crm/migrations/0010_backfill_quote_engagements.py +40 -0
- crm/migrations/0011_lead_engagement.py +26 -0
- crm/migrations/0012_backfill_lead_engagements.py +31 -0
- crm/migrations/0013_backfill_activity_communications.py +30 -0
- crm/migrations/0014_tighten.py +35 -0
- crm/migrations/0015_engagement_owner_team.py +34 -0
- crm/migrations/0016_stamp_owner_team.py +27 -0
- crm/migrations/0017_engagement_metadata_gin.py +21 -0
- crm/migrations/0018_lead_source_ai_chat.py +32 -0
- crm/migrations/0019_closed_signed_stage.py +31 -0
- crm/migrations/0020_us_english_choice_labels.py +44 -0
- crm/migrations/__init__.py +0 -0
- crm/models.py +1075 -0
- crm/pipelines.py +126 -0
- crm/registries.py +335 -0
- crm/serializers.py +123 -0
- crm/tasks.py +326 -0
- crm/templatetags/__init__.py +0 -0
- crm/templatetags/crm_tags.py +19 -0
- crm/tests/__init__.py +0 -0
- crm/tests/helpers.py +81 -0
- crm/tests/test_api.py +601 -0
- crm/tests/test_assist_api.py +141 -0
- crm/tests/test_create_screens.py +187 -0
- crm/tests/test_engagement_models.py +353 -0
- crm/tests/test_engagement_services.py +241 -0
- crm/tests/test_erp_views.py +1035 -0
- crm/tests/test_field_inventory.py +402 -0
- crm/tests/test_lead_intake.py +360 -0
- crm/tests/test_lead_numbers.py +77 -0
- crm/tests/test_leads.py +313 -0
- crm/tests/test_owner_team.py +392 -0
- crm/tests/test_owner_team_migration.py +84 -0
- crm/tests/test_p4_screens.py +541 -0
- crm/tests/test_party_picker.py +120 -0
- crm/tests/test_quote_engagements.py +595 -0
- crm/tests/test_quote_from_engagement.py +163 -0
- crm/tests/test_reconstructed_history.py +126 -0
- crm/tests/test_registries.py +147 -0
- crm/tests/test_reopen_forbidden.py +69 -0
- crm/tests/test_seeding_and_checks.py +269 -0
- crm/tests/test_signals.py +464 -0
- crm/tests/test_step6_backfill.py +630 -0
- crm/tests/test_task_updated.py +176 -0
- crm/tests/test_tasks.py +293 -0
- crm/tests/test_touchpoints.py +241 -0
- crm/timeline.py +250 -0
- crm/touchpoints.py +371 -0
- crm/urls.py +33 -0
- crm/views.py +137 -0
- crm_import/__init__.py +6 -0
- crm_import/ai.py +757 -0
- crm_import/appliers/__init__.py +84 -0
- crm_import/appliers/activity.py +113 -0
- crm_import/appliers/associations.py +192 -0
- crm_import/appliers/base.py +363 -0
- crm_import/appliers/communications.py +262 -0
- crm_import/appliers/consent.py +266 -0
- crm_import/appliers/deals.py +870 -0
- crm_import/appliers/owners.py +85 -0
- crm_import/appliers/parties.py +389 -0
- crm_import/appliers/pipelines.py +116 -0
- crm_import/appliers/relationships.py +237 -0
- crm_import/appliers/tasks.py +252 -0
- crm_import/apps.py +12 -0
- crm_import/canonical/__init__.py +52 -0
- crm_import/canonical/io.py +206 -0
- crm_import/canonical/schema.py +388 -0
- crm_import/canonical/validate.py +671 -0
- crm_import/compare.py +294 -0
- crm_import/erp_urls.py +28 -0
- crm_import/erp_views.py +71 -0
- crm_import/locks.py +111 -0
- crm_import/management/__init__.py +0 -0
- crm_import/management/commands/__init__.py +0 -0
- crm_import/management/commands/check_canonical_export.py +63 -0
- crm_import/management/commands/crm_export_adapt.py +100 -0
- crm_import/management/commands/crm_import.py +320 -0
- crm_import/match.py +933 -0
- crm_import/migrations/0001_initial.py +416 -0
- crm_import/migrations/0002_us_english_choice_labels.py +33 -0
- crm_import/migrations/__init__.py +0 -0
- crm_import/models.py +334 -0
- crm_import/report.py +297 -0
- crm_import/review.py +1162 -0
- crm_import/runner.py +526 -0
- crm_import/sidecar.py +110 -0
- crm_import/stage.py +641 -0
- crm_import/tests/__init__.py +0 -0
- crm_import/tests/canonical_cases.py +102 -0
- crm_import/tests/fixtures/ai/recorded.json +26 -0
- crm_import/tests/fixtures/canonical/invalid/adapter-version-mismatch/case.json +13 -0
- crm_import/tests/fixtures/canonical/invalid/adapter-version-mismatch/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/archived-not-enumerated/case.json +14 -0
- crm_import/tests/fixtures/canonical/invalid/archived-not-enumerated/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/consent-shape/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/consent-shape/consent.jsonl +3 -0
- crm_import/tests/fixtures/canonical/invalid/consent-shape/validation.expected.json +18 -0
- crm_import/tests/fixtures/canonical/invalid/coverage-inconsistent/case.json +28 -0
- crm_import/tests/fixtures/canonical/invalid/coverage-inconsistent/validation.expected.json +18 -0
- crm_import/tests/fixtures/canonical/invalid/coverage-reason-missing/case.json +14 -0
- crm_import/tests/fixtures/canonical/invalid/coverage-reason-missing/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/dangling-association/associations.jsonl +4 -0
- crm_import/tests/fixtures/canonical/invalid/dangling-association/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/dangling-association/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/duplicate-key/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/duplicate-key/pipelines.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/duplicate-key/property_defs.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/duplicate-key/validation.expected.json +18 -0
- crm_import/tests/fixtures/canonical/invalid/duplicate-source-id/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/duplicate-source-id/contacts.jsonl +5 -0
- crm_import/tests/fixtures/canonical/invalid/duplicate-source-id/validation.expected.json +18 -0
- crm_import/tests/fixtures/canonical/invalid/file-absent-unknown/case.json +39 -0
- crm_import/tests/fixtures/canonical/invalid/file-absent-unknown/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/file-missing/case.json +6 -0
- crm_import/tests/fixtures/canonical/invalid/file-missing/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/hash-mismatch/case.json +4 -0
- crm_import/tests/fixtures/canonical/invalid/hash-mismatch/deals.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/hash-mismatch/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/inconsistent/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/inconsistent/consent.jsonl +3 -0
- crm_import/tests/fixtures/canonical/invalid/inconsistent/contacts.jsonl +3 -0
- crm_import/tests/fixtures/canonical/invalid/inconsistent/tasks.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/inconsistent/validation.expected.json +24 -0
- crm_import/tests/fixtures/canonical/invalid/invalid-encoding/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/invalid-encoding/owners.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/invalid-encoding/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/invalid-value/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/invalid-value/deals.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/invalid-value/pipelines.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/invalid-value/validation.expected.json +24 -0
- crm_import/tests/fixtures/canonical/invalid/malformed-lines/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/malformed-lines/tasks.jsonl +5 -0
- crm_import/tests/fixtures/canonical/invalid/malformed-lines/validation.expected.json +24 -0
- crm_import/tests/fixtures/canonical/invalid/manifest-invalid-json/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/manifest-invalid-json/manifest.json +1 -0
- crm_import/tests/fixtures/canonical/invalid/manifest-invalid-json/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/manifest-missing/case.json +6 -0
- crm_import/tests/fixtures/canonical/invalid/manifest-missing/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/manifest-provider-mismatch/case.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/manifest-provider-mismatch/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/missing-data-key/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/missing-data-key/contacts.jsonl +3 -0
- crm_import/tests/fixtures/canonical/invalid/missing-data-key/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/missing-envelope-key/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/missing-envelope-key/contacts.jsonl +3 -0
- crm_import/tests/fixtures/canonical/invalid/missing-envelope-key/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/object-type-missing/case.json +19 -0
- crm_import/tests/fixtures/canonical/invalid/object-type-missing/validation.expected.json +18 -0
- crm_import/tests/fixtures/canonical/invalid/pipeline-key-shape/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/pipeline-key-shape/pipelines.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/pipeline-key-shape/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/pipeline-kind-mismatch/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/pipeline-kind-mismatch/relationships.jsonl +1 -0
- crm_import/tests/fixtures/canonical/invalid/pipeline-kind-mismatch/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/row-count-mismatch/case.json +14 -0
- crm_import/tests/fixtures/canonical/invalid/row-count-mismatch/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/source-mismatch/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/source-mismatch/deals.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/source-mismatch/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/stage-not-in-pipeline/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/stage-not-in-pipeline/deals.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/stage-not-in-pipeline/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/task-due-shape/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/task-due-shape/tasks.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/task-due-shape/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/unknown-key/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/unknown-key/contacts.jsonl +3 -0
- crm_import/tests/fixtures/canonical/invalid/unknown-key/validation.expected.json +18 -0
- crm_import/tests/fixtures/canonical/invalid/unknown-reason-code/case.json +28 -0
- crm_import/tests/fixtures/canonical/invalid/unknown-reason-code/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/unknown-version-manifest/case.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/unknown-version-manifest/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/unknown-version-record/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/unknown-version-record/contacts.jsonl +3 -0
- crm_import/tests/fixtures/canonical/invalid/unknown-version-record/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/unresolved-ref-partial/associations.jsonl +4 -0
- crm_import/tests/fixtures/canonical/invalid/unresolved-ref-partial/case.json +28 -0
- crm_import/tests/fixtures/canonical/invalid/unresolved-ref-partial/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/unsorted/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/unsorted/contacts.jsonl +3 -0
- crm_import/tests/fixtures/canonical/invalid/unsorted/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/wrong-object-type/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/wrong-object-type/deals.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/wrong-object-type/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/wrong-ref-type/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/wrong-ref-type/deals.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/wrong-ref-type/validation.expected.json +12 -0
- crm_import/tests/fixtures/canonical/invalid/wrong-type/case.json +3 -0
- crm_import/tests/fixtures/canonical/invalid/wrong-type/deals.jsonl +2 -0
- crm_import/tests/fixtures/canonical/invalid/wrong-type/validation.expected.json +18 -0
- crm_import/tests/fixtures/canonical/valid-small/associations.jsonl +3 -0
- crm_import/tests/fixtures/canonical/valid-small/communications.jsonl +2 -0
- crm_import/tests/fixtures/canonical/valid-small/companies.jsonl +2 -0
- crm_import/tests/fixtures/canonical/valid-small/consent.jsonl +3 -0
- crm_import/tests/fixtures/canonical/valid-small/contacts.jsonl +3 -0
- crm_import/tests/fixtures/canonical/valid-small/deals.jsonl +2 -0
- crm_import/tests/fixtures/canonical/valid-small/expected/validation.expected.json +34 -0
- crm_import/tests/fixtures/canonical/valid-small/manifest.json +113 -0
- crm_import/tests/fixtures/canonical/valid-small/owners.jsonl +2 -0
- crm_import/tests/fixtures/canonical/valid-small/pipelines.jsonl +2 -0
- crm_import/tests/fixtures/canonical/valid-small/property_defs.jsonl +2 -0
- crm_import/tests/fixtures/canonical/valid-small/relationships.jsonl +1 -0
- crm_import/tests/fixtures/canonical/valid-small/tasks.jsonl +2 -0
- crm_import/tests/staging_helpers.py +147 -0
- crm_import/tests/test_ai.py +805 -0
- crm_import/tests/test_appliers.py +543 -0
- crm_import/tests/test_appliers_activity.py +654 -0
- crm_import/tests/test_appliers_deals.py +1008 -0
- crm_import/tests/test_appliers_deals_fixture.py +98 -0
- crm_import/tests/test_appliers_pg.py +82 -0
- crm_import/tests/test_canonical.py +409 -0
- crm_import/tests/test_job_models.py +447 -0
- crm_import/tests/test_review_views.py +833 -0
- crm_import/tests/test_runner.py +390 -0
- crm_import/tests/test_runner_pg.py +106 -0
- crm_import/tests/test_staging.py +817 -0
- crm_import/tests/test_staging_pg.py +92 -0
- crm_import/views/__init__.py +1 -0
- crm_import/views/review.py +605 -0
- crm_import/writelog.py +544 -0
- customers/__init__.py +0 -0
- customers/admin.py +37 -0
- customers/apps.py +5 -0
- customers/erp_urls.py +45 -0
- customers/erp_views.py +726 -0
- customers/forms.py +97 -0
- customers/management/__init__.py +0 -0
- customers/management/commands/__init__.py +0 -0
- customers/management/commands/check_tighten.py +27 -0
- customers/migrations/0001_initial.py +221 -0
- customers/migrations/0002_initial.py +67 -0
- customers/migrations/0003_customer_user.py +27 -0
- customers/migrations/0004_backfill_user_identity.py +34 -0
- customers/migrations/0005_party_links.py +87 -0
- customers/migrations/0006_rerun_identity_backfill.py +33 -0
- customers/migrations/0007_tighten.py +85 -0
- customers/migrations/0008_identity_retire_precheck.py +42 -0
- customers/migrations/0009_remove_customer_supabase_user_id.py +22 -0
- customers/migrations/__init__.py +0 -0
- customers/models.py +367 -0
- customers/pre_tighten.py +133 -0
- customers/serializers.py +71 -0
- customers/test_erased_display.py +68 -0
- customers/test_m3_xss.py +67 -0
- customers/test_portal_link_readonly.py +66 -0
- customers/test_quick_create_tenant.py +86 -0
- customers/test_tighten.py +315 -0
- customers/tests.py +59 -0
- customers/tighten.py +127 -0
- customers/urls.py +9 -0
- customers/views.py +35 -0
- discounts/__init__.py +0 -0
- discounts/admin.py +42 -0
- discounts/apps.py +7 -0
- discounts/erp_urls.py +17 -0
- discounts/erp_views.py +186 -0
- discounts/forms.py +81 -0
- discounts/migrations/0001_initial.py +141 -0
- discounts/migrations/__init__.py +0 -0
- discounts/models.py +78 -0
- discounts/serializers.py +31 -0
- discounts/urls.py +8 -0
- discounts/views.py +166 -0
- documents/__init__.py +0 -0
- documents/admin.py +14 -0
- documents/apps.py +5 -0
- documents/brand.py +31 -0
- documents/erp_urls.py +7 -0
- documents/erp_views.py +38 -0
- documents/management/__init__.py +0 -0
- documents/management/commands/__init__.py +0 -0
- documents/management/commands/auto_match_docs.py +414 -0
- documents/matcher.py +418 -0
- documents/migrations/0001_initial.py +116 -0
- documents/migrations/0002_initial.py +26 -0
- documents/migrations/__init__.py +0 -0
- documents/models.py +65 -0
- documents/serializers.py +40 -0
- documents/services/__init__.py +0 -0
- documents/services/document_context.py +363 -0
- documents/services/pdf.py +82 -0
- documents/templates/documents/base_document.html +351 -0
- documents/templates/documents/purchase_order.html +38 -0
- documents/templates/documents/sales_invoice.html +79 -0
- documents/templates/documents/sales_quote.html +82 -0
- documents/tests/__init__.py +0 -0
- documents/tests/test_auto_match.py +458 -0
- documents/tests/test_document_addresses.py +93 -0
- documents/tests/test_document_fonts.py +92 -0
- documents/tests/test_pdf_service.py +70 -0
- documents/tests/test_quote_pdf_service.py +146 -0
- documents/tests/test_trackc.py +223 -0
- documents/tests/test_upload_caps.py +78 -0
- documents/text_extract.py +52 -0
- documents/tigris_inventory.py +99 -0
- documents/urls.py +8 -0
- documents/views.py +19 -0
- erp_assist/__init__.py +0 -0
- erp_assist/core/__init__.py +21 -0
- erp_assist/core/_cache.py +109 -0
- erp_assist/core/_writable_fields.py +683 -0
- erp_assist/core/client.py +270 -0
- erp_assist/core/crm.py +565 -0
- erp_assist/core/customers.py +258 -0
- erp_assist/core/inventory.py +154 -0
- erp_assist/core/orders.py +526 -0
- erp_assist/core/parties.py +188 -0
- erp_assist/core/pricing.py +208 -0
- erp_assist/core/products.py +558 -0
- erp_assist/core/purchasing.py +343 -0
- erp_assist/http_adapter.py +27 -0
- erp_assist/mcp_adapter.py +2222 -0
- erp_assist/tests/__init__.py +0 -0
- erp_assist/tests/test_api_e2e.py +263 -0
- erp_assist/tests/test_crm_report_tools.py +149 -0
- erp_assist/tests/test_crm_tools.py +394 -0
- erp_assist/tests/test_customer_writable.py +35 -0
- erp_assist/tests/test_party_ambiguity.py +246 -0
- erp_assist/tests/test_quote_pipeline_moved.py +44 -0
- fincas-0.4.1.dist-info/METADATA +216 -0
- fincas-0.4.1.dist-info/RECORD +2326 -0
- fincas-0.4.1.dist-info/WHEEL +5 -0
- fincas-0.4.1.dist-info/licenses/LICENSE +21 -0
- fincas-0.4.1.dist-info/top_level.txt +26 -0
- fulfillment/__init__.py +0 -0
- fulfillment/admin.py +204 -0
- fulfillment/apps.py +5 -0
- fulfillment/carriers/__init__.py +26 -0
- fulfillment/carriers/base.py +118 -0
- fulfillment/carriers/easypost_carrier.py +184 -0
- fulfillment/carriers/manual.py +74 -0
- fulfillment/carriers/registry.py +41 -0
- fulfillment/erp_urls.py +17 -0
- fulfillment/erp_views.py +337 -0
- fulfillment/forms.py +63 -0
- fulfillment/label_service.py +293 -0
- fulfillment/migrations/0001_initial.py +120 -0
- fulfillment/migrations/0002_initial.py +79 -0
- fulfillment/migrations/0003_initial.py +27 -0
- fulfillment/migrations/__init__.py +0 -0
- fulfillment/models.py +117 -0
- fulfillment/printer.py +95 -0
- fulfillment/serializers.py +19 -0
- fulfillment/templates/admin/fulfillment/pickticket/change_form.html +143 -0
- fulfillment/tests/__init__.py +0 -0
- fulfillment/tests/test_carriers.py +82 -0
- fulfillment/tests/test_company_scoping.py +119 -0
- fulfillment/tests/test_m2d_print.py +69 -0
- fulfillment/tests/test_pick_ticket_transitions.py +100 -0
- fulfillment/urls.py +9 -0
- fulfillment/views.py +55 -0
- golden_erp/__init__.py +34 -0
- golden_erp/addons/__init__.py +7 -0
- golden_erp/addons/aircall/__init__.py +13 -0
- golden_erp/addons/aircall/adapter.py +304 -0
- golden_erp/addons/aircall/fixtures/comment-update/account.json +4 -0
- golden_erp/addons/aircall/fixtures/comment-update/case.json +37 -0
- golden_erp/addons/aircall/fixtures/comment-update/db.expected.json +57 -0
- golden_erp/addons/aircall/fixtures/comment-update/inbound/001.json +38 -0
- golden_erp/addons/aircall/fixtures/comment-update/inbound/002.json +49 -0
- golden_erp/addons/aircall/fixtures/comment-update/requests.expected.json +1 -0
- golden_erp/addons/aircall/fixtures/erased-call-skipped/account.json +4 -0
- golden_erp/addons/aircall/fixtures/erased-call-skipped/case.json +34 -0
- golden_erp/addons/aircall/fixtures/erased-call-skipped/db.expected.json +20 -0
- golden_erp/addons/aircall/fixtures/erased-call-skipped/inbound/001.json +38 -0
- golden_erp/addons/aircall/fixtures/erased-call-skipped/requests.expected.json +1 -0
- golden_erp/addons/aircall/fixtures/erased-number-skipped/account.json +4 -0
- golden_erp/addons/aircall/fixtures/erased-number-skipped/case.json +25 -0
- golden_erp/addons/aircall/fixtures/erased-number-skipped/db.expected.json +32 -0
- golden_erp/addons/aircall/fixtures/erased-number-skipped/inbound/001.json +38 -0
- golden_erp/addons/aircall/fixtures/erased-number-skipped/requests.expected.json +1 -0
- golden_erp/addons/aircall/fixtures/ignored-event/account.json +4 -0
- golden_erp/addons/aircall/fixtures/ignored-event/case.json +30 -0
- golden_erp/addons/aircall/fixtures/ignored-event/db.expected.json +17 -0
- golden_erp/addons/aircall/fixtures/ignored-event/inbound/001.json +14 -0
- golden_erp/addons/aircall/fixtures/ignored-event/requests.expected.json +1 -0
- golden_erp/addons/aircall/fixtures/inbound-answered-known/account.json +4 -0
- golden_erp/addons/aircall/fixtures/inbound-answered-known/case.json +36 -0
- golden_erp/addons/aircall/fixtures/inbound-answered-known/db.expected.json +50 -0
- golden_erp/addons/aircall/fixtures/inbound-answered-known/inbound/001.json +43 -0
- golden_erp/addons/aircall/fixtures/inbound-answered-known/requests.expected.json +1 -0
- golden_erp/addons/aircall/fixtures/missed-unknown-number/account.json +4 -0
- golden_erp/addons/aircall/fixtures/missed-unknown-number/case.json +30 -0
- golden_erp/addons/aircall/fixtures/missed-unknown-number/db.expected.json +50 -0
- golden_erp/addons/aircall/fixtures/missed-unknown-number/inbound/001.json +34 -0
- golden_erp/addons/aircall/fixtures/missed-unknown-number/requests.expected.json +1 -0
- golden_erp/addons/aircall/fixtures/newer-schema/account.json +4 -0
- golden_erp/addons/aircall/fixtures/newer-schema/case.json +28 -0
- golden_erp/addons/aircall/fixtures/newer-schema/db.expected.json +9 -0
- golden_erp/addons/aircall/fixtures/newer-schema/inbound/001.json +38 -0
- golden_erp/addons/aircall/fixtures/newer-schema/requests.expected.json +1 -0
- golden_erp/addons/aircall/fixtures/outbound-known/account.json +4 -0
- golden_erp/addons/aircall/fixtures/outbound-known/case.json +33 -0
- golden_erp/addons/aircall/fixtures/outbound-known/db.expected.json +42 -0
- golden_erp/addons/aircall/fixtures/outbound-known/inbound/001.json +38 -0
- golden_erp/addons/aircall/fixtures/outbound-known/requests.expected.json +1 -0
- golden_erp/addons/aircall/fixtures/poll-backstop/account.json +6 -0
- golden_erp/addons/aircall/fixtures/poll-backstop/case.json +50 -0
- golden_erp/addons/aircall/fixtures/poll-backstop/db.expected.json +42 -0
- golden_erp/addons/aircall/fixtures/poll-backstop/requests.expected.json +32 -0
- golden_erp/addons/aircall/fixtures/poll-backstop/responses/001-page1.json +54 -0
- golden_erp/addons/aircall/fixtures/poll-backstop/responses/002-page2.json +54 -0
- golden_erp/addons/aircall/fixtures/poll-backstop/responses/003-held.json +26 -0
- golden_erp/addons/aircall/fixtures/replayed-event/account.json +4 -0
- golden_erp/addons/aircall/fixtures/replayed-event/case.json +34 -0
- golden_erp/addons/aircall/fixtures/replayed-event/db.expected.json +50 -0
- golden_erp/addons/aircall/fixtures/replayed-event/inbound/001.json +38 -0
- golden_erp/addons/aircall/fixtures/replayed-event/requests.expected.json +1 -0
- golden_erp/addons/aircall/fixtures/token-mismatch/account.json +4 -0
- golden_erp/addons/aircall/fixtures/token-mismatch/case.json +30 -0
- golden_erp/addons/aircall/fixtures/token-mismatch/db.expected.json +9 -0
- golden_erp/addons/aircall/fixtures/token-mismatch/inbound/001.json +38 -0
- golden_erp/addons/aircall/fixtures/token-mismatch/requests.expected.json +1 -0
- golden_erp/addons/aircall/fixtures/voicemail/account.json +4 -0
- golden_erp/addons/aircall/fixtures/voicemail/case.json +30 -0
- golden_erp/addons/aircall/fixtures/voicemail/db.expected.json +50 -0
- golden_erp/addons/aircall/fixtures/voicemail/inbound/001.json +34 -0
- golden_erp/addons/aircall/fixtures/voicemail/requests.expected.json +1 -0
- golden_erp/addons/aircall/mapping.py +198 -0
- golden_erp/addons/aircall/plugin.py +26 -0
- golden_erp/addons/aircall/tests/__init__.py +0 -0
- golden_erp/addons/aircall/tests/helpers.py +42 -0
- golden_erp/addons/aircall/tests/test_aircall.py +406 -0
- golden_erp/addons/aircall/tests/test_contract.py +33 -0
- golden_erp/addons/aircall/tests/test_mapping.py +92 -0
- golden_erp/addons/aircall/values.py +62 -0
- golden_erp/addons/clickup/__init__.py +14 -0
- golden_erp/addons/clickup/adapter.py +1135 -0
- golden_erp/addons/clickup/fixtures/assignee-unknown/account.json +18 -0
- golden_erp/addons/clickup/fixtures/assignee-unknown/case.json +45 -0
- golden_erp/addons/clickup/fixtures/assignee-unknown/db.expected.json +30 -0
- golden_erp/addons/clickup/fixtures/assignee-unknown/inbound/001.json +36 -0
- golden_erp/addons/clickup/fixtures/assignee-unknown/requests.expected.json +1 -0
- golden_erp/addons/clickup/fixtures/deleted-cancels/account.json +18 -0
- golden_erp/addons/clickup/fixtures/deleted-cancels/case.json +65 -0
- golden_erp/addons/clickup/fixtures/deleted-cancels/db.expected.json +64 -0
- golden_erp/addons/clickup/fixtures/deleted-cancels/inbound/001-deleted.json +24 -0
- golden_erp/addons/clickup/fixtures/deleted-cancels/inbound/002-deleted.json +24 -0
- golden_erp/addons/clickup/fixtures/deleted-cancels/requests.expected.json +1 -0
- golden_erp/addons/clickup/fixtures/echo-no-op/account.json +18 -0
- golden_erp/addons/clickup/fixtures/echo-no-op/case.json +59 -0
- golden_erp/addons/clickup/fixtures/echo-no-op/db.expected.json +48 -0
- golden_erp/addons/clickup/fixtures/echo-no-op/inbound/001-echo.json +24 -0
- golden_erp/addons/clickup/fixtures/echo-no-op/requests.expected.json +26 -0
- golden_erp/addons/clickup/fixtures/echo-no-op/responses/001.json +40 -0
- golden_erp/addons/clickup/fixtures/echo-no-op/responses/002.json +40 -0
- golden_erp/addons/clickup/fixtures/erase/account.json +18 -0
- golden_erp/addons/clickup/fixtures/erase/case.json +59 -0
- golden_erp/addons/clickup/fixtures/erase/db.expected.json +38 -0
- golden_erp/addons/clickup/fixtures/erase/requests.expected.json +25 -0
- golden_erp/addons/clickup/fixtures/erase/responses/001.json +34 -0
- golden_erp/addons/clickup/fixtures/erase/responses/002.json +9 -0
- golden_erp/addons/clickup/fixtures/inbound-create-linked/account.json +18 -0
- golden_erp/addons/clickup/fixtures/inbound-create-linked/case.json +36 -0
- golden_erp/addons/clickup/fixtures/inbound-create-linked/db.expected.json +38 -0
- golden_erp/addons/clickup/fixtures/inbound-create-linked/inbound/001-created.json +24 -0
- golden_erp/addons/clickup/fixtures/inbound-create-linked/requests.expected.json +14 -0
- golden_erp/addons/clickup/fixtures/inbound-create-linked/responses/001.json +47 -0
- golden_erp/addons/clickup/fixtures/inbound-engagement-refused/account.json +18 -0
- golden_erp/addons/clickup/fixtures/inbound-engagement-refused/case.json +56 -0
- golden_erp/addons/clickup/fixtures/inbound-engagement-refused/db.expected.json +30 -0
- golden_erp/addons/clickup/fixtures/inbound-engagement-refused/inbound/001.json +43 -0
- golden_erp/addons/clickup/fixtures/inbound-engagement-refused/requests.expected.json +1 -0
- golden_erp/addons/clickup/fixtures/inbound-erased-skipped/account.json +18 -0
- golden_erp/addons/clickup/fixtures/inbound-erased-skipped/case.json +46 -0
- golden_erp/addons/clickup/fixtures/inbound-erased-skipped/db.expected.json +31 -0
- golden_erp/addons/clickup/fixtures/inbound-erased-skipped/inbound/001.json +36 -0
- golden_erp/addons/clickup/fixtures/inbound-erased-skipped/requests.expected.json +1 -0
- golden_erp/addons/clickup/fixtures/inbound-stale-ignored/account.json +18 -0
- golden_erp/addons/clickup/fixtures/inbound-stale-ignored/case.json +45 -0
- golden_erp/addons/clickup/fixtures/inbound-stale-ignored/db.expected.json +30 -0
- golden_erp/addons/clickup/fixtures/inbound-stale-ignored/inbound/001-stale.json +36 -0
- golden_erp/addons/clickup/fixtures/inbound-stale-ignored/requests.expected.json +1 -0
- golden_erp/addons/clickup/fixtures/inbound-status-map/account.json +18 -0
- golden_erp/addons/clickup/fixtures/inbound-status-map/case.json +48 -0
- golden_erp/addons/clickup/fixtures/inbound-status-map/db.expected.json +30 -0
- golden_erp/addons/clickup/fixtures/inbound-status-map/inbound/001-in-review.json +36 -0
- golden_erp/addons/clickup/fixtures/inbound-status-map/inbound/002-closed.json +36 -0
- golden_erp/addons/clickup/fixtures/inbound-status-map/requests.expected.json +1 -0
- golden_erp/addons/clickup/fixtures/inbound-unlinked-ignored/account.json +18 -0
- golden_erp/addons/clickup/fixtures/inbound-unlinked-ignored/case.json +35 -0
- golden_erp/addons/clickup/fixtures/inbound-unlinked-ignored/db.expected.json +9 -0
- golden_erp/addons/clickup/fixtures/inbound-unlinked-ignored/inbound/001-unlinked.json +30 -0
- golden_erp/addons/clickup/fixtures/inbound-unlinked-ignored/inbound/002-other-list.json +37 -0
- golden_erp/addons/clickup/fixtures/inbound-unlinked-ignored/requests.expected.json +1 -0
- golden_erp/addons/clickup/fixtures/newer-schema/account.json +18 -0
- golden_erp/addons/clickup/fixtures/newer-schema/case.json +34 -0
- golden_erp/addons/clickup/fixtures/newer-schema/db.expected.json +9 -0
- golden_erp/addons/clickup/fixtures/newer-schema/inbound/001.json +37 -0
- golden_erp/addons/clickup/fixtures/newer-schema/requests.expected.json +1 -0
- golden_erp/addons/clickup/fixtures/poll-pages/account.json +18 -0
- golden_erp/addons/clickup/fixtures/poll-pages/case.json +52 -0
- golden_erp/addons/clickup/fixtures/poll-pages/db.expected.json +49 -0
- golden_erp/addons/clickup/fixtures/poll-pages/requests.expected.json +38 -0
- golden_erp/addons/clickup/fixtures/poll-pages/responses/001.json +81 -0
- golden_erp/addons/clickup/fixtures/poll-pages/responses/002.json +55 -0
- golden_erp/addons/clickup/fixtures/poll-pages/responses/003.json +22 -0
- golden_erp/addons/clickup/fixtures/push-complete/account.json +18 -0
- golden_erp/addons/clickup/fixtures/push-complete/case.json +51 -0
- golden_erp/addons/clickup/fixtures/push-complete/db.expected.json +41 -0
- golden_erp/addons/clickup/fixtures/push-complete/requests.expected.json +14 -0
- golden_erp/addons/clickup/fixtures/push-complete/responses/001.json +40 -0
- golden_erp/addons/clickup/fixtures/push-create/account.json +18 -0
- golden_erp/addons/clickup/fixtures/push-create/case.json +43 -0
- golden_erp/addons/clickup/fixtures/push-create/db.expected.json +38 -0
- golden_erp/addons/clickup/fixtures/push-create/requests.expected.json +38 -0
- golden_erp/addons/clickup/fixtures/push-create/responses/001.json +17 -0
- golden_erp/addons/clickup/fixtures/push-create/responses/002.json +40 -0
- golden_erp/addons/clickup/fixtures/push-create-timeout/account.json +18 -0
- golden_erp/addons/clickup/fixtures/push-create-timeout/case.json +49 -0
- golden_erp/addons/clickup/fixtures/push-create-timeout/db.expected.json +47 -0
- golden_erp/addons/clickup/fixtures/push-create-timeout/requests.expected.json +84 -0
- golden_erp/addons/clickup/fixtures/push-create-timeout/responses/001.json +18 -0
- golden_erp/addons/clickup/fixtures/push-create-timeout/responses/002.json +12 -0
- golden_erp/addons/clickup/fixtures/push-create-timeout/responses/003.json +45 -0
- golden_erp/addons/clickup/fixtures/push-create-timeout/responses/004.json +40 -0
- golden_erp/addons/clickup/fixtures/push-edit/account.json +18 -0
- golden_erp/addons/clickup/fixtures/push-edit/case.json +52 -0
- golden_erp/addons/clickup/fixtures/push-edit/db.expected.json +41 -0
- golden_erp/addons/clickup/fixtures/push-edit/requests.expected.json +14 -0
- golden_erp/addons/clickup/fixtures/push-edit/responses/001.json +40 -0
- golden_erp/addons/clickup/fixtures/push-reschedule/account.json +18 -0
- golden_erp/addons/clickup/fixtures/push-reschedule/case.json +52 -0
- golden_erp/addons/clickup/fixtures/push-reschedule/db.expected.json +42 -0
- golden_erp/addons/clickup/fixtures/push-reschedule/requests.expected.json +15 -0
- golden_erp/addons/clickup/fixtures/push-reschedule/responses/001.json +40 -0
- golden_erp/addons/clickup/fixtures/rate-limited/account.json +18 -0
- golden_erp/addons/clickup/fixtures/rate-limited/case.json +54 -0
- golden_erp/addons/clickup/fixtures/rate-limited/db.expected.json +38 -0
- golden_erp/addons/clickup/fixtures/rate-limited/requests.expected.json +14 -0
- golden_erp/addons/clickup/fixtures/rate-limited/responses/001.json +18 -0
- golden_erp/addons/clickup/fixtures/webhook-replayed/account.json +18 -0
- golden_erp/addons/clickup/fixtures/webhook-replayed/case.json +40 -0
- golden_erp/addons/clickup/fixtures/webhook-replayed/db.expected.json +38 -0
- golden_erp/addons/clickup/fixtures/webhook-replayed/inbound/001.json +24 -0
- golden_erp/addons/clickup/fixtures/webhook-replayed/requests.expected.json +14 -0
- golden_erp/addons/clickup/fixtures/webhook-replayed/responses/001.json +41 -0
- golden_erp/addons/clickup/fixtures/webhook-tampered/account.json +18 -0
- golden_erp/addons/clickup/fixtures/webhook-tampered/case.json +33 -0
- golden_erp/addons/clickup/fixtures/webhook-tampered/db.expected.json +9 -0
- golden_erp/addons/clickup/fixtures/webhook-tampered/inbound/001.json +24 -0
- golden_erp/addons/clickup/fixtures/webhook-tampered/requests.expected.json +1 -0
- golden_erp/addons/clickup/mapping.py +226 -0
- golden_erp/addons/clickup/plugin.py +26 -0
- golden_erp/addons/clickup/tests/__init__.py +0 -0
- golden_erp/addons/clickup/tests/seed.py +99 -0
- golden_erp/addons/clickup/tests/test_adapter.py +606 -0
- golden_erp/addons/clickup/tests/test_contract.py +36 -0
- golden_erp/addons/clickup/tests/test_mapping.py +82 -0
- golden_erp/addons/clickup/values.py +69 -0
- golden_erp/addons/example_audit_notifier/__init__.py +5 -0
- golden_erp/addons/example_audit_notifier/plugin.py +100 -0
- golden_erp/addons/fixture_crm/__init__.py +13 -0
- golden_erp/addons/fixture_crm/adapter.py +235 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-erased-skipped/account.json +6 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-erased-skipped/case.json +27 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-erased-skipped/db.expected.json +20 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-erased-skipped/inbound/001.json +16 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-erased-skipped/requests.expected.json +1 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-known-party/account.json +6 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-known-party/case.json +19 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-known-party/db.expected.json +42 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-known-party/inbound/001.json +16 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-known-party/requests.expected.json +1 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-unknown-party/account.json +6 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-unknown-party/case.json +19 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-unknown-party/db.expected.json +9 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-unknown-party/inbound/001.json +16 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-unknown-party/requests.expected.json +1 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-unsupported-type/account.json +6 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-unsupported-type/case.json +19 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-unsupported-type/db.expected.json +9 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-unsupported-type/inbound/001.json +16 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/inbound-unsupported-type/requests.expected.json +1 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/newer-schema/account.json +6 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/newer-schema/case.json +21 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/newer-schema/db.expected.json +9 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/newer-schema/inbound/001.json +16 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/newer-schema/requests.expected.json +1 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/poll-pages/account.json +7 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/poll-pages/case.json +39 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/poll-pages/db.expected.json +73 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/poll-pages/requests.expected.json +27 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/poll-pages/responses/001-page1.json +30 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/poll-pages/responses/002-page2.json +29 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/poll-pages/responses/003-empty.json +17 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-create/account.json +6 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-create/case.json +26 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-create/db.expected.json +26 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-create/requests.expected.json +17 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-create/responses/001-create.json +14 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-create-timeout/account.json +6 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-create-timeout/case.json +32 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-create-timeout/db.expected.json +26 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-create-timeout/requests.expected.json +29 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-create-timeout/responses/001-create-lost.json +12 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-create-timeout/responses/002-search.json +15 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-update/account.json +6 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-update/case.json +33 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-update/db.expected.json +26 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-update/requests.expected.json +16 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/push-update/responses/001-patch.json +11 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/rate-limited/account.json +6 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/rate-limited/case.json +29 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/rate-limited/db.expected.json +17 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/rate-limited/requests.expected.json +17 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/rate-limited/responses/001-throttled.json +17 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-stale/account.json +6 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-stale/case.json +23 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-stale/db.expected.json +9 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-stale/inbound/001.json +23 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-stale/requests.expected.json +1 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-tampered/account.json +6 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-tampered/case.json +23 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-tampered/db.expected.json +9 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-tampered/inbound/001.json +23 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-tampered/requests.expected.json +1 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-valid/account.json +6 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-valid/case.json +23 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-valid/db.expected.json +50 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-valid/inbound/001.json +23 -0
- golden_erp/addons/fixture_crm/fixtures/fixture/webhook-valid/requests.expected.json +1 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/newer-schema/account.json +4 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/newer-schema/case.json +21 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/newer-schema/db.expected.json +9 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/newer-schema/inbound/001.json +16 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/newer-schema/requests.expected.json +1 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-per-grant/account.json +4 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-per-grant/case.json +48 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-per-grant/db.expected.json +42 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-per-grant/requests.expected.json +14 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-per-grant/responses/001-page.json +29 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-per-grant/responses/002-empty.json +17 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-refreshes-token/account.json +4 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-refreshes-token/case.json +52 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-refreshes-token/db.expected.json +42 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-refreshes-token/requests.expected.json +29 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-refreshes-token/responses/001-token.json +13 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-refreshes-token/responses/002-page.json +29 -0
- golden_erp/addons/fixture_crm/fixtures/fixture_oauth/poll-refreshes-token/responses/003-empty.json +17 -0
- golden_erp/addons/fixture_crm/mapping.py +55 -0
- golden_erp/addons/fixture_crm/plugin.py +22 -0
- golden_erp/addons/fixture_crm/tests/__init__.py +0 -0
- golden_erp/addons/fixture_crm/tests/test_contract.py +33 -0
- golden_erp/addons/fixture_crm/tests/test_mapping.py +29 -0
- golden_erp/addons/fixture_crm/values.py +29 -0
- golden_erp/addons/gmail/__init__.py +10 -0
- golden_erp/addons/gmail/adapter.py +844 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/case.json +87 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/db.expected.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/requests.expected.json +98 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/responses/001.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/responses/002.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/responses/003.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/responses/004.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/responses/005.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/responses/006.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/responses/007.json +74 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/responses/008.json +51 -0
- golden_erp/addons/gmail/fixtures/gmail/bcc-copy-adds-participant/responses/009.json +78 -0
- golden_erp/addons/gmail/fixtures/gmail/erased-sender-skipped/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/erased-sender-skipped/case.json +69 -0
- golden_erp/addons/gmail/fixtures/gmail/erased-sender-skipped/db.expected.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/erased-sender-skipped/requests.expected.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/erased-sender-skipped/responses/001.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/erased-sender-skipped/responses/002.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/erased-sender-skipped/responses/003.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/erased-sender-skipped/responses/004.json +51 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/case.json +63 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/db.expected.json +42 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/requests.expected.json +98 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/responses/001.json +118 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/responses/002.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/responses/003.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/responses/004.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/responses/005.json +48 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/responses/006.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/responses/007.json +48 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/responses/008.json +75 -0
- golden_erp/addons/gmail/fixtures/gmail/excluded-label/responses/009.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/first-sync-lists-recent/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/first-sync-lists-recent/case.json +57 -0
- golden_erp/addons/gmail/fixtures/gmail/first-sync-lists-recent/db.expected.json +42 -0
- golden_erp/addons/gmail/fixtures/gmail/first-sync-lists-recent/requests.expected.json +59 -0
- golden_erp/addons/gmail/fixtures/gmail/first-sync-lists-recent/responses/001.json +14 -0
- golden_erp/addons/gmail/fixtures/gmail/first-sync-lists-recent/responses/002.json +21 -0
- golden_erp/addons/gmail/fixtures/gmail/first-sync-lists-recent/responses/003.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/first-sync-lists-recent/responses/004.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/first-sync-lists-recent/responses/005.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/first-sync-lists-recent/responses/006.json +74 -0
- golden_erp/addons/gmail/fixtures/gmail/golden-send-bcc-skipped/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/golden-send-bcc-skipped/case.json +69 -0
- golden_erp/addons/gmail/fixtures/gmail/golden-send-bcc-skipped/db.expected.json +85 -0
- golden_erp/addons/gmail/fixtures/gmail/golden-send-bcc-skipped/requests.expected.json +86 -0
- golden_erp/addons/gmail/fixtures/gmail/golden-send-bcc-skipped/responses/001.json +78 -0
- golden_erp/addons/gmail/fixtures/gmail/golden-send-bcc-skipped/responses/002.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/golden-send-bcc-skipped/responses/003.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/golden-send-bcc-skipped/responses/004.json +55 -0
- golden_erp/addons/gmail/fixtures/gmail/golden-send-bcc-skipped/responses/005.json +51 -0
- golden_erp/addons/gmail/fixtures/gmail/golden-send-bcc-skipped/responses/006.json +78 -0
- golden_erp/addons/gmail/fixtures/gmail/golden-send-bcc-skipped/responses/007.json +51 -0
- golden_erp/addons/gmail/fixtures/gmail/golden-send-bcc-skipped/responses/008.json +78 -0
- golden_erp/addons/gmail/fixtures/gmail/history-expired-resyncs/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/history-expired-resyncs/case.json +63 -0
- golden_erp/addons/gmail/fixtures/gmail/history-expired-resyncs/db.expected.json +42 -0
- golden_erp/addons/gmail/fixtures/gmail/history-expired-resyncs/requests.expected.json +73 -0
- golden_erp/addons/gmail/fixtures/gmail/history-expired-resyncs/responses/001.json +21 -0
- golden_erp/addons/gmail/fixtures/gmail/history-expired-resyncs/responses/002.json +12 -0
- golden_erp/addons/gmail/fixtures/gmail/history-expired-resyncs/responses/003.json +20 -0
- golden_erp/addons/gmail/fixtures/gmail/history-expired-resyncs/responses/004.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/history-expired-resyncs/responses/005.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/history-expired-resyncs/responses/006.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/history-expired-resyncs/responses/007.json +74 -0
- golden_erp/addons/gmail/fixtures/gmail/html-only-body/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/html-only-body/case.json +63 -0
- golden_erp/addons/gmail/fixtures/gmail/html-only-body/db.expected.json +42 -0
- golden_erp/addons/gmail/fixtures/gmail/html-only-body/requests.expected.json +50 -0
- golden_erp/addons/gmail/fixtures/gmail/html-only-body/responses/001.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/html-only-body/responses/002.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/html-only-body/responses/003.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/html-only-body/responses/004.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/html-only-body/responses/005.json +74 -0
- golden_erp/addons/gmail/fixtures/gmail/inbound-known-contact/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/inbound-known-contact/case.json +63 -0
- golden_erp/addons/gmail/fixtures/gmail/inbound-known-contact/db.expected.json +42 -0
- golden_erp/addons/gmail/fixtures/gmail/inbound-known-contact/requests.expected.json +50 -0
- golden_erp/addons/gmail/fixtures/gmail/inbound-known-contact/responses/001.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/inbound-known-contact/responses/002.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/inbound-known-contact/responses/003.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/inbound-known-contact/responses/004.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/inbound-known-contact/responses/005.json +94 -0
- golden_erp/addons/gmail/fixtures/gmail/newer-schema/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/newer-schema/case.json +50 -0
- golden_erp/addons/gmail/fixtures/gmail/newer-schema/db.expected.json +9 -0
- golden_erp/addons/gmail/fixtures/gmail/newer-schema/inbound/001.json +90 -0
- golden_erp/addons/gmail/fixtures/gmail/newer-schema/requests.expected.json +1 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-invalid-grant-revokes/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-invalid-grant-revokes/case.json +74 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-invalid-grant-revokes/db.expected.json +9 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-invalid-grant-revokes/requests.expected.json +31 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-invalid-grant-revokes/responses/001.json +15 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-invalid-grant-revokes/responses/002.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-refresh/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-refresh/case.json +64 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-refresh/db.expected.json +42 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-refresh/requests.expected.json +65 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-refresh/responses/001.json +14 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-refresh/responses/002.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-refresh/responses/003.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-refresh/responses/004.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-refresh/responses/005.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/oauth-refresh/responses/006.json +74 -0
- golden_erp/addons/gmail/fixtures/gmail/outbound-from-owner/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/outbound-from-owner/case.json +63 -0
- golden_erp/addons/gmail/fixtures/gmail/outbound-from-owner/db.expected.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/outbound-from-owner/requests.expected.json +50 -0
- golden_erp/addons/gmail/fixtures/gmail/outbound-from-owner/responses/001.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/outbound-from-owner/responses/002.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/outbound-from-owner/responses/003.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/outbound-from-owner/responses/004.json +59 -0
- golden_erp/addons/gmail/fixtures/gmail/outbound-from-owner/responses/005.json +86 -0
- golden_erp/addons/gmail/fixtures/gmail/push-body-not-a-notification/account.json +6 -0
- golden_erp/addons/gmail/fixtures/gmail/push-body-not-a-notification/case.json +49 -0
- golden_erp/addons/gmail/fixtures/gmail/push-body-not-a-notification/db.expected.json +9 -0
- golden_erp/addons/gmail/fixtures/gmail/push-body-not-a-notification/inbound/push.json +95 -0
- golden_erp/addons/gmail/fixtures/gmail/push-body-not-a-notification/requests.expected.json +1 -0
- golden_erp/addons/gmail/fixtures/gmail/push-notification-polls/account.json +6 -0
- golden_erp/addons/gmail/fixtures/gmail/push-notification-polls/case.json +55 -0
- golden_erp/addons/gmail/fixtures/gmail/push-notification-polls/db.expected.json +57 -0
- golden_erp/addons/gmail/fixtures/gmail/push-notification-polls/inbound/push.json +18 -0
- golden_erp/addons/gmail/fixtures/gmail/push-notification-polls/requests.expected.json +58 -0
- golden_erp/addons/gmail/fixtures/gmail/push-notification-polls/responses/001.json +27 -0
- golden_erp/addons/gmail/fixtures/gmail/push-notification-polls/responses/002.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/push-notification-polls/responses/003.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/push-notification-polls/responses/004.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/push-notification-polls/responses/005.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/push-notification-polls/responses/006.json +74 -0
- golden_erp/addons/gmail/fixtures/gmail/push-wrong-audience/account.json +6 -0
- golden_erp/addons/gmail/fixtures/gmail/push-wrong-audience/case.json +49 -0
- golden_erp/addons/gmail/fixtures/gmail/push-wrong-audience/db.expected.json +9 -0
- golden_erp/addons/gmail/fixtures/gmail/push-wrong-audience/inbound/push.json +18 -0
- golden_erp/addons/gmail/fixtures/gmail/push-wrong-audience/requests.expected.json +10 -0
- golden_erp/addons/gmail/fixtures/gmail/push-wrong-audience/responses/001.json +27 -0
- golden_erp/addons/gmail/fixtures/gmail/same-message-two-mailboxes/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/same-message-two-mailboxes/case.json +87 -0
- golden_erp/addons/gmail/fixtures/gmail/same-message-two-mailboxes/db.expected.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/same-message-two-mailboxes/requests.expected.json +86 -0
- golden_erp/addons/gmail/fixtures/gmail/same-message-two-mailboxes/responses/001.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/same-message-two-mailboxes/responses/002.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/same-message-two-mailboxes/responses/003.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/same-message-two-mailboxes/responses/004.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/same-message-two-mailboxes/responses/005.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/same-message-two-mailboxes/responses/006.json +51 -0
- golden_erp/addons/gmail/fixtures/gmail/same-message-two-mailboxes/responses/007.json +78 -0
- golden_erp/addons/gmail/fixtures/gmail/same-message-two-mailboxes/responses/008.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/case.json +102 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/db.expected.json +131 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/requests.expected.json +134 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/responses/001.json +58 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/responses/002.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/responses/003.json +58 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/responses/004.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/responses/005.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/responses/006.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/responses/007.json +74 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/responses/008.json +59 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/responses/009.json +86 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/responses/010.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/responses/011.json +59 -0
- golden_erp/addons/gmail/fixtures/gmail/thread-across-mailboxes/responses/012.json +86 -0
- golden_erp/addons/gmail/fixtures/gmail/unknown-only-skipped/account.json +4 -0
- golden_erp/addons/gmail/fixtures/gmail/unknown-only-skipped/case.json +63 -0
- golden_erp/addons/gmail/fixtures/gmail/unknown-only-skipped/db.expected.json +9 -0
- golden_erp/addons/gmail/fixtures/gmail/unknown-only-skipped/requests.expected.json +74 -0
- golden_erp/addons/gmail/fixtures/gmail/unknown-only-skipped/responses/001.json +98 -0
- golden_erp/addons/gmail/fixtures/gmail/unknown-only-skipped/responses/002.json +17 -0
- golden_erp/addons/gmail/fixtures/gmail/unknown-only-skipped/responses/003.json +38 -0
- golden_erp/addons/gmail/fixtures/gmail/unknown-only-skipped/responses/004.json +47 -0
- golden_erp/addons/gmail/fixtures/gmail/unknown-only-skipped/responses/005.json +51 -0
- golden_erp/addons/gmail/fixtures/gmail/unknown-only-skipped/responses/006.json +51 -0
- golden_erp/addons/gmail/fixtures/gmail/unknown-only-skipped/responses/007.json +51 -0
- golden_erp/addons/gmail/mapping.py +317 -0
- golden_erp/addons/gmail/plugin.py +23 -0
- golden_erp/addons/gmail/pubsub.py +143 -0
- golden_erp/addons/gmail/tests/__init__.py +0 -0
- golden_erp/addons/gmail/tests/helpers.py +121 -0
- golden_erp/addons/gmail/tests/seed.py +92 -0
- golden_erp/addons/gmail/tests/test_contract.py +30 -0
- golden_erp/addons/gmail/tests/test_gmail.py +525 -0
- golden_erp/addons/gmail/tests/test_gmail_pg.py +82 -0
- golden_erp/addons/gmail/tests/test_mapping.py +101 -0
- golden_erp/addons/gmail/tests/test_pubsub.py +87 -0
- golden_erp/addons/gmail/values.py +47 -0
- golden_erp/addons/google_ads/__init__.py +1 -0
- golden_erp/addons/google_ads/adapter.py +301 -0
- golden_erp/addons/google_ads/conversions.py +150 -0
- golden_erp/addons/google_ads/fixtures/batch-partial-failure/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/batch-partial-failure/case.json +81 -0
- golden_erp/addons/google_ads/fixtures/batch-partial-failure/db.expected.json +65 -0
- golden_erp/addons/google_ads/fixtures/batch-partial-failure/requests.expected.json +66 -0
- golden_erp/addons/google_ads/fixtures/batch-partial-failure/responses/001.json +16 -0
- golden_erp/addons/google_ads/fixtures/batch-partial-failure/responses/002.json +56 -0
- golden_erp/addons/google_ads/fixtures/click-too-old/account.json +10 -0
- golden_erp/addons/google_ads/fixtures/click-too-old/case.json +37 -0
- golden_erp/addons/google_ads/fixtures/click-too-old/db.expected.json +25 -0
- golden_erp/addons/google_ads/fixtures/click-too-old/requests.expected.json +1 -0
- golden_erp/addons/google_ads/fixtures/consent-override/account.json +10 -0
- golden_erp/addons/google_ads/fixtures/consent-override/case.json +37 -0
- golden_erp/addons/google_ads/fixtures/consent-override/db.expected.json +37 -0
- golden_erp/addons/google_ads/fixtures/consent-override/requests.expected.json +44 -0
- golden_erp/addons/google_ads/fixtures/consent-override/responses/001.json +16 -0
- golden_erp/addons/google_ads/fixtures/consent-override/responses/002.json +16 -0
- golden_erp/addons/google_ads/fixtures/erased-party/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/erased-party/case.json +38 -0
- golden_erp/addons/google_ads/fixtures/erased-party/db.expected.json +25 -0
- golden_erp/addons/google_ads/fixtures/erased-party/requests.expected.json +1 -0
- golden_erp/addons/google_ads/fixtures/landing-url-click-parse/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/landing-url-click-parse/case.json +20 -0
- golden_erp/addons/google_ads/fixtures/landing-url-click-parse/db.expected.json +17 -0
- golden_erp/addons/google_ads/fixtures/landing-url-click-parse/inbound/001.json +20 -0
- golden_erp/addons/google_ads/fixtures/landing-url-click-parse/requests.expected.json +1 -0
- golden_erp/addons/google_ads/fixtures/newer-schema/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/newer-schema/case.json +22 -0
- golden_erp/addons/google_ads/fixtures/newer-schema/db.expected.json +9 -0
- golden_erp/addons/google_ads/fixtures/newer-schema/inbound/001.json +7 -0
- golden_erp/addons/google_ads/fixtures/newer-schema/requests.expected.json +1 -0
- golden_erp/addons/google_ads/fixtures/null-amount-no-value/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/null-amount-no-value/case.json +37 -0
- golden_erp/addons/google_ads/fixtures/null-amount-no-value/db.expected.json +38 -0
- golden_erp/addons/google_ads/fixtures/null-amount-no-value/requests.expected.json +43 -0
- golden_erp/addons/google_ads/fixtures/null-amount-no-value/responses/001.json +16 -0
- golden_erp/addons/google_ads/fixtures/null-amount-no-value/responses/002.json +16 -0
- golden_erp/addons/google_ads/fixtures/pipeline-unmapped/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/pipeline-unmapped/case.json +37 -0
- golden_erp/addons/google_ads/fixtures/pipeline-unmapped/db.expected.json +25 -0
- golden_erp/addons/google_ads/fixtures/pipeline-unmapped/requests.expected.json +1 -0
- golden_erp/addons/google_ads/fixtures/reopen-retracts/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/reopen-retracts/case.json +40 -0
- golden_erp/addons/google_ads/fixtures/reopen-retracts/db.expected.json +45 -0
- golden_erp/addons/google_ads/fixtures/reopen-retracts/requests.expected.json +39 -0
- golden_erp/addons/google_ads/fixtures/reopen-retracts/responses/001.json +16 -0
- golden_erp/addons/google_ads/fixtures/reopen-retracts/responses/002.json +16 -0
- golden_erp/addons/google_ads/fixtures/replay-idempotent/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/replay-idempotent/case.json +38 -0
- golden_erp/addons/google_ads/fixtures/replay-idempotent/db.expected.json +37 -0
- golden_erp/addons/google_ads/fixtures/replay-idempotent/requests.expected.json +1 -0
- golden_erp/addons/google_ads/fixtures/rewin-needs-review/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/rewin-needs-review/case.json +43 -0
- golden_erp/addons/google_ads/fixtures/rewin-needs-review/db.expected.json +52 -0
- golden_erp/addons/google_ads/fixtures/rewin-needs-review/requests.expected.json +1 -0
- golden_erp/addons/google_ads/fixtures/touchpoint-post-unknown-email/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/touchpoint-post-unknown-email/case.json +20 -0
- golden_erp/addons/google_ads/fixtures/touchpoint-post-unknown-email/db.expected.json +24 -0
- golden_erp/addons/google_ads/fixtures/touchpoint-post-unknown-email/inbound/001.json +21 -0
- golden_erp/addons/google_ads/fixtures/touchpoint-post-unknown-email/requests.expected.json +1 -0
- golden_erp/addons/google_ads/fixtures/two-currencies/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/two-currencies/case.json +59 -0
- golden_erp/addons/google_ads/fixtures/two-currencies/db.expected.json +62 -0
- golden_erp/addons/google_ads/fixtures/two-currencies/requests.expected.json +55 -0
- golden_erp/addons/google_ads/fixtures/two-currencies/responses/001.json +16 -0
- golden_erp/addons/google_ads/fixtures/two-currencies/responses/002.json +17 -0
- golden_erp/addons/google_ads/fixtures/won-no-click/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/won-no-click/case.json +58 -0
- golden_erp/addons/google_ads/fixtures/won-no-click/db.expected.json +39 -0
- golden_erp/addons/google_ads/fixtures/won-no-click/requests.expected.json +1 -0
- golden_erp/addons/google_ads/fixtures/won-with-gbraid/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/won-with-gbraid/case.json +41 -0
- golden_erp/addons/google_ads/fixtures/won-with-gbraid/db.expected.json +44 -0
- golden_erp/addons/google_ads/fixtures/won-with-gbraid/requests.expected.json +44 -0
- golden_erp/addons/google_ads/fixtures/won-with-gbraid/responses/001.json +16 -0
- golden_erp/addons/google_ads/fixtures/won-with-gbraid/responses/002.json +16 -0
- golden_erp/addons/google_ads/fixtures/won-with-gclid/account.json +9 -0
- golden_erp/addons/google_ads/fixtures/won-with-gclid/case.json +37 -0
- golden_erp/addons/google_ads/fixtures/won-with-gclid/db.expected.json +37 -0
- golden_erp/addons/google_ads/fixtures/won-with-gclid/requests.expected.json +44 -0
- golden_erp/addons/google_ads/fixtures/won-with-gclid/responses/001.json +16 -0
- golden_erp/addons/google_ads/fixtures/won-with-gclid/responses/002.json +16 -0
- golden_erp/addons/google_ads/mapping.py +140 -0
- golden_erp/addons/google_ads/plugin.py +41 -0
- golden_erp/addons/google_ads/tests/__init__.py +0 -0
- golden_erp/addons/google_ads/tests/test_adapter.py +343 -0
- golden_erp/addons/google_ads/tests/test_contract.py +101 -0
- golden_erp/addons/google_ads/tests/test_conversions.py +60 -0
- golden_erp/addons/google_ads/tests/test_mapping.py +87 -0
- golden_erp/addons/google_ads/values.py +79 -0
- golden_erp/addons/hubspot_export/__init__.py +4 -0
- golden_erp/addons/hubspot_export/adapter.py +163 -0
- golden_erp/addons/hubspot_export/convert.py +750 -0
- golden_erp/addons/hubspot_export/fixtures/cases/archived-forbidden/case.json +15 -0
- golden_erp/addons/hubspot_export/fixtures/cases/archived-forbidden/expected/manifest.expected.json +117 -0
- golden_erp/addons/hubspot_export/fixtures/cases/archived-forbidden/overlay/crawl/errors.json +16 -0
- golden_erp/addons/hubspot_export/fixtures/cases/archived-not-enumerated/case.json +12 -0
- golden_erp/addons/hubspot_export/fixtures/cases/archived-not-enumerated/expected/manifest.expected.json +111 -0
- golden_erp/addons/hubspot_export/fixtures/cases/association-paged/case.json +9 -0
- golden_erp/addons/hubspot_export/fixtures/cases/association-paged/expected/manifest.expected.json +111 -0
- golden_erp/addons/hubspot_export/fixtures/cases/association-paged/overlay/crawl/tickets/page-0001.json +95 -0
- golden_erp/addons/hubspot_export/fixtures/cases/body-truncated/case.json +9 -0
- golden_erp/addons/hubspot_export/fixtures/cases/body-truncated/expected/manifest.expected.json +111 -0
- golden_erp/addons/hubspot_export/fixtures/cases/body-truncated/overlay/crawl/notes/page-0001.json +82 -0
- golden_erp/addons/hubspot_export/fixtures/cases/count-mismatch/case.json +9 -0
- golden_erp/addons/hubspot_export/fixtures/cases/count-mismatch/expected/manifest.expected.json +111 -0
- golden_erp/addons/hubspot_export/fixtures/cases/count-mismatch/overlay/crawl/companies/count.json +21 -0
- golden_erp/addons/hubspot_export/fixtures/cases/crawl-failed/case.json +5 -0
- golden_erp/addons/hubspot_export/fixtures/cases/crawl-failed/overlay/crawl/errors.json +13 -0
- golden_erp/addons/hubspot_export/fixtures/cases/export-no-time-zone/case.json +8 -0
- golden_erp/addons/hubspot_export/fixtures/cases/export-truncated/case.json +12 -0
- golden_erp/addons/hubspot_export/fixtures/cases/export-truncated/expected/manifest.expected.json +156 -0
- golden_erp/addons/hubspot_export/fixtures/cases/export-truncated/overlay/export/deals.csv +4 -0
- golden_erp/addons/hubspot_export/fixtures/cases/file-absent/case.json +12 -0
- golden_erp/addons/hubspot_export/fixtures/cases/file-absent/expected/manifest.expected.json +111 -0
- golden_erp/addons/hubspot_export/fixtures/cases/forbidden/case.json +12 -0
- golden_erp/addons/hubspot_export/fixtures/cases/forbidden/expected/manifest.expected.json +109 -0
- golden_erp/addons/hubspot_export/fixtures/cases/forbidden/overlay/crawl/errors.json +17 -0
- golden_erp/addons/hubspot_export/fixtures/cases/history-absent/case.json +11 -0
- golden_erp/addons/hubspot_export/fixtures/cases/history-absent/expected/manifest.expected.json +101 -0
- golden_erp/addons/hubspot_export/fixtures/cases/mixed/case.json +15 -0
- golden_erp/addons/hubspot_export/fixtures/cases/mixed/expected/manifest.expected.json +111 -0
- golden_erp/addons/hubspot_export/fixtures/cases/mixed/overlay/export/export.json +7 -0
- golden_erp/addons/hubspot_export/fixtures/cases/mixed/overlay/export/tasks.csv +3 -0
- golden_erp/addons/hubspot_export/fixtures/cases/newer-schema/case.json +5 -0
- golden_erp/addons/hubspot_export/fixtures/cases/newer-schema/overlay/crawl/contacts/page-0001.json +107 -0
- golden_erp/addons/hubspot_export/fixtures/cases/page-missing/case.json +12 -0
- golden_erp/addons/hubspot_export/fixtures/cases/page-missing/expected/manifest.expected.json +111 -0
- golden_erp/addons/hubspot_export/fixtures/cases/pair-forbidden/case.json +12 -0
- golden_erp/addons/hubspot_export/fixtures/cases/pair-forbidden/expected/manifest.expected.json +111 -0
- golden_erp/addons/hubspot_export/fixtures/cases/pair-forbidden/overlay/crawl/errors.json +13 -0
- golden_erp/addons/hubspot_export/fixtures/cases/pair-not-exported/case.json +12 -0
- golden_erp/addons/hubspot_export/fixtures/cases/pair-not-exported/expected/manifest.expected.json +111 -0
- golden_erp/addons/hubspot_export/fixtures/cases/search-capped/case.json +12 -0
- golden_erp/addons/hubspot_export/fixtures/cases/search-capped/expected/manifest.expected.json +117 -0
- golden_erp/addons/hubspot_export/fixtures/cases/search-capped/overlay/crawl/contacts/page-0001.json +115 -0
- golden_erp/addons/hubspot_export/fixtures/cases/search-capped/overlay/crawl/contacts/page-0002.json +73 -0
- golden_erp/addons/hubspot_export/fixtures/cases/unknown-owner/case.json +9 -0
- golden_erp/addons/hubspot_export/fixtures/cases/unknown-owner/expected/manifest.expected.json +111 -0
- golden_erp/addons/hubspot_export/fixtures/cases/unknown-owner/overlay/crawl/deals/page-0002.json +81 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/associations/contacts-companies/page-0001.json +144 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/associations/deals-contacts/page-0001.json +143 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/calls/archived/page-0001.json +16 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/calls/page-0001.json +78 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/companies/archived/page-0001.json +31 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/companies/count.json +21 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/companies/page-0001.json +84 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/contacts/archived/page-0001.json +32 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/contacts/page-0001.json +107 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/contacts/page-0002.json +66 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/deals/archived/page-0001.json +34 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/deals/page-0001.json +127 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/deals/page-0002.json +81 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/emails/archived/page-0001.json +16 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/emails/page-0001.json +89 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/errors.json +7 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/history/contacts/page-0001.json +105 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/history/deals/page-0001.json +151 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/meetings/archived/page-0001.json +16 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/meetings/page-0001.json +79 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/notes/archived/page-0001.json +16 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/notes/page-0001.json +81 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/owners-archived.json +34 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/owners.json +66 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/pipelines-deals.json +130 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/pipelines-tickets.json +68 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/properties-calls.json +170 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/properties-companies.json +193 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/properties-contacts.json +335 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/properties-deals.json +298 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/properties-emails.json +150 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/properties-meetings.json +143 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/properties-notes.json +107 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/properties-tasks.json +199 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/properties-tickets.json +159 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/recording.json +16 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/subscriptions/page-0001.json +77 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/tasks/archived/page-0001.json +16 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/tasks/page-0001.json +141 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/tickets/archived/page-0001.json +16 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/crawl/tickets/page-0001.json +89 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/associations.expected.jsonl +19 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/communications.expected.jsonl +8 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/companies.expected.jsonl +5 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/consent.expected.jsonl +5 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/contacts.expected.jsonl +8 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/deals.expected.jsonl +7 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/import-report.expected.json +717 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/manifest.expected.json +105 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/owners.expected.jsonl +4 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/pipelines.expected.jsonl +3 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/property_defs.expected.jsonl +107 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/relationships.expected.jsonl +2 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/expected/tasks.expected.jsonl +4 -0
- golden_erp/addons/hubspot_export/fixtures/crawl-small/mapping.toml +42 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/expected/associations.expected.jsonl +9 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/expected/companies.expected.jsonl +2 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/expected/consent.expected.jsonl +1 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/expected/contacts.expected.jsonl +3 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/expected/deals.expected.jsonl +3 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/expected/manifest.expected.json +152 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/expected/owners.expected.jsonl +4 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/expected/pipelines.expected.jsonl +3 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/expected/property_defs.expected.jsonl +79 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/expected/relationships.expected.jsonl +1 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/expected/tasks.expected.jsonl +2 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/companies.csv +3 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/contacts.csv +4 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/deals.csv +4 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/export.json +15 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/owners-archived.json +33 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/owners.json +64 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/pipelines-deals.json +130 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/pipelines-tickets.json +68 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/properties-companies.json +193 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/properties-contacts.json +335 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/properties-deals.json +298 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/properties-tasks.json +199 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/properties-tickets.json +159 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/tasks.csv +3 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/export/tickets.csv +2 -0
- golden_erp/addons/hubspot_export/fixtures/export-csv/mapping.toml +5 -0
- golden_erp/addons/hubspot_export/mapping.py +230 -0
- golden_erp/addons/hubspot_export/model.py +138 -0
- golden_erp/addons/hubspot_export/plugin.py +27 -0
- golden_erp/addons/hubspot_export/reader_crawl.py +346 -0
- golden_erp/addons/hubspot_export/reader_csv.py +334 -0
- golden_erp/addons/hubspot_export/recording.py +243 -0
- golden_erp/addons/hubspot_export/tests/__init__.py +0 -0
- golden_erp/addons/hubspot_export/tests/helpers.py +77 -0
- golden_erp/addons/hubspot_export/tests/test_adapter.py +661 -0
- golden_erp/addons/hubspot_export/values.py +219 -0
- golden_erp/addons/klaviyo/__init__.py +12 -0
- golden_erp/addons/klaviyo/adapter.py +816 -0
- golden_erp/addons/klaviyo/fixtures/erase/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/erase/case.json +33 -0
- golden_erp/addons/klaviyo/fixtures/erase/db.expected.json +17 -0
- golden_erp/addons/klaviyo/fixtures/erase/requests.expected.json +27 -0
- golden_erp/addons/klaviyo/fixtures/erase/responses/001.json +12 -0
- golden_erp/addons/klaviyo/fixtures/erased-profile-skipped/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/erased-profile-skipped/case.json +31 -0
- golden_erp/addons/klaviyo/fixtures/erased-profile-skipped/db.expected.json +20 -0
- golden_erp/addons/klaviyo/fixtures/erased-profile-skipped/inbound/001-event.json +29 -0
- golden_erp/addons/klaviyo/fixtures/erased-profile-skipped/requests.expected.json +1 -0
- golden_erp/addons/klaviyo/fixtures/events-received-opened/account.json +7 -0
- golden_erp/addons/klaviyo/fixtures/events-received-opened/case.json +60 -0
- golden_erp/addons/klaviyo/fixtures/events-received-opened/db.expected.json +66 -0
- golden_erp/addons/klaviyo/fixtures/events-received-opened/requests.expected.json +19 -0
- golden_erp/addons/klaviyo/fixtures/events-received-opened/responses/001.json +99 -0
- golden_erp/addons/klaviyo/fixtures/events-received-opened/responses/002.json +73 -0
- golden_erp/addons/klaviyo/fixtures/existing-profile-opt-out-pulled/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/existing-profile-opt-out-pulled/case.json +38 -0
- golden_erp/addons/klaviyo/fixtures/existing-profile-opt-out-pulled/db.expected.json +64 -0
- golden_erp/addons/klaviyo/fixtures/existing-profile-opt-out-pulled/requests.expected.json +39 -0
- golden_erp/addons/klaviyo/fixtures/existing-profile-opt-out-pulled/responses/001.json +17 -0
- golden_erp/addons/klaviyo/fixtures/existing-profile-opt-out-pulled/responses/002.json +32 -0
- golden_erp/addons/klaviyo/fixtures/hard-bounce-pulled/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/hard-bounce-pulled/case.json +40 -0
- golden_erp/addons/klaviyo/fixtures/hard-bounce-pulled/db.expected.json +47 -0
- golden_erp/addons/klaviyo/fixtures/hard-bounce-pulled/inbound/001-event.json +31 -0
- golden_erp/addons/klaviyo/fixtures/hard-bounce-pulled/requests.expected.json +1 -0
- golden_erp/addons/klaviyo/fixtures/newer-schema-refused/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/newer-schema-refused/case.json +21 -0
- golden_erp/addons/klaviyo/fixtures/newer-schema-refused/db.expected.json +9 -0
- golden_erp/addons/klaviyo/fixtures/newer-schema-refused/inbound/001-event.json +29 -0
- golden_erp/addons/klaviyo/fixtures/newer-schema-refused/requests.expected.json +1 -0
- golden_erp/addons/klaviyo/fixtures/profile-granted/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/profile-granted/case.json +38 -0
- golden_erp/addons/klaviyo/fixtures/profile-granted/db.expected.json +40 -0
- golden_erp/addons/klaviyo/fixtures/profile-granted/requests.expected.json +73 -0
- golden_erp/addons/klaviyo/fixtures/profile-granted/responses/001.json +17 -0
- golden_erp/addons/klaviyo/fixtures/profile-granted/responses/002.json +12 -0
- golden_erp/addons/klaviyo/fixtures/profile-no-consent-not-sent/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/profile-no-consent-not-sent/case.json +57 -0
- golden_erp/addons/klaviyo/fixtures/profile-no-consent-not-sent/db.expected.json +41 -0
- golden_erp/addons/klaviyo/fixtures/profile-no-consent-not-sent/requests.expected.json +1 -0
- golden_erp/addons/klaviyo/fixtures/profile-withdrawn-unsubscribes/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/profile-withdrawn-unsubscribes/case.json +52 -0
- golden_erp/addons/klaviyo/fixtures/profile-withdrawn-unsubscribes/db.expected.json +47 -0
- golden_erp/addons/klaviyo/fixtures/profile-withdrawn-unsubscribes/requests.expected.json +32 -0
- golden_erp/addons/klaviyo/fixtures/profile-withdrawn-unsubscribes/responses/001.json +12 -0
- golden_erp/addons/klaviyo/fixtures/rate-limited/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/rate-limited/case.json +38 -0
- golden_erp/addons/klaviyo/fixtures/rate-limited/db.expected.json +26 -0
- golden_erp/addons/klaviyo/fixtures/rate-limited/requests.expected.json +25 -0
- golden_erp/addons/klaviyo/fixtures/rate-limited/responses/001.json +21 -0
- golden_erp/addons/klaviyo/fixtures/reconcile-sweep/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/reconcile-sweep/case.json +65 -0
- golden_erp/addons/klaviyo/fixtures/reconcile-sweep/db.expected.json +74 -0
- golden_erp/addons/klaviyo/fixtures/reconcile-sweep/requests.expected.json +73 -0
- golden_erp/addons/klaviyo/fixtures/reconcile-sweep/responses/001.json +17 -0
- golden_erp/addons/klaviyo/fixtures/reconcile-sweep/responses/002.json +12 -0
- golden_erp/addons/klaviyo/fixtures/segment-lists/account.json +9 -0
- golden_erp/addons/klaviyo/fixtures/segment-lists/case.json +80 -0
- golden_erp/addons/klaviyo/fixtures/segment-lists/db.expected.json +50 -0
- golden_erp/addons/klaviyo/fixtures/segment-lists/requests.expected.json +46 -0
- golden_erp/addons/klaviyo/fixtures/segment-lists/responses/001.json +17 -0
- golden_erp/addons/klaviyo/fixtures/segment-lists/responses/002.json +12 -0
- golden_erp/addons/klaviyo/fixtures/spam-pulled/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/spam-pulled/case.json +40 -0
- golden_erp/addons/klaviyo/fixtures/spam-pulled/db.expected.json +64 -0
- golden_erp/addons/klaviyo/fixtures/spam-pulled/inbound/001-event.json +29 -0
- golden_erp/addons/klaviyo/fixtures/spam-pulled/requests.expected.json +1 -0
- golden_erp/addons/klaviyo/fixtures/subscribed-ignored/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/subscribed-ignored/case.json +34 -0
- golden_erp/addons/klaviyo/fixtures/subscribed-ignored/db.expected.json +28 -0
- golden_erp/addons/klaviyo/fixtures/subscribed-ignored/inbound/001-event.json +29 -0
- golden_erp/addons/klaviyo/fixtures/subscribed-ignored/requests.expected.json +1 -0
- golden_erp/addons/klaviyo/fixtures/suppression-pushed/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/suppression-pushed/case.json +53 -0
- golden_erp/addons/klaviyo/fixtures/suppression-pushed/db.expected.json +48 -0
- golden_erp/addons/klaviyo/fixtures/suppression-pushed/requests.expected.json +61 -0
- golden_erp/addons/klaviyo/fixtures/suppression-pushed/responses/001.json +12 -0
- golden_erp/addons/klaviyo/fixtures/suppression-pushed/responses/002.json +12 -0
- golden_erp/addons/klaviyo/fixtures/unknown-profile-dropped/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/unknown-profile-dropped/case.json +19 -0
- golden_erp/addons/klaviyo/fixtures/unknown-profile-dropped/db.expected.json +9 -0
- golden_erp/addons/klaviyo/fixtures/unknown-profile-dropped/inbound/001-event.json +29 -0
- golden_erp/addons/klaviyo/fixtures/unknown-profile-dropped/requests.expected.json +1 -0
- golden_erp/addons/klaviyo/fixtures/unsubscribe-pulled/account.json +6 -0
- golden_erp/addons/klaviyo/fixtures/unsubscribe-pulled/case.json +50 -0
- golden_erp/addons/klaviyo/fixtures/unsubscribe-pulled/db.expected.json +71 -0
- golden_erp/addons/klaviyo/fixtures/unsubscribe-pulled/inbound/001-event.json +29 -0
- golden_erp/addons/klaviyo/fixtures/unsubscribe-pulled/requests.expected.json +1 -0
- golden_erp/addons/klaviyo/mapping.py +272 -0
- golden_erp/addons/klaviyo/plugin.py +31 -0
- golden_erp/addons/klaviyo/segments.py +120 -0
- golden_erp/addons/klaviyo/tests/__init__.py +0 -0
- golden_erp/addons/klaviyo/tests/seed.py +78 -0
- golden_erp/addons/klaviyo/tests/test_contract.py +39 -0
- golden_erp/addons/klaviyo/tests/test_klaviyo.py +640 -0
- golden_erp/addons/klaviyo/values.py +70 -0
- golden_erp/integrations.py +134 -0
- golden_erp/paths.py +15 -0
- golden_erp/settings/__init__.py +0 -0
- golden_erp/settings/base.py +810 -0
- golden_erp/settings/prod.py +190 -0
- golden_erp/static/assets/css/auth.css +318 -0
- golden_erp/static/assets/css/erp-compat.css +241 -0
- golden_erp/static/assets/css/erp-custom.css +264 -0
- golden_erp/static/assets/css/tabler-bindings.css +188 -0
- golden_erp/static/assets/css/tabler-icons.css +126 -0
- golden_erp/static/assets/css/tabler-vendors.min.css +8 -0
- golden_erp/static/assets/css/tabler.min.css +9 -0
- golden_erp/static/assets/css/themes/ember.css +58 -0
- golden_erp/static/assets/css/themes/eva-01.css +446 -0
- golden_erp/static/assets/css/themes/fincas.css +58 -0
- golden_erp/static/assets/css/themes/golden.css +58 -0
- golden_erp/static/assets/css/themes/graphite.css +58 -0
- golden_erp/static/assets/css/themes/midnight.css +58 -0
- golden_erp/static/assets/css/themes/paper.css +58 -0
- golden_erp/static/assets/css/themes/sage.css +58 -0
- golden_erp/static/assets/css/themes/slate.css +58 -0
- golden_erp/static/assets/fonts/docs/barlow-400.ttf +0 -0
- golden_erp/static/assets/fonts/docs/barlow-600.ttf +0 -0
- golden_erp/static/assets/fonts/docs/barlow-700.ttf +0 -0
- golden_erp/static/assets/fonts/docs/barlow-800.ttf +0 -0
- golden_erp/static/assets/fonts/docs/roboto-mono-400.ttf +0 -0
- golden_erp/static/assets/fonts/docs/roboto-mono-500.ttf +0 -0
- golden_erp/static/assets/fonts/docs/source-sans-3-400.ttf +0 -0
- golden_erp/static/assets/fonts/docs/source-sans-3-600.ttf +0 -0
- golden_erp/static/assets/fonts/tabler-icons-subset.ttf +0 -0
- golden_erp/static/assets/fonts/tabler-icons-subset.woff +0 -0
- golden_erp/static/assets/fonts/tabler-icons-subset.woff2 +0 -0
- golden_erp/static/assets/img/apple-icon.png +0 -0
- golden_erp/static/assets/img/bg-smart-home-1.jpg +0 -0
- golden_erp/static/assets/img/bg-smart-home-2.jpg +0 -0
- golden_erp/static/assets/img/bruce-mars.jpg +0 -0
- golden_erp/static/assets/img/curved-images/curved0.jpg +0 -0
- golden_erp/static/assets/img/curved-images/curved1.jpg +0 -0
- golden_erp/static/assets/img/curved-images/curved10.jpg +0 -0
- golden_erp/static/assets/img/curved-images/curved11.jpg +0 -0
- golden_erp/static/assets/img/curved-images/curved14.jpg +0 -0
- golden_erp/static/assets/img/curved-images/curved6.jpg +0 -0
- golden_erp/static/assets/img/curved-images/curved7.jpg +0 -0
- golden_erp/static/assets/img/curved-images/curved8.jpg +0 -0
- golden_erp/static/assets/img/curved-images/curved9.jpg +0 -0
- golden_erp/static/assets/img/curved-images/white-curved.jpg +0 -0
- golden_erp/static/assets/img/down-arrow-dark.svg +11 -0
- golden_erp/static/assets/img/down-arrow-white.svg +1 -0
- golden_erp/static/assets/img/down-arrow.svg +11 -0
- golden_erp/static/assets/img/favicon.png +0 -0
- golden_erp/static/assets/img/favicon.svg +13 -0
- golden_erp/static/assets/img/home-decor-1.jpg +0 -0
- golden_erp/static/assets/img/home-decor-2.jpg +0 -0
- golden_erp/static/assets/img/home-decor-3.jpg +0 -0
- golden_erp/static/assets/img/icons/flags/AU.png +0 -0
- golden_erp/static/assets/img/icons/flags/BR.png +0 -0
- golden_erp/static/assets/img/icons/flags/DE.png +0 -0
- golden_erp/static/assets/img/icons/flags/GB.png +0 -0
- golden_erp/static/assets/img/icons/flags/US.png +0 -0
- golden_erp/static/assets/img/illustrations/chat.png +0 -0
- golden_erp/static/assets/img/illustrations/danger-chat-ill.png +0 -0
- golden_erp/static/assets/img/illustrations/dark-lock-ill.png +0 -0
- golden_erp/static/assets/img/illustrations/error-404.png +0 -0
- golden_erp/static/assets/img/illustrations/error-500.png +0 -0
- golden_erp/static/assets/img/illustrations/lock.png +0 -0
- golden_erp/static/assets/img/illustrations/rocket-white.png +0 -0
- golden_erp/static/assets/img/ivana-square.jpg +0 -0
- golden_erp/static/assets/img/ivana-squares.jpg +0 -0
- golden_erp/static/assets/img/ivancik.jpg +0 -0
- golden_erp/static/assets/img/kal-visuals-square.jpg +0 -0
- golden_erp/static/assets/img/logo-ct-dark.png +0 -0
- golden_erp/static/assets/img/logo-ct.png +0 -0
- golden_erp/static/assets/img/logo.svg +11 -0
- golden_erp/static/assets/img/logos/gray-logos/logo-coinbase.svg +16 -0
- golden_erp/static/assets/img/logos/gray-logos/logo-nasa.svg +9 -0
- golden_erp/static/assets/img/logos/gray-logos/logo-netflix.svg +9 -0
- golden_erp/static/assets/img/logos/gray-logos/logo-pinterest.svg +9 -0
- golden_erp/static/assets/img/logos/gray-logos/logo-spotify.svg +9 -0
- golden_erp/static/assets/img/logos/gray-logos/logo-vodafone.svg +9 -0
- golden_erp/static/assets/img/logos/mastercard.png +0 -0
- golden_erp/static/assets/img/logos/visa.png +0 -0
- golden_erp/static/assets/img/marie.jpg +0 -0
- golden_erp/static/assets/img/meeting.jpg +0 -0
- golden_erp/static/assets/img/mercedes-eqc.png +0 -0
- golden_erp/static/assets/img/office-dark.jpg +0 -0
- golden_erp/static/assets/img/shapes/pattern-lines.svg +91 -0
- golden_erp/static/assets/img/shapes/waves-white.svg +48 -0
- golden_erp/static/assets/img/small-logos/icon-bulb.svg +37 -0
- golden_erp/static/assets/img/small-logos/icon-sun-cloud.png +0 -0
- golden_erp/static/assets/img/small-logos/logo-asana.svg +16 -0
- golden_erp/static/assets/img/small-logos/logo-atlassian.svg +16 -0
- golden_erp/static/assets/img/small-logos/logo-invision.svg +10 -0
- golden_erp/static/assets/img/small-logos/logo-jira.svg +21 -0
- golden_erp/static/assets/img/small-logos/logo-slack.svg +12 -0
- golden_erp/static/assets/img/small-logos/logo-spotify.svg +9 -0
- golden_erp/static/assets/img/small-logos/logo-xd.svg +11 -0
- golden_erp/static/assets/img/team-1.jpg +0 -0
- golden_erp/static/assets/img/team-2.jpg +0 -0
- golden_erp/static/assets/img/team-3.jpg +0 -0
- golden_erp/static/assets/img/team-4.jpg +0 -0
- golden_erp/static/assets/img/team-5.jpg +0 -0
- golden_erp/static/assets/img/vr-bg.jpg +0 -0
- golden_erp/static/assets/js/plugins/amcharts/animated.js +13 -0
- golden_erp/static/assets/js/plugins/amcharts/core.js +39339 -0
- golden_erp/static/assets/js/plugins/amcharts/maps.js +6133 -0
- golden_erp/static/assets/js/plugins/amcharts/worldLow.js +16230 -0
- golden_erp/static/assets/js/plugins/chartjs.min.js +13 -0
- golden_erp/static/assets/js/plugins/choices.min.js +11 -0
- golden_erp/static/assets/js/plugins/countup.min.js +1 -0
- golden_erp/static/assets/js/plugins/datatables.js +1283 -0
- golden_erp/static/assets/js/plugins/dragula/dragula.js +1079 -0
- golden_erp/static/assets/js/plugins/dragula/dragula.min.js +1 -0
- golden_erp/static/assets/js/plugins/dropzone.min.js +1 -0
- golden_erp/static/assets/js/plugins/flatpickr.min.js +2 -0
- golden_erp/static/assets/js/plugins/fullcalendar.min.js +6 -0
- golden_erp/static/assets/js/plugins/jkanban/jkanban.js +1870 -0
- golden_erp/static/assets/js/plugins/jkanban/jkanban.min.js +1 -0
- golden_erp/static/assets/js/plugins/leaflet.js +4629 -0
- golden_erp/static/assets/js/plugins/moment.min.js +8 -0
- golden_erp/static/assets/js/plugins/multistep-form.js +167 -0
- golden_erp/static/assets/js/plugins/nouislider.min.js +2 -0
- golden_erp/static/assets/js/plugins/orbit-controls.js +1049 -0
- golden_erp/static/assets/js/plugins/photoswipe-ui-default.min.js +858 -0
- golden_erp/static/assets/js/plugins/photoswipe.min.js +4 -0
- golden_erp/static/assets/js/plugins/quill.min.js +8 -0
- golden_erp/static/assets/js/plugins/round-slider.min.js +271 -0
- golden_erp/static/assets/js/plugins/sweetalert.min.js +5 -0
- golden_erp/static/assets/js/plugins/threejs.js +52759 -0
- golden_erp/static/assets/js/plugins/tilt.min.js +508 -0
- golden_erp/static/assets/js/tabler.min.js +13 -0
- golden_erp/static/images/logo-80.webp +0 -0
- golden_erp/templates/403.html +7 -0
- golden_erp/templates/404.html +6 -0
- golden_erp/templates/500.html +5 -0
- golden_erp/templates/base.html +155 -0
- golden_erp/templates/content/detail.html +97 -0
- golden_erp/templates/discounts/detail.html +132 -0
- golden_erp/templates/discounts/generate.html +108 -0
- golden_erp/templates/erp/_column_chooser.html +42 -0
- golden_erp/templates/erp/_definition_fieldsets.html +43 -0
- golden_erp/templates/erp/_definition_groups.html +21 -0
- golden_erp/templates/erp/_doc_people.html +37 -0
- golden_erp/templates/erp/_list_a11y_js.html +28 -0
- golden_erp/templates/erp/_list_a11y_script.html +6 -0
- golden_erp/templates/erp/_list_caption.html +1 -0
- golden_erp/templates/erp/_list_export.html +11 -0
- golden_erp/templates/erp/_list_live_region.html +2 -0
- golden_erp/templates/erp/_list_responsive.html +27 -0
- golden_erp/templates/erp/_list_sort_inputs.html +1 -0
- golden_erp/templates/erp/_list_tools_js.html +47 -0
- golden_erp/templates/erp/_other_data.html +26 -0
- golden_erp/templates/erp/_party_search_js.html +146 -0
- golden_erp/templates/erp/_report_heading.html +1 -0
- golden_erp/templates/erp/_saved_filters.html +44 -0
- golden_erp/templates/erp/_tracking_section.html +44 -0
- golden_erp/templates/erp/_tracking_section_js.html +115 -0
- golden_erp/templates/erp/_unify_upload_form.html +16 -0
- golden_erp/templates/erp/account.html +52 -0
- golden_erp/templates/erp/account_edit.html +39 -0
- golden_erp/templates/erp/accounting_account_register.html +129 -0
- golden_erp/templates/erp/accounting_dashboard.html +175 -0
- golden_erp/templates/erp/accounting_entries.html +112 -0
- golden_erp/templates/erp/accounting_entry_detail.html +72 -0
- golden_erp/templates/erp/accounting_import.html +171 -0
- golden_erp/templates/erp/accounting_periods.html +82 -0
- golden_erp/templates/erp/accounting_recon.html +98 -0
- golden_erp/templates/erp/accounting_trial_balance.html +112 -0
- golden_erp/templates/erp/crm/_communication.html +23 -0
- golden_erp/templates/erp/crm/_list_header.html +9 -0
- golden_erp/templates/erp/crm/_log_form.html +67 -0
- golden_erp/templates/erp/crm/_new_party_link.html +2 -0
- golden_erp/templates/erp/crm/_pager.html +16 -0
- golden_erp/templates/erp/crm/_task_row_actions.html +17 -0
- golden_erp/templates/erp/crm/_timeline.html +65 -0
- golden_erp/templates/erp/crm/admin_form.html +37 -0
- golden_erp/templates/erp/crm/create_form.html +60 -0
- golden_erp/templates/erp/crm/engagement_detail.html +417 -0
- golden_erp/templates/erp/crm/engagement_form.html +45 -0
- golden_erp/templates/erp/crm/engagement_list.html +248 -0
- golden_erp/templates/erp/crm/lead_list.html +95 -0
- golden_erp/templates/erp/crm/log_form.html +16 -0
- golden_erp/templates/erp/crm/my_day.html +86 -0
- golden_erp/templates/erp/crm/pipeline_list.html +74 -0
- golden_erp/templates/erp/crm/task_list.html +107 -0
- golden_erp/templates/erp/crm/timeline.html +22 -0
- golden_erp/templates/erp/crm_import/_queue_header.html +14 -0
- golden_erp/templates/erp/crm_import/_queue_row.html +175 -0
- golden_erp/templates/erp/crm_import/bulk_confirm.html +24 -0
- golden_erp/templates/erp/crm_import/job_list.html +15 -0
- golden_erp/templates/erp/crm_import/job_overview.html +157 -0
- golden_erp/templates/erp/crm_import/queue.html +292 -0
- golden_erp/templates/erp/crm_import/report.html +139 -0
- golden_erp/templates/erp/crm_report.html +184 -0
- golden_erp/templates/erp/customer_address_form.html +147 -0
- golden_erp/templates/erp/customer_detail.html +421 -0
- golden_erp/templates/erp/dashboard.html +242 -0
- golden_erp/templates/erp/document_form.html +2980 -0
- golden_erp/templates/erp/document_library.html +165 -0
- golden_erp/templates/erp/email_verify.html +25 -0
- golden_erp/templates/erp/email_verify_email.html +11 -0
- golden_erp/templates/erp/form.html +89 -0
- golden_erp/templates/erp/integrations.html +257 -0
- golden_erp/templates/erp/invoice_detail.html +168 -0
- golden_erp/templates/erp/list.html +321 -0
- golden_erp/templates/erp/parties/party_detail.html +550 -0
- golden_erp/templates/erp/parties/party_list.html +198 -0
- golden_erp/templates/erp/parties_merge/review.html +256 -0
- golden_erp/templates/erp/password_change.html +50 -0
- golden_erp/templates/erp/pick_ticket_print.html +168 -0
- golden_erp/templates/erp/price_list_detail.html +136 -0
- golden_erp/templates/erp/product_detail.html +312 -0
- golden_erp/templates/erp/product_profile.html +807 -0
- golden_erp/templates/erp/purchase_order_receive.html +125 -0
- golden_erp/templates/erp/report.html +187 -0
- golden_erp/templates/erp/settings/labels.html +56 -0
- golden_erp/templates/erp/settings/team_form.html +52 -0
- golden_erp/templates/erp/settings/teams.html +46 -0
- golden_erp/templates/erp/unify_batch_detail.html +117 -0
- golden_erp/templates/erp/unify_batch_list.html +57 -0
- golden_erp/templates/erp/unify_batch_upload.html +26 -0
- golden_erp/templates/erp/user_create.html +69 -0
- golden_erp/templates/erp/user_list.html +97 -0
- golden_erp/templates/erp/user_roles.html +43 -0
- golden_erp/templates/errors/base.html +59 -0
- golden_erp/templates/includes/footer.html +11 -0
- golden_erp/templates/includes/navigation.html +92 -0
- golden_erp/templates/includes/scripts.html +81 -0
- golden_erp/templates/includes/scroll_regions.html +44 -0
- golden_erp/templates/includes/sidebar.html +106 -0
- golden_erp/templates/includes/submit_guard.html +61 -0
- golden_erp/templates/registration/auth_base.html +44 -0
- golden_erp/templates/registration/login.html +71 -0
- golden_erp/templates/registration/password_reset.html +24 -0
- golden_erp/templates/registration/password_reset_complete.html +10 -0
- golden_erp/templates/registration/password_reset_confirm.html +49 -0
- golden_erp/templates/registration/password_reset_done.html +11 -0
- golden_erp/templates/registration/password_reset_email.html +9 -0
- golden_erp/templates/registration/password_reset_subject.txt +1 -0
- golden_erp/urls.py +103 -0
- inventory/__init__.py +0 -0
- inventory/admin.py +33 -0
- inventory/apps.py +5 -0
- inventory/erp_urls.py +15 -0
- inventory/erp_views.py +107 -0
- inventory/forms.py +31 -0
- inventory/migrations/0001_initial.py +156 -0
- inventory/migrations/0002_initial.py +39 -0
- inventory/migrations/0003_warehouse_company.py +26 -0
- inventory/migrations/__init__.py +0 -0
- inventory/models.py +198 -0
- inventory/serializers.py +19 -0
- inventory/tests.py +158 -0
- inventory/urls.py +9 -0
- inventory/views.py +43 -0
- llmhub/__init__.py +15 -0
- llmhub/admin.py +48 -0
- llmhub/apps.py +15 -0
- llmhub/audit.py +97 -0
- llmhub/checks.py +40 -0
- llmhub/client.py +680 -0
- llmhub/conf.py +310 -0
- llmhub/crypto.py +106 -0
- llmhub/drift.py +101 -0
- llmhub/erp_forms.py +125 -0
- llmhub/erp_urls.py +14 -0
- llmhub/erp_views.py +467 -0
- llmhub/management/__init__.py +0 -0
- llmhub/management/commands/__init__.py +0 -0
- llmhub/management/commands/llmhub_check.py +100 -0
- llmhub/middleware.py +40 -0
- llmhub/migrations/0001_initial.py +237 -0
- llmhub/migrations/__init__.py +0 -0
- llmhub/models.py +288 -0
- llmhub/purposes.py +141 -0
- llmhub/signals.py +81 -0
- llmhub/static/llmhub/settings.js +131 -0
- llmhub/templates/llmhub/settings.html +392 -0
- llmhub/tests/__init__.py +0 -0
- llmhub/tests/helpers.py +138 -0
- llmhub/tests/test_audit.py +175 -0
- llmhub/tests/test_chat_registry.py +103 -0
- llmhub/tests/test_client.py +474 -0
- llmhub/tests/test_commands.py +222 -0
- llmhub/tests/test_conf.py +248 -0
- llmhub/tests/test_purposes.py +66 -0
- llmhub/tests/test_security_guards.py +102 -0
- llmhub/tests/test_views.py +445 -0
- orders/__init__.py +0 -0
- orders/admin.py +177 -0
- orders/apps.py +8 -0
- orders/convert.py +283 -0
- orders/duplicate.py +178 -0
- orders/erp_urls.py +41 -0
- orders/erp_views.py +1493 -0
- orders/forms.py +451 -0
- orders/line_locks.py +91 -0
- orders/management/__init__.py +0 -0
- orders/management/commands/__init__.py +0 -0
- orders/management/commands/import_bc_invoice.py +237 -0
- orders/migrations/0001_initial.py +920 -0
- orders/migrations/0002_initial.py +91 -0
- orders/migrations/0003_initial.py +440 -0
- orders/migrations/0004_order_guest_email_alter_order_customer.py +35 -0
- orders/migrations/0005_order_uniq_order_stripe_pi.py +21 -0
- orders/migrations/0006_quote_legacy_pipeline_fields.py +63 -0
- orders/migrations/0007_quote_order_engagement.py +50 -0
- orders/migrations/0008_document_contact.py +92 -0
- orders/migrations/0009_us_english_choice_labels.py +103 -0
- orders/migrations/__init__.py +0 -0
- orders/models.py +1373 -0
- orders/people.py +144 -0
- orders/posting.py +80 -0
- orders/revisions.py +62 -0
- orders/serializers.py +299 -0
- orders/shipping_service.py +406 -0
- orders/signals.py +56 -0
- orders/test_m3_mass_assignment.py +151 -0
- orders/test_m3_xss.py +99 -0
- orders/test_stripe_pi_unique.py +47 -0
- orders/tests/__init__.py +0 -0
- orders/tests/test_company_scoping.py +193 -0
- orders/tests/test_convert.py +113 -0
- orders/tests/test_default_company.py +48 -0
- orders/tests/test_document_people.py +246 -0
- orders/tests/test_double_submit.py +172 -0
- orders/tests/test_duplicate.py +147 -0
- orders/tests/test_full_chain_totals.py +191 -0
- orders/tests/test_line_item_blank_row.py +343 -0
- orders/tests/test_m2d_token_isolation.py +101 -0
- orders/tests/test_order_create_requires_line.py +168 -0
- orders/tests/test_order_idempotency.py +110 -0
- orders/tests/test_quote_document_views.py +230 -0
- orders/tests/test_quote_list_engagement.py +39 -0
- orders/tests/test_quote_revisions.py +127 -0
- orders/tests/test_quote_to_order.py +349 -0
- orders/tests/test_recalculate.py +549 -0
- orders/tests/test_sales_invoice_by_token.py +107 -0
- orders/tests/test_sales_invoice_model.py +75 -0
- orders/tests/test_sales_invoice_reconcile.py +196 -0
- orders/tests/test_serializer_enforcement.py +241 -0
- orders/tests/test_shipment_group_moves.py +670 -0
- orders/tests/test_sibling_quotes.py +86 -0
- orders/tests/test_status_transitions.py +202 -0
- orders/tests/test_stripe_pi_race.py +140 -0
- orders/tests/test_suborder_status_guard.py +89 -0
- orders/urls.py +37 -0
- orders/views.py +666 -0
- parties/__init__.py +5 -0
- parties/_registry.py +52 -0
- parties/admin.py +98 -0
- parties/apps.py +52 -0
- parties/backfill.py +861 -0
- parties/checks.py +61 -0
- parties/classification_registry.py +186 -0
- parties/consent.py +228 -0
- parties/constants.py +16 -0
- parties/dedupe.py +334 -0
- parties/dedupe_legacy.py +275 -0
- parties/dedupe_parties.py +158 -0
- parties/display.py +39 -0
- parties/envelope.py +291 -0
- parties/erasure.py +1460 -0
- parties/erasure_api.py +66 -0
- parties/erasure_urls.py +9 -0
- parties/erp_urls.py +38 -0
- parties/erp_views.py +1109 -0
- parties/forms.py +638 -0
- parties/management/__init__.py +0 -0
- parties/management/commands/__init__.py +0 -0
- parties/management/commands/backfill_parties.py +69 -0
- parties/management/commands/check_erasure.py +55 -0
- parties/management/commands/erase_party.py +57 -0
- parties/management/commands/party_dedupe_propose.py +44 -0
- parties/management/commands/party_dedupe_report.py +278 -0
- parties/management/commands/reconcile_parties.py +67 -0
- parties/management/commands/seed_parties.py +212 -0
- parties/match.py +55 -0
- parties/merge.py +807 -0
- parties/merge_queue.py +279 -0
- parties/merge_urls.py +9 -0
- parties/merge_views.py +507 -0
- parties/migrations/0001_initial.py +797 -0
- parties/migrations/0002_backfill.py +54 -0
- parties/migrations/0003_partymergelog.py +98 -0
- parties/migrations/0004_promoted_columns.py +61 -0
- parties/migrations/0005_stamp_owner_team.py +27 -0
- parties/migrations/0006_party_metadata_gin.py +21 -0
- parties/migrations/0007_export_pii_permission.py +25 -0
- parties/migrations/0008_us_english_choice_labels.py +21 -0
- parties/migrations/__init__.py +0 -0
- parties/mirror.py +178 -0
- parties/models.py +807 -0
- parties/normalize.py +253 -0
- parties/ownership.py +113 -0
- parties/portal.py +411 -0
- parties/receivers.py +19 -0
- parties/reconcile.py +310 -0
- parties/relationship_registry.py +200 -0
- parties/role_registry.py +173 -0
- parties/serializers.py +696 -0
- parties/sync.py +678 -0
- parties/tests/__init__.py +0 -0
- parties/tests/factories.py +51 -0
- parties/tests/test_api.py +589 -0
- parties/tests/test_backfill.py +549 -0
- parties/tests/test_classification.py +208 -0
- parties/tests/test_consent_writebacks.py +94 -0
- parties/tests/test_dedupe.py +350 -0
- parties/tests/test_envelope.py +139 -0
- parties/tests/test_erasure.py +967 -0
- parties/tests/test_erasure_sweep.py +367 -0
- parties/tests/test_erasure_sweep_adapters.py +486 -0
- parties/tests/test_erp_views.py +485 -0
- parties/tests/test_merge.py +544 -0
- parties/tests/test_merge_views.py +208 -0
- parties/tests/test_metadata_merge.py +126 -0
- parties/tests/test_models.py +558 -0
- parties/tests/test_normalize.py +285 -0
- parties/tests/test_reconcile.py +164 -0
- parties/tests/test_registries.py +242 -0
- parties/tests/test_relationship_picker.py +157 -0
- parties/tests/test_signals.py +172 -0
- parties/tests/test_sync.py +317 -0
- parties/urls.py +26 -0
- parties/views.py +389 -0
- parties/widgets.py +75 -0
- payments/__init__.py +0 -0
- payments/admin.py +64 -0
- payments/apps.py +5 -0
- payments/erp_urls.py +23 -0
- payments/erp_views.py +355 -0
- payments/forms.py +86 -0
- payments/gateways/__init__.py +17 -0
- payments/gateways/base.py +111 -0
- payments/gateways/manual.py +55 -0
- payments/gateways/registry.py +43 -0
- payments/gateways/stripe_gateway.py +238 -0
- payments/gateways/usdc.py +100 -0
- payments/migrations/0001_initial.py +240 -0
- payments/migrations/0002_payment_idempotency_key.py +20 -0
- payments/migrations/0003_us_english_choice_labels.py +31 -0
- payments/migrations/__init__.py +0 -0
- payments/models.py +238 -0
- payments/posting.py +83 -0
- payments/serializers.py +19 -0
- payments/services.py +355 -0
- payments/tests/__init__.py +0 -0
- payments/tests/test_closed_period.py +182 -0
- payments/tests/test_gateways.py +97 -0
- payments/tests/test_invoice_fk.py +50 -0
- payments/tests/test_invoice_links.py +68 -0
- payments/tests/test_payment_idempotency.py +65 -0
- payments/tests/test_record_payment.py +243 -0
- payments/tests/test_refund.py +210 -0
- payments/tests/test_trackc.py +204 -0
- payments/urls.py +8 -0
- payments/views.py +65 -0
- portal/__init__.py +0 -0
- portal/admin.py +2 -0
- portal/apps.py +6 -0
- portal/migrations/__init__.py +0 -0
- portal/models.py +2 -0
- portal/serializers.py +385 -0
- portal/test_party.py +312 -0
- portal/tests.py +168 -0
- portal/urls.py +36 -0
- portal/views.py +301 -0
- pricing/__init__.py +1 -0
- pricing/admin.py +38 -0
- pricing/apps.py +5 -0
- pricing/erp_urls.py +15 -0
- pricing/erp_views.py +95 -0
- pricing/forms.py +41 -0
- pricing/migrations/0001_initial.py +156 -0
- pricing/migrations/0002_initial.py +30 -0
- pricing/migrations/__init__.py +0 -0
- pricing/models/__init__.py +13 -0
- pricing/models/price_book.py +89 -0
- pricing/serializers.py +28 -0
- pricing/urls.py +14 -0
- pricing/views.py +47 -0
- products/__init__.py +0 -0
- products/admin.py +172 -0
- products/apps.py +12 -0
- products/data/cw_energy_solar_panel_specs.json +548 -0
- products/data/seo_quality_defaults.json +25 -0
- products/erp_urls.py +37 -0
- products/erp_views.py +670 -0
- products/forms.py +133 -0
- products/management/__init__.py +0 -0
- products/management/commands/__init__.py +0 -0
- products/management/commands/audit_mpn_coverage.py +185 -0
- products/management/commands/backfill_enphase_iq8.py +337 -0
- products/management/commands/create_grid_interactive_inverters.py +84 -0
- products/management/commands/create_kara_firma_products.py +300 -0
- products/management/commands/export_prices.py +109 -0
- products/management/commands/fix_forge_image_ids.py +55 -0
- products/management/commands/import_products.py +246 -0
- products/management/commands/populate_suresine_options.py +191 -0
- products/management/commands/restructure_dc_appliances.py +419 -0
- products/management/commands/set_structured_specs.py +205 -0
- products/management/commands/update_prices.py +160 -0
- products/migrations/0001_initial.py +735 -0
- products/migrations/0002_initial.py +73 -0
- products/migrations/0003_category_body_copy.py +22 -0
- products/migrations/0004_product_safety_warnings.py +22 -0
- products/migrations/0005_variant_seo.py +30 -0
- products/migrations/__init__.py +0 -0
- products/models.py +615 -0
- products/seo_checks.py +121 -0
- products/seo_quality.py +330 -0
- products/serializers.py +488 -0
- products/templatetags/__init__.py +0 -0
- products/templatetags/bunny_images.py +58 -0
- products/test_category_body_copy.py +186 -0
- products/test_m3_xss.py +125 -0
- products/test_product_profile_slots.py +106 -0
- products/test_product_safety_warnings.py +128 -0
- products/test_seo_quality.py +203 -0
- products/test_variant_seo.py +69 -0
- products/tests.py +649 -0
- products/tests_storefront_catalog.py +195 -0
- products/tests_storefront_taxonomy.py +319 -0
- products/urls.py +24 -0
- products/views.py +304 -0
- purchasing/__init__.py +0 -0
- purchasing/admin.py +57 -0
- purchasing/apps.py +8 -0
- purchasing/duplicate.py +86 -0
- purchasing/erp_urls.py +25 -0
- purchasing/erp_views.py +600 -0
- purchasing/forms.py +233 -0
- purchasing/migrations/0001_initial.py +774 -0
- purchasing/migrations/0002_us_english_choice_labels.py +34 -0
- purchasing/migrations/__init__.py +0 -0
- purchasing/models.py +581 -0
- purchasing/posting.py +90 -0
- purchasing/serializers.py +84 -0
- purchasing/services.py +193 -0
- purchasing/signals.py +33 -0
- purchasing/tests/__init__.py +0 -0
- purchasing/tests/test_company_scoping.py +163 -0
- purchasing/tests/test_duplicate.py +86 -0
- purchasing/tests/test_landed_cost.py +165 -0
- purchasing/tests/test_po_editor.py +219 -0
- purchasing/tests/test_po_editor_transitions.py +123 -0
- purchasing/tests/test_po_transitions.py +103 -0
- purchasing/tests/test_recalculate.py +223 -0
- purchasing/tests/test_receiving.py +253 -0
- purchasing/tests/test_serializer_enforcement.py +129 -0
- purchasing/urls.py +16 -0
- purchasing/views.py +157 -0
- reporting/__init__.py +0 -0
- reporting/admin.py +11 -0
- reporting/api.py +439 -0
- reporting/api_urls.py +19 -0
- reporting/apps.py +5 -0
- reporting/crm_reports.py +800 -0
- reporting/erp_urls.py +11 -0
- reporting/erp_views.py +711 -0
- reporting/migrations/0001_initial.py +38 -0
- reporting/migrations/__init__.py +0 -0
- reporting/models.py +19 -0
- reporting/serializers.py +10 -0
- reporting/test_crm_report_api.py +520 -0
- reporting/test_crm_reports.py +610 -0
- reporting/tests.py +317 -0
- reporting/urls.py +8 -0
- reporting/views.py +17 -0
- unify/__init__.py +0 -0
- unify/admin.py +39 -0
- unify/appliers.py +153 -0
- unify/apply.py +226 -0
- unify/apps.py +5 -0
- unify/erp_urls.py +17 -0
- unify/erp_views.py +298 -0
- unify/ingest.py +161 -0
- unify/management/__init__.py +0 -0
- unify/management/commands/__init__.py +0 -0
- unify/management/commands/unify_apply.py +79 -0
- unify/migrations/0001_initial.py +279 -0
- unify/migrations/0002_dedupe_source_kind.py +35 -0
- unify/migrations/0003_crm_source_kind.py +27 -0
- unify/migrations/0004_us_english_choice_labels.py +27 -0
- unify/migrations/__init__.py +0 -0
- unify/models.py +239 -0
- unify/propose.py +409 -0
- unify/tests.py +192 -0
- unify/tests_appliers.py +70 -0
- unify/tests_propose.py +231 -0
- unify/tests_views.py +152 -0
- unify/views.py +2 -0
- webhooks/__init__.py +1 -0
- webhooks/admin.py +32 -0
- webhooks/apps.py +14 -0
- webhooks/erp_urls.py +11 -0
- webhooks/erp_views.py +134 -0
- webhooks/events.py +401 -0
- webhooks/migrations/0001_initial.py +113 -0
- webhooks/migrations/0002_webhookdeliverylog_attempts_and_more.py +31 -0
- webhooks/migrations/0003_webhookdeliverylog_delivery_id.py +18 -0
- webhooks/migrations/__init__.py +0 -0
- webhooks/models.py +104 -0
- webhooks/outbox.py +330 -0
- webhooks/serializers.py +53 -0
- webhooks/services.py +244 -0
- webhooks/tests/__init__.py +1 -0
- webhooks/tests/test_api.py +61 -0
- webhooks/tests/test_company_scoping.py +143 -0
- webhooks/tests/test_crm_events.py +133 -0
- webhooks/tests/test_erp_screens.py +149 -0
- webhooks/tests/test_outbox_delivery.py +283 -0
- webhooks/tests/test_payload_versions.py +317 -0
- webhooks/tests/test_services.py +167 -0
- webhooks/tests/test_trackc.py +160 -0
- webhooks/urls.py +11 -0
- webhooks/views.py +60 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
"""What every CRM applier shares (docs/crm/phase5-importer.md 1.5, 4.5, 4.10).
|
|
2
|
+
|
|
3
|
+
``run(handler, company, staged, run=..., approval_row=...)`` is the
|
|
4
|
+
``unify`` apply hook for one row. Around the type's ``handler`` it:
|
|
5
|
+
|
|
6
|
+
1. finds the row's job (``ImportJobBatch``) and refuses a batch of another
|
|
7
|
+
company (tenant isolation: ``unify.apply`` passes the batch's company,
|
|
8
|
+
and every target the handler loads is filtered by it);
|
|
9
|
+
2. skips a record whose id **or any alias** belongs to an erased person
|
|
10
|
+
(``unify.apply`` already checks the id; aliases are checked here), and
|
|
11
|
+
scrubs the staged row as ``unify`` does;
|
|
12
|
+
3. returns the earlier ``applied_ref`` when a crash left this row's writes
|
|
13
|
+
committed but its ``ApprovalRow`` unmarked (4.10: the write log names the
|
|
14
|
+
approval row);
|
|
15
|
+
4. runs the handler in one savepoint inside ``suppressed()`` (no lifecycle
|
|
16
|
+
signal, no webhook: the import sends nothing, hand-off 6), with the job
|
|
17
|
+
lock taken first (``writelog.lock_job``: Job → Customer → Party → User);
|
|
18
|
+
5. turns failures into the coded errors of 4.1 (``RowError``):
|
|
19
|
+
``dependency_missing``, ``constraint``, ``conflict_stale``,
|
|
20
|
+
``invalid_value``, ``erased``.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
from dataclasses import dataclass
|
|
26
|
+
from functools import cached_property
|
|
27
|
+
|
|
28
|
+
from django.contrib.contenttypes.models import ContentType
|
|
29
|
+
from django.core.exceptions import ValidationError
|
|
30
|
+
from django.db import IntegrityError, transaction
|
|
31
|
+
from django.utils import timezone
|
|
32
|
+
|
|
33
|
+
from .. import writelog
|
|
34
|
+
|
|
35
|
+
DEPENDENCY_MISSING = "dependency_missing"
|
|
36
|
+
CONSTRAINT = "constraint"
|
|
37
|
+
CONFLICT_STALE = "conflict_stale"
|
|
38
|
+
INVALID_VALUE = "invalid_value"
|
|
39
|
+
ERASED = "erased"
|
|
40
|
+
ERROR_CODES = (DEPENDENCY_MISSING, CONSTRAINT, CONFLICT_STALE, INVALID_VALUE, ERASED)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class RowError(ValueError):
|
|
44
|
+
"""A refused row. ``unify.apply`` stores ``str(exc)``, which starts with the code."""
|
|
45
|
+
|
|
46
|
+
coded = True # unify.apply: store the message as is
|
|
47
|
+
|
|
48
|
+
def __init__(self, code: str, message: str):
|
|
49
|
+
if code not in ERROR_CODES:
|
|
50
|
+
raise ValueError(f"Unknown row error code {code!r}.")
|
|
51
|
+
self.code = code
|
|
52
|
+
super().__init__(f"{code}: {message}")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class Row:
|
|
57
|
+
"""One approved staged row, as a handler sees it."""
|
|
58
|
+
|
|
59
|
+
company: object
|
|
60
|
+
job: object
|
|
61
|
+
staged: object
|
|
62
|
+
approval_row: object
|
|
63
|
+
session: writelog.WriteSession
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def record(self) -> dict:
|
|
67
|
+
return self.staged.raw or {}
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def data(self) -> dict:
|
|
71
|
+
return self.record.get("data") or {}
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def properties(self) -> dict:
|
|
75
|
+
return self.record.get("properties") or {}
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def mapped(self) -> dict:
|
|
79
|
+
return self.staged.mapped_values or {}
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def decision(self) -> str:
|
|
83
|
+
return self.mapped.get("decision") or ""
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def values(self) -> dict:
|
|
87
|
+
"""``compare.project`` of the record, minus fields a reviewer kept."""
|
|
88
|
+
return self.mapped.get("values") or {}
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def kept(self) -> set:
|
|
92
|
+
return set(self.mapped.get("keep") or ())
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def provider(self) -> str:
|
|
96
|
+
return self.job.source.split(":", 1)[0]
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def source_tag(self) -> str:
|
|
100
|
+
"""``source`` on contact points and relationships, ``marketable_source``."""
|
|
101
|
+
return f"import:{self.provider}"[:64]
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def object_type(self) -> str:
|
|
105
|
+
return self.record.get("object_type") or ""
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def source_object_type(self) -> str:
|
|
109
|
+
return self.record.get("source_object_type") or self.object_type
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def keys(self) -> list[str]:
|
|
113
|
+
"""The record's source id, then its aliases."""
|
|
114
|
+
keys = [str(self.record.get("source_id"))]
|
|
115
|
+
keys += [str(a) for a in self.record.get("aliases") or [] if str(a) not in keys]
|
|
116
|
+
return keys
|
|
117
|
+
|
|
118
|
+
@cached_property
|
|
119
|
+
def mapping(self) -> dict:
|
|
120
|
+
return self.job.mapping or {}
|
|
121
|
+
|
|
122
|
+
def property_targets(self) -> dict:
|
|
123
|
+
"""``{property name: target}`` from the mapping file (2.12); unnamed = sidecar."""
|
|
124
|
+
section = self.mapping.get(self.object_type) or {}
|
|
125
|
+
return dict(section.get("properties") or {})
|
|
126
|
+
|
|
127
|
+
def target(self, model):
|
|
128
|
+
"""The approved ``target`` row of a link or update, from this tenant only."""
|
|
129
|
+
target = self.mapped.get("target") or {}
|
|
130
|
+
if not target.get("id"):
|
|
131
|
+
raise RowError(INVALID_VALUE, "The approved decision names no target.")
|
|
132
|
+
found = model._base_manager.filter(pk=target["id"], company_id=self.company.pk).first()
|
|
133
|
+
if found is None:
|
|
134
|
+
raise RowError(CONFLICT_STALE, f"The target {model._meta.verbose_name} is gone, or "
|
|
135
|
+
"belongs to another company; re-run matching.")
|
|
136
|
+
return found
|
|
137
|
+
|
|
138
|
+
# --- ExternalRefs -------------------------------------------------------
|
|
139
|
+
|
|
140
|
+
def ref_for(self, obj, source_id, *, object_type=None, metadata=None):
|
|
141
|
+
"""Add the ExternalRef ``(source, object_type, source_id) -> obj``, or
|
|
142
|
+
return the one that already says so. One that names another row is a
|
|
143
|
+
``constraint`` error (two source records cannot claim one key)."""
|
|
144
|
+
from core.models import ExternalRef
|
|
145
|
+
|
|
146
|
+
object_type = object_type or self.source_object_type
|
|
147
|
+
ct = ContentType.objects.get_for_model(type(obj))
|
|
148
|
+
existing = ExternalRef._base_manager.filter(
|
|
149
|
+
company_id=self.company.pk, source=self.job.source, object_type=object_type,
|
|
150
|
+
source_id=str(source_id),
|
|
151
|
+
).first()
|
|
152
|
+
if existing is not None:
|
|
153
|
+
if existing.content_type_id == ct.pk and str(existing.object_id) == str(obj.pk):
|
|
154
|
+
return existing
|
|
155
|
+
raise RowError(CONSTRAINT, f"{object_type} {source_id} is already linked to another record.")
|
|
156
|
+
ref = ExternalRef.objects.create(
|
|
157
|
+
company_id=self.company.pk, source=self.job.source, object_type=object_type,
|
|
158
|
+
source_id=str(source_id), content_type=ct, object_id=obj.pk,
|
|
159
|
+
last_synced_at=timezone.now(), metadata=metadata or {},
|
|
160
|
+
)
|
|
161
|
+
return self.session.link(ref)
|
|
162
|
+
|
|
163
|
+
def refs_for(self, obj, *, metadata=None) -> None:
|
|
164
|
+
"""One ExternalRef per id and alias (1.2), all to ``obj``."""
|
|
165
|
+
for key in self.keys:
|
|
166
|
+
self.ref_for(obj, key, metadata=metadata)
|
|
167
|
+
|
|
168
|
+
def resolve(self, ref: dict | None, model, *, required: bool = True):
|
|
169
|
+
"""The golden row a ``*_ref`` names (``{object_type, source_id}``), by
|
|
170
|
+
ExternalRef only (1.2: never by name). Unresolved and ``required`` is
|
|
171
|
+
``dependency_missing``, naming the ref."""
|
|
172
|
+
if not ref:
|
|
173
|
+
return None
|
|
174
|
+
found = resolve_ref(self.job, ref, model)
|
|
175
|
+
if found is None and required:
|
|
176
|
+
raise RowError(DEPENDENCY_MISSING, f"{ref.get('object_type')} {ref.get('source_id')} is not "
|
|
177
|
+
"imported yet (apply it, then retry this row).")
|
|
178
|
+
return found
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def source_object_types(job, object_type: str) -> list[str]:
|
|
182
|
+
"""``ExternalRef.object_type`` values a canonical type was staged under in
|
|
183
|
+
``job`` (``source_object_type``), plus the canonical name itself."""
|
|
184
|
+
from crm_import.models import ImportJobBatch
|
|
185
|
+
from unify.models import StagedRow
|
|
186
|
+
|
|
187
|
+
if len(_TYPES) > 64 and str(job.pk) not in _TYPES:
|
|
188
|
+
_TYPES.clear() # a long-running worker: keep the memo small
|
|
189
|
+
cache = _TYPES.setdefault(str(job.pk), {})
|
|
190
|
+
if object_type not in cache:
|
|
191
|
+
batch_ids = ImportJobBatch._base_manager.filter(job_id=job.pk, object_type=object_type).values("batch_id")
|
|
192
|
+
found = set(
|
|
193
|
+
StagedRow.objects.filter(batch_id__in=batch_ids)
|
|
194
|
+
.values_list("raw__source_object_type", flat=True).distinct()
|
|
195
|
+
)
|
|
196
|
+
cache[object_type] = sorted({object_type, *(t for t in found if isinstance(t, str) and t)})
|
|
197
|
+
return cache[object_type]
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
_TYPES: dict[str, dict[str, list[str]]] = {}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def resolve_ref(job, ref: dict, model):
|
|
204
|
+
"""The ``model`` row an ExternalRef of ``job``'s source names, or None."""
|
|
205
|
+
from core.models import ExternalRef
|
|
206
|
+
|
|
207
|
+
ct = ContentType.objects.get_for_model(model)
|
|
208
|
+
sid = str(ref.get("source_id") or "")
|
|
209
|
+
if not sid:
|
|
210
|
+
return None
|
|
211
|
+
hit = ExternalRef._base_manager.filter(
|
|
212
|
+
company_id=job.company_id, source=job.source, source_id=sid, content_type=ct,
|
|
213
|
+
object_type__in=source_object_types(job, ref.get("object_type") or ""),
|
|
214
|
+
).values_list("object_id", flat=True).first()
|
|
215
|
+
if hit is None:
|
|
216
|
+
return None
|
|
217
|
+
return model._base_manager.filter(pk=hit, company_id=job.company_id).first()
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
# --- the hook ---------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _erased_keys(job, record: dict) -> list[str]:
|
|
224
|
+
from core.provenance import is_erased_source
|
|
225
|
+
|
|
226
|
+
object_type = record.get("source_object_type") or record.get("object_type") or ""
|
|
227
|
+
keys = [str(record.get("source_id") or "")] + [str(a) for a in record.get("aliases") or []]
|
|
228
|
+
return [k for k in keys if k and is_erased_source(job.company_id, job.source, object_type, k)]
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
#: Target types an activity (task, communication) may name a person by.
|
|
232
|
+
PERSON_TARGET_TYPES = ("contact",)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _erased_targets(job, record: dict) -> bool:
|
|
236
|
+
"""Whether a task or communication is about an erased person: one of its
|
|
237
|
+
``target_refs`` names an erased contact. Its text is that person's (a note
|
|
238
|
+
has no participants to give it away), so it is skipped like the person."""
|
|
239
|
+
from core.provenance import is_erased_source
|
|
240
|
+
|
|
241
|
+
if record.get("object_type") not in ("task", "communication"):
|
|
242
|
+
return False
|
|
243
|
+
for ref in (record.get("data") or {}).get("target_refs") or []:
|
|
244
|
+
if not ref or ref.get("object_type") not in PERSON_TARGET_TYPES or not ref.get("source_id"):
|
|
245
|
+
continue
|
|
246
|
+
for otype in source_object_types(job, ref["object_type"]):
|
|
247
|
+
if is_erased_source(job.company_id, job.source, otype, str(ref["source_id"])):
|
|
248
|
+
return True
|
|
249
|
+
return False
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
#: Types whose record names a person by an address (match.address_hashes):
|
|
253
|
+
#: one under an active erasure suppression skips the whole record (3.1 step
|
|
254
|
+
#: 5). A consent fact is about its address; a communication with an erased
|
|
255
|
+
#: participant is that person's correspondence (staging skips it too).
|
|
256
|
+
PERSON_ADDRESS_TYPES = ("contact", "owner", "consent", "communication")
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _erased_points(job, record: dict) -> set:
|
|
260
|
+
"""Address hashes of the record that carry an active erasure suppression
|
|
261
|
+
(3.1 step 5): the person may have been erased after staging, or entered by
|
|
262
|
+
hand and erased, with no ExternalRef to say so."""
|
|
263
|
+
from crm_import.match import address_hashes
|
|
264
|
+
from parties.erasure import erasure_suppression_q
|
|
265
|
+
from parties.models import Suppression
|
|
266
|
+
|
|
267
|
+
otype = record.get("object_type") or ""
|
|
268
|
+
if otype not in (*PERSON_ADDRESS_TYPES, "company"):
|
|
269
|
+
return set()
|
|
270
|
+
hashes = address_hashes(otype, record)
|
|
271
|
+
if not hashes:
|
|
272
|
+
return set()
|
|
273
|
+
return set(Suppression.objects.filter(
|
|
274
|
+
erasure_suppression_q(), company_id=job.company_id, lifted_at__isnull=True, address_hash__in=hashes,
|
|
275
|
+
).values_list("address_hash", flat=True))
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def _scrub_erased(staged) -> None:
|
|
279
|
+
from unify.apply import ERASED_SOURCE_ERROR
|
|
280
|
+
from unify.models import StagedRow
|
|
281
|
+
|
|
282
|
+
StagedRow.objects.filter(pk=staged.pk).update(raw={"erased": True}, mapped_values={}, proposed_mapping={},
|
|
283
|
+
error=ERASED_SOURCE_ERROR, updated_at=timezone.now())
|
|
284
|
+
staged.raw, staged.mapped_values, staged.proposed_mapping = {"erased": True}, {}, {}
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _previous_ref(approval_row, record: dict) -> str | None:
|
|
288
|
+
"""4.10: this row's writes committed in a run whose ``ApprovalRow`` update
|
|
289
|
+
did not. The applied record is the one the row's own ExternalRef (its
|
|
290
|
+
source id) names, whatever else the row wrote first (a team, a ref).
|
|
291
|
+
|
|
292
|
+
Looked up by the staged row, not the approval row: a crashed run may be
|
|
293
|
+
cancelled and the row applied by a new run with a new ``ApprovalRow``
|
|
294
|
+
(step 8's resume), which must not write it a second time."""
|
|
295
|
+
from core.models import ExternalRef
|
|
296
|
+
from crm_import.models import ImportWriteLog
|
|
297
|
+
|
|
298
|
+
links = ImportWriteLog._base_manager.filter(approval_row__staged_row_id=approval_row.staged_row_id,
|
|
299
|
+
undone_at__isnull=True)
|
|
300
|
+
first = links.select_related("content_type").order_by("seq").first()
|
|
301
|
+
if first is None:
|
|
302
|
+
return None
|
|
303
|
+
job = first.job
|
|
304
|
+
ref = ExternalRef._base_manager.filter(
|
|
305
|
+
company_id=job.company_id, source=job.source, source_id=str(record.get("source_id")),
|
|
306
|
+
object_type=record.get("source_object_type") or record.get("object_type"),
|
|
307
|
+
).select_related("content_type").first()
|
|
308
|
+
if ref is None:
|
|
309
|
+
return applied_ref(first.content_type.model_class(), first.object_id)
|
|
310
|
+
return applied_ref(ref.content_type.model_class(), ref.object_id)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def applied_ref(model, pk) -> str:
|
|
314
|
+
return f"{model._meta.label_lower}:{pk}"
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def run(handler, company, staged, *, run=None, approval_row=None, **_context) -> str:
|
|
318
|
+
from core.plugins.dispatch import suppressed
|
|
319
|
+
|
|
320
|
+
if run is None or approval_row is None:
|
|
321
|
+
raise RowError(INVALID_VALUE, "CRM rows are applied through an approval run.")
|
|
322
|
+
job = writelog.job_for_batch(run.batch)
|
|
323
|
+
if job.company_id != company.pk or run.batch.company_id != company.pk:
|
|
324
|
+
raise RowError(INVALID_VALUE, "The batch belongs to another company.")
|
|
325
|
+
if approval_row.run_id != run.pk or approval_row.staged_row_id != staged.pk:
|
|
326
|
+
raise RowError(INVALID_VALUE, "The approval row is not this run's row.")
|
|
327
|
+
record = staged.raw or {}
|
|
328
|
+
erased_points = _erased_points(job, record) if not record.get("erased") else set()
|
|
329
|
+
if record.get("erased") or _erased_keys(job, record) or _erased_targets(job, record) or (
|
|
330
|
+
erased_points and record.get("object_type") in PERSON_ADDRESS_TYPES):
|
|
331
|
+
_scrub_erased(staged)
|
|
332
|
+
raise RowError(ERASED, "this source record belongs to a person whose data was erased; "
|
|
333
|
+
"it is not imported again.")
|
|
334
|
+
if erased_points:
|
|
335
|
+
# An organisation is not the person: it only loses the erased numbers.
|
|
336
|
+
from crm_import.match import strip_erased_points
|
|
337
|
+
|
|
338
|
+
staged.raw = record = strip_erased_points(record, erased_points)
|
|
339
|
+
previous = _previous_ref(approval_row, record)
|
|
340
|
+
if previous is not None:
|
|
341
|
+
return previous
|
|
342
|
+
row = Row(company=company, job=job, staged=staged, approval_row=approval_row,
|
|
343
|
+
session=writelog.WriteSession(job, approval_row))
|
|
344
|
+
try:
|
|
345
|
+
with suppressed(), transaction.atomic():
|
|
346
|
+
writelog.lock_job(job.pk) # first: Job → Customer → Party → User
|
|
347
|
+
ref = handler(row)
|
|
348
|
+
if record.get("object_type") == "company" and _erased_points(job, record) - erased_points:
|
|
349
|
+
raise RowError(CONFLICT_STALE, "a number of this company was erased while it was being "
|
|
350
|
+
"imported; retry the row.")
|
|
351
|
+
if _erased_keys(job, record) or _erased_targets(job, record) or (
|
|
352
|
+
record.get("object_type") in PERSON_ADDRESS_TYPES and _erased_points(job, record)):
|
|
353
|
+
# Erased while this row was being written (erasure re-keys the
|
|
354
|
+
# refs under its own locks): write nothing.
|
|
355
|
+
raise RowError(ERASED, "this source record was erased while it was being imported.")
|
|
356
|
+
row.session.flush()
|
|
357
|
+
except RowError:
|
|
358
|
+
raise
|
|
359
|
+
except IntegrityError as exc:
|
|
360
|
+
raise RowError(CONSTRAINT, str(exc).splitlines()[0][:500]) from exc
|
|
361
|
+
except ValidationError as exc:
|
|
362
|
+
raise RowError(INVALID_VALUE, "; ".join(exc.messages)[:500]) from exc
|
|
363
|
+
return ref
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"""Notes, meetings, calls, emails → communications (docs/crm/phase5-importer.md
|
|
2
|
+
2.10; hand-off sections 5 and 6).
|
|
3
|
+
|
|
4
|
+
Every record goes through ``communications.ingest.record``, one call per
|
|
5
|
+
row, inside the row's transaction and ``suppressed()`` (``base.run``):
|
|
6
|
+
|
|
7
|
+
- ``provider`` is the job's provider and ``external_id`` the record's source
|
|
8
|
+
id, so ``record`` upserts by its own ``ExternalRef`` (``source=<provider>``,
|
|
9
|
+
``object_type`` ``message`` / ``call`` / ``meeting``): **a re-ingest whose
|
|
10
|
+
payload hashes the same is a no-op**, and so is any re-ingest of a
|
|
11
|
+
communication erasure scrubbed. The applier also links the job's own ref
|
|
12
|
+
(``source=<provider>:<account>``, the canonical ``source_object_type``) so
|
|
13
|
+
staging recognises the record next time (``na unchanged`` / ``update``).
|
|
14
|
+
- ``envelope`` is the canonical ``raw`` (``{schema_version, provider,
|
|
15
|
+
payload}``); ``known_max_version`` is the newest payload version the
|
|
16
|
+
provider's adapter writes (``raw_schema_version`` on the registered
|
|
17
|
+
``BaseCrmExportAdapter``, else ``KNOWN_RAW_VERSIONS``, else the mapping
|
|
18
|
+
file's ``[communication] raw_schema_version``); otherwise the row fails
|
|
19
|
+
``invalid_value``.
|
|
20
|
+
- **Engagement linkage is explicit**: ``engagement=`` the associated deal's
|
|
21
|
+
engagement (``activity.targets``), else ``link_engagement=False``. The
|
|
22
|
+
hand-off's correction stands: there is no ``"explicit"`` mode.
|
|
23
|
+
- ``party=`` the first associated contact or company; else ``record``'s
|
|
24
|
+
counterparty rule. ``performed_by`` is the owner. ``is_editable=False``.
|
|
25
|
+
- A null ``direction`` is the mapping file's ``[communication]
|
|
26
|
+
default_direction``, else ``invalid_value`` (never guessed); a null
|
|
27
|
+
``status`` is ``scheduled`` for a future meeting or call, else
|
|
28
|
+
``completed``. Duration fields are dropped for kinds without
|
|
29
|
+
``has_duration``.
|
|
30
|
+
- ``last_activity_at``: ``record`` does not move it inside ``suppressed()``,
|
|
31
|
+
so the applier calls ``touch_activity`` for a completed communication of a
|
|
32
|
+
counting kind (``activity.touch_activity``, logged).
|
|
33
|
+
- Participants are resolved by ``record`` against the contact points already
|
|
34
|
+
imported (contacts apply before communications, 4.2). The applier does
|
|
35
|
+
**not** run ``resolve_unlinked`` over older participants: linking them to
|
|
36
|
+
imported parties would make those parties' undo refuse. Run
|
|
37
|
+
``manage.py resolve_participants`` once the import is accepted
|
|
38
|
+
(``docs/crm/importing.md``).
|
|
39
|
+
|
|
40
|
+
**Write log.** A new communication is a ``create`` with its participants,
|
|
41
|
+
raw sidecar and both refs. A re-ingest that changed snapshots the row and
|
|
42
|
+
its raw first; ``record`` replaces the participants, so the old ones are
|
|
43
|
+
logged as ``deleted`` (undo re-inserts them) and the new ones as creates.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
from __future__ import annotations
|
|
47
|
+
|
|
48
|
+
from django.contrib.contenttypes.models import ContentType
|
|
49
|
+
from django.utils import timezone
|
|
50
|
+
|
|
51
|
+
from core.plugins.payroll import AdapterError
|
|
52
|
+
|
|
53
|
+
from ..sidecar import SidecarRefused, put
|
|
54
|
+
from .activity import owner_of, targets, touch_activity
|
|
55
|
+
from .base import CONFLICT_STALE, INVALID_VALUE, Row, RowError, applied_ref
|
|
56
|
+
from .deals import parse_instant
|
|
57
|
+
|
|
58
|
+
#: Payload versions of providers whose adapter golden ships but a deployment
|
|
59
|
+
#: may not enable (the export can be adapted on another machine).
|
|
60
|
+
KNOWN_RAW_VERSIONS = {"hubspot": 1}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def known_max_version(provider: str, mapping: dict | None = None) -> int:
|
|
64
|
+
"""The newest raw payload version golden accepts from ``provider``: the
|
|
65
|
+
registered adapter's ``raw_schema_version``, else ``KNOWN_RAW_VERSIONS``,
|
|
66
|
+
else the mapping file's ``[communication] raw_schema_version`` (an
|
|
67
|
+
operator importing another tool's export declares it)."""
|
|
68
|
+
from core.plugins.registry import plugin_registry
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
adapter = (plugin_registry.get_crm_export_adapters() or {}).get(provider)
|
|
72
|
+
except Exception: # noqa: BLE001 — a misconfigured registry is not this row's problem
|
|
73
|
+
adapter = None
|
|
74
|
+
version = getattr(adapter, "raw_schema_version", None) if adapter is not None else None
|
|
75
|
+
version = version or KNOWN_RAW_VERSIONS.get(provider) or ((mapping or {}).get("communication") or {}).get(
|
|
76
|
+
"raw_schema_version")
|
|
77
|
+
if isinstance(version, bool) or not isinstance(version, int) or version < 1:
|
|
78
|
+
raise RowError(INVALID_VALUE, f"golden does not know which raw payload versions the {provider!r} adapter "
|
|
79
|
+
"writes: enable its plugin, or set [communication] raw_schema_version in the "
|
|
80
|
+
"mapping file.")
|
|
81
|
+
return version
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _direction(row: Row, kind_entry) -> str:
|
|
85
|
+
direction = row.data.get("direction") or ((row.mapping.get("communication") or {}).get("default_direction"))
|
|
86
|
+
if direction is None and len(kind_entry.directions) == 1:
|
|
87
|
+
direction = kind_entry.directions[0] # a note is internal
|
|
88
|
+
if direction not in kind_entry.directions:
|
|
89
|
+
raise RowError(INVALID_VALUE, f"a {kind_entry.name} is {', '.join(kind_entry.directions)}, not "
|
|
90
|
+
f"{direction!r}; set [communication] default_direction in the mapping file "
|
|
91
|
+
"to import records without one.")
|
|
92
|
+
return direction
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _status(row: Row, occurred_at) -> str:
|
|
96
|
+
from communications.models import Communication
|
|
97
|
+
|
|
98
|
+
status = row.data.get("status")
|
|
99
|
+
if status is None:
|
|
100
|
+
future = occurred_at > timezone.now()
|
|
101
|
+
return Communication.Status.SCHEDULED if future else Communication.Status.COMPLETED
|
|
102
|
+
if status not in Communication.Status.values:
|
|
103
|
+
raise RowError(INVALID_VALUE, f"communication status {status!r} is not one of "
|
|
104
|
+
f"{', '.join(Communication.Status.values)}.")
|
|
105
|
+
return status
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _existing(row: Row, provider: str, external_id: str):
|
|
109
|
+
from communications.models import Communication
|
|
110
|
+
from core.models import ExternalRef
|
|
111
|
+
|
|
112
|
+
hit = ExternalRef._base_manager.filter(
|
|
113
|
+
company_id=row.company.pk, source=provider, source_id=external_id,
|
|
114
|
+
content_type=ContentType.objects.get_for_model(Communication),
|
|
115
|
+
).values_list("object_id", flat=True).first()
|
|
116
|
+
if hit is None:
|
|
117
|
+
return None
|
|
118
|
+
return Communication._base_manager.filter(pk=hit, company_id=row.company.pk).first()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _targets(row: Row) -> dict:
|
|
122
|
+
"""The mapping file's property targets: its tables are the provider's
|
|
123
|
+
(``[note.properties]``, ``[call.properties]``, …), so by the record's
|
|
124
|
+
``source_object_type``."""
|
|
125
|
+
section = row.mapping.get(row.source_object_type) or {}
|
|
126
|
+
return dict(section.get("properties") or {}) if isinstance(section, dict) else {}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _lock_parties(row: Row, linked, existing) -> None:
|
|
130
|
+
"""Lock every party the row will point at (the targets, the participants
|
|
131
|
+
``record`` will resolve, the existing row's party) right after the job
|
|
132
|
+
lock and before ``record`` locks the communication: Job → Party, the order
|
|
133
|
+
erasure takes too."""
|
|
134
|
+
from communications.participants import match, normalize_address
|
|
135
|
+
from core.identity.resolve import lock_login_rows
|
|
136
|
+
|
|
137
|
+
ids = {getattr(linked.party, "pk", None), getattr(linked.engagement, "party_id", None),
|
|
138
|
+
getattr(existing, "party_id", None)}
|
|
139
|
+
for p in row.data.get("participants") or []:
|
|
140
|
+
channel, normalized = normalize_address(p.get("address") or "")
|
|
141
|
+
if normalized:
|
|
142
|
+
ids.add(match(row.company.pk, channel, normalized)[0])
|
|
143
|
+
ids.discard(None)
|
|
144
|
+
if ids:
|
|
145
|
+
lock_login_rows(parties=sorted(ids, key=str))
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _participants(row: Row) -> list[dict]:
|
|
149
|
+
out = []
|
|
150
|
+
for p in row.data.get("participants") or []:
|
|
151
|
+
out.append({"role": p.get("role"), "address": p.get("address") or "", "display_name": p.get("name") or ""})
|
|
152
|
+
return out
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def apply(row: Row) -> str:
|
|
156
|
+
from communications import ingest
|
|
157
|
+
from communications.kinds import get_kind
|
|
158
|
+
from communications.models import Communication, CommunicationParticipant, CommunicationRaw
|
|
159
|
+
from core.models import ExternalRef
|
|
160
|
+
|
|
161
|
+
from .. import writelog
|
|
162
|
+
|
|
163
|
+
if row.decision not in ("create", "update"):
|
|
164
|
+
raise RowError(INVALID_VALUE, f"a communication row cannot be applied as {row.decision!r}.")
|
|
165
|
+
data = row.data
|
|
166
|
+
kind = data.get("kind")
|
|
167
|
+
entry = get_kind(kind)
|
|
168
|
+
if entry is None:
|
|
169
|
+
raise RowError(INVALID_VALUE, f"communication kind {kind!r} is not registered "
|
|
170
|
+
"(GOLDEN_COMMUNICATION_KINDS).")
|
|
171
|
+
occurred_at = parse_instant(data.get("occurred_at"))
|
|
172
|
+
if occurred_at is None:
|
|
173
|
+
raise RowError(INVALID_VALUE, "occurred_at is not a UTC instant.")
|
|
174
|
+
ended_at = parse_instant(data.get("ended_at")) if entry.has_duration else None
|
|
175
|
+
if ended_at is not None and ended_at < occurred_at:
|
|
176
|
+
ended_at = None
|
|
177
|
+
provider = row.provider
|
|
178
|
+
external_id = str(row.record.get("source_id"))
|
|
179
|
+
owner, owner_flags = owner_of(row)
|
|
180
|
+
linked = targets(row)
|
|
181
|
+
existing = _existing(row, provider, external_id)
|
|
182
|
+
_lock_parties(row, linked, existing)
|
|
183
|
+
old_parts, raw = {}, None
|
|
184
|
+
direction, status = _direction(row, entry), _status(row, occurred_at)
|
|
185
|
+
if existing is not None:
|
|
186
|
+
# Snapshot what record() may change before it runs: the row, its raw, its participants.
|
|
187
|
+
row.session.touch(Communication, existing.pk)
|
|
188
|
+
raw = CommunicationRaw._base_manager.filter(communication=existing).first()
|
|
189
|
+
if raw is not None:
|
|
190
|
+
row.session.touch(CommunicationRaw, raw.pk)
|
|
191
|
+
old_parts = {p.pk: writelog.snapshot(CommunicationParticipant, p.pk)
|
|
192
|
+
for p in CommunicationParticipant._base_manager.filter(communication=existing)}
|
|
193
|
+
for ref_pk in ExternalRef._base_manager.filter(
|
|
194
|
+
company_id=row.company.pk, source=provider, source_id=external_id,
|
|
195
|
+
content_type=ContentType.objects.get_for_model(Communication)).values_list("pk", flat=True):
|
|
196
|
+
row.session.touch(ExternalRef, ref_pk) # record() bumps its last_synced_at
|
|
197
|
+
try:
|
|
198
|
+
result = ingest.record(
|
|
199
|
+
row.company, kind, direction=direction, occurred_at=occurred_at,
|
|
200
|
+
participants=_participants(row), provider=provider, external_id=external_id,
|
|
201
|
+
envelope=data.get("raw"), known_max_version=known_max_version(provider, row.mapping),
|
|
202
|
+
subject=data.get("subject") or "", body_text=data.get("body_text") or "",
|
|
203
|
+
summary=data.get("summary") or "", status=status, ended_at=ended_at,
|
|
204
|
+
duration_seconds=data.get("duration_seconds") if entry.has_duration else None,
|
|
205
|
+
engagement=linked.engagement, party=linked.party, performed_by=owner,
|
|
206
|
+
metadata=dict(existing.metadata or {}) if existing is not None else {},
|
|
207
|
+
is_editable=False, link_engagement=False,
|
|
208
|
+
)
|
|
209
|
+
except (ingest.IngestError, AdapterError, ValueError) as exc:
|
|
210
|
+
if isinstance(exc, RowError):
|
|
211
|
+
raise
|
|
212
|
+
raise RowError(INVALID_VALUE, str(exc)[:500]) from exc
|
|
213
|
+
comm = result.communication
|
|
214
|
+
if existing is None and not result.created:
|
|
215
|
+
# record() lost a race for its ref to a concurrent first import and
|
|
216
|
+
# rewrote that row: nothing here snapshotted it, so write nothing.
|
|
217
|
+
raise RowError(CONFLICT_STALE, "this communication was imported concurrently; retry the row.")
|
|
218
|
+
scrubbed = CommunicationRaw._base_manager.filter(communication=comm, payload=ingest.ERASED_PAYLOAD).exists()
|
|
219
|
+
if result.created:
|
|
220
|
+
row.session.create(comm)
|
|
221
|
+
for part in CommunicationParticipant._base_manager.filter(communication=comm):
|
|
222
|
+
row.session.create(part)
|
|
223
|
+
raw = CommunicationRaw._base_manager.filter(communication=comm).first()
|
|
224
|
+
if raw is not None:
|
|
225
|
+
row.session.create(raw)
|
|
226
|
+
ref = ExternalRef._base_manager.get(company_id=row.company.pk, source=provider,
|
|
227
|
+
object_type=ingest.object_type_for(kind), source_id=external_id)
|
|
228
|
+
row.session.link(ref)
|
|
229
|
+
elif result.changed:
|
|
230
|
+
for pk, before in old_parts.items():
|
|
231
|
+
row.session.deleted(CommunicationParticipant, pk, before)
|
|
232
|
+
for part in CommunicationParticipant._base_manager.filter(communication=comm):
|
|
233
|
+
row.session.create(part)
|
|
234
|
+
if raw is None:
|
|
235
|
+
raw = CommunicationRaw._base_manager.filter(communication=comm).first()
|
|
236
|
+
if raw is not None:
|
|
237
|
+
row.session.create(raw)
|
|
238
|
+
elif not scrubbed:
|
|
239
|
+
# The payload hashes the same, but what lives outside it (the
|
|
240
|
+
# associations, the owner, a mapped direction) may not: an approved
|
|
241
|
+
# update applies those columns, logged (``touch`` above).
|
|
242
|
+
fixes = {"engagement_id": getattr(linked.engagement, "pk", None),
|
|
243
|
+
"performed_by_id": getattr(owner, "pk", None), "direction": direction, "status": status}
|
|
244
|
+
if linked.party is not None:
|
|
245
|
+
fixes["party_id"] = linked.party.pk
|
|
246
|
+
fixes = {k: v for k, v in fixes.items() if getattr(comm, k) != v}
|
|
247
|
+
if fixes:
|
|
248
|
+
row.session.update(comm, **fixes)
|
|
249
|
+
if not scrubbed and (result.changed or row.decision == "update"):
|
|
250
|
+
if comm.engagement_id and comm.status == Communication.Status.COMPLETED and entry.counts_as_activity:
|
|
251
|
+
touch_activity(row, comm.engagement_id, comm.occurred_at)
|
|
252
|
+
values = {n: v for n, v in row.properties.items() if _targets(row).get(n, "sidecar") == "sidecar"}
|
|
253
|
+
# body_html stays in the raw payload (CommunicationRaw, view_raw_communication), not here.
|
|
254
|
+
derived = {"import_flags": owner_flags, "import_unresolved_targets": linked.unresolved,
|
|
255
|
+
"import_other_targets": linked.others}
|
|
256
|
+
try:
|
|
257
|
+
put(comm, provider, values, derived={k: v for k, v in derived.items() if v}, session=row.session)
|
|
258
|
+
except SidecarRefused as exc:
|
|
259
|
+
raise RowError(INVALID_VALUE, str(exc)) from exc
|
|
260
|
+
if not scrubbed: # erasure scrubbed it: add nothing that points at it
|
|
261
|
+
row.refs_for(comm)
|
|
262
|
+
return applied_ref(Communication, comm.pk)
|