celerp 2.3.4__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.4 → celerp-2.3.5}/PKG-INFO +1 -1
- celerp-2.3.5/celerp/capacity.py +22 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/db.py +10 -7
- {celerp-2.3.4 → celerp-2.3.5}/celerp/main.py +2 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/modules/loader.py +232 -9
- {celerp-2.3.4 → celerp-2.3.5}/celerp/modules/slots.py +27 -8
- {celerp-2.3.4 → celerp-2.3.5}/celerp/projections/engine.py +8 -5
- celerp-2.3.5/celerp/routers/search.py +305 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp.egg-info/PKG-INFO +1 -1
- {celerp-2.3.4 → celerp-2.3.5}/celerp.egg-info/SOURCES.txt +8 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp.egg-info/scm_file_list.json +18 -0
- celerp-2.3.5/celerp.egg-info/scm_version.json +8 -0
- {celerp-2.3.4 → 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.4 → celerp-2.3.5}/default_modules/celerp-contacts/__init__.py +5 -0
- {celerp-2.3.4 → 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.4 → celerp-2.3.5}/default_modules/celerp-docs/__init__.py +5 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/routes.py +4 -15
- celerp-2.3.5/default_modules/celerp-docs/celerp_docs/search.py +68 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-inventory/__init__.py +5 -0
- {celerp-2.3.4 → 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.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/__init__.py +5 -0
- {celerp-2.3.4 → 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.4 → celerp-2.3.5}/default_modules/celerp-subscriptions/__init__.py +5 -0
- {celerp-2.3.4 → 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.4 → celerp-2.3.5}/default_modules/first_party.lock.json +6 -6
- {celerp-2.3.4 → celerp-2.3.5}/ui/api_client.py +631 -159
- {celerp-2.3.4 → celerp-2.3.5}/ui/app.py +9 -9
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/shell.py +63 -18
- {celerp-2.3.4 → celerp-2.3.5}/ui/locales/am.json +3 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/locales/ar.json +3 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/locales/de.json +3 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/locales/en.json +3 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/locales/es.json +3 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/locales/fr.json +3 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/locales/id.json +3 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/locales/it.json +3 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/locales/ja.json +3 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/locales/pt.json +3 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/locales/th.json +3 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/locales/vi.json +3 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/auth.py +8 -15
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/inventory.py +173 -77
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/notifications.py +7 -19
- celerp-2.3.5/ui/routes/search.py +218 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/settings.py +12 -25
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/stars.py +11 -16
- celerp-2.3.5/ui/security.py +44 -0
- celerp-2.3.4/celerp.egg-info/scm_version.json +0 -8
- celerp-2.3.4/ui/routes/search.py +0 -170
- celerp-2.3.4/ui/security.py +0 -19
- {celerp-2.3.4 → celerp-2.3.5}/CLA.md +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/CONTRIBUTING.md +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/LICENSE +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/LICENSING.md +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/MANIFEST.in +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/NOTICE +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/README.md +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/alembic.ini +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/__main__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/batch.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/cleanup.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/commands.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/conversations.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/files.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/intent.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/llm.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/memory.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/models.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/page_count.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/quota.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/service.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/ai/tools.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/alembic.ini +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/alembic_config.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/cli.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/compat.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/compute/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/compute/aggregations.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/compute/valuation.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/config.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/base.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/daily_scheduler.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/http.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/images.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/quickbooks.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/registry.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/relay_token.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/shopify.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/sync_runner.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/upsert.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/util.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/webhooks.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/woocommerce.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/connectors/xero.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/constants.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/embedded_pg.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/events/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/events/engine.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/events/schemas.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/events/types.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/gateway/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/gateway/client.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/gateway/state.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/importers/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/importers/importer.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/importers/schema.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/inventory_codes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/middleware.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/README.md +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/_auto_stamp.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/_data_reconcile.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/_json_compat.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/env.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/script.py.mako +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/a0b1c2d3e4f5_seed_landed_cost_clearing_accounts.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/a1b2c3d4e5f6_add_doc_share_tokens.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/b1c2d3e4f5a6_add_supporter_badges.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/b2c3d4e5f6a7_add_import_batches.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/b3c4d5e6f7a8_expand_role_permissions_to_role_grants.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/bc0d1e2f3a4b_barcode_unique_index.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/c1d2e3f4a5b6_add_marketplace.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/c2d3e4f5a6b7_add_is_sync_to_shopify.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/c4d5e6f7a8b9_account_cash_flow_category.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/c9d8e7f6a5b4_seed_shrinkage_writeoff_account.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/d0e1f2a3b4c5_add_share_token_expiry.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/d2e3f4a5b6c7_add_password_reset_token.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/d5e6f7a8b9c0_rename_fx_rounding_to_fx_difference.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/e3f4a5b6c7d8_add_company_is_active.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/e4f5a6b7c8d9_backfill_connector_idempotency_key.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/e7c9a1b3d5f2_work_center_default_columns.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/f1a2b3c4d5e6_move_accounts_marketplace_to_modules.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/f6a7b8c9d0e1_seed_fx_rounding_account.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/f8a9b0c1d2e3_work_center_default_backfill.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/fd5de461e14e_initial_schema.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/g1h2i3j4k5l6_add_consignment_flag.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/h2i3j4k5l6m7_add_bank_accounts_and_reconciliation.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/j4k5l6m7n8o9_labels_db_persistence.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/k5l6m7n8o9p0_add_reconciliation_v2.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/l6m7n8o9p0q1_add_sync_runs_table.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/m7n8o9p0q1r2_add_connector_configs_and_outbound_queue.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/n8o9p0q1r2s3_backfill_payment_date.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/o9p0q1r2s3t4_backfill_item_price_fields.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/p1q2r3s4t5u6_add_session_registry_and_user_auth_state.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/q2r3s4t5u6v7_add_system_runtime_state.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/r3s4t5u6v7w8_add_projections_company_entity_type_index.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/s4t5u6v7w8x9_drop_user_company_id_role.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/t5u6v7w8x9y0_seed_inventory_sub_accounts.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/u6v7w8x9y0z1_backfill_item_prices_from_attributes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/v7w8x9y0z1a2_backfill_purchase_unit_defaults.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/w8x9y0z1a2b3_backfill_category_unit_defaults.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/x7y8z9a0b1c2_add_projection_created_at.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/y8z9a0b1c2d3_per_company_ledger_idempotency.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/migrations/versions/z9a0b1c2d3e4_work_centers.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/accounting.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/ai.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/auth.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/base.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/company.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/connector_config.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/import_batch.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/ledger.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/marketplace.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/notification.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/projections.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/share.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/supporter.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/models/sync_run.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/modules/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/modules/api.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/modules/audit.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/modules/demotion.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/modules/importer.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/modules/license.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/modules/meta.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/modules/migrations_runner.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/modules/references.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/modules/registry.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/notifications/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/notifications/service.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/notifications/sse.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/output/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/output/branding.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/output/doc_print.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/output/pdf.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/output/share_render.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/projections/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/projections/handlers/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/projections/handlers/marketplace.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/projections/handlers/scanning.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/projections/handlers/shopify.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/projections/handlers/system.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/routers/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/routers/auth.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/routers/companies.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/routers/debug.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/routers/doctor.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/routers/events.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/routers/health.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/routers/ledger.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/routers/notifications.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/routers/stars.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/routers/system.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/schemas/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/activity_redaction.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/attachments.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/auth.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/auto_je.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/backup.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/backup_export.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/backup_import.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/backup_repo.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/backup_scheduler.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/backup_state.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/cogs_backfill.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/cost_visibility.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/demo.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/dev_release_guard.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/email.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/field_schema.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/fulfill.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/holdings.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/je_keys.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/landed_cost.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/line_measures.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/list_behavior.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/money.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/payments.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/permissions.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/pick.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/pricing.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/relay_share.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/reorder.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/runtime_state.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/session_tracker.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/shipping.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/star_cta.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/status_doc_backfill.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/supporter_badge.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/system_health.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/services/units.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/session_gate.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp/tax_regimes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp.egg-info/dependency_links.txt +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp.egg-info/entry_points.txt +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp.egg-info/requires.txt +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/celerp.egg-info/top_level.txt +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/conftest.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/conftest_support.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/LICENSE +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/api_setup.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/csv_parser.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/matcher.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/models.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/projections.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/celerp_accounting/ui_routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/balance-sheet.html +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/cash-flow.html +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-csv.csv +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-print.html +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/extended-journal.html +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/general-ledger.html +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/journal-csv.csv +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/journal-print.html +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/journal.html +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/ledger.html +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/pnl.html +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/statement.html +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/report_goldens/trial-balance.html +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_accounting_banking.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_accounting_banking_routers.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_accounting_gaps.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_accounting_import_idempotency.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_cash_flow.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_financial_reports_ui.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_journal_gl_soa.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_journal_gl_soa_ui.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_reconciliation_v2.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_reports_end_to_end.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-accounting/tests/test_route_permissions.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-admin/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-admin/celerp_admin/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-admin/celerp_admin/routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-admin/celerp_admin/setup.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/celerp_ai/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/celerp_ai/routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/celerp_ai/setup.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/celerp_ai/ui_routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/conftest.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_batch.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_cleanup.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_conversations.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_coverage_gaps.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_intent.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_llm.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_memory.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_models.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_page_count.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_quota.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_router.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_routes_coverage.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_service.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-ai/tests/test_tools.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-backup/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-backup/celerp_backup/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-backup/celerp_backup/routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-backup/celerp_backup/setup.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/celerp_connectors/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/celerp_connectors/models.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/celerp_connectors/routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/conftest.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_compliance.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_connector_correctness.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_connectors.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_credentials_routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_images.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_outbound.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_quickbooks.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_rate_limiting.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_shopify.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_wiring.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_woocommerce.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_woocommerce_webhooks.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-connectors/tests/test_xero.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-contacts/LICENSE +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-contacts/celerp_contacts/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-contacts/celerp_contacts/migrations.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-contacts/celerp_contacts/projections.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-contacts/celerp_contacts/services.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-contacts/celerp_contacts/ui_routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-dashboard/LICENSE +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-dashboard/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-dashboard/celerp_dashboard/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-dashboard/celerp_dashboard/routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-dashboard/celerp_dashboard/setup.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/LICENSE +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/api_setup.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/doc_constants.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/doc_email.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/doc_projections.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/doc_service.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/models_share.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/routes_payments.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/routes_share.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/sequences.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/taxes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/celerp_docs/ui_routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/conftest.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_audits.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_bulk_payment_alloc_lock.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_consolidate_lots.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_cross_lot_settlement.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_freight_je.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_freight_lines.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_fulfill_no_split.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_fulfillment_activity.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_inbound_je_lifecycle.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_inventory_account_reconciliation.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_landed_receive.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_line_delete_persist.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_line_identifier.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_line_page_patch_truncate.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_list_concurrency.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_list_outcome_concurrency.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_list_page_no_full_state.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_list_query_pushdown.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_memo_close.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_memo_close_projection.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_memo_close_review_fixes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_memo_lifecycle_concurrency.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_memo_line_labels.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_memo_unfulfilled_filter.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_payment_void_activity.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_receive_sku_batch.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_send_visibility.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_service_lines.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_sold_label_ordering.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_void_guards.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-docs/tests/test_writeoffs.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-inventory/LICENSE +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/models_import_batch.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/projections.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/routes_attachments.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/routes_scanning.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/services.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-inventory/celerp_inventory/ui_routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-inventory/tests/test_item_recipe_projection.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-inventory/tests/test_item_workflow_projection.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-inventory/tests/test_landed_cost_projection.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/LICENSE +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/am.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/ar.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/de.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/en.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/es.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/fr.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/id.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/it.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/ja.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/pt.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/th.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/locales/vi.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/models.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/presets.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/service.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/celerp_labels/ui_routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/requirements.txt +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/tests/test_labels.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-labels/tests/test_labels_module.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/LICENSE +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/costing.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/expansion.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/labor.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/migrations.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/projection_handler.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/celerp_manufacturing/ui_routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/requirements.txt +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_auto_complete_on_finalize.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_bom_removed.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_build_api.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_completion_lock_order.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_item_recipe_api.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_item_workflow_api.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_labor_providers.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_manufacture_from_doc.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_manufacturing.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_manufacturing_import_idempotency.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_manufacturing_module.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_mfg_events.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_phase2_manufacturing_validations.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_production_order.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_recipe_costing.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_recipe_expansion.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_recost_api.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_run_records.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_to_make_allocation.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_where_used.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_work_centers_and_settings.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-manufacturing/tests/test_workflow_time.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-reports/LICENSE +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-reports/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-reports/celerp_reports/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-reports/celerp_reports/api_setup.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-reports/celerp_reports/routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-reports/celerp_reports/ui_routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-reports/tests/test_reports_full.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-reports/tests/test_reports_unit.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-subscriptions/LICENSE +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-subscriptions/celerp_subscriptions/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-subscriptions/celerp_subscriptions/ui_routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-subscriptions/tests/test_subscriptions.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-subscriptions/tests/test_subscriptions_ui.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/LICENSE +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/accessory_fashion.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/activewear.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/art_photography.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/audio_equipment.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/bag_handbag.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/banknote.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/beauty_tool.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/bed_bedroom.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/beer.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/beverage_nonalc.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/body_part_auto.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/book.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/bottoms.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/brake_suspension.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/bullion_coin.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/camera.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/colored_stone.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/comic.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/commercial_space.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/component_part.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/confectionery.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/consulting_service.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/decorative_art.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/diamond.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/drawing.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/dress_jumpsuit.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_auto.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_component.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/emerald.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/engine_part.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fastener.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fertilizer_chemical.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/film_video.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fine_writing_instrument.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fluid_lubricant.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/footwear.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fragrance.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_food.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_produce.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/frozen_food.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/gaming_console.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/gold_bullion.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/grain_cereal.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/haircare.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/hand_tool.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/ingredient_bulk.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/interior_part.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/jewelry.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/kitchen_dining.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/laptop.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/lighting.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/livestock_feed.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/makeup.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/measuring_instrument.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/medal_token.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/mineral_specimen.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/mobile_phone.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/music_cd.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/music_vinyl.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/nail.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/numismatic_coin.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/outdoor_furniture.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/outerwear.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/packaged_food.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/painting.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/parking_bay.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/pearl.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/personal_care.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/pipe_plumbing.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/platinum_bullion.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/power_tool.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/print_edition.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/residential_unit.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/rough_gemstone.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/ruby.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/saas_plan.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/safety_ppe.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/sapphire.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/sculpture.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/seating.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/seeds.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/silver_bullion.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/skincare.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/soft_furnishing.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/software_addon.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/software_license.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/spirit.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/storage_furniture.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/swimwear.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/table_desk.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/tablet.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/tire_wheel.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/tops.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/trading_card.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/tv_display.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/video_game.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/watch.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/watch_strap.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/categories/wine.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/agricultural.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/artwork.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/automotive.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/blank.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/books_media.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/coins_precious_metals.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/consulting.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/cosmetics.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/electronics.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/fashion.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/food_beverage.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/furniture.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/gemstones.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/hardware.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/property_rental.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/saas.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/watches.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/presets/wine_spirits.json +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/celerp_verticals/ui_routes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/tests/test_verticals.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/default_modules/celerp-verticals/tests/test_verticals_routers.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/legal/OFFICIAL-COMPONENTS.md +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/legal/TRADEMARK.md +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/packaging/winget/Celerp.Celerp.installer.yaml +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/packaging/winget/Celerp.Celerp.locale.en-US.yaml +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/packaging/winget/Celerp.Celerp.yaml +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/packaging/winget/README.md +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/pyproject.toml +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/setup.cfg +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/test_helpers.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/activity.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/attrs.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/backup.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/cloud_gate.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/currency.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/files.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/journal.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/notes.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/phone.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/report_kit.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/components/table.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/config.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/i18n.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/marketplace_catalog.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/__init__.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/account.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/accounting.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/accounting_import.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/contacts.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/csv_import.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/dashboard.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/docs_import.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/documents.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/events.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/financial_reports.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/lists_import.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/manufacturing.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/modules_page.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/reconciliation.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/reports.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/settings_accounting.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/settings_cloud.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/settings_connectors.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/settings_contacts.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/settings_general.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/settings_import.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/settings_inventory.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/settings_manufacturing.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/settings_payments.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/settings_purchasing.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/settings_sales.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/setup.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/subscriptions.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/routes/subscriptions_import.py +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/static/app.css +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/static/htmx.min.js +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/static/icon.png +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/static/logo.png +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/static/vendor/intl-tel-input/img/flags.webp +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/static/vendor/intl-tel-input/img/flags@2x.webp +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/static/vendor/intl-tel-input/intlTelInput.min.css +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/static/vendor/intl-tel-input/intlTelInput.min.js +0 -0
- {celerp-2.3.4 → celerp-2.3.5}/ui/static/vendor/intl-tel-input/intlTelInputWithUtils.min.js +0 -0
- {celerp-2.3.4 → 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,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
|
|
@@ -35,6 +35,7 @@ import functools
|
|
|
35
35
|
import hashlib
|
|
36
36
|
import importlib
|
|
37
37
|
import importlib.util
|
|
38
|
+
import inspect
|
|
38
39
|
import json
|
|
39
40
|
import logging
|
|
40
41
|
import os
|
|
@@ -45,7 +46,7 @@ from pathlib import Path
|
|
|
45
46
|
from celerp.modules.importer import PREMIUM_MARKER
|
|
46
47
|
from celerp.modules.license import check_license, exchange_api_key_for_jwt, is_premium_path
|
|
47
48
|
from celerp.modules.meta import META_FILENAME
|
|
48
|
-
from celerp.modules.slots import register as register_slot
|
|
49
|
+
from celerp.modules.slots import register as register_slot, resolve_handler
|
|
49
50
|
from celerp.services.permissions import is_permission_key
|
|
50
51
|
|
|
51
52
|
log = logging.getLogger(__name__)
|
|
@@ -808,10 +809,16 @@ def _load_one(pkg_path: Path, pkg_name: str, *, trusted: bool = False) -> dict |
|
|
|
808
809
|
f" {_MODULE_AI_API_URL}"
|
|
809
810
|
)
|
|
810
811
|
|
|
812
|
+
slots_manifest = manifest.get("slots") or {}
|
|
813
|
+
|
|
811
814
|
# A slot item naming a permission key outside the registry would KeyError in
|
|
812
815
|
# the sidebar builder on every page render, taking the whole UI down for
|
|
813
|
-
# every user. Refuse the module here, with the bad key named, instead.
|
|
814
|
-
|
|
816
|
+
# every user. Refuse the module here, with the bad key named, instead. The
|
|
817
|
+
# search_provider slot has its own stricter validation below (which also
|
|
818
|
+
# checks its permission), so it is skipped here.
|
|
819
|
+
for slot_name, contribution in slots_manifest.items():
|
|
820
|
+
if slot_name == _SEARCH_PROVIDER_SLOT:
|
|
821
|
+
continue
|
|
815
822
|
items = contribution if isinstance(contribution, list) else [contribution]
|
|
816
823
|
for item in items:
|
|
817
824
|
perm = item.get("permission") if isinstance(item, dict) else None
|
|
@@ -829,14 +836,38 @@ def _load_one(pkg_path: Path, pkg_name: str, *, trusted: bool = False) -> dict |
|
|
|
829
836
|
f"closest existing key."
|
|
830
837
|
)
|
|
831
838
|
|
|
832
|
-
#
|
|
833
|
-
|
|
839
|
+
# Validate the search_provider descriptor and resolve its handler BEFORE any
|
|
840
|
+
# slot is registered, so a broken provider rejects the whole module cleanly
|
|
841
|
+
# (no half-registered slots) rather than first surfacing as a degraded source
|
|
842
|
+
# when a user types into search.
|
|
843
|
+
prepared_search_provider = None
|
|
844
|
+
if _SEARCH_PROVIDER_SLOT in slots_manifest:
|
|
845
|
+
try:
|
|
846
|
+
prepared_search_provider = _prepare_search_provider(
|
|
847
|
+
pkg_name, pkg_path, slots_manifest[_SEARCH_PROVIDER_SLOT],
|
|
848
|
+
trusted=trusted,
|
|
849
|
+
)
|
|
850
|
+
except ModuleLoadError:
|
|
851
|
+
log.error("Module %r rejected: invalid search_provider slot", pkg_name)
|
|
852
|
+
for key in list(sys.modules.keys()):
|
|
853
|
+
if key == pkg_name or key.startswith(pkg_name + "."):
|
|
854
|
+
sys.modules.pop(key, None)
|
|
855
|
+
raise
|
|
856
|
+
|
|
857
|
+
# Register extension slots (search_provider is registered from its prepared
|
|
858
|
+
# descriptor below, never through the generic path).
|
|
859
|
+
for slot_name, contribution in slots_manifest.items():
|
|
860
|
+
if slot_name == _SEARCH_PROVIDER_SLOT:
|
|
861
|
+
continue
|
|
834
862
|
if isinstance(contribution, dict):
|
|
835
863
|
register_slot(slot_name, {**contribution, "_module": pkg_name})
|
|
836
864
|
elif isinstance(contribution, list):
|
|
837
865
|
for item in contribution:
|
|
838
866
|
register_slot(slot_name, {**item, "_module": pkg_name})
|
|
839
867
|
|
|
868
|
+
if prepared_search_provider is not None:
|
|
869
|
+
register_slot(_SEARCH_PROVIDER_SLOT, prepared_search_provider)
|
|
870
|
+
|
|
840
871
|
# Register module-contributed UI translation catalogs (the `locales`
|
|
841
872
|
# manifest key, mirroring `slots` above). Each entry maps a language code to
|
|
842
873
|
# {"file": <path>, "rtl": <bool>}. Pushed into ui.i18n through a lazy import
|
|
@@ -1004,6 +1035,31 @@ def _flag_dynamic_import(node: ast.Call, violations: set[str]) -> None:
|
|
|
1004
1035
|
violations.add(hit)
|
|
1005
1036
|
|
|
1006
1037
|
|
|
1038
|
+
def _module_source_file(pkg_path: Path, dotted_module_path: str) -> Path | None:
|
|
1039
|
+
"""The local ``.py`` (or package ``__init__.py``) inside ``pkg_path`` that a
|
|
1040
|
+
dotted module path names, or None if no such source lives in the installed
|
|
1041
|
+
module tree.
|
|
1042
|
+
|
|
1043
|
+
Handles both the flat layout (``pkg_path`` IS the top-level package, its
|
|
1044
|
+
folder name == the package) and the nested GitHub-style layout (the package
|
|
1045
|
+
sits one level in, at ``pkg_path/<top_pkg>``). Used to prove a search
|
|
1046
|
+
handler's source is owned by the module before core imports it, and to seed
|
|
1047
|
+
the protected-BSL AST scan from that same file.
|
|
1048
|
+
"""
|
|
1049
|
+
parts = dotted_module_path.split(".")
|
|
1050
|
+
if not parts or not parts[0]:
|
|
1051
|
+
return None
|
|
1052
|
+
top_pkg = parts[0]
|
|
1053
|
+
pkg_dir = pkg_path if pkg_path.name == top_pkg else pkg_path / top_pkg
|
|
1054
|
+
entry = pkg_dir.joinpath(*parts[1:]).with_suffix(".py")
|
|
1055
|
+
if entry.exists():
|
|
1056
|
+
return entry
|
|
1057
|
+
entry = pkg_dir.joinpath(*parts[1:], "__init__.py")
|
|
1058
|
+
if entry.exists():
|
|
1059
|
+
return entry
|
|
1060
|
+
return None
|
|
1061
|
+
|
|
1062
|
+
|
|
1007
1063
|
def _ast_scan_module_file(pkg_path: Path, dotted_module_path: str) -> set[str]:
|
|
1008
1064
|
"""Protected-BSL-internal imports reachable from the given entry module.
|
|
1009
1065
|
|
|
@@ -1038,10 +1094,8 @@ def _ast_scan_module_file(pkg_path: Path, dotted_module_path: str) -> set[str]:
|
|
|
1038
1094
|
return cand
|
|
1039
1095
|
return None
|
|
1040
1096
|
|
|
1041
|
-
entry =
|
|
1042
|
-
if
|
|
1043
|
-
entry = pkg_dir.joinpath(*parts[1:], "__init__.py")
|
|
1044
|
-
if not entry.exists():
|
|
1097
|
+
entry = _module_source_file(pkg_path, dotted_module_path)
|
|
1098
|
+
if entry is None:
|
|
1045
1099
|
return set()
|
|
1046
1100
|
|
|
1047
1101
|
violations: set[str] = set()
|
|
@@ -1084,3 +1138,172 @@ def _ast_scan_module_file(pkg_path: Path, dotted_module_path: str) -> set[str]:
|
|
|
1084
1138
|
elif isinstance(node, ast.Call):
|
|
1085
1139
|
_flag_dynamic_import(node, violations)
|
|
1086
1140
|
return violations
|
|
1141
|
+
|
|
1142
|
+
|
|
1143
|
+
# The search_provider slot has a stricter contract than the generic slots: a
|
|
1144
|
+
# single descriptor (never a list), a closed key set, and a locally-owned async
|
|
1145
|
+
# handler resolved at load time. The template linter mirrors these exactly.
|
|
1146
|
+
_SEARCH_PROVIDER_SLOT = "search_provider"
|
|
1147
|
+
_SEARCH_PROVIDER_KEYS = frozenset({"handler", "result_key", "permission"})
|
|
1148
|
+
_SEARCH_RESULT_KEYS = frozenset({"items", "entries"})
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
def _enclosing_first_party_module(source_file: Path, expected_name: str) -> Path | None:
|
|
1152
|
+
"""The nearest ancestor directory of ``source_file`` that is a content-verified
|
|
1153
|
+
first-party module folder named ``expected_name``, or None.
|
|
1154
|
+
|
|
1155
|
+
Used to accept a first-party module whose handler resolves to the SAME
|
|
1156
|
+
first-party module already loaded from another location (a shipped default
|
|
1157
|
+
scanned from two roots - e.g. the repo copy and a reseeded copy). is_first_party
|
|
1158
|
+
requires the lock name AND a matching content digest, so a match here is
|
|
1159
|
+
content-identical to the module being loaded; a resolution to core, or to any
|
|
1160
|
+
other module, has no such ancestor and is rejected.
|
|
1161
|
+
"""
|
|
1162
|
+
for parent in source_file.parents:
|
|
1163
|
+
if parent.name == expected_name and is_first_party(parent):
|
|
1164
|
+
return parent
|
|
1165
|
+
return None
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
def _handler_source_owned(
|
|
1169
|
+
proof: str | None, pkg_root: str, pkg_name: str, trusted: bool
|
|
1170
|
+
) -> bool:
|
|
1171
|
+
"""True if a resolved handler/module source file legitimately belongs to the
|
|
1172
|
+
module being loaded.
|
|
1173
|
+
|
|
1174
|
+
It must live under the module's own package root. For a content-verified
|
|
1175
|
+
first-party module ONLY, a source under a different copy of the SAME first-party
|
|
1176
|
+
module (same lock name and verified digest) is also legitimate - the one case
|
|
1177
|
+
where importlib returns an identically-named default already loaded from another
|
|
1178
|
+
root. ``is_relative_to`` returns False for paths on different drives rather than
|
|
1179
|
+
raising, so it needs no cross-drive guard. Never accepts a resolution to core or
|
|
1180
|
+
to a different module, and every untrusted module is held to strict same-tree.
|
|
1181
|
+
"""
|
|
1182
|
+
if not proof:
|
|
1183
|
+
return False
|
|
1184
|
+
real = Path(os.path.realpath(proof))
|
|
1185
|
+
if real.is_relative_to(pkg_root):
|
|
1186
|
+
return True
|
|
1187
|
+
if not trusted:
|
|
1188
|
+
return False
|
|
1189
|
+
return _enclosing_first_party_module(real, pkg_name) is not None
|
|
1190
|
+
|
|
1191
|
+
|
|
1192
|
+
def _prepare_search_provider(
|
|
1193
|
+
pkg_name: str, pkg_path: Path, contribution, *, trusted: bool
|
|
1194
|
+
) -> dict:
|
|
1195
|
+
"""Validate a ``search_provider`` descriptor and resolve its handler at load
|
|
1196
|
+
time, returning the runtime descriptor to register.
|
|
1197
|
+
|
|
1198
|
+
The slot takes exactly one dict: one module, one provider, one results
|
|
1199
|
+
bucket, so a module can never overwrite its own search bucket. The descriptor
|
|
1200
|
+
must carry exactly ``{handler, result_key, permission}`` (extra keys are
|
|
1201
|
+
rejected, never ignored, so a misspelling fails loudly); ``result_key`` is one
|
|
1202
|
+
of ``{items, entries}``; ``permission`` is a known key. The handler
|
|
1203
|
+
``module:function`` must name source that lives inside this module's own tree,
|
|
1204
|
+
must import no protected BSL internal (third-party only), and must resolve at
|
|
1205
|
+
load to an async callable. A provider that cannot pass all of this fails
|
|
1206
|
+
module load rather than first surfacing as a degraded source when a user types
|
|
1207
|
+
into search. Raises :class:`ModuleLoadError` on any violation.
|
|
1208
|
+
"""
|
|
1209
|
+
if not isinstance(contribution, dict):
|
|
1210
|
+
raise ModuleLoadError(
|
|
1211
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} takes exactly one descriptor dict, "
|
|
1212
|
+
f"not a {type(contribution).__name__}."
|
|
1213
|
+
)
|
|
1214
|
+
keys = set(contribution)
|
|
1215
|
+
if keys != set(_SEARCH_PROVIDER_KEYS):
|
|
1216
|
+
missing = sorted(_SEARCH_PROVIDER_KEYS - keys)
|
|
1217
|
+
extra = sorted(keys - _SEARCH_PROVIDER_KEYS)
|
|
1218
|
+
raise ModuleLoadError(
|
|
1219
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} descriptor keys must be exactly "
|
|
1220
|
+
f"{sorted(_SEARCH_PROVIDER_KEYS)} (missing={missing}, extra={extra})."
|
|
1221
|
+
)
|
|
1222
|
+
result_key = contribution["result_key"]
|
|
1223
|
+
if result_key not in _SEARCH_RESULT_KEYS:
|
|
1224
|
+
raise ModuleLoadError(
|
|
1225
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} result_key {result_key!r} must be one "
|
|
1226
|
+
f"of {sorted(_SEARCH_RESULT_KEYS)}."
|
|
1227
|
+
)
|
|
1228
|
+
perm = contribution["permission"]
|
|
1229
|
+
if not is_permission_key(perm):
|
|
1230
|
+
raise ModuleLoadError(
|
|
1231
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} names unknown permission key {perm!r}."
|
|
1232
|
+
)
|
|
1233
|
+
handler_path = contribution["handler"]
|
|
1234
|
+
if not isinstance(handler_path, str) or handler_path.count(":") != 1:
|
|
1235
|
+
raise ModuleLoadError(
|
|
1236
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} handler {handler_path!r} must be "
|
|
1237
|
+
f"'module.path:function'."
|
|
1238
|
+
)
|
|
1239
|
+
module_path, func_name = handler_path.split(":", 1)
|
|
1240
|
+
if not module_path or not func_name:
|
|
1241
|
+
raise ModuleLoadError(
|
|
1242
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} handler {handler_path!r} must name a "
|
|
1243
|
+
f"non-empty module path and function."
|
|
1244
|
+
)
|
|
1245
|
+
# Local ownership: the handler must resolve to source inside this module's own
|
|
1246
|
+
# tree, so a manifest can never point core at 'celerp.some_internal:fn' and
|
|
1247
|
+
# have it imported on demand around the protected-import gate.
|
|
1248
|
+
if _module_source_file(pkg_path, module_path) is None:
|
|
1249
|
+
raise ModuleLoadError(
|
|
1250
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} handler {handler_path!r} does not "
|
|
1251
|
+
f"resolve to source inside module {pkg_name!r}."
|
|
1252
|
+
)
|
|
1253
|
+
# The handler is a lazily-imported entry point, so it goes through the same
|
|
1254
|
+
# transitive protected-BSL scan as the route entry modules (third-party only).
|
|
1255
|
+
if not trusted:
|
|
1256
|
+
violations = _ast_scan_module_file(pkg_path, module_path)
|
|
1257
|
+
if violations:
|
|
1258
|
+
raise ModuleLoadError(
|
|
1259
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} handler imports protected BSL "
|
|
1260
|
+
f"internals ({', '.join(sorted(violations))})."
|
|
1261
|
+
)
|
|
1262
|
+
try:
|
|
1263
|
+
handler = resolve_handler(handler_path)
|
|
1264
|
+
except Exception as exc:
|
|
1265
|
+
raise ModuleLoadError(
|
|
1266
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} handler {handler_path!r} failed to "
|
|
1267
|
+
f"resolve ({type(exc).__name__})."
|
|
1268
|
+
)
|
|
1269
|
+
if not callable(handler):
|
|
1270
|
+
raise ModuleLoadError(
|
|
1271
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} handler {handler_path!r} is not callable."
|
|
1272
|
+
)
|
|
1273
|
+
if not inspect.iscoroutinefunction(handler):
|
|
1274
|
+
raise ModuleLoadError(
|
|
1275
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} handler {handler_path!r} must be async; "
|
|
1276
|
+
f"the aggregator awaits it."
|
|
1277
|
+
)
|
|
1278
|
+
# Provenance: an on-disk file matching the dotted path is not proof of what
|
|
1279
|
+
# importlib actually resolved. A decoy source shipped inside the module's own
|
|
1280
|
+
# tree (e.g. a celerp/ai/service.py) satisfies the existence and AST checks
|
|
1281
|
+
# above, yet importlib returns the already-loaded REAL core module of the same
|
|
1282
|
+
# dotted name, binding the provider to arbitrary code. Require that BOTH the
|
|
1283
|
+
# resolved module's file AND the handler's own source file be owned by this
|
|
1284
|
+
# module (_handler_source_owned): under its own package root, or - for a
|
|
1285
|
+
# content-verified first-party module only - inside the same first-party module
|
|
1286
|
+
# (same lock name and digest) loaded from another root. realpath collapses
|
|
1287
|
+
# symlinks and '..' so neither can point a proof outside the tree. This runs for
|
|
1288
|
+
# every module: a first-party manifest whose handler resolves to core, or to a
|
|
1289
|
+
# different module, is rejected exactly as an untrusted decoy is.
|
|
1290
|
+
pkg_root = os.path.realpath(pkg_path)
|
|
1291
|
+
try:
|
|
1292
|
+
resolved_module = importlib.import_module(module_path)
|
|
1293
|
+
module_file = getattr(resolved_module, "__file__", None)
|
|
1294
|
+
handler_file = inspect.getsourcefile(inspect.unwrap(handler))
|
|
1295
|
+
except Exception as exc:
|
|
1296
|
+
raise ModuleLoadError(
|
|
1297
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} handler {handler_path!r} source could "
|
|
1298
|
+
f"not be located ({type(exc).__name__})."
|
|
1299
|
+
)
|
|
1300
|
+
for proof in (module_file, handler_file):
|
|
1301
|
+
if not _handler_source_owned(proof, pkg_root, pkg_name, trusted):
|
|
1302
|
+
raise ModuleLoadError(
|
|
1303
|
+
f"Slot {_SEARCH_PROVIDER_SLOT!r} handler {handler_path!r} resolves to "
|
|
1304
|
+
f"source outside module {pkg_name!r}'s own package tree."
|
|
1305
|
+
)
|
|
1306
|
+
# Runtime-owned trust metadata is injected AFTER the manifest contribution, and
|
|
1307
|
+
# the closed key set above already rejects a manifest that tries to supply
|
|
1308
|
+
# _module / _first_party itself, so neither can be spoofed.
|
|
1309
|
+
return {**contribution, "_module": pkg_name, "_first_party": trusted}
|
|
@@ -17,6 +17,14 @@ import_adapter Source option in the CSV import page
|
|
|
17
17
|
category_schema Default field definitions for a named category
|
|
18
18
|
projection_handler Maps event-type prefixes to a handler function
|
|
19
19
|
on_company_created Async callback(session, company_id) fired after a new company is persisted
|
|
20
|
+
search_provider Contributes rows to the global search bar. Exactly one descriptor
|
|
21
|
+
dict per module: {"handler", "result_key", "permission"}. handler
|
|
22
|
+
names an in-module "module.path:function" resolved and validated
|
|
23
|
+
async at load, invoked as
|
|
24
|
+
`async def handler(session, company_id, role, q, limit) -> dict`
|
|
25
|
+
returning {result_key: [rows]}; result_key is "items" or "entries";
|
|
26
|
+
permission gates the source per company role. See the module loader
|
|
27
|
+
for the full descriptor contract.
|
|
20
28
|
|
|
21
29
|
Usage in core UI
|
|
22
30
|
----------------
|
|
@@ -29,9 +37,26 @@ Usage in core UI
|
|
|
29
37
|
"""
|
|
30
38
|
from __future__ import annotations
|
|
31
39
|
|
|
40
|
+
from typing import Callable
|
|
41
|
+
|
|
32
42
|
_slots: dict[str, list[dict]] = {}
|
|
33
43
|
|
|
34
44
|
|
|
45
|
+
def resolve_handler(dotted: str) -> Callable:
|
|
46
|
+
"""Resolve a "module.path:function" string to the callable it names.
|
|
47
|
+
|
|
48
|
+
Raises ImportError if the module cannot be imported and AttributeError if
|
|
49
|
+
the module has no such attribute. Callers wrap this in their own try/except
|
|
50
|
+
to apply their failure policy (swallow, propagate, log-and-skip); the shared
|
|
51
|
+
resolver never decides that policy, it only does the import and lookup.
|
|
52
|
+
"""
|
|
53
|
+
import importlib
|
|
54
|
+
|
|
55
|
+
module_path, func_name = dotted.rsplit(":", 1)
|
|
56
|
+
mod = importlib.import_module(module_path)
|
|
57
|
+
return getattr(mod, func_name)
|
|
58
|
+
|
|
59
|
+
|
|
35
60
|
def register(slot: str, contribution: dict) -> None:
|
|
36
61
|
"""Register a module contribution into a named slot.
|
|
37
62
|
|
|
@@ -64,7 +89,6 @@ async def fire_lifecycle(slot: str, **kwargs) -> None:
|
|
|
64
89
|
(with traceback) and swallowed, so a recurrence surfaces as an alert
|
|
65
90
|
instead of vanishing.
|
|
66
91
|
"""
|
|
67
|
-
import importlib
|
|
68
92
|
import logging
|
|
69
93
|
|
|
70
94
|
_log = logging.getLogger(__name__)
|
|
@@ -74,9 +98,7 @@ async def fire_lifecycle(slot: str, **kwargs) -> None:
|
|
|
74
98
|
if not handler_path:
|
|
75
99
|
continue
|
|
76
100
|
try:
|
|
77
|
-
|
|
78
|
-
mod = importlib.import_module(mod_path)
|
|
79
|
-
func = getattr(mod, func_name)
|
|
101
|
+
func = resolve_handler(handler_path)
|
|
80
102
|
await func(**kwargs)
|
|
81
103
|
except Exception as exc:
|
|
82
104
|
_log.exception(
|
|
@@ -90,7 +112,6 @@ async def fire_lifecycle_strict(slot_name: str, **kwargs) -> None:
|
|
|
90
112
|
|
|
91
113
|
Use for slots where a handler must be able to block the action.
|
|
92
114
|
"""
|
|
93
|
-
import importlib
|
|
94
115
|
import logging
|
|
95
116
|
from fastapi import HTTPException
|
|
96
117
|
|
|
@@ -101,9 +122,7 @@ async def fire_lifecycle_strict(slot_name: str, **kwargs) -> None:
|
|
|
101
122
|
if not handler_path:
|
|
102
123
|
continue
|
|
103
124
|
try:
|
|
104
|
-
|
|
105
|
-
mod = importlib.import_module(mod_path)
|
|
106
|
-
func = getattr(mod, func_name)
|
|
125
|
+
func = resolve_handler(handler_path)
|
|
107
126
|
await func(**kwargs)
|
|
108
127
|
except HTTPException:
|
|
109
128
|
raise
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
-
import importlib
|
|
7
6
|
import logging
|
|
8
7
|
from datetime import datetime, timezone
|
|
9
8
|
|
|
@@ -18,11 +17,15 @@ log = logging.getLogger(__name__)
|
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
def _resolve_module_handler(dotted: str):
|
|
21
|
-
"""Import and return a handler callable from a 'module.path:function' string.
|
|
20
|
+
"""Import and return a handler callable from a 'module.path:function' string.
|
|
21
|
+
|
|
22
|
+
Returns None on any resolution failure so a single bad projection_handler
|
|
23
|
+
slot cannot stop the engine from picking up its siblings.
|
|
24
|
+
"""
|
|
25
|
+
from celerp.modules.slots import resolve_handler
|
|
26
|
+
|
|
22
27
|
try:
|
|
23
|
-
|
|
24
|
-
mod = importlib.import_module(module_path)
|
|
25
|
-
return getattr(mod, func_name)
|
|
28
|
+
return resolve_handler(dotted)
|
|
26
29
|
except Exception as exc:
|
|
27
30
|
log.error("ProjectionEngine: cannot resolve module handler %r: %s", dotted, exc)
|
|
28
31
|
return None
|