celerp 2.3.3__tar.gz → 2.3.5__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-2.3.3 → celerp-2.3.5}/PKG-INFO +1 -1
- celerp-2.3.5/celerp/capacity.py +22 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/db.py +10 -7
- {celerp-2.3.3 → celerp-2.3.5}/celerp/gateway/client.py +225 -70
- {celerp-2.3.3 → celerp-2.3.5}/celerp/main.py +2 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/modules/loader.py +232 -9
- {celerp-2.3.3 → celerp-2.3.5}/celerp/modules/slots.py +27 -8
- {celerp-2.3.3 → celerp-2.3.5}/celerp/projections/engine.py +8 -5
- celerp-2.3.5/celerp/routers/search.py +305 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp.egg-info/PKG-INFO +1 -1
- {celerp-2.3.3 → celerp-2.3.5}/celerp.egg-info/SOURCES.txt +11 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp.egg-info/scm_file_list.json +31 -0
- celerp-2.3.5/celerp.egg-info/scm_version.json +8 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/__init__.py +5 -0
- celerp-2.3.5/default_modules/celerp-accounting/celerp_accounting/search.py +30 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-contacts/__init__.py +5 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-contacts/celerp_contacts/routes.py +6 -24
- celerp-2.3.5/default_modules/celerp-contacts/celerp_contacts/search.py +75 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/__init__.py +5 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/doc_projections.py +11 -2
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/routes.py +362 -76
- celerp-2.3.5/default_modules/celerp-docs/celerp_docs/search.py +68 -0
- celerp-2.3.5/default_modules/celerp-docs/tests/test_line_page_patch_truncate.py +245 -0
- celerp-2.3.5/default_modules/celerp-docs/tests/test_list_page_no_full_state.py +151 -0
- celerp-2.3.5/default_modules/celerp-docs/tests/test_list_query_pushdown.py +399 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/__init__.py +5 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/routes.py +76 -103
- celerp-2.3.5/default_modules/celerp-inventory/celerp_inventory/search.py +265 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/__init__.py +5 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/routes.py +3 -31
- celerp-2.3.5/default_modules/celerp-manufacturing/celerp_manufacturing/search.py +74 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-subscriptions/__init__.py +5 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-subscriptions/celerp_subscriptions/routes.py +4 -41
- celerp-2.3.5/default_modules/celerp-subscriptions/celerp_subscriptions/search.py +85 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/first_party.lock.json +6 -6
- {celerp-2.3.3 → celerp-2.3.5}/ui/api_client.py +753 -128
- {celerp-2.3.3 → celerp-2.3.5}/ui/app.py +17 -9
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/shell.py +150 -29
- {celerp-2.3.3 → celerp-2.3.5}/ui/locales/am.json +4 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/locales/ar.json +4 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/locales/de.json +4 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/locales/en.json +4 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/locales/es.json +4 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/locales/fr.json +4 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/locales/id.json +4 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/locales/it.json +4 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/locales/ja.json +4 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/locales/pt.json +4 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/locales/th.json +4 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/locales/vi.json +4 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/auth.py +8 -15
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/documents.py +288 -115
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/inventory.py +173 -77
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/notifications.py +7 -19
- celerp-2.3.5/ui/routes/search.py +218 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/settings.py +18 -27
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/stars.py +11 -16
- celerp-2.3.5/ui/security.py +44 -0
- celerp-2.3.3/celerp.egg-info/scm_version.json +0 -8
- celerp-2.3.3/ui/routes/search.py +0 -170
- celerp-2.3.3/ui/security.py +0 -19
- {celerp-2.3.3 → celerp-2.3.5}/CLA.md +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/CONTRIBUTING.md +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/LICENSE +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/LICENSING.md +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/MANIFEST.in +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/NOTICE +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/README.md +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/alembic.ini +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/__main__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/batch.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/cleanup.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/commands.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/conversations.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/files.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/intent.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/llm.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/memory.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/models.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/page_count.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/quota.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/service.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/ai/tools.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/alembic.ini +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/alembic_config.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/cli.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/compat.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/compute/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/compute/aggregations.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/compute/valuation.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/config.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/base.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/daily_scheduler.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/http.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/images.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/quickbooks.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/registry.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/relay_token.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/shopify.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/sync_runner.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/upsert.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/util.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/webhooks.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/woocommerce.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/connectors/xero.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/constants.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/embedded_pg.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/events/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/events/engine.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/events/schemas.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/events/types.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/gateway/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/gateway/state.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/importers/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/importers/importer.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/importers/schema.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/inventory_codes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/middleware.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/README.md +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/_auto_stamp.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/_data_reconcile.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/_json_compat.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/env.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/script.py.mako +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/a0b1c2d3e4f5_seed_landed_cost_clearing_accounts.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/a1b2c3d4e5f6_add_doc_share_tokens.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/b1c2d3e4f5a6_add_supporter_badges.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/b2c3d4e5f6a7_add_import_batches.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/b3c4d5e6f7a8_expand_role_permissions_to_role_grants.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/bc0d1e2f3a4b_barcode_unique_index.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/c1d2e3f4a5b6_add_marketplace.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/c2d3e4f5a6b7_add_is_sync_to_shopify.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/c4d5e6f7a8b9_account_cash_flow_category.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/c9d8e7f6a5b4_seed_shrinkage_writeoff_account.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/d0e1f2a3b4c5_add_share_token_expiry.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/d2e3f4a5b6c7_add_password_reset_token.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/d5e6f7a8b9c0_rename_fx_rounding_to_fx_difference.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/e3f4a5b6c7d8_add_company_is_active.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/e4f5a6b7c8d9_backfill_connector_idempotency_key.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/e7c9a1b3d5f2_work_center_default_columns.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/f1a2b3c4d5e6_move_accounts_marketplace_to_modules.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/f6a7b8c9d0e1_seed_fx_rounding_account.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/f8a9b0c1d2e3_work_center_default_backfill.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/fd5de461e14e_initial_schema.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/g1h2i3j4k5l6_add_consignment_flag.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/h2i3j4k5l6m7_add_bank_accounts_and_reconciliation.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/j4k5l6m7n8o9_labels_db_persistence.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/k5l6m7n8o9p0_add_reconciliation_v2.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/l6m7n8o9p0q1_add_sync_runs_table.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/m7n8o9p0q1r2_add_connector_configs_and_outbound_queue.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/n8o9p0q1r2s3_backfill_payment_date.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/o9p0q1r2s3t4_backfill_item_price_fields.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/p1q2r3s4t5u6_add_session_registry_and_user_auth_state.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/q2r3s4t5u6v7_add_system_runtime_state.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/r3s4t5u6v7w8_add_projections_company_entity_type_index.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/s4t5u6v7w8x9_drop_user_company_id_role.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/t5u6v7w8x9y0_seed_inventory_sub_accounts.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/u6v7w8x9y0z1_backfill_item_prices_from_attributes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/v7w8x9y0z1a2_backfill_purchase_unit_defaults.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/w8x9y0z1a2b3_backfill_category_unit_defaults.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/x7y8z9a0b1c2_add_projection_created_at.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/y8z9a0b1c2d3_per_company_ledger_idempotency.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/migrations/versions/z9a0b1c2d3e4_work_centers.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/accounting.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/ai.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/auth.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/base.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/company.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/connector_config.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/import_batch.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/ledger.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/marketplace.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/notification.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/projections.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/share.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/supporter.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/models/sync_run.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/modules/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/modules/api.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/modules/audit.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/modules/demotion.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/modules/importer.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/modules/license.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/modules/meta.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/modules/migrations_runner.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/modules/references.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/modules/registry.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/notifications/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/notifications/service.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/notifications/sse.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/output/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/output/branding.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/output/doc_print.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/output/pdf.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/output/share_render.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/projections/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/projections/handlers/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/projections/handlers/marketplace.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/projections/handlers/scanning.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/projections/handlers/shopify.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/projections/handlers/system.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/routers/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/routers/auth.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/routers/companies.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/routers/debug.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/routers/doctor.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/routers/events.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/routers/health.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/routers/ledger.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/routers/notifications.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/routers/stars.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/routers/system.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/schemas/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/activity_redaction.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/attachments.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/auth.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/auto_je.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/backup.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/backup_export.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/backup_import.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/backup_repo.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/backup_scheduler.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/backup_state.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/cogs_backfill.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/cost_visibility.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/demo.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/dev_release_guard.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/email.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/field_schema.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/fulfill.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/holdings.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/je_keys.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/landed_cost.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/line_measures.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/list_behavior.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/money.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/payments.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/permissions.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/pick.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/pricing.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/relay_share.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/reorder.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/runtime_state.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/session_tracker.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/shipping.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/star_cta.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/status_doc_backfill.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/supporter_badge.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/system_health.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/services/units.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/session_gate.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp/tax_regimes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp.egg-info/dependency_links.txt +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp.egg-info/entry_points.txt +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp.egg-info/requires.txt +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/celerp.egg-info/top_level.txt +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/conftest.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/conftest_support.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/LICENSE +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/api_setup.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/csv_parser.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/matcher.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/models.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/projections.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/ui_routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/balance-sheet.html +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/cash-flow.html +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-csv.csv +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-print.html +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/extended-journal.html +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/general-ledger.html +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/journal-csv.csv +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/journal-print.html +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/journal.html +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/ledger.html +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/pnl.html +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/statement.html +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/trial-balance.html +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_accounting_banking.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_accounting_banking_routers.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_accounting_gaps.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_accounting_import_idempotency.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_cash_flow.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_financial_reports_ui.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_journal_gl_soa.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_journal_gl_soa_ui.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_reconciliation_v2.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_reports_end_to_end.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_route_permissions.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-admin/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-admin/celerp_admin/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-admin/celerp_admin/routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-admin/celerp_admin/setup.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/celerp_ai/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/celerp_ai/routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/celerp_ai/setup.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/celerp_ai/ui_routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/conftest.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_batch.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_cleanup.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_conversations.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_coverage_gaps.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_intent.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_llm.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_memory.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_models.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_page_count.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_quota.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_router.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_routes_coverage.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_service.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_tools.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-backup/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-backup/celerp_backup/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-backup/celerp_backup/routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-backup/celerp_backup/setup.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/celerp_connectors/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/celerp_connectors/models.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/celerp_connectors/routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/conftest.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_compliance.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_connector_correctness.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_connectors.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_credentials_routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_images.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_outbound.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_quickbooks.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_rate_limiting.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_shopify.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_wiring.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_woocommerce.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_woocommerce_webhooks.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_xero.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-contacts/LICENSE +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-contacts/celerp_contacts/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-contacts/celerp_contacts/migrations.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-contacts/celerp_contacts/projections.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-contacts/celerp_contacts/services.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-contacts/celerp_contacts/ui_routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-dashboard/LICENSE +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-dashboard/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-dashboard/celerp_dashboard/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-dashboard/celerp_dashboard/routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-dashboard/celerp_dashboard/setup.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/LICENSE +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/api_setup.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/doc_constants.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/doc_email.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/doc_service.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/models_share.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/routes_payments.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/routes_share.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/sequences.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/taxes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/ui_routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/conftest.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_audits.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_bulk_payment_alloc_lock.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_consolidate_lots.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_cross_lot_settlement.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_freight_je.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_freight_lines.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_fulfill_no_split.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_fulfillment_activity.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_inbound_je_lifecycle.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_inventory_account_reconciliation.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_landed_receive.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_line_delete_persist.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_line_identifier.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_list_concurrency.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_list_outcome_concurrency.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_memo_close.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_memo_close_projection.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_memo_close_review_fixes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_memo_lifecycle_concurrency.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_memo_line_labels.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_memo_unfulfilled_filter.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_payment_void_activity.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_receive_sku_batch.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_send_visibility.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_service_lines.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_sold_label_ordering.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_void_guards.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_writeoffs.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/LICENSE +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/models_import_batch.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/projections.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/routes_attachments.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/routes_scanning.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/services.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/ui_routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/tests/test_item_recipe_projection.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/tests/test_item_workflow_projection.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-inventory/tests/test_landed_cost_projection.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/LICENSE +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/am.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/ar.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/de.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/en.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/es.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/fr.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/id.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/it.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/ja.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/pt.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/th.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/vi.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/models.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/presets.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/service.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/ui_routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/requirements.txt +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/tests/test_labels.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-labels/tests/test_labels_module.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/LICENSE +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/costing.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/expansion.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/labor.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/migrations.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/projection_handler.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/ui_routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/requirements.txt +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_auto_complete_on_finalize.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_bom_removed.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_build_api.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_completion_lock_order.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_item_recipe_api.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_item_workflow_api.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_labor_providers.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_manufacture_from_doc.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_manufacturing.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_manufacturing_import_idempotency.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_manufacturing_module.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_mfg_events.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_phase2_manufacturing_validations.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_production_order.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_recipe_costing.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_recipe_expansion.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_recost_api.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_run_records.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_to_make_allocation.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_where_used.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_work_centers_and_settings.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_workflow_time.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-reports/LICENSE +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-reports/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-reports/celerp_reports/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-reports/celerp_reports/api_setup.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-reports/celerp_reports/routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-reports/celerp_reports/ui_routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-reports/tests/test_reports_full.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-reports/tests/test_reports_unit.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-subscriptions/LICENSE +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-subscriptions/celerp_subscriptions/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-subscriptions/celerp_subscriptions/ui_routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-subscriptions/tests/test_subscriptions.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-subscriptions/tests/test_subscriptions_ui.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/LICENSE +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/accessory_fashion.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/activewear.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/art_photography.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/audio_equipment.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/bag_handbag.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/banknote.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/beauty_tool.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/bed_bedroom.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/beer.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/beverage_nonalc.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/body_part_auto.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/book.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/bottoms.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/brake_suspension.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/bullion_coin.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/camera.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/colored_stone.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/comic.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/commercial_space.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/component_part.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/confectionery.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/consulting_service.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/decorative_art.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/diamond.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/drawing.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/dress_jumpsuit.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_auto.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_component.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/emerald.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/engine_part.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fastener.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fertilizer_chemical.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/film_video.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fine_writing_instrument.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fluid_lubricant.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/footwear.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fragrance.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_food.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_produce.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/frozen_food.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/gaming_console.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/gold_bullion.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/grain_cereal.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/haircare.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/hand_tool.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/ingredient_bulk.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/interior_part.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/jewelry.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/kitchen_dining.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/laptop.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/lighting.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/livestock_feed.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/makeup.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/measuring_instrument.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/medal_token.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/mineral_specimen.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/mobile_phone.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/music_cd.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/music_vinyl.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/nail.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/numismatic_coin.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/outdoor_furniture.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/outerwear.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/packaged_food.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/painting.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/parking_bay.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/pearl.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/personal_care.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/pipe_plumbing.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/platinum_bullion.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/power_tool.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/print_edition.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/residential_unit.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/rough_gemstone.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/ruby.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/saas_plan.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/safety_ppe.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/sapphire.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/sculpture.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/seating.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/seeds.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/silver_bullion.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/skincare.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/soft_furnishing.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/software_addon.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/software_license.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/spirit.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/storage_furniture.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/swimwear.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/table_desk.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/tablet.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/tire_wheel.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/tops.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/trading_card.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/tv_display.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/video_game.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/watch.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/watch_strap.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/wine.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/agricultural.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/artwork.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/automotive.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/blank.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/books_media.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/coins_precious_metals.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/consulting.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/cosmetics.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/electronics.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/fashion.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/food_beverage.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/furniture.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/gemstones.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/hardware.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/property_rental.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/saas.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/watches.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/wine_spirits.json +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/ui_routes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/tests/test_verticals.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/default_modules/celerp-verticals/tests/test_verticals_routers.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/legal/OFFICIAL-COMPONENTS.md +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/legal/TRADEMARK.md +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/packaging/winget/Celerp.Celerp.installer.yaml +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/packaging/winget/Celerp.Celerp.locale.en-US.yaml +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/packaging/winget/Celerp.Celerp.yaml +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/packaging/winget/README.md +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/pyproject.toml +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/setup.cfg +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/test_helpers.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/activity.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/attrs.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/backup.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/cloud_gate.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/currency.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/files.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/journal.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/notes.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/phone.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/report_kit.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/components/table.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/config.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/i18n.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/marketplace_catalog.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/__init__.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/account.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/accounting.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/accounting_import.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/contacts.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/csv_import.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/dashboard.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/docs_import.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/events.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/financial_reports.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/lists_import.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/manufacturing.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/modules_page.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/reconciliation.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/reports.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/settings_accounting.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/settings_cloud.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/settings_connectors.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/settings_contacts.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/settings_general.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/settings_import.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/settings_inventory.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/settings_manufacturing.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/settings_payments.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/settings_purchasing.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/settings_sales.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/setup.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/subscriptions.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/routes/subscriptions_import.py +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/static/app.css +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/static/htmx.min.js +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/static/icon.png +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/static/logo.png +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/static/vendor/intl-tel-input/img/flags.webp +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/static/vendor/intl-tel-input/img/flags@2x.webp +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/static/vendor/intl-tel-input/intlTelInput.min.css +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/static/vendor/intl-tel-input/intlTelInput.min.js +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/static/vendor/intl-tel-input/intlTelInputWithUtils.min.js +0 -0
- {celerp-2.3.3 → celerp-2.3.5}/ui/static/vendor/intl-tel-input/utils.js +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Copyright (c) 2026 Noah Severs
|
|
2
|
+
# SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
"""Request-capacity constants shared by the API pool and the local UI transport.
|
|
4
|
+
|
|
5
|
+
The app launches one uvicorn worker (both `celerp start` and the Electron shell
|
|
6
|
+
run `uvicorn celerp.main:app` without `--workers`), so one API process owns one
|
|
7
|
+
request connection pool. These constants are the single source of truth for that
|
|
8
|
+
pool's size and for how many connections the web UI is allowed to open into that
|
|
9
|
+
process, so the two can never drift apart. The base size is the interactive
|
|
10
|
+
ceiling; the overflow is held back for background work, relay, auth, and bursts.
|
|
11
|
+
|
|
12
|
+
This module has no side effects and imports nothing from the app, so both the
|
|
13
|
+
database engine and the UI transport can read it without an import cycle.
|
|
14
|
+
"""
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
# Base connections the single API request pool keeps open, and the extra it may
|
|
18
|
+
# open under burst before refusing. The web UI's interactive transport uses the
|
|
19
|
+
# base size as its own connection ceiling, so a page fan-out can never demand
|
|
20
|
+
# more connections than the pool holds for interactive work.
|
|
21
|
+
REQUEST_DB_POOL_SIZE = 10
|
|
22
|
+
REQUEST_DB_MAX_OVERFLOW = 5
|
|
@@ -9,6 +9,7 @@ from sqlalchemy import text as _sql_text
|
|
|
9
9
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
|
10
10
|
from sqlalchemy.pool import NullPool
|
|
11
11
|
|
|
12
|
+
from celerp.capacity import REQUEST_DB_MAX_OVERFLOW, REQUEST_DB_POOL_SIZE
|
|
12
13
|
from celerp.config import settings
|
|
13
14
|
|
|
14
15
|
# Shared advisory-lock key that serialises schema migrations across every process
|
|
@@ -33,11 +34,13 @@ def mask_db_credentials(text: str) -> str:
|
|
|
33
34
|
_REQUEST_LOCK_TIMEOUT_MS = "3000"
|
|
34
35
|
_REQUEST_STATEMENT_TIMEOUT_MS = "30000"
|
|
35
36
|
|
|
36
|
-
# Pool budget:
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
37
|
+
# Pool budget: the app runs one API worker (both `celerp start` and the Electron
|
|
38
|
+
# shell launch uvicorn without --workers), so this single process owns one request
|
|
39
|
+
# pool of REQUEST_DB_POOL_SIZE base connections plus REQUEST_DB_MAX_OVERFLOW under
|
|
40
|
+
# burst. The base size is also the web UI's interactive connection ceiling, kept in
|
|
41
|
+
# lockstep through celerp.capacity so the two never drift. Postgres default
|
|
42
|
+
# max_connections=100 leaves ample headroom for migrations, admin tools, and
|
|
43
|
+
# background jobs beyond this pool.
|
|
41
44
|
if os.environ.get("CELERP_TEST_NULLPOOL"):
|
|
42
45
|
# Test mode: a fresh connection per use that closes on return, so a failed
|
|
43
46
|
# test can't leave a poisoned/locked connection lingering in a pooled
|
|
@@ -49,8 +52,8 @@ else:
|
|
|
49
52
|
settings.database_url,
|
|
50
53
|
future=True,
|
|
51
54
|
pool_pre_ping=True,
|
|
52
|
-
pool_size=
|
|
53
|
-
max_overflow=
|
|
55
|
+
pool_size=REQUEST_DB_POOL_SIZE,
|
|
56
|
+
max_overflow=REQUEST_DB_MAX_OVERFLOW,
|
|
54
57
|
# Bound how long any query may wait on a lock or run, so a stuck query is
|
|
55
58
|
# cancelled instead of pinning one of the few pooled connections for the
|
|
56
59
|
# full request lifetime (lock_timeout 3s, statement_timeout 30s, in ms).
|
|
@@ -26,7 +26,6 @@ from websockets.exceptions import ConnectionClosed
|
|
|
26
26
|
|
|
27
27
|
log = logging.getLogger(__name__)
|
|
28
28
|
|
|
29
|
-
_PING_INTERVAL = 30 # seconds
|
|
30
29
|
_BACKOFF_MAX = 60 # seconds
|
|
31
30
|
# Consecutive auth rejections before the client stops retrying: a rejected
|
|
32
31
|
# credential never heals on its own, so beyond a small allowance for a
|
|
@@ -37,6 +36,10 @@ _AUTH_FAILED_MAX = 3
|
|
|
37
36
|
# a revoke-then-reshare so it does not flap connect/disconnect).
|
|
38
37
|
_REAP_INTERVAL = 15 * 60 # seconds
|
|
39
38
|
_REAP_GRACE = 5 * 60 # seconds
|
|
39
|
+
# A single websocket send that cannot be handed to the transport within this long means the
|
|
40
|
+
# socket is wedged (a stalled or backpressured peer). Bound every send so it surfaces as an
|
|
41
|
+
# error instead of pinning the proxy task holding a relay slot forever.
|
|
42
|
+
_SEND_DEADLINE = 30 # seconds
|
|
40
43
|
|
|
41
44
|
|
|
42
45
|
def _shop_key(handle: str | None) -> str:
|
|
@@ -85,6 +88,22 @@ class GatewayClient:
|
|
|
85
88
|
# Hold strong refs to fire-and-forget tasks so the loop can't GC them mid-run
|
|
86
89
|
# (a dropped task = a lost proxy response or webhook sync).
|
|
87
90
|
self._bg_tasks: set = set()
|
|
91
|
+
# In-flight proxy tasks keyed by relay request id so an http.cancel frame can
|
|
92
|
+
# abort exactly the one request it names, and no other.
|
|
93
|
+
self._inflight: dict[str, asyncio.Task] = {}
|
|
94
|
+
# Connection generation: bumped on every teardown so a response produced by a
|
|
95
|
+
# request that outlived its socket can be recognised as stale and dropped
|
|
96
|
+
# rather than sent on the freshly rebuilt connection.
|
|
97
|
+
self._generation: int = 0
|
|
98
|
+
# One shared httpx client for all proxied requests, built lazily with bounded
|
|
99
|
+
# connection limits. A fresh client per request opened an unbounded number of
|
|
100
|
+
# pools under load; one bounded client caps the concurrency into the local app.
|
|
101
|
+
self._http_client: Any = None
|
|
102
|
+
# Observability counters for the proxy path, surfaced when the connection ends.
|
|
103
|
+
self._proxied_count = 0
|
|
104
|
+
self._cancelled_count = 0
|
|
105
|
+
self._timeout_count = 0
|
|
106
|
+
self._stale_dropped_count = 0
|
|
88
107
|
# Resolve local server ports for proxy routing.
|
|
89
108
|
# In Electron builds the ports are dynamic; Electron passes them via
|
|
90
109
|
# CELERP_API_PORT / CELERP_UI_PORT env vars so we don't rely on the
|
|
@@ -122,6 +141,22 @@ class GatewayClient:
|
|
|
122
141
|
self._bg_tasks.add(task)
|
|
123
142
|
task.add_done_callback(self._bg_tasks.discard)
|
|
124
143
|
|
|
144
|
+
def _spawn_proxy(self, payload: dict) -> None:
|
|
145
|
+
"""Run a proxied request fire-and-forget, keyed by its relay request id so an
|
|
146
|
+
http.cancel frame can abort exactly that task. The key is cleared when the task
|
|
147
|
+
finishes (a cancel arriving after completion is then a harmless no-op)."""
|
|
148
|
+
request_id = payload.get("id", "")
|
|
149
|
+
task = asyncio.create_task(self._handle_proxy_request(payload))
|
|
150
|
+
self._bg_tasks.add(task)
|
|
151
|
+
self._inflight[request_id] = task
|
|
152
|
+
|
|
153
|
+
def _done(t: asyncio.Task) -> None:
|
|
154
|
+
self._bg_tasks.discard(t)
|
|
155
|
+
if self._inflight.get(request_id) is t:
|
|
156
|
+
del self._inflight[request_id]
|
|
157
|
+
|
|
158
|
+
task.add_done_callback(_done)
|
|
159
|
+
|
|
125
160
|
# ── Public API ─────────────────────────────────────────────────────
|
|
126
161
|
|
|
127
162
|
async def run(self) -> None:
|
|
@@ -198,6 +233,7 @@ class GatewayClient:
|
|
|
198
233
|
await ws.close()
|
|
199
234
|
except Exception:
|
|
200
235
|
pass
|
|
236
|
+
await self._close_http_client()
|
|
201
237
|
|
|
202
238
|
async def _should_reap(self) -> bool:
|
|
203
239
|
"""A free instance with no live share and no recent proxied request should
|
|
@@ -293,40 +329,61 @@ class GatewayClient:
|
|
|
293
329
|
import ssl as _ssl
|
|
294
330
|
_ssl_ctx = _ssl.create_default_context()
|
|
295
331
|
_ssl_ctx.set_alpn_protocols(["http/1.1"])
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
"
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
332
|
+
try:
|
|
333
|
+
async with websockets.connect(
|
|
334
|
+
self._url, ssl=_ssl_ctx, ping_interval=20, ping_timeout=20, max_size=160 * 1024 * 1024
|
|
335
|
+
) as ws:
|
|
336
|
+
self._ws = ws
|
|
337
|
+
# Read current TOS version from config
|
|
338
|
+
from celerp.config import read_config
|
|
339
|
+
cfg = read_config() or {}
|
|
340
|
+
tos_version = cfg.get("cloud", {}).get("tos_version", "")
|
|
341
|
+
# App version: the Electron wrapper passes the release version via
|
|
342
|
+
# CELERP_APP_VERSION; fall back to the package version. Sent on every
|
|
343
|
+
# connect so the handshake reflects the build that is actually running.
|
|
344
|
+
from celerp import __version__ as _pkg_version
|
|
345
|
+
app_version = os.environ.get("CELERP_APP_VERSION") or _pkg_version
|
|
346
|
+
# Send hello handshake
|
|
347
|
+
await self._send(ws, {
|
|
348
|
+
"type": "hello",
|
|
349
|
+
"id": str(uuid.uuid4()),
|
|
350
|
+
"payload": {
|
|
351
|
+
"gateway_token": self._token,
|
|
352
|
+
"instance_id": self._instance_id,
|
|
353
|
+
"tos_version": tos_version,
|
|
354
|
+
"version": app_version,
|
|
355
|
+
},
|
|
356
|
+
})
|
|
357
|
+
# Message dispatch loop
|
|
358
|
+
async for raw in ws:
|
|
359
|
+
try:
|
|
360
|
+
msg = json.loads(raw)
|
|
361
|
+
except json.JSONDecodeError:
|
|
362
|
+
log.warning("Gateway sent non-JSON frame: %r", raw)
|
|
363
|
+
continue
|
|
364
|
+
await self._dispatch(msg)
|
|
365
|
+
finally:
|
|
366
|
+
# Teardown runs on every exit - clean end of the message stream OR an
|
|
367
|
+
# abnormal disconnect raised mid-serve. Kept in a finally so an exception
|
|
368
|
+
# from the async-for can't leave a dangling socket, an unfenced generation,
|
|
369
|
+
# and a stuck status behind.
|
|
370
|
+
self._ws = None
|
|
371
|
+
# A new generation for the next connection: any proxy response still in
|
|
372
|
+
# flight from this socket is now stale and must not be sent on the rebuilt
|
|
373
|
+
# one. Cancel the in-flight proxy tasks that belong to the dead connection -
|
|
374
|
+
# their responses can never be delivered on a socket that no longer exists.
|
|
375
|
+
self._generation += 1
|
|
376
|
+
for task in list(self._inflight.values()):
|
|
377
|
+
if not task.done():
|
|
378
|
+
task.cancel()
|
|
379
|
+
self._inflight.clear()
|
|
380
|
+
log.debug(
|
|
381
|
+
"Gateway proxy activity this connection: proxied=%d cancelled=%d "
|
|
382
|
+
"timed_out=%d stale_dropped=%d",
|
|
383
|
+
self._proxied_count, self._cancelled_count,
|
|
384
|
+
self._timeout_count, self._stale_dropped_count,
|
|
385
|
+
)
|
|
386
|
+
self._set_status("inactive")
|
|
330
387
|
|
|
331
388
|
async def _dispatch(self, msg: dict) -> None:
|
|
332
389
|
msg_type = msg.get("type", "")
|
|
@@ -414,7 +471,13 @@ class GatewayClient:
|
|
|
414
471
|
set_subscription_state(tier, status)
|
|
415
472
|
|
|
416
473
|
elif msg_type == "http.request":
|
|
417
|
-
self.
|
|
474
|
+
self._spawn_proxy(payload)
|
|
475
|
+
|
|
476
|
+
elif msg_type == "http.cancel":
|
|
477
|
+
request_id = payload.get("id", "")
|
|
478
|
+
task = self._inflight.get(request_id)
|
|
479
|
+
if task is not None and not task.done():
|
|
480
|
+
task.cancel()
|
|
418
481
|
|
|
419
482
|
elif msg_type == "shopify.webhook":
|
|
420
483
|
self._spawn(self._handle_shopify_webhook(payload))
|
|
@@ -533,6 +596,31 @@ class GatewayClient:
|
|
|
533
596
|
except Exception as exc:
|
|
534
597
|
log.warning("invoice.payment handling failed (entity=%s): %s", entity_id, exc)
|
|
535
598
|
|
|
599
|
+
def _get_http_client(self):
|
|
600
|
+
"""Return the one shared httpx client used for every proxied request, building
|
|
601
|
+
it lazily on first use. A bounded connection pool caps how many concurrent
|
|
602
|
+
requests this client can drive into the local app, so a burst of relayed
|
|
603
|
+
requests can no longer open an unbounded number of pools. The default timeout
|
|
604
|
+
is the fixed cap; a per-request timeout_ms tightens it further."""
|
|
605
|
+
import httpx
|
|
606
|
+
|
|
607
|
+
if self._http_client is None:
|
|
608
|
+
self._http_client = httpx.AsyncClient(
|
|
609
|
+
timeout=180.0,
|
|
610
|
+
limits=httpx.Limits(max_connections=32, max_keepalive_connections=8),
|
|
611
|
+
)
|
|
612
|
+
return self._http_client
|
|
613
|
+
|
|
614
|
+
async def _close_http_client(self) -> None:
|
|
615
|
+
"""Close the shared httpx client if one was built. Safe to call when none was."""
|
|
616
|
+
client = self._http_client
|
|
617
|
+
self._http_client = None
|
|
618
|
+
if client is not None:
|
|
619
|
+
try:
|
|
620
|
+
await client.aclose()
|
|
621
|
+
except Exception:
|
|
622
|
+
pass
|
|
623
|
+
|
|
536
624
|
async def _handle_proxy_request(self, payload: dict) -> None:
|
|
537
625
|
"""Handle a proxied HTTP request from the relay.
|
|
538
626
|
|
|
@@ -545,10 +633,14 @@ class GatewayClient:
|
|
|
545
633
|
local access.
|
|
546
634
|
"""
|
|
547
635
|
import base64
|
|
548
|
-
import httpx
|
|
549
636
|
|
|
550
637
|
# Activity stamp for the reaper's grace window: any proxied request counts.
|
|
551
638
|
self._last_request_monotonic = time.monotonic()
|
|
639
|
+
self._proxied_count += 1
|
|
640
|
+
# The generation this request belongs to: if the socket is rebuilt before the
|
|
641
|
+
# response is ready, self._generation advances past this and the response is
|
|
642
|
+
# dropped rather than sent on a connection that never issued the request.
|
|
643
|
+
generation = self._generation
|
|
552
644
|
|
|
553
645
|
request_id = payload.get("id", "")
|
|
554
646
|
method = payload.get("method", "GET")
|
|
@@ -557,6 +649,13 @@ class GatewayClient:
|
|
|
557
649
|
headers = payload.get("headers", {})
|
|
558
650
|
body_b64 = payload.get("body_b64", "")
|
|
559
651
|
body = base64.b64decode(body_b64) if body_b64 else None
|
|
652
|
+
# Additive per-request deadline: a numeric timeout_ms bounds this request below
|
|
653
|
+
# the fixed cap so a single slow local handler can't pin a relay slot for 180s.
|
|
654
|
+
# Absent or non-numeric leaves the default cap in force.
|
|
655
|
+
timeout_ms = payload.get("timeout_ms")
|
|
656
|
+
deadline_s: float | None = None
|
|
657
|
+
if isinstance(timeout_ms, (int, float)) and not isinstance(timeout_ms, bool) and timeout_ms > 0:
|
|
658
|
+
deadline_s = timeout_ms / 1000.0
|
|
560
659
|
|
|
561
660
|
# SSE / long-poll paths cannot be proxied over the WS request/response
|
|
562
661
|
# protocol. Return an empty stream so the browser doesn't 500.
|
|
@@ -599,47 +698,98 @@ class GatewayClient:
|
|
|
599
698
|
if query:
|
|
600
699
|
url = f"{url}?{query}"
|
|
601
700
|
|
|
701
|
+
client = self._get_http_client()
|
|
602
702
|
try:
|
|
603
|
-
|
|
703
|
+
if deadline_s is not None:
|
|
704
|
+
# asyncio.wait_for, not asyncio.timeout: the latter is 3.11+, and this package
|
|
705
|
+
# supports Python >=3.10 where it does not exist. wait_for cancels the request and
|
|
706
|
+
# raises TimeoutError on the deadline, which the handler below turns into an error
|
|
707
|
+
# response.
|
|
708
|
+
resp = await asyncio.wait_for(
|
|
709
|
+
client.request(
|
|
710
|
+
method=method,
|
|
711
|
+
url=url,
|
|
712
|
+
headers=headers,
|
|
713
|
+
content=body,
|
|
714
|
+
),
|
|
715
|
+
deadline_s,
|
|
716
|
+
)
|
|
717
|
+
else:
|
|
604
718
|
resp = await client.request(
|
|
605
719
|
method=method,
|
|
606
720
|
url=url,
|
|
607
721
|
headers=headers,
|
|
608
722
|
content=body,
|
|
609
723
|
)
|
|
610
|
-
|
|
611
|
-
#
|
|
612
|
-
#
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
724
|
+
except asyncio.CancelledError:
|
|
725
|
+
# http.cancel aborted this request: emit nothing and let the cancellation
|
|
726
|
+
# propagate so the task is recorded cancelled.
|
|
727
|
+
self._cancelled_count += 1
|
|
728
|
+
raise
|
|
729
|
+
except TimeoutError:
|
|
730
|
+
# The per-request deadline elapsed before the local handler answered. Surface
|
|
731
|
+
# it as an error response instead of hanging to the fixed cap.
|
|
732
|
+
self._timeout_count += 1
|
|
733
|
+
log.warning("Proxy request timed out after %sms for %s %s", timeout_ms, method, path)
|
|
734
|
+
if generation == self._generation:
|
|
735
|
+
await self._send(self._ws, {
|
|
736
|
+
"type": "http.response",
|
|
737
|
+
"payload": {
|
|
738
|
+
"id": request_id,
|
|
739
|
+
"status": 504,
|
|
740
|
+
"headers": [["content-type", "text/plain"]],
|
|
741
|
+
"body_b64": base64.b64encode(b"Local app timed out").decode(),
|
|
742
|
+
},
|
|
743
|
+
})
|
|
744
|
+
else:
|
|
745
|
+
self._stale_dropped_count += 1
|
|
746
|
+
return
|
|
630
747
|
except Exception as exc:
|
|
631
748
|
log.warning("Proxy request failed for %s %s: %s", method, path, exc)
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
"
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
749
|
+
if generation == self._generation:
|
|
750
|
+
await self._send(self._ws, {
|
|
751
|
+
"type": "http.response",
|
|
752
|
+
"payload": {
|
|
753
|
+
"id": request_id,
|
|
754
|
+
"status": 502,
|
|
755
|
+
"headers": [["content-type", "text/plain"]],
|
|
756
|
+
"body_b64": base64.b64encode(
|
|
757
|
+
f"Local app error: {type(exc).__name__}: {exc}".encode()
|
|
758
|
+
).decode(),
|
|
759
|
+
},
|
|
760
|
+
})
|
|
761
|
+
else:
|
|
762
|
+
self._stale_dropped_count += 1
|
|
763
|
+
return
|
|
764
|
+
|
|
765
|
+
# The socket that carried this request may have been rebuilt while it was in
|
|
766
|
+
# flight. A response from a superseded generation belongs to a connection the
|
|
767
|
+
# relay no longer has; sending it on the new socket would answer the wrong
|
|
768
|
+
# request, so it is dropped.
|
|
769
|
+
if generation != self._generation:
|
|
770
|
+
self._stale_dropped_count += 1
|
|
771
|
+
return
|
|
772
|
+
|
|
773
|
+
resp_body_b64 = base64.b64encode(resp.content).decode() if resp.content else ""
|
|
774
|
+
# Serialize as an ORDERED LIST of pairs (not a dict): a response can carry several
|
|
775
|
+
# Set-Cookie headers (login/refresh emit access_token + refresh_token), and a dict would
|
|
776
|
+
# collapse them into one comma-joined value the browser can't parse, so the refresh
|
|
777
|
+
# cookie never reaches the browser and the session dies at the access token's hard cap.
|
|
778
|
+
# multi_items() keeps each header separate. Drop content-length; the relay recomputes it.
|
|
779
|
+
_skip = {"transfer-encoding", "connection", "keep-alive", "content-length"}
|
|
780
|
+
resp_headers = [
|
|
781
|
+
[k, v] for k, v in resp.headers.multi_items()
|
|
782
|
+
if k.lower() not in _skip
|
|
783
|
+
]
|
|
784
|
+
await self._send(self._ws, {
|
|
785
|
+
"type": "http.response",
|
|
786
|
+
"payload": {
|
|
787
|
+
"id": request_id,
|
|
788
|
+
"status": resp.status_code,
|
|
789
|
+
"headers": resp_headers,
|
|
790
|
+
"body_b64": resp_body_b64,
|
|
791
|
+
},
|
|
792
|
+
})
|
|
643
793
|
|
|
644
794
|
async def send_message(self, msg_type: str, **payload) -> None:
|
|
645
795
|
"""Send a JSON message over the active WS connection.
|
|
@@ -652,7 +802,12 @@ class GatewayClient:
|
|
|
652
802
|
|
|
653
803
|
@staticmethod
|
|
654
804
|
async def _send(ws, message: dict) -> None:
|
|
655
|
-
|
|
805
|
+
# Bound the send: a websocket send awaits until the frame is handed to the transport, and a
|
|
806
|
+
# stalled or backpressured peer would otherwise block it forever, pinning the proxy task and
|
|
807
|
+
# its relay slot. On the deadline the send is cancelled and TimeoutError surfaces to the
|
|
808
|
+
# caller, which lets the wedged socket be torn down and rebuilt. asyncio.wait_for, not
|
|
809
|
+
# asyncio.timeout: the latter is 3.11+ and this package supports Python >=3.10.
|
|
810
|
+
await asyncio.wait_for(ws.send(json.dumps(message)), _SEND_DEADLINE)
|
|
656
811
|
|
|
657
812
|
|
|
658
813
|
# Module-level singleton — set by main.py lifespan
|
|
@@ -26,6 +26,7 @@ from fastapi.staticfiles import StaticFiles
|
|
|
26
26
|
from celerp.routers import auth, companies, ledger
|
|
27
27
|
from celerp.routers import health, notifications, system, events as events_router_mod
|
|
28
28
|
from celerp.routers import stars as stars_router_mod
|
|
29
|
+
from celerp.routers import search as search_router_mod
|
|
29
30
|
|
|
30
31
|
import celerp.models # noqa: F401 - ensures kernel models (UserCompany, ImportBatch, DocShareToken) are registered
|
|
31
32
|
|
|
@@ -466,6 +467,7 @@ app.include_router(system.router, prefix="/system", tags=["system"])
|
|
|
466
467
|
app.include_router(stars_router_mod.router, prefix="/stars", tags=["stars"])
|
|
467
468
|
app.include_router(notifications.router)
|
|
468
469
|
app.include_router(events_router_mod.router)
|
|
470
|
+
app.include_router(search_router_mod.router, tags=["search"])
|
|
469
471
|
|
|
470
472
|
# Backup router — always registered; individual endpoints gate on cloud connection.
|
|
471
473
|
# celerp_backup lives in default_modules/celerp-backup/ which is not on sys.path
|