celerp 1.2.4__tar.gz → 1.2.6__tar.gz
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.
- {celerp-1.2.4 → celerp-1.2.6}/CONTRIBUTING.md +37 -2
- {celerp-1.2.4 → celerp-1.2.6}/PKG-INFO +6 -3
- {celerp-1.2.4 → celerp-1.2.6}/README.md +5 -2
- celerp-1.2.6/celerp/__main__.py +14 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/conversations.py +1 -1
- {celerp-1.2.4 → celerp-1.2.6}/celerp/cli.py +84 -11
- {celerp-1.2.4 → celerp-1.2.6}/celerp/config.py +5 -1
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/daily_scheduler.py +25 -1
- celerp-1.2.6/celerp/connectors/relay_token.py +50 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/shopify.py +21 -5
- {celerp-1.2.4 → celerp-1.2.6}/celerp/events/engine.py +6 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/gateway/client.py +46 -7
- {celerp-1.2.4 → celerp-1.2.6}/celerp/main.py +26 -1
- {celerp-1.2.4 → celerp-1.2.6}/celerp/middleware.py +7 -4
- celerp-1.2.6/celerp/migrations/_data_reconcile.py +113 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/notifications/service.py +1 -1
- {celerp-1.2.4 → celerp-1.2.6}/celerp/routers/health.py +2 -5
- {celerp-1.2.4 → celerp-1.2.6}/celerp/routers/stars.py +7 -3
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/backup.py +3 -94
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/backup_export.py +17 -28
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/backup_import.py +42 -5
- celerp-1.2.6/celerp/services/backup_repo.py +241 -0
- celerp-1.2.6/celerp/services/backup_scheduler.py +107 -0
- celerp-1.2.6/celerp/services/backup_state.py +31 -0
- celerp-1.2.6/celerp/services/dev_release_guard.py +100 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/field_schema.py +5 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/supporter_badge.py +5 -3
- {celerp-1.2.4 → celerp-1.2.6}/celerp.egg-info/PKG-INFO +6 -3
- {celerp-1.2.4 → celerp-1.2.6}/celerp.egg-info/SOURCES.txt +9 -1
- {celerp-1.2.4 → celerp-1.2.6}/celerp.egg-info/scm_file_list.json +16 -2
- celerp-1.2.6/celerp.egg-info/scm_version.json +8 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/celerp_ai/routes.py +2 -1
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_conversations.py +30 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-backup/celerp_backup/routes.py +26 -37
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/tests/test_connectors.py +2 -0
- celerp-1.2.6/default_modules/celerp-connectors/tests/test_images.py +138 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/tests/test_shopify.py +32 -0
- celerp-1.2.6/default_modules/celerp-connectors/tests/test_wiring.py +129 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-contacts/celerp_contacts/routes.py +3 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-contacts/celerp_contacts/services.py +6 -2
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/celerp_docs/doc_service.py +9 -8
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/celerp_docs/routes.py +40 -16
- celerp-1.2.6/default_modules/celerp-docs/tests/test_line_delete_persist.py +85 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/celerp_inventory/routes.py +35 -38
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-subscriptions/celerp_subscriptions/routes.py +1 -1
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-subscriptions/tests/test_subscriptions.py +24 -0
- {celerp-1.2.4 → celerp-1.2.6}/pyproject.toml +6 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/api_client.py +49 -29
- {celerp-1.2.4 → celerp-1.2.6}/ui/app.py +15 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/components/activity.py +60 -2
- {celerp-1.2.4 → celerp-1.2.6}/ui/components/backup.py +5 -15
- {celerp-1.2.4 → celerp-1.2.6}/ui/components/shell.py +96 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/components/table.py +31 -10
- {celerp-1.2.4 → celerp-1.2.6}/ui/locales/ar.json +1 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/locales/de.json +1 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/locales/en.json +3 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/locales/es.json +1 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/locales/fr.json +1 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/locales/id.json +1 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/locales/it.json +1 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/locales/ja.json +1 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/locales/pt.json +1 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/locales/th.json +1 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/locales/vi.json +1 -7
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/auth.py +6 -2
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/dashboard.py +1 -1
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/documents.py +39 -19
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/inventory.py +18 -18
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/settings.py +78 -75
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/settings_cloud.py +0 -2
- celerp-1.2.4/celerp/services/backup_files.py +0 -181
- celerp-1.2.4/celerp/services/backup_scheduler.py +0 -171
- celerp-1.2.4/celerp.egg-info/scm_version.json +0 -8
- {celerp-1.2.4 → celerp-1.2.6}/CLA.md +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/LICENSE +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/LICENSING.md +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/MANIFEST.in +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/NOTICE +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/alembic.ini +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/batch.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/cleanup.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/commands.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/files.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/intent.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/llm.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/memory.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/models.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/page_count.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/quota.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/service.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/ai/tools.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/alembic.ini +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/alembic_config.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/compute/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/compute/aggregations.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/compute/valuation.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/base.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/http.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/images.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/outbound_queue.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/quickbooks.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/registry.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/sync_runner.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/upsert.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/webhooks.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/woocommerce.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/connectors/xero.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/constants.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/db.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/events/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/events/schemas.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/events/types.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/gateway/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/gateway/state.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/importers/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/importers/importer.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/importers/schema.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/README.md +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/_auto_stamp.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/env.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/script.py.mako +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/a0b1c2d3e4f5_seed_landed_cost_clearing_accounts.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/a1b2c3d4e5f6_add_doc_share_tokens.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/b1c2d3e4f5a6_add_supporter_badges.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/b2c3d4e5f6a7_add_import_batches.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/c1d2e3f4a5b6_add_marketplace.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/d2e3f4a5b6c7_add_password_reset_token.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/e3f4a5b6c7d8_add_company_is_active.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/f1a2b3c4d5e6_move_accounts_marketplace_to_modules.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/fd5de461e14e_initial_schema.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/g1h2i3j4k5l6_add_consignment_flag.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/h2i3j4k5l6m7_add_bank_accounts_and_reconciliation.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/j4k5l6m7n8o9_labels_db_persistence.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/k5l6m7n8o9p0_add_reconciliation_v2.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/l6m7n8o9p0q1_add_sync_runs_table.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/m7n8o9p0q1r2_add_connector_configs_and_outbound_queue.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/n8o9p0q1r2s3_backfill_payment_date.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/o9p0q1r2s3t4_backfill_item_price_fields.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/p1q2r3s4t5u6_add_session_registry_and_user_auth_state.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/q2r3s4t5u6v7_add_system_runtime_state.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/r3s4t5u6v7w8_add_projections_company_entity_type_index.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/s4t5u6v7w8x9_drop_user_company_id_role.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/t5u6v7w8x9y0_seed_inventory_sub_accounts.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/u6v7w8x9y0z1_backfill_item_prices_from_attributes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/v7w8x9y0z1a2_backfill_purchase_unit_defaults.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/w8x9y0z1a2b3_backfill_category_unit_defaults.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/x7y8z9a0b1c2_add_projection_created_at.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/y8z9a0b1c2d3_per_company_ledger_idempotency.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/migrations/versions/z9a0b1c2d3e4_work_centers.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/accounting.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/ai.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/auth.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/base.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/company.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/connector_config.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/import_batch.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/ledger.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/marketplace.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/notification.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/projections.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/share.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/supporter.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/models/sync_run.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/modules/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/modules/api.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/modules/audit.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/modules/license.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/modules/loader.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/modules/references.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/modules/registry.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/modules/slots.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/notifications/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/notifications/sse.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/output/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/output/pdf.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/output/share_render.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/projections/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/projections/engine.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/projections/handlers/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/projections/handlers/marketplace.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/projections/handlers/scanning.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/projections/handlers/system.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/routers/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/routers/auth.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/routers/companies.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/routers/debug.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/routers/doctor.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/routers/events.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/routers/ledger.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/routers/notifications.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/routers/system.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/schemas/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/activity_redaction.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/attachments.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/auth.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/auto_je.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/demo.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/email.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/fulfill.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/je_keys.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/landed_cost.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/line_measures.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/list_behavior.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/money.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/pick.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/runtime_state.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/session_tracker.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/star_cta.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/system_health.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/services/units.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/session_gate.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp/tax_regimes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp.egg-info/dependency_links.txt +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp.egg-info/entry_points.txt +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp.egg-info/requires.txt +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/celerp.egg-info/top_level.txt +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/conftest.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/LICENSE +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/celerp_accounting/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/celerp_accounting/api_setup.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/celerp_accounting/csv_parser.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/celerp_accounting/matcher.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/celerp_accounting/models.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/celerp_accounting/projections.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/celerp_accounting/routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/celerp_accounting/ui_routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/tests/test_accounting_banking.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/tests/test_accounting_banking_routers.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/tests/test_accounting_gaps.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/tests/test_accounting_import_idempotency.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-accounting/tests/test_reconciliation_v2.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-admin/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-admin/celerp_admin/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-admin/celerp_admin/routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-admin/celerp_admin/setup.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/celerp_ai/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/celerp_ai/setup.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/celerp_ai/ui_routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/conftest.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_batch.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_cleanup.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_coverage_gaps.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_intent.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_llm.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_memory.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_models.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_page_count.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_quota.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_router.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_routes_coverage.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_service.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-ai/tests/test_tools.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-backup/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-backup/celerp_backup/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-backup/celerp_backup/setup.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/celerp_connectors/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/celerp_connectors/models.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/celerp_connectors/routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/tests/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/tests/conftest.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/tests/test_compliance.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/tests/test_outbound.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/tests/test_quickbooks.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/tests/test_rate_limiting.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/tests/test_woocommerce.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-connectors/tests/test_xero.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-contacts/LICENSE +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-contacts/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-contacts/celerp_contacts/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-contacts/celerp_contacts/migrations.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-contacts/celerp_contacts/projections.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-contacts/celerp_contacts/ui_routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-dashboard/LICENSE +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-dashboard/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-dashboard/celerp_dashboard/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-dashboard/celerp_dashboard/routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-dashboard/celerp_dashboard/setup.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/LICENSE +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/celerp_docs/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/celerp_docs/api_setup.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/celerp_docs/doc_constants.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/celerp_docs/doc_projections.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/celerp_docs/models_share.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/celerp_docs/routes_share.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/celerp_docs/sequences.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/celerp_docs/taxes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/celerp_docs/ui_routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/tests/conftest.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/tests/test_audits.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/tests/test_freight_je.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/tests/test_freight_lines.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/tests/test_fulfill_no_split.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/tests/test_fulfillment_activity.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/tests/test_inbound_je_lifecycle.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/tests/test_inventory_account_reconciliation.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/tests/test_landed_receive.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/tests/test_payment_void_activity.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/tests/test_send_visibility.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-docs/tests/test_service_lines.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/LICENSE +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/celerp_inventory/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/celerp_inventory/models_import_batch.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/celerp_inventory/projections.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/celerp_inventory/routes_attachments.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/celerp_inventory/routes_scanning.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/celerp_inventory/services.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/celerp_inventory/ui_routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/tests/test_item_recipe_projection.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/tests/test_item_workflow_projection.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-inventory/tests/test_landed_cost_projection.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/LICENSE +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/celerp_labels/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/celerp_labels/migrations/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/celerp_labels/migrations/labels_001_create_label_templates.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/celerp_labels/models.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/celerp_labels/presets.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/celerp_labels/routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/celerp_labels/service.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/celerp_labels/ui_routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/requirements.txt +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/tests/test_labels.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-labels/tests/test_labels_module.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/LICENSE +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/celerp_manufacturing/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/celerp_manufacturing/costing.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/celerp_manufacturing/expansion.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/celerp_manufacturing/labor.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/celerp_manufacturing/migrations.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/celerp_manufacturing/projection_handler.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/celerp_manufacturing/routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/celerp_manufacturing/ui_routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/requirements.txt +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_bom_removed.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_build_api.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_item_recipe_api.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_item_workflow_api.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_labor_providers.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_manufacture_from_doc.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_manufacturing.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_manufacturing_import_idempotency.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_manufacturing_module.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_mfg_events.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_phase2_manufacturing_validations.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_production_order.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_recipe_costing.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_recipe_expansion.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_recost_api.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_to_make_allocation.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_where_used.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_work_centers_and_settings.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-manufacturing/tests/test_workflow_time.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-reports/LICENSE +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-reports/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-reports/celerp_reports/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-reports/celerp_reports/api_setup.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-reports/celerp_reports/routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-reports/celerp_reports/ui_routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-reports/tests/test_reports_full.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-reports/tests/test_reports_unit.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-subscriptions/LICENSE +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-subscriptions/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-subscriptions/celerp_subscriptions/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-subscriptions/celerp_subscriptions/ui_routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-subscriptions/tests/test_subscriptions_ui.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/LICENSE +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/accessory_fashion.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/activewear.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/art_photography.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/audio_equipment.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/bag_handbag.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/banknote.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/beauty_tool.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/bed_bedroom.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/beer.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/beverage_nonalc.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/body_part_auto.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/book.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/bottoms.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/brake_suspension.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/bullion_coin.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/camera.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/colored_stone.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/comic.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/commercial_space.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/component_part.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/confectionery.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/consulting_service.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/decorative_art.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/diamond.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/drawing.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/dress_jumpsuit.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_auto.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_component.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/emerald.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/engine_part.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/fastener.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/fertilizer_chemical.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/film_video.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/fine_writing_instrument.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/fluid_lubricant.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/footwear.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/fragrance.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_food.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_produce.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/frozen_food.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/gaming_console.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/gold_bullion.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/grain_cereal.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/haircare.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/hand_tool.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/ingredient_bulk.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/interior_part.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/jewelry.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/kitchen_dining.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/laptop.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/lighting.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/livestock_feed.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/makeup.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/measuring_instrument.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/medal_token.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/mineral_specimen.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/mobile_phone.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/music_cd.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/music_vinyl.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/nail.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/numismatic_coin.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/outdoor_furniture.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/outerwear.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/packaged_food.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/painting.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/parking_bay.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/pearl.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/personal_care.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/pipe_plumbing.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/platinum_bullion.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/power_tool.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/print_edition.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/residential_unit.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/rough_gemstone.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/ruby.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/saas_plan.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/safety_ppe.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/sapphire.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/sculpture.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/seating.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/seeds.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/silver_bullion.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/skincare.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/soft_furnishing.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/software_addon.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/software_license.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/spirit.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/storage_furniture.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/swimwear.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/table_desk.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/tablet.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/tire_wheel.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/tops.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/trading_card.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/tv_display.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/video_game.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/watch.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/watch_strap.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/categories/wine.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/agricultural.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/artwork.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/automotive.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/blank.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/books_media.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/coins_precious_metals.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/consulting.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/cosmetics.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/electronics.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/fashion.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/food_beverage.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/furniture.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/gemstones.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/hardware.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/property_rental.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/saas.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/watches.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/presets/wine_spirits.json +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/celerp_verticals/ui_routes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/tests/test_verticals.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/default_modules/celerp-verticals/tests/test_verticals_routers.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/legal/OFFICIAL-COMPONENTS.md +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/legal/TRADEMARK.md +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/memory/fix-receive-goods-bugs.md +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/setup.cfg +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/test_helpers.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/components/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/components/cloud_gate.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/components/currency.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/components/files.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/components/notes.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/components/phone.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/config.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/i18n.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/__init__.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/accounting.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/accounting_import.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/contacts.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/csv_import.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/docs_import.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/events.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/lists_import.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/manufacturing.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/notifications.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/reconciliation.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/reports.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/search.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/settings_accounting.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/settings_connectors.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/settings_contacts.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/settings_general.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/settings_import.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/settings_inventory.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/settings_manufacturing.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/settings_purchasing.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/settings_sales.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/setup.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/stars.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/subscriptions.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/routes/subscriptions_import.py +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/static/app.css +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/static/htmx.min.js +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/static/icon.png +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/static/logo.png +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/static/vendor/intl-tel-input/img/flags.webp +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/static/vendor/intl-tel-input/img/flags@2x.webp +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/static/vendor/intl-tel-input/intlTelInput.min.css +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/static/vendor/intl-tel-input/intlTelInput.min.js +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/static/vendor/intl-tel-input/intlTelInputWithUtils.min.js +0 -0
- {celerp-1.2.4 → celerp-1.2.6}/ui/static/vendor/intl-tel-input/utils.js +0 -0
|
@@ -39,8 +39,9 @@ Trademarks are not licensed by any code license; see `legal/TRADEMARK.md`.
|
|
|
39
39
|
## CLI commands (pip install)
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
celerp init
|
|
43
|
-
celerp start
|
|
42
|
+
celerp init # first-time setup: DB + migrations + config, then launches the servers
|
|
43
|
+
celerp init --no-start # same setup, but exit WITHOUT launching (service-managed/headless)
|
|
44
|
+
celerp start # launch API + UI (e.g. from systemd, after `init --no-start`)
|
|
44
45
|
celerp migrate # apply pending migrations after an upgrade
|
|
45
46
|
celerp status # show config, DB connection, migration state
|
|
46
47
|
celerp demo # seed demo data
|
|
@@ -56,9 +57,43 @@ celerp upgrade # pip install --upgrade celerp + migrate
|
|
|
56
57
|
| `--ui-port` | `8080` | UI server port |
|
|
57
58
|
| `--cloud-token` | _(empty)_ | Celerp Cloud token (optional) |
|
|
58
59
|
| `--force` | off | Overwrite existing config |
|
|
60
|
+
| `--yes` / `-y` | off | Skip the `--force` wipe confirmation (non-interactive) |
|
|
61
|
+
| `--no-start` | off | Set up, then exit WITHOUT launching servers (service-managed/headless) |
|
|
59
62
|
|
|
60
63
|
To change ports after init, edit `~/.config/celerp/config.toml` directly.
|
|
61
64
|
|
|
65
|
+
### Run as a service (systemd)
|
|
66
|
+
|
|
67
|
+
`celerp init` launches the servers and blocks (good for the one-command desktop
|
|
68
|
+
flow). For a headless box where a process manager owns the lifecycle, set up with
|
|
69
|
+
`--no-start` and let systemd run `celerp start`:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# First boot: provision DB + migrations + config, then exit (do not block).
|
|
73
|
+
sudo celerp init --no-start \
|
|
74
|
+
--db-url "postgresql+asyncpg://celerp:<password>@localhost:5432/celerp" \
|
|
75
|
+
--api-port 8000 --ui-port 8080
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```ini
|
|
79
|
+
# /etc/systemd/system/celerp.service
|
|
80
|
+
[Unit]
|
|
81
|
+
Description=Celerp
|
|
82
|
+
After=network.target postgresql.service
|
|
83
|
+
|
|
84
|
+
[Service]
|
|
85
|
+
ExecStart=/usr/local/bin/celerp start
|
|
86
|
+
Restart=on-failure
|
|
87
|
+
User=celerp
|
|
88
|
+
|
|
89
|
+
[Install]
|
|
90
|
+
WantedBy=multi-user.target
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
sudo systemctl enable --now celerp
|
|
95
|
+
```
|
|
96
|
+
|
|
62
97
|
## Troubleshooting
|
|
63
98
|
|
|
64
99
|
| Error | Fix |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: celerp
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.6
|
|
4
4
|
Summary: Free, self-hosted ERP for small businesses
|
|
5
5
|
License: Business Source License 1.1
|
|
6
6
|
|
|
@@ -214,13 +214,16 @@ Or install via pip:
|
|
|
214
214
|
|
|
215
215
|
```bash
|
|
216
216
|
pip install celerp
|
|
217
|
-
celerp init
|
|
218
|
-
celerp start
|
|
217
|
+
celerp init # sets up the database and launches Celerp
|
|
219
218
|
```
|
|
220
219
|
|
|
221
220
|
Open **http://localhost:8080**. Done.
|
|
222
221
|
Your office can securely access the system at your IP address :8080.
|
|
223
222
|
|
|
223
|
+
Running headless or under a process manager? Use `celerp init --no-start` to set up
|
|
224
|
+
without launching, then have your service run `celerp start` — see
|
|
225
|
+
[Run as a service (systemd)](CONTRIBUTING.md#run-as-a-service-systemd).
|
|
226
|
+
|
|
224
227
|
---
|
|
225
228
|
|
|
226
229
|
## What's inside
|
|
@@ -43,13 +43,16 @@ Or install via pip:
|
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
45
|
pip install celerp
|
|
46
|
-
celerp init
|
|
47
|
-
celerp start
|
|
46
|
+
celerp init # sets up the database and launches Celerp
|
|
48
47
|
```
|
|
49
48
|
|
|
50
49
|
Open **http://localhost:8080**. Done.
|
|
51
50
|
Your office can securely access the system at your IP address :8080.
|
|
52
51
|
|
|
52
|
+
Running headless or under a process manager? Use `celerp init --no-start` to set up
|
|
53
|
+
without launching, then have your service run `celerp start` — see
|
|
54
|
+
[Run as a service (systemd)](CONTRIBUTING.md#run-as-a-service-systemd).
|
|
55
|
+
|
|
53
56
|
---
|
|
54
57
|
|
|
55
58
|
## What's inside
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Copyright (c) 2026 Noah Severs
|
|
2
|
+
# SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
"""Module entrypoint so `python -m celerp <command>` runs the CLI.
|
|
4
|
+
|
|
5
|
+
The packaged Electron launcher invokes the bundled Python by module
|
|
6
|
+
(`python -m celerp migrate`) rather than via the `celerp` console script,
|
|
7
|
+
which is not on PATH inside the app bundle. This mirrors `python -m alembic`.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from celerp.cli import main
|
|
12
|
+
|
|
13
|
+
if __name__ == "__main__":
|
|
14
|
+
main()
|
|
@@ -82,7 +82,7 @@ async def list_conversations(
|
|
|
82
82
|
AIConversation.company_id == company_id,
|
|
83
83
|
AIConversation.user_id == user_id,
|
|
84
84
|
)
|
|
85
|
-
.order_by(AIConversation.updated_at.desc())
|
|
85
|
+
.order_by(AIConversation.updated_at.desc(), AIConversation.id.desc()) # id tiebreaker → stable pagination
|
|
86
86
|
.limit(limit)
|
|
87
87
|
.offset(offset)
|
|
88
88
|
)
|
|
@@ -418,6 +418,42 @@ def _run_migrations(db_url: str) -> None:
|
|
|
418
418
|
sys.exit(1)
|
|
419
419
|
|
|
420
420
|
|
|
421
|
+
def _reconcile_after_migrate(db_url: str) -> None:
|
|
422
|
+
"""Replay data-backfill migrations the auto-stamp walker skips on a develop
|
|
423
|
+
(create_all) database, so a develop→release in-place upgrade preserves data.
|
|
424
|
+
|
|
425
|
+
Gated by an instance_meta marker so it runs once per version; the backfills
|
|
426
|
+
are idempotent, so a redundant run would be a no-op anyway. The projection
|
|
427
|
+
rebuild (the other half of the version-change reconcile) runs in the API
|
|
428
|
+
lifespan, where module projection handlers are loaded.
|
|
429
|
+
"""
|
|
430
|
+
import sqlalchemy as _sa
|
|
431
|
+
|
|
432
|
+
from celerp import __version__
|
|
433
|
+
from celerp.migrations._data_reconcile import (
|
|
434
|
+
BACKFILL_VERSION_KEY,
|
|
435
|
+
get_meta,
|
|
436
|
+
replay_data_backfills,
|
|
437
|
+
set_meta,
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
sync_url = (
|
|
441
|
+
db_url.replace("postgresql+asyncpg://", "postgresql://")
|
|
442
|
+
.replace("postgresql+psycopg2://", "postgresql://")
|
|
443
|
+
)
|
|
444
|
+
engine = _sa.create_engine(sync_url, pool_pre_ping=True)
|
|
445
|
+
try:
|
|
446
|
+
with engine.begin() as conn:
|
|
447
|
+
if get_meta(conn, BACKFILL_VERSION_KEY) == __version__:
|
|
448
|
+
return # already reconciled for this version
|
|
449
|
+
replayed = replay_data_backfills(conn)
|
|
450
|
+
set_meta(conn, BACKFILL_VERSION_KEY, __version__)
|
|
451
|
+
if replayed:
|
|
452
|
+
click.echo(f" · Reconciled {len(replayed)} data-backfill migration(s) for {__version__}")
|
|
453
|
+
finally:
|
|
454
|
+
engine.dispose()
|
|
455
|
+
|
|
456
|
+
|
|
421
457
|
# ── Commands ──────────────────────────────────────────────────────────────────
|
|
422
458
|
|
|
423
459
|
@click.group()
|
|
@@ -430,8 +466,15 @@ def main() -> None:
|
|
|
430
466
|
@click.option("--api-port", default=None, type=int, help="API server port (default 8000).")
|
|
431
467
|
@click.option("--ui-port", default=None, type=int, help="UI server port (default 8080).")
|
|
432
468
|
@click.option("--cloud-token", default=None, help="Celerp Cloud token (optional).")
|
|
433
|
-
@click.option("--force", is_flag=True, help="
|
|
434
|
-
|
|
469
|
+
@click.option("--force", is_flag=True, help="Reconfigure: WIPES the database and all attached files.")
|
|
470
|
+
@click.option("--yes", "-y", "assume_yes", is_flag=True, help="Skip the --force wipe confirmation (non-interactive use).")
|
|
471
|
+
@click.option(
|
|
472
|
+
"--no-start", "no_start", is_flag=True,
|
|
473
|
+
help="Provision the database, run migrations, and write config, then exit "
|
|
474
|
+
"WITHOUT launching the servers. For service-managed/headless installs "
|
|
475
|
+
"where a process manager (e.g. systemd) runs `celerp start`.",
|
|
476
|
+
)
|
|
477
|
+
def init(db_url, api_port, ui_port, cloud_token, force, assume_yes, no_start):
|
|
435
478
|
"""Initialize Celerp: write config and run database migrations."""
|
|
436
479
|
config_path = _config_path()
|
|
437
480
|
|
|
@@ -441,6 +484,21 @@ def init(db_url, api_port, ui_port, cloud_token, force):
|
|
|
441
484
|
return
|
|
442
485
|
|
|
443
486
|
if force:
|
|
487
|
+
# --force is destructive: it drops the database AND removes attached files.
|
|
488
|
+
# init can run under sudo, so warn (with full paths) and confirm before wiping.
|
|
489
|
+
from celerp.config import settings
|
|
490
|
+
_purge_dirs = [
|
|
491
|
+
settings.data_dir / "static" / "attachments",
|
|
492
|
+
settings.data_dir / "ai_uploads",
|
|
493
|
+
]
|
|
494
|
+
click.echo("⚠ `init --force` permanently WIPES this instance:")
|
|
495
|
+
click.echo(f" - database: {db_url or _DEFAULT_DB_URL}")
|
|
496
|
+
for _d in _purge_dirs:
|
|
497
|
+
click.echo(f" - files: {_d.resolve()}")
|
|
498
|
+
click.echo(" Make sure you have a backup.")
|
|
499
|
+
if not assume_yes and not click.confirm("Continue?", default=False):
|
|
500
|
+
click.echo("Aborted.")
|
|
501
|
+
return
|
|
444
502
|
_stop_servers()
|
|
445
503
|
|
|
446
504
|
enabled_modules: list[str] = []
|
|
@@ -469,6 +527,13 @@ def init(db_url, api_port, ui_port, cloud_token, force):
|
|
|
469
527
|
)
|
|
470
528
|
sys.exit(1)
|
|
471
529
|
click.echo(" ✓ Database ready (fresh)")
|
|
530
|
+
# Wipe attached files too, so a forced re-init is a truly fresh instance and no
|
|
531
|
+
# orphaned files remain. Recreated automatically on next boot.
|
|
532
|
+
import shutil
|
|
533
|
+
for _d in _purge_dirs:
|
|
534
|
+
if _d.exists():
|
|
535
|
+
shutil.rmtree(_d, ignore_errors=True)
|
|
536
|
+
click.echo(f" ✓ Removed {_d.resolve()}")
|
|
472
537
|
else:
|
|
473
538
|
# Test DB connection — auto-provision if running as root
|
|
474
539
|
click.echo("Connecting to database...")
|
|
@@ -549,10 +614,13 @@ def init(db_url, api_port, ui_port, cloud_token, force):
|
|
|
549
614
|
from celerp.gateway.state import build_handoff_url as _handoff
|
|
550
615
|
if _settings.star_cta_enabled:
|
|
551
616
|
click.echo(
|
|
552
|
-
"New and independent -
|
|
617
|
+
"New and independent - early stargazers are how other teams find us.\n"
|
|
553
618
|
f" Back us early: {_handoff('/github', medium='cli')}\n"
|
|
554
619
|
)
|
|
555
620
|
|
|
621
|
+
if no_start:
|
|
622
|
+
click.echo("Setup complete. Start the servers with: celerp start")
|
|
623
|
+
return
|
|
556
624
|
_start(cfg)
|
|
557
625
|
|
|
558
626
|
|
|
@@ -674,15 +742,20 @@ def start():
|
|
|
674
742
|
|
|
675
743
|
|
|
676
744
|
@main.command()
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
745
|
+
@click.option("--db-url", default=None, help="Database URL (overrides config; used by the packaged launcher).")
|
|
746
|
+
def migrate(db_url):
|
|
747
|
+
"""Apply pending database migrations, then the develop→release reconcile."""
|
|
748
|
+
url = db_url
|
|
749
|
+
if url is None:
|
|
750
|
+
cfg = _read_config()
|
|
751
|
+
if not cfg:
|
|
752
|
+
click.echo("Not initialized. Run `celerp init` first.", err=True)
|
|
753
|
+
sys.exit(1)
|
|
754
|
+
url = cfg["database"]["url"]
|
|
683
755
|
click.echo("Running migrations...")
|
|
684
|
-
_run_migrations(
|
|
685
|
-
_post_migration_grants(
|
|
756
|
+
_run_migrations(url)
|
|
757
|
+
_post_migration_grants(url)
|
|
758
|
+
_reconcile_after_migrate(url)
|
|
686
759
|
click.echo(" ✓ Done")
|
|
687
760
|
|
|
688
761
|
|
|
@@ -20,6 +20,9 @@ class Settings(BaseSettings):
|
|
|
20
20
|
jwt_algorithm: str = "HS256"
|
|
21
21
|
access_token_expire_minutes: int = 15
|
|
22
22
|
refresh_token_expire_days: int = 30
|
|
23
|
+
# Log the UI out after this many minutes of no user interaction (client-side idle timer).
|
|
24
|
+
# Uniform across direct and relay access; set to 0 to disable.
|
|
25
|
+
idle_logout_minutes: int = 15
|
|
23
26
|
# Set to "true" to allow the default JWT secret (CI only).
|
|
24
27
|
allow_insecure_jwt: str = "false"
|
|
25
28
|
# Logging level for both API and UI processes. Override with LOG_LEVEL env var.
|
|
@@ -31,7 +34,8 @@ class Settings(BaseSettings):
|
|
|
31
34
|
celerp_public_url: str = ""
|
|
32
35
|
# Cloud Relay (opt-in - leave blank to disable entirely).
|
|
33
36
|
# Set GATEWAY_TOKEN to activate the persistent WS connection to relay.celerp.com.
|
|
34
|
-
# No
|
|
37
|
+
# No `[gateway_token]` means no gateway connection, no product telemetry, and
|
|
38
|
+
# no cloud dependency, except a startup subscription check.
|
|
35
39
|
gateway_token: str = ""
|
|
36
40
|
gateway_url: str = "wss://relay.celerp.com/ws/connect"
|
|
37
41
|
# Unique instance identifier sent to gateway (auto-generated if blank).
|
|
@@ -46,10 +46,13 @@ async def check_and_run_daily_syncs(
|
|
|
46
46
|
synced: list[str] = []
|
|
47
47
|
|
|
48
48
|
async with get_session_ctx() as session:
|
|
49
|
+
# Reconcile EVERY enabled connector once a day — including realtime
|
|
50
|
+
# (webhook) ones — so a daily incremental pass backstops any webhooks
|
|
51
|
+
# missed while the instance/tunnel was offline (idempotency keys make
|
|
52
|
+
# webhook + reconcile converge to a single write).
|
|
49
53
|
rows = await session.execute(
|
|
50
54
|
sa.select(ConnectorConfig).where(
|
|
51
55
|
ConnectorConfig.company_id == company_id,
|
|
52
|
-
ConnectorConfig.sync_frequency == SyncFrequency.DAILY.value,
|
|
53
56
|
)
|
|
54
57
|
)
|
|
55
58
|
configs = [row[0] for row in rows]
|
|
@@ -118,3 +121,24 @@ async def scheduler_loop(company_id: str, token_fetcher: TokenFetcher | None = N
|
|
|
118
121
|
except Exception as exc:
|
|
119
122
|
log.error("daily_scheduler: error: %s", exc)
|
|
120
123
|
await asyncio.sleep(_CHECK_INTERVAL_SECONDS)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
async def _distinct_company_ids() -> list[str]:
|
|
127
|
+
from celerp.db import get_session_ctx
|
|
128
|
+
async with get_session_ctx() as session:
|
|
129
|
+
rows = await session.execute(sa.select(ConnectorConfig.company_id).distinct())
|
|
130
|
+
return [r[0] for r in rows]
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
async def scheduler_loop_all(token_fetcher: TokenFetcher | None = None) -> None:
|
|
134
|
+
"""Reconciliation backstop: hourly, run any due daily syncs for every company
|
|
135
|
+
that has a connector configured. Started from the API lifespan."""
|
|
136
|
+
while True:
|
|
137
|
+
try:
|
|
138
|
+
for company_id in await _distinct_company_ids():
|
|
139
|
+
synced = await check_and_run_daily_syncs(company_id, token_fetcher=token_fetcher)
|
|
140
|
+
if synced:
|
|
141
|
+
log.info("daily_scheduler: synced %s for %s", ", ".join(synced), company_id)
|
|
142
|
+
except Exception as exc:
|
|
143
|
+
log.error("daily_scheduler: loop error: %s", exc)
|
|
144
|
+
await asyncio.sleep(_CHECK_INTERVAL_SECONDS)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Copyright (c) 2026 Noah Severs
|
|
2
|
+
# SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
"""Fetch a short-lived connector access token from the relay.
|
|
4
|
+
|
|
5
|
+
Autonomous syncs (the reconciliation scheduler and webhook-triggered syncs) run
|
|
6
|
+
inside the core process, so unlike the manual sync route — where the UI passes
|
|
7
|
+
the token in the request body — they must fetch the token themselves. The relay
|
|
8
|
+
holds the encrypted token and returns a short-lived copy to the authenticated
|
|
9
|
+
instance. Returns None when there is no relay session (e.g. a self-hosted
|
|
10
|
+
instance not connected to Celerp Cloud), in which case the caller skips.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import logging
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
log = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from celerp.connectors.base import ConnectorContext
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
async def fetch_context(company_id: str, connector_name: str) -> "ConnectorContext | None":
|
|
24
|
+
import httpx
|
|
25
|
+
|
|
26
|
+
from celerp.connectors.base import ConnectorContext
|
|
27
|
+
from celerp.gateway.state import get_session_token, relay_http_url, relay_session_headers
|
|
28
|
+
|
|
29
|
+
if not get_session_token():
|
|
30
|
+
return None # no cloud session → no relay token available
|
|
31
|
+
try:
|
|
32
|
+
async with httpx.AsyncClient(timeout=15.0) as c:
|
|
33
|
+
r = await c.get(
|
|
34
|
+
f"{relay_http_url()}/tokens/{connector_name}/access-token",
|
|
35
|
+
headers=relay_session_headers(),
|
|
36
|
+
)
|
|
37
|
+
if r.status_code != 200:
|
|
38
|
+
log.debug("relay token fetch for %s returned %d", connector_name, r.status_code)
|
|
39
|
+
return None
|
|
40
|
+
data = r.json()
|
|
41
|
+
except Exception as exc:
|
|
42
|
+
log.warning("relay token fetch for %s failed: %s", connector_name, exc)
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
return ConnectorContext(
|
|
46
|
+
company_id=company_id,
|
|
47
|
+
access_token=data["access_token"],
|
|
48
|
+
store_handle=data.get("store_handle"),
|
|
49
|
+
extra=data.get("extra"),
|
|
50
|
+
)
|
|
@@ -40,6 +40,17 @@ _API_VERSION = "2024-01"
|
|
|
40
40
|
_PAGE_LIMIT = 250 # Shopify max per page
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
def _money(v) -> float | None:
|
|
44
|
+
"""Parse a Shopify money value to float. Returns None only when genuinely
|
|
45
|
+
absent (missing/null/empty) — a real price of 0 stays 0.0, not None."""
|
|
46
|
+
if v is None or v == "":
|
|
47
|
+
return None
|
|
48
|
+
try:
|
|
49
|
+
return float(v)
|
|
50
|
+
except (TypeError, ValueError):
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
|
|
43
54
|
def _base_url(ctx: ConnectorContext) -> str:
|
|
44
55
|
if not ctx.store_handle:
|
|
45
56
|
raise ValueError("ConnectorContext.store_handle is required for Shopify")
|
|
@@ -126,7 +137,7 @@ class ShopifyConnector(ConnectorBase):
|
|
|
126
137
|
sku=sku,
|
|
127
138
|
name=name,
|
|
128
139
|
sell_by="piece",
|
|
129
|
-
sale_price=
|
|
140
|
+
sale_price=_money(variant.get("price")),
|
|
130
141
|
quantity=float(variant.get("inventory_quantity") or 0),
|
|
131
142
|
idempotency_key=idempotency_key,
|
|
132
143
|
)
|
|
@@ -162,14 +173,19 @@ class ShopifyConnector(ConnectorBase):
|
|
|
162
173
|
|
|
163
174
|
images: list[dict] = product.get("images", [])
|
|
164
175
|
|
|
176
|
+
from sqlalchemy import func
|
|
177
|
+
|
|
165
178
|
async with get_async_session() as session:
|
|
166
|
-
|
|
179
|
+
# Resolve the item by SKU with a DB-side filter (case-insensitive),
|
|
180
|
+
# returning the single match — never load the whole catalog into
|
|
181
|
+
# memory per product (that was O(products × catalog_size)).
|
|
182
|
+
row = (await session.execute(
|
|
167
183
|
select(Projection).where(
|
|
168
184
|
Projection.company_id == ctx.company_id,
|
|
169
185
|
Projection.entity_type == "item",
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
186
|
+
func.lower(Projection.state["sku"].astext) == sku.strip().lower(),
|
|
187
|
+
).limit(1)
|
|
188
|
+
)).scalar_one_or_none()
|
|
173
189
|
if row is None:
|
|
174
190
|
return
|
|
175
191
|
|
|
@@ -49,6 +49,12 @@ async def _check_period_lock(session, company_id, data: dict) -> None:
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
async def emit_event(session, **kwargs) -> LedgerEntry:
|
|
52
|
+
# A backup represents a clean point in time: while one is building, pause writes
|
|
53
|
+
# (reads, which never emit, are unaffected) so nothing changes mid-backup.
|
|
54
|
+
from celerp.services.backup_state import is_active as _backup_active
|
|
55
|
+
if _backup_active():
|
|
56
|
+
raise HTTPException(status_code=503, detail="Backup in progress, try again shortly.")
|
|
57
|
+
|
|
52
58
|
schema = EVENT_SCHEMA_MAP.get(kwargs["event_type"])
|
|
53
59
|
if schema is None:
|
|
54
60
|
raise ValueError(f"Unknown event_type: {kwargs['event_type']}")
|
|
@@ -240,6 +240,9 @@ class GatewayClient:
|
|
|
240
240
|
elif msg_type == "http.request":
|
|
241
241
|
asyncio.create_task(self._handle_proxy_request(payload))
|
|
242
242
|
|
|
243
|
+
elif msg_type == "shopify.webhook":
|
|
244
|
+
asyncio.create_task(self._handle_shopify_webhook(payload))
|
|
245
|
+
|
|
243
246
|
else:
|
|
244
247
|
log.debug("Unhandled gateway message type: %s", msg_type)
|
|
245
248
|
|
|
@@ -267,6 +270,38 @@ class GatewayClient:
|
|
|
267
270
|
except Exception as exc:
|
|
268
271
|
log.warning("Gateway: failed to persist feature_flags: %s", exc)
|
|
269
272
|
|
|
273
|
+
async def _handle_shopify_webhook(self, payload: dict) -> None:
|
|
274
|
+
"""A Shopify webhook the relay forwarded. Trigger a targeted incremental
|
|
275
|
+
sync for the affected entity on each company with Shopify configured
|
|
276
|
+
(idempotency keys dedupe against the reconciliation pass)."""
|
|
277
|
+
topic = payload.get("topic", "")
|
|
278
|
+
data = payload.get("data") or {}
|
|
279
|
+
try:
|
|
280
|
+
import sqlalchemy as sa
|
|
281
|
+
|
|
282
|
+
from celerp.connectors.base import SyncDirection
|
|
283
|
+
from celerp.connectors.relay_token import fetch_context
|
|
284
|
+
from celerp.connectors.webhooks import WebhookEvent, handle_webhook
|
|
285
|
+
from celerp.db import get_session_ctx
|
|
286
|
+
from celerp.models.connector_config import ConnectorConfig
|
|
287
|
+
|
|
288
|
+
async with get_session_ctx() as session:
|
|
289
|
+
rows = await session.execute(
|
|
290
|
+
sa.select(ConnectorConfig.company_id, ConnectorConfig.direction).where(
|
|
291
|
+
ConnectorConfig.connector == "shopify"
|
|
292
|
+
)
|
|
293
|
+
)
|
|
294
|
+
configs = rows.all()
|
|
295
|
+
|
|
296
|
+
event = WebhookEvent(platform="shopify", topic=topic, payload=data)
|
|
297
|
+
for company_id, direction in configs:
|
|
298
|
+
ctx = await fetch_context(company_id, "shopify")
|
|
299
|
+
if ctx is None:
|
|
300
|
+
continue
|
|
301
|
+
await handle_webhook(event, ctx, direction=SyncDirection(direction))
|
|
302
|
+
except Exception as exc:
|
|
303
|
+
log.warning("shopify webhook handling failed (topic=%s): %s", topic, exc)
|
|
304
|
+
|
|
270
305
|
async def _handle_proxy_request(self, payload: dict) -> None:
|
|
271
306
|
"""Handle a proxied HTTP request from the relay.
|
|
272
307
|
|
|
@@ -298,7 +333,7 @@ class GatewayClient:
|
|
|
298
333
|
"payload": {
|
|
299
334
|
"id": request_id,
|
|
300
335
|
"status": 200,
|
|
301
|
-
"headers":
|
|
336
|
+
"headers": [["content-type", "text/event-stream"], ["cache-control", "no-cache"]],
|
|
302
337
|
"body_b64": base64.b64encode(b"data: {}\n\n").decode(),
|
|
303
338
|
},
|
|
304
339
|
})
|
|
@@ -326,12 +361,16 @@ class GatewayClient:
|
|
|
326
361
|
content=body,
|
|
327
362
|
)
|
|
328
363
|
resp_body_b64 = base64.b64encode(resp.content).decode() if resp.content else ""
|
|
329
|
-
#
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
364
|
+
# Serialize as an ORDERED LIST of pairs (not a dict): a response can carry several
|
|
365
|
+
# Set-Cookie headers (login/refresh emit access_token + refresh_token), and a dict would
|
|
366
|
+
# collapse them into one comma-joined value the browser can't parse — so the refresh
|
|
367
|
+
# cookie never reaches the browser and the session dies at the access token's hard cap.
|
|
368
|
+
# multi_items() keeps each header separate. Drop content-length; the relay recomputes it.
|
|
369
|
+
_skip = {"transfer-encoding", "connection", "keep-alive", "content-length"}
|
|
370
|
+
resp_headers = [
|
|
371
|
+
[k, v] for k, v in resp.headers.multi_items()
|
|
333
372
|
if k.lower() not in _skip
|
|
334
|
-
|
|
373
|
+
]
|
|
335
374
|
await self._send(self._ws, {
|
|
336
375
|
"type": "http.response",
|
|
337
376
|
"payload": {
|
|
@@ -348,7 +387,7 @@ class GatewayClient:
|
|
|
348
387
|
"payload": {
|
|
349
388
|
"id": request_id,
|
|
350
389
|
"status": 502,
|
|
351
|
-
"headers":
|
|
390
|
+
"headers": [["content-type", "text/plain"]],
|
|
352
391
|
"body_b64": base64.b64encode(
|
|
353
392
|
f"Local app error: {type(exc).__name__}: {exc}".encode()
|
|
354
393
|
).decode(),
|
|
@@ -89,8 +89,9 @@ async def _try_auto_activate() -> None:
|
|
|
89
89
|
_prev_level = _httpx_log.level
|
|
90
90
|
_httpx_log.setLevel(logging.WARNING)
|
|
91
91
|
try:
|
|
92
|
+
from celerp import __version__ as _ver
|
|
92
93
|
async with httpx.AsyncClient(timeout=10.0) as c:
|
|
93
|
-
r = await c.post(f"{relay_base}/auth/activate", json={"instance_id": iid})
|
|
94
|
+
r = await c.post(f"{relay_base}/auth/activate", json={"instance_id": iid, "version": _ver})
|
|
94
95
|
finally:
|
|
95
96
|
_httpx_log.setLevel(_prev_level)
|
|
96
97
|
if r.status_code != 200:
|
|
@@ -199,6 +200,22 @@ async def lifespan(_app: FastAPI):
|
|
|
199
200
|
"_module": "_kernel",
|
|
200
201
|
})
|
|
201
202
|
|
|
203
|
+
# Develop→release guard: on a version change, rebuild projections with the
|
|
204
|
+
# release's handlers (now that all handlers are registered). Gated by a
|
|
205
|
+
# marker so it runs once per version. Non-fatal: a failure must not block
|
|
206
|
+
# boot — the marker stays unset and a later boot retries.
|
|
207
|
+
try:
|
|
208
|
+
from celerp.db import SessionLocal as _GuardSession
|
|
209
|
+
from celerp.services.dev_release_guard import run_upgrade_guard
|
|
210
|
+
async with _GuardSession() as _guard_sess:
|
|
211
|
+
await run_upgrade_guard(_guard_sess)
|
|
212
|
+
await _guard_sess.commit()
|
|
213
|
+
except Exception:
|
|
214
|
+
logging.getLogger(__name__).exception(
|
|
215
|
+
"Develop→release upgrade guard failed (non-fatal); projections may be "
|
|
216
|
+
"stale until rebuilt via doctor or /ledger/rebuild"
|
|
217
|
+
)
|
|
218
|
+
|
|
202
219
|
# Start gateway client if configured (opt-in, no-op if GATEWAY_TOKEN is blank)
|
|
203
220
|
gateway_task = None
|
|
204
221
|
if settings.gateway_token:
|
|
@@ -230,6 +247,13 @@ async def lifespan(_app: FastAPI):
|
|
|
230
247
|
from celerp.services.session_tracker import run_jti_cleanup_loop
|
|
231
248
|
jti_cleanup_task = asyncio.create_task(run_jti_cleanup_loop())
|
|
232
249
|
|
|
250
|
+
# Connector reconciliation scheduler: a daily incremental sync per connector,
|
|
251
|
+
# backstopping any realtime webhooks missed while offline. No-op without a
|
|
252
|
+
# relay session (self-hosted instances skip token fetch).
|
|
253
|
+
from celerp.connectors.daily_scheduler import scheduler_loop_all
|
|
254
|
+
from celerp.connectors.relay_token import fetch_context as _connector_token_fetcher
|
|
255
|
+
connector_sched_task = asyncio.create_task(scheduler_loop_all(token_fetcher=_connector_token_fetcher))
|
|
256
|
+
|
|
233
257
|
yield
|
|
234
258
|
|
|
235
259
|
# Terminate all active SSE connections so Uvicorn doesn't hang on shutdown
|
|
@@ -239,6 +263,7 @@ async def lifespan(_app: FastAPI):
|
|
|
239
263
|
# Stop background tasks
|
|
240
264
|
cleanup_task.cancel()
|
|
241
265
|
jti_cleanup_task.cancel()
|
|
266
|
+
connector_sched_task.cancel()
|
|
242
267
|
try:
|
|
243
268
|
await cleanup_task
|
|
244
269
|
except asyncio.CancelledError:
|
|
@@ -73,10 +73,13 @@ class MaxBodySizeMiddleware:
|
|
|
73
73
|
await self.app(scope, receive, send)
|
|
74
74
|
return
|
|
75
75
|
|
|
76
|
-
# Bulk file/cert import
|
|
77
|
-
# exempt
|
|
78
|
-
# size and the per-file 50 MB limit in store_upload().
|
|
79
|
-
|
|
76
|
+
# Bulk file/cert import and backup restore legitimately upload large archives;
|
|
77
|
+
# exempt them from the body cap. Bulk imports are bounded by the WS tunnel frame
|
|
78
|
+
# size and the per-file 50 MB limit in store_upload(); a .celerp-backup restore is
|
|
79
|
+
# a trusted whole-instance archive (DB + files) that is inherently large.
|
|
80
|
+
if scope.get("path", "").endswith(
|
|
81
|
+
("/items/files/bulk", "/items/attachments/bulk", "/backup/import", "/backup/import-bootstrap")
|
|
82
|
+
):
|
|
80
83
|
await self.app(scope, receive, send)
|
|
81
84
|
return
|
|
82
85
|
|