celerp 2.3.1__tar.gz → 2.3.2__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.1 → celerp-2.3.2}/PKG-INFO +1 -1
- {celerp-2.3.1 → celerp-2.3.2}/celerp/events/schemas.py +43 -4
- celerp-2.3.2/celerp/inventory_codes.py +87 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/main.py +9 -0
- celerp-2.3.2/celerp/migrations/versions/bc0d1e2f3a4b_barcode_unique_index.py +119 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/projections.py +16 -1
- {celerp-2.3.1 → celerp-2.3.2}/celerp/projections/engine.py +26 -2
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/fulfill.py +22 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/tax_regimes.py +16 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp.egg-info/PKG-INFO +1 -1
- {celerp-2.3.1 → celerp-2.3.2}/celerp.egg-info/SOURCES.txt +5 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp.egg-info/scm_file_list.json +9 -0
- celerp-2.3.2/celerp.egg-info/scm_version.json +8 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/routes.py +225 -90
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_audits.py +326 -13
- celerp-2.3.2/default_modules/celerp-docs/tests/test_list_concurrency.py +178 -0
- celerp-2.3.2/default_modules/celerp-docs/tests/test_list_outcome_concurrency.py +364 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/celerp_inventory/routes.py +137 -63
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/celerp_inventory/routes_scanning.py +3 -1
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/celerp_inventory/services.py +96 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/celerp_manufacturing/routes.py +25 -0
- celerp-2.3.2/default_modules/celerp-manufacturing/tests/test_completion_lock_order.py +240 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_run_records.py +18 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/first_party.lock.json +3 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/api_client.py +18 -5
- {celerp-2.3.1 → celerp-2.3.2}/ui/locales/am.json +10 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/locales/ar.json +10 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/locales/de.json +10 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/locales/en.json +10 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/locales/es.json +10 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/locales/fr.json +10 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/locales/id.json +10 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/locales/it.json +10 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/locales/ja.json +10 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/locales/pt.json +10 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/locales/th.json +10 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/locales/vi.json +10 -3
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/documents.py +245 -80
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/inventory.py +15 -1
- celerp-2.3.1/celerp.egg-info/scm_version.json +0 -8
- {celerp-2.3.1 → celerp-2.3.2}/CLA.md +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/CONTRIBUTING.md +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/LICENSE +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/LICENSING.md +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/MANIFEST.in +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/NOTICE +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/README.md +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/alembic.ini +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/__main__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/batch.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/cleanup.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/commands.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/conversations.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/files.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/intent.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/llm.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/memory.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/models.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/page_count.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/quota.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/service.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/ai/tools.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/alembic.ini +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/alembic_config.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/cli.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/compat.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/compute/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/compute/aggregations.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/compute/valuation.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/config.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/base.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/daily_scheduler.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/http.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/images.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/quickbooks.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/registry.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/relay_token.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/shopify.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/sync_runner.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/upsert.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/util.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/webhooks.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/woocommerce.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/connectors/xero.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/constants.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/db.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/embedded_pg.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/events/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/events/engine.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/events/types.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/gateway/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/gateway/client.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/gateway/state.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/importers/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/importers/importer.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/importers/schema.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/middleware.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/README.md +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/_auto_stamp.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/_data_reconcile.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/_json_compat.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/env.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/script.py.mako +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/a0b1c2d3e4f5_seed_landed_cost_clearing_accounts.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/a1b2c3d4e5f6_add_doc_share_tokens.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/b1c2d3e4f5a6_add_supporter_badges.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/b2c3d4e5f6a7_add_import_batches.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/b3c4d5e6f7a8_expand_role_permissions_to_role_grants.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/c1d2e3f4a5b6_add_marketplace.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/c2d3e4f5a6b7_add_is_sync_to_shopify.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/c4d5e6f7a8b9_account_cash_flow_category.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/d0e1f2a3b4c5_add_share_token_expiry.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/d2e3f4a5b6c7_add_password_reset_token.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/d5e6f7a8b9c0_rename_fx_rounding_to_fx_difference.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/e3f4a5b6c7d8_add_company_is_active.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/e4f5a6b7c8d9_backfill_connector_idempotency_key.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/e7c9a1b3d5f2_work_center_default_columns.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/f1a2b3c4d5e6_move_accounts_marketplace_to_modules.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/f6a7b8c9d0e1_seed_fx_rounding_account.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/f8a9b0c1d2e3_work_center_default_backfill.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/fd5de461e14e_initial_schema.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/g1h2i3j4k5l6_add_consignment_flag.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/h2i3j4k5l6m7_add_bank_accounts_and_reconciliation.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/j4k5l6m7n8o9_labels_db_persistence.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/k5l6m7n8o9p0_add_reconciliation_v2.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/l6m7n8o9p0q1_add_sync_runs_table.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/m7n8o9p0q1r2_add_connector_configs_and_outbound_queue.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/n8o9p0q1r2s3_backfill_payment_date.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/o9p0q1r2s3t4_backfill_item_price_fields.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/p1q2r3s4t5u6_add_session_registry_and_user_auth_state.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/q2r3s4t5u6v7_add_system_runtime_state.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/r3s4t5u6v7w8_add_projections_company_entity_type_index.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/s4t5u6v7w8x9_drop_user_company_id_role.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/t5u6v7w8x9y0_seed_inventory_sub_accounts.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/u6v7w8x9y0z1_backfill_item_prices_from_attributes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/v7w8x9y0z1a2_backfill_purchase_unit_defaults.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/w8x9y0z1a2b3_backfill_category_unit_defaults.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/x7y8z9a0b1c2_add_projection_created_at.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/y8z9a0b1c2d3_per_company_ledger_idempotency.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/migrations/versions/z9a0b1c2d3e4_work_centers.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/accounting.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/ai.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/auth.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/base.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/company.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/connector_config.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/import_batch.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/ledger.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/marketplace.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/notification.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/share.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/supporter.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/models/sync_run.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/modules/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/modules/api.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/modules/audit.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/modules/demotion.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/modules/importer.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/modules/license.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/modules/loader.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/modules/meta.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/modules/migrations_runner.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/modules/references.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/modules/registry.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/modules/slots.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/notifications/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/notifications/service.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/notifications/sse.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/output/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/output/branding.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/output/doc_print.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/output/pdf.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/output/share_render.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/projections/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/projections/handlers/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/projections/handlers/marketplace.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/projections/handlers/scanning.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/projections/handlers/shopify.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/projections/handlers/system.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/routers/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/routers/auth.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/routers/companies.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/routers/debug.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/routers/doctor.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/routers/events.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/routers/health.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/routers/ledger.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/routers/notifications.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/routers/stars.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/routers/system.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/schemas/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/activity_redaction.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/attachments.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/auth.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/auto_je.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/backup.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/backup_export.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/backup_import.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/backup_repo.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/backup_scheduler.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/backup_state.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/cogs_backfill.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/cost_visibility.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/demo.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/dev_release_guard.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/email.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/field_schema.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/holdings.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/je_keys.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/landed_cost.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/line_measures.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/list_behavior.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/money.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/payments.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/permissions.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/pick.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/pricing.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/relay_share.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/reorder.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/runtime_state.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/session_tracker.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/shipping.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/star_cta.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/status_doc_backfill.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/supporter_badge.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/system_health.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/services/units.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp/session_gate.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp.egg-info/dependency_links.txt +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp.egg-info/entry_points.txt +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp.egg-info/requires.txt +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/celerp.egg-info/top_level.txt +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/conftest.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/conftest_support.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/LICENSE +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/celerp_accounting/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/celerp_accounting/api_setup.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/celerp_accounting/csv_parser.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/celerp_accounting/matcher.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/celerp_accounting/models.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/celerp_accounting/projections.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/celerp_accounting/routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/celerp_accounting/ui_routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/balance-sheet.html +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/cash-flow.html +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-csv.csv +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-print.html +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/extended-journal.html +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/general-ledger.html +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/journal-csv.csv +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/journal-print.html +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/journal.html +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/ledger.html +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/pnl.html +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/statement.html +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/report_goldens/trial-balance.html +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/test_accounting_banking.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/test_accounting_banking_routers.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/test_accounting_gaps.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/test_accounting_import_idempotency.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/test_cash_flow.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/test_financial_reports_ui.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/test_journal_gl_soa.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/test_journal_gl_soa_ui.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/test_reconciliation_v2.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/test_reports_end_to_end.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-accounting/tests/test_route_permissions.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-admin/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-admin/celerp_admin/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-admin/celerp_admin/routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-admin/celerp_admin/setup.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/celerp_ai/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/celerp_ai/routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/celerp_ai/setup.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/celerp_ai/ui_routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/conftest.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_batch.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_cleanup.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_conversations.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_coverage_gaps.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_intent.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_llm.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_memory.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_models.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_page_count.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_quota.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_router.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_routes_coverage.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_service.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-ai/tests/test_tools.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-backup/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-backup/celerp_backup/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-backup/celerp_backup/routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-backup/celerp_backup/setup.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/celerp_connectors/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/celerp_connectors/models.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/celerp_connectors/routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/conftest.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_compliance.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_connector_correctness.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_connectors.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_credentials_routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_images.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_outbound.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_quickbooks.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_rate_limiting.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_shopify.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_wiring.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_woocommerce.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_woocommerce_webhooks.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-connectors/tests/test_xero.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-contacts/LICENSE +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-contacts/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-contacts/celerp_contacts/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-contacts/celerp_contacts/migrations.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-contacts/celerp_contacts/projections.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-contacts/celerp_contacts/routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-contacts/celerp_contacts/services.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-contacts/celerp_contacts/ui_routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-dashboard/LICENSE +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-dashboard/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-dashboard/celerp_dashboard/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-dashboard/celerp_dashboard/routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-dashboard/celerp_dashboard/setup.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/LICENSE +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/api_setup.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/doc_constants.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/doc_email.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/doc_projections.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/doc_service.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/models_share.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/routes_payments.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/routes_share.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/sequences.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/taxes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/celerp_docs/ui_routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/conftest.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_consolidate_lots.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_freight_je.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_freight_lines.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_fulfill_no_split.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_fulfillment_activity.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_inbound_je_lifecycle.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_inventory_account_reconciliation.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_landed_receive.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_line_delete_persist.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_line_identifier.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_payment_void_activity.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_receive_sku_batch.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_send_visibility.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_service_lines.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_void_guards.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-docs/tests/test_writeoffs.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/LICENSE +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/celerp_inventory/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/celerp_inventory/models_import_batch.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/celerp_inventory/projections.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/celerp_inventory/routes_attachments.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/celerp_inventory/ui_routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/tests/test_item_recipe_projection.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/tests/test_item_workflow_projection.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-inventory/tests/test_landed_cost_projection.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/LICENSE +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/locales/am.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/locales/ar.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/locales/de.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/locales/en.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/locales/es.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/locales/fr.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/locales/id.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/locales/it.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/locales/ja.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/locales/pt.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/locales/th.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/locales/vi.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/models.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/presets.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/service.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/celerp_labels/ui_routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/requirements.txt +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/tests/test_labels.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-labels/tests/test_labels_module.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/LICENSE +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/celerp_manufacturing/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/celerp_manufacturing/costing.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/celerp_manufacturing/expansion.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/celerp_manufacturing/labor.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/celerp_manufacturing/migrations.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/celerp_manufacturing/projection_handler.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/celerp_manufacturing/ui_routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/requirements.txt +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_auto_complete_on_finalize.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_bom_removed.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_build_api.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_item_recipe_api.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_item_workflow_api.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_labor_providers.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_manufacture_from_doc.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_manufacturing.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_manufacturing_import_idempotency.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_manufacturing_module.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_mfg_events.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_phase2_manufacturing_validations.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_production_order.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_recipe_costing.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_recipe_expansion.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_recost_api.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_to_make_allocation.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_where_used.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_work_centers_and_settings.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-manufacturing/tests/test_workflow_time.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-reports/LICENSE +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-reports/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-reports/celerp_reports/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-reports/celerp_reports/api_setup.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-reports/celerp_reports/routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-reports/celerp_reports/ui_routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-reports/tests/test_reports_full.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-reports/tests/test_reports_unit.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-subscriptions/LICENSE +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-subscriptions/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-subscriptions/celerp_subscriptions/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-subscriptions/celerp_subscriptions/routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-subscriptions/celerp_subscriptions/ui_routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-subscriptions/tests/test_subscriptions.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-subscriptions/tests/test_subscriptions_ui.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/LICENSE +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/accessory_fashion.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/activewear.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/art_photography.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/audio_equipment.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/bag_handbag.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/banknote.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/beauty_tool.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/bed_bedroom.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/beer.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/beverage_nonalc.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/body_part_auto.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/book.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/bottoms.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/brake_suspension.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/bullion_coin.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/camera.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/colored_stone.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/comic.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/commercial_space.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/component_part.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/confectionery.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/consulting_service.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/decorative_art.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/diamond.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/drawing.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/dress_jumpsuit.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_auto.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_component.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/emerald.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/engine_part.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/fastener.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/fertilizer_chemical.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/film_video.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/fine_writing_instrument.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/fluid_lubricant.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/footwear.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/fragrance.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_food.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_produce.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/frozen_food.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/gaming_console.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/gold_bullion.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/grain_cereal.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/haircare.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/hand_tool.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/ingredient_bulk.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/interior_part.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/jewelry.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/kitchen_dining.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/laptop.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/lighting.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/livestock_feed.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/makeup.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/measuring_instrument.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/medal_token.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/mineral_specimen.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/mobile_phone.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/music_cd.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/music_vinyl.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/nail.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/numismatic_coin.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/outdoor_furniture.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/outerwear.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/packaged_food.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/painting.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/parking_bay.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/pearl.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/personal_care.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/pipe_plumbing.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/platinum_bullion.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/power_tool.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/print_edition.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/residential_unit.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/rough_gemstone.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/ruby.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/saas_plan.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/safety_ppe.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/sapphire.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/sculpture.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/seating.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/seeds.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/silver_bullion.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/skincare.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/soft_furnishing.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/software_addon.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/software_license.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/spirit.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/storage_furniture.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/swimwear.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/table_desk.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/tablet.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/tire_wheel.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/tops.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/trading_card.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/tv_display.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/video_game.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/watch.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/watch_strap.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/categories/wine.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/agricultural.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/artwork.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/automotive.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/blank.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/books_media.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/coins_precious_metals.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/consulting.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/cosmetics.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/electronics.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/fashion.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/food_beverage.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/furniture.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/gemstones.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/hardware.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/property_rental.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/saas.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/watches.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/presets/wine_spirits.json +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/celerp_verticals/ui_routes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/tests/test_verticals.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/default_modules/celerp-verticals/tests/test_verticals_routers.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/legal/OFFICIAL-COMPONENTS.md +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/legal/TRADEMARK.md +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/packaging/winget/Celerp.Celerp.installer.yaml +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/packaging/winget/Celerp.Celerp.locale.en-US.yaml +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/packaging/winget/Celerp.Celerp.yaml +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/packaging/winget/README.md +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/pyproject.toml +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/setup.cfg +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/test_helpers.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/app.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/activity.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/attrs.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/backup.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/cloud_gate.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/currency.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/files.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/journal.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/notes.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/phone.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/report_kit.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/shell.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/components/table.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/config.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/i18n.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/marketplace_catalog.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/__init__.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/account.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/accounting.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/accounting_import.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/auth.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/contacts.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/csv_import.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/dashboard.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/docs_import.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/events.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/financial_reports.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/lists_import.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/manufacturing.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/modules_page.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/notifications.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/reconciliation.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/reports.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/search.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/settings.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/settings_accounting.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/settings_cloud.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/settings_connectors.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/settings_contacts.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/settings_general.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/settings_import.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/settings_inventory.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/settings_manufacturing.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/settings_payments.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/settings_purchasing.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/settings_sales.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/setup.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/stars.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/subscriptions.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/routes/subscriptions_import.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/security.py +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/static/app.css +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/static/htmx.min.js +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/static/icon.png +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/static/logo.png +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/static/vendor/intl-tel-input/img/flags.webp +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/static/vendor/intl-tel-input/img/flags@2x.webp +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/static/vendor/intl-tel-input/intlTelInput.min.css +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/static/vendor/intl-tel-input/intlTelInput.min.js +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/static/vendor/intl-tel-input/intlTelInputWithUtils.min.js +0 -0
- {celerp-2.3.1 → celerp-2.3.2}/ui/static/vendor/intl-tel-input/utils.js +0 -0
|
@@ -5,7 +5,18 @@ from __future__ import annotations
|
|
|
5
5
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
-
from pydantic import BaseModel, Field
|
|
8
|
+
from pydantic import BaseModel, Field, model_validator
|
|
9
|
+
|
|
10
|
+
# The SKU/barcode write-time predicates live in celerp.inventory_codes so the event
|
|
11
|
+
# boundary, the interactive routes, the allocation service, and the scanner share one
|
|
12
|
+
# source of truth. reject_comma_sku/SKU_COMMA_MESSAGE are re-exported here because
|
|
13
|
+
# celerp_inventory.routes imports them from this module.
|
|
14
|
+
from celerp.inventory_codes import ( # noqa: F401 - re-exported for celerp_inventory
|
|
15
|
+
SKU_COMMA_MESSAGE,
|
|
16
|
+
reject_comma_sku,
|
|
17
|
+
validate_barcode,
|
|
18
|
+
validate_sku,
|
|
19
|
+
)
|
|
9
20
|
|
|
10
21
|
|
|
11
22
|
# -----------------
|
|
@@ -13,7 +24,27 @@ from pydantic import BaseModel, Field
|
|
|
13
24
|
# -----------------
|
|
14
25
|
|
|
15
26
|
|
|
16
|
-
class
|
|
27
|
+
class _SkuGuard(BaseModel):
|
|
28
|
+
"""Mixin: enforce the SKU and barcode invariants on any item event that sets them.
|
|
29
|
+
|
|
30
|
+
SKU: no comma (Celerp's OR operator in the SKU/search syntax) and a bounded length.
|
|
31
|
+
Barcode: digits only and a bounded length. These are the canonical write-time
|
|
32
|
+
predicates; interactive routes wrap them to surface a friendly 422, every other
|
|
33
|
+
emitter hits them here at the event boundary (imports, connector upserts, document
|
|
34
|
+
receiving). Replay never runs these schemas (the reducer does), so enforcing here
|
|
35
|
+
can never brick a historical projection.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
@model_validator(mode="before")
|
|
39
|
+
@classmethod
|
|
40
|
+
def _guard_item_codes(cls, data: Any) -> Any:
|
|
41
|
+
if isinstance(data, dict):
|
|
42
|
+
validate_sku(data.get("sku"))
|
|
43
|
+
validate_barcode(data.get("barcode"))
|
|
44
|
+
return data
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ItemCreated(_SkuGuard):
|
|
17
48
|
sku: str
|
|
18
49
|
name: str
|
|
19
50
|
quantity: float = 0
|
|
@@ -28,7 +59,7 @@ class ItemCreated(BaseModel):
|
|
|
28
59
|
model_config = {"extra": "allow"}
|
|
29
60
|
|
|
30
61
|
|
|
31
|
-
class ItemSnapshot(
|
|
62
|
+
class ItemSnapshot(_SkuGuard):
|
|
32
63
|
"""Snapshot of full item state - used for imports. sku/name optional (absent in some sources)."""
|
|
33
64
|
|
|
34
65
|
sku: str | None = None
|
|
@@ -53,6 +84,14 @@ class ItemSnapshot(BaseModel):
|
|
|
53
84
|
class ItemUpdated(BaseModel):
|
|
54
85
|
fields_changed: dict[str, dict[str, Any]]
|
|
55
86
|
|
|
87
|
+
@model_validator(mode="after")
|
|
88
|
+
def _guard_item_codes(self) -> "ItemUpdated":
|
|
89
|
+
if "sku" in self.fields_changed:
|
|
90
|
+
validate_sku((self.fields_changed.get("sku") or {}).get("new"))
|
|
91
|
+
if "barcode" in self.fields_changed:
|
|
92
|
+
validate_barcode((self.fields_changed.get("barcode") or {}).get("new"))
|
|
93
|
+
return self
|
|
94
|
+
|
|
56
95
|
|
|
57
96
|
class ItemPricingSet(BaseModel):
|
|
58
97
|
price_type: str
|
|
@@ -188,7 +227,7 @@ class ItemMerged(BaseModel):
|
|
|
188
227
|
source_entity_ids: list[str]
|
|
189
228
|
|
|
190
229
|
|
|
191
|
-
class ItemPatched(
|
|
230
|
+
class ItemPatched(_SkuGuard):
|
|
192
231
|
"""CSV upsert patch: accepts any item data fields."""
|
|
193
232
|
model_config = {"extra": "allow"}
|
|
194
233
|
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Copyright (c) 2026 Noah Severs
|
|
2
|
+
# SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
|
|
4
|
+
"""Canonical inventory code limits and validation - one source of truth.
|
|
5
|
+
|
|
6
|
+
The SKU/barcode invariants live here so the event boundary (celerp.events.schemas),
|
|
7
|
+
the interactive inventory routes, the allocation service, and the scanner all share
|
|
8
|
+
the exact same rules. A comma is Celerp's OR operator in the SKU/search syntax, so a
|
|
9
|
+
SKU may never contain one (it would split into separate codes wherever SKUs are
|
|
10
|
+
matched). A barcode is a numeric physical-lot identifier and must be unique per
|
|
11
|
+
company - enforced at the event boundary (format) and by a partial unique index on
|
|
12
|
+
the projections table (uniqueness).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
MAX_BARCODE_LEN = 64
|
|
20
|
+
MAX_SKU_LEN = 255
|
|
21
|
+
MAX_SCAN_CODE_LEN = max(MAX_BARCODE_LEN, MAX_SKU_LEN)
|
|
22
|
+
|
|
23
|
+
# Partial unique index enforcing at-most-one item per (company, barcode). Declared on
|
|
24
|
+
# the Projection model so create_all builds it for the test schema, and created on
|
|
25
|
+
# existing databases by the barcode-uniqueness migration. Named here so the applier
|
|
26
|
+
# can tell a barcode violation apart from the (company_id, entity_id) primary-key race.
|
|
27
|
+
BARCODE_UNIQUE_INDEX = "uq_projection_company_item_barcode"
|
|
28
|
+
|
|
29
|
+
SKU_COMMA_MESSAGE = "SKU cannot contain a comma"
|
|
30
|
+
SKU_TOO_LONG_MESSAGE = f"SKU cannot exceed {MAX_SKU_LEN} characters"
|
|
31
|
+
BARCODE_NOT_DIGITS_MESSAGE = "Barcode must contain only digits"
|
|
32
|
+
BARCODE_TOO_LONG_MESSAGE = f"Barcode cannot exceed {MAX_BARCODE_LEN} characters"
|
|
33
|
+
BARCODE_CONFLICT_MESSAGE = "Barcode '{barcode}' already exists"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def reject_comma_sku(sku: Any) -> Any:
|
|
37
|
+
"""Reject a comma-bearing SKU. Returns the sku for chaining."""
|
|
38
|
+
if sku is not None and "," in str(sku):
|
|
39
|
+
raise ValueError(SKU_COMMA_MESSAGE)
|
|
40
|
+
return sku
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def validate_sku(sku: Any) -> Any:
|
|
44
|
+
"""Reject a comma-bearing or over-long SKU. Returns the sku for chaining."""
|
|
45
|
+
reject_comma_sku(sku)
|
|
46
|
+
if sku is not None and len(str(sku)) > MAX_SKU_LEN:
|
|
47
|
+
raise ValueError(SKU_TOO_LONG_MESSAGE)
|
|
48
|
+
return sku
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def validate_barcode(barcode: Any) -> Any:
|
|
52
|
+
"""Reject a non-digit or over-long barcode. An absent/empty barcode is allowed."""
|
|
53
|
+
if barcode is None:
|
|
54
|
+
return barcode
|
|
55
|
+
s = str(barcode)
|
|
56
|
+
if s == "":
|
|
57
|
+
return barcode
|
|
58
|
+
if not s.isdigit():
|
|
59
|
+
raise ValueError(BARCODE_NOT_DIGITS_MESSAGE)
|
|
60
|
+
if len(s) > MAX_BARCODE_LEN:
|
|
61
|
+
raise ValueError(BARCODE_TOO_LONG_MESSAGE)
|
|
62
|
+
return barcode
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class BarcodeConflictError(Exception):
|
|
66
|
+
"""A write violated the (company, item, barcode) uniqueness invariant.
|
|
67
|
+
|
|
68
|
+
Raised by the projection applier when the DB unique index rejects an insert - the
|
|
69
|
+
final defense for any writer that bypasses the application lock (imports,
|
|
70
|
+
connectors, a future writer). The API layer maps it to 409.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
def __init__(self, barcode: str | None = None):
|
|
74
|
+
self.barcode = barcode
|
|
75
|
+
super().__init__(
|
|
76
|
+
BARCODE_CONFLICT_MESSAGE.format(barcode=barcode) if barcode else "Barcode already exists"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def is_barcode_unique_violation(exc: Exception) -> bool:
|
|
81
|
+
"""True when an IntegrityError is the barcode unique-index violation (not the PK race)."""
|
|
82
|
+
orig = getattr(exc, "orig", None)
|
|
83
|
+
if getattr(orig, "constraint_name", None) == BARCODE_UNIQUE_INDEX:
|
|
84
|
+
return True
|
|
85
|
+
# Expression-index violations do not always populate constraint_name across drivers;
|
|
86
|
+
# the index name still appears in the server message.
|
|
87
|
+
return BARCODE_UNIQUE_INDEX in str(exc)
|
|
@@ -13,6 +13,7 @@ from slowapi.errors import RateLimitExceeded
|
|
|
13
13
|
from slowapi.util import get_remote_address
|
|
14
14
|
|
|
15
15
|
from celerp.db import engine, mask_db_credentials
|
|
16
|
+
from celerp.inventory_codes import BarcodeConflictError
|
|
16
17
|
from celerp.config import settings, assert_secure_jwt, ensure_instance_id, load_cloud_config, load_backup_config
|
|
17
18
|
load_cloud_config()
|
|
18
19
|
load_backup_config()
|
|
@@ -447,6 +448,14 @@ async def rate_limit_handler(_request: Request, _exc: RateLimitExceeded):
|
|
|
447
448
|
return JSONResponse(status_code=429, content={"detail": "Rate limit exceeded"})
|
|
448
449
|
|
|
449
450
|
|
|
451
|
+
@app.exception_handler(BarcodeConflictError)
|
|
452
|
+
async def barcode_conflict_handler(_request: Request, exc: BarcodeConflictError):
|
|
453
|
+
# The projection applier raises this when the barcode unique index rejects a write
|
|
454
|
+
# that bypassed the allocation lock (imports, connectors). A more specific handler
|
|
455
|
+
# than the Exception catch-all, so it maps to 409 instead of a masked 500.
|
|
456
|
+
return JSONResponse(status_code=409, content={"detail": str(exc)})
|
|
457
|
+
|
|
458
|
+
|
|
450
459
|
# Kernel routes — always present regardless of module configuration
|
|
451
460
|
app.include_router(health.router, tags=["system"])
|
|
452
461
|
app.include_router(auth.router, prefix="/auth", tags=["auth"])
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Copyright (c) 2026 Noah Severs
|
|
2
|
+
# SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
|
|
4
|
+
"""Enforce at-most-one item per (company, barcode) with a partial unique index.
|
|
5
|
+
|
|
6
|
+
Revision ID: bc0d1e2f3a4b
|
|
7
|
+
Revises: b3c4d5e6f7a8
|
|
8
|
+
Create Date: 2026-08-25
|
|
9
|
+
|
|
10
|
+
Context
|
|
11
|
+
-------
|
|
12
|
+
A barcode identifies at most one physical-lot item per company. Until now that was
|
|
13
|
+
only enforced by an application check under a lock; any writer bypassing the lock
|
|
14
|
+
(imports, connectors, a future writer) could create duplicates, and legacy databases
|
|
15
|
+
may already hold some.
|
|
16
|
+
|
|
17
|
+
This migration is the final defense: a PostgreSQL partial expression unique index on
|
|
18
|
+
``(company_id, state ->> 'barcode')`` for item projections with a non-empty barcode.
|
|
19
|
+
|
|
20
|
+
It refuses to create the index while incompatible data exists rather than silently
|
|
21
|
+
renaming or clearing anything. A preflight scans for duplicate non-empty barcodes,
|
|
22
|
+
barcodes over the length limit, SKUs over the length limit, and comma-bearing SKUs,
|
|
23
|
+
and stops with an actionable report (company, value, affected entity ids) so an
|
|
24
|
+
operator can remediate and re-run.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import sqlalchemy as sa
|
|
30
|
+
from alembic import op
|
|
31
|
+
|
|
32
|
+
from celerp.inventory_codes import BARCODE_UNIQUE_INDEX, MAX_BARCODE_LEN, MAX_SKU_LEN
|
|
33
|
+
|
|
34
|
+
revision = "bc0d1e2f3a4b"
|
|
35
|
+
down_revision = "b3c4d5e6f7a8"
|
|
36
|
+
branch_labels = None
|
|
37
|
+
depends_on = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _preflight(conn) -> list[str]:
|
|
41
|
+
"""Return a list of human-readable remediation problems; empty means clean."""
|
|
42
|
+
problems: list[str] = []
|
|
43
|
+
|
|
44
|
+
dups = conn.execute(
|
|
45
|
+
sa.text(
|
|
46
|
+
"SELECT company_id, state ->> 'barcode' AS barcode, "
|
|
47
|
+
" array_agg(entity_id ORDER BY entity_id) AS entities "
|
|
48
|
+
"FROM projections "
|
|
49
|
+
"WHERE entity_type = 'item' AND NULLIF(state ->> 'barcode', '') IS NOT NULL "
|
|
50
|
+
"GROUP BY company_id, state ->> 'barcode' "
|
|
51
|
+
"HAVING count(*) > 1"
|
|
52
|
+
)
|
|
53
|
+
).fetchall()
|
|
54
|
+
for row in dups:
|
|
55
|
+
problems.append(
|
|
56
|
+
f"duplicate barcode {row.barcode!r} in company {row.company_id}: entities {list(row.entities)}"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
long_barcodes = conn.execute(
|
|
60
|
+
sa.text(
|
|
61
|
+
"SELECT company_id, entity_id, state ->> 'barcode' AS barcode "
|
|
62
|
+
"FROM projections "
|
|
63
|
+
"WHERE entity_type = 'item' AND length(state ->> 'barcode') > :n"
|
|
64
|
+
),
|
|
65
|
+
{"n": MAX_BARCODE_LEN},
|
|
66
|
+
).fetchall()
|
|
67
|
+
for row in long_barcodes:
|
|
68
|
+
problems.append(
|
|
69
|
+
f"barcode {row.barcode!r} over {MAX_BARCODE_LEN} chars in company {row.company_id} entity {row.entity_id}"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
long_skus = conn.execute(
|
|
73
|
+
sa.text(
|
|
74
|
+
"SELECT company_id, entity_id "
|
|
75
|
+
"FROM projections "
|
|
76
|
+
"WHERE entity_type = 'item' AND length(state ->> 'sku') > :n"
|
|
77
|
+
),
|
|
78
|
+
{"n": MAX_SKU_LEN},
|
|
79
|
+
).fetchall()
|
|
80
|
+
for row in long_skus:
|
|
81
|
+
problems.append(
|
|
82
|
+
f"SKU over {MAX_SKU_LEN} chars in company {row.company_id} entity {row.entity_id}"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
comma_skus = conn.execute(
|
|
86
|
+
sa.text(
|
|
87
|
+
"SELECT company_id, entity_id, state ->> 'sku' AS sku "
|
|
88
|
+
"FROM projections "
|
|
89
|
+
"WHERE entity_type = 'item' AND position(',' in state ->> 'sku') > 0"
|
|
90
|
+
)
|
|
91
|
+
).fetchall()
|
|
92
|
+
for row in comma_skus:
|
|
93
|
+
problems.append(
|
|
94
|
+
f"comma-bearing SKU {row.sku!r} in company {row.company_id} entity {row.entity_id}"
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return problems
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def upgrade() -> None:
|
|
101
|
+
conn = op.get_bind()
|
|
102
|
+
|
|
103
|
+
problems = _preflight(conn)
|
|
104
|
+
if problems:
|
|
105
|
+
raise RuntimeError(
|
|
106
|
+
"Cannot create the barcode uniqueness index: incompatible item data exists. "
|
|
107
|
+
"Resolve each of the following (rename or clear the barcode/SKU on the affected "
|
|
108
|
+
"items), then re-run the migration:\n - " + "\n - ".join(problems)
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
op.execute(
|
|
112
|
+
f"CREATE UNIQUE INDEX IF NOT EXISTS {BARCODE_UNIQUE_INDEX} "
|
|
113
|
+
"ON projections (company_id, (state ->> 'barcode')) "
|
|
114
|
+
"WHERE entity_type = 'item' AND NULLIF(state ->> 'barcode', '') IS NOT NULL"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def downgrade() -> None:
|
|
119
|
+
op.execute(f"DROP INDEX IF EXISTS {BARCODE_UNIQUE_INDEX}")
|
|
@@ -9,12 +9,27 @@ import sqlalchemy as sa
|
|
|
9
9
|
from sqlalchemy import BigInteger, Boolean, DateTime, ForeignKey, PrimaryKeyConstraint, String, Text
|
|
10
10
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
11
11
|
|
|
12
|
+
from celerp.inventory_codes import BARCODE_UNIQUE_INDEX
|
|
12
13
|
from celerp.models.base import Base
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class Projection(Base):
|
|
16
17
|
__tablename__ = "projections"
|
|
17
|
-
__table_args__ = (
|
|
18
|
+
__table_args__ = (
|
|
19
|
+
PrimaryKeyConstraint("company_id", "entity_id"),
|
|
20
|
+
# At most one item per (company, non-empty barcode). The final defense behind
|
|
21
|
+
# the application allocation lock: imports, connectors, or a future writer that
|
|
22
|
+
# bypasses the lock still cannot create a duplicate barcode. Declared here so
|
|
23
|
+
# create_all builds it for the test schema; created on existing databases by the
|
|
24
|
+
# barcode-uniqueness migration.
|
|
25
|
+
sa.Index(
|
|
26
|
+
BARCODE_UNIQUE_INDEX,
|
|
27
|
+
"company_id",
|
|
28
|
+
sa.text("(state ->> 'barcode')"),
|
|
29
|
+
unique=True,
|
|
30
|
+
postgresql_where=sa.text("entity_type = 'item' AND NULLIF(state ->> 'barcode', '') IS NOT NULL"),
|
|
31
|
+
),
|
|
32
|
+
)
|
|
18
33
|
|
|
19
34
|
entity_id: Mapped[str] = mapped_column(Text, nullable=False)
|
|
20
35
|
company_id: Mapped[uuid.UUID] = mapped_column(sa.Uuid(as_uuid=True), ForeignKey("companies.id"), nullable=False)
|
|
@@ -10,6 +10,7 @@ from datetime import datetime, timezone
|
|
|
10
10
|
from sqlalchemy import delete, select
|
|
11
11
|
from sqlalchemy.exc import IntegrityError
|
|
12
12
|
|
|
13
|
+
from celerp.inventory_codes import BarcodeConflictError, is_barcode_unique_violation
|
|
13
14
|
from celerp.models.ledger import LedgerEntry
|
|
14
15
|
from celerp.models.projections import Projection
|
|
15
16
|
|
|
@@ -130,10 +131,33 @@ class ProjectionEngine:
|
|
|
130
131
|
)
|
|
131
132
|
await session.flush()
|
|
132
133
|
return
|
|
133
|
-
except IntegrityError:
|
|
134
|
+
except IntegrityError as exc:
|
|
135
|
+
# Only the (company_id, entity_id) primary-key race is a benign
|
|
136
|
+
# concurrent-first-insert to retry as an update on the winner's row.
|
|
137
|
+
# A barcode unique-index violation is a real conflict - surface it so
|
|
138
|
+
# the API maps it to 409 rather than swallowing it as a PK race.
|
|
139
|
+
if is_barcode_unique_violation(exc):
|
|
140
|
+
raise BarcodeConflictError((fields.get("state") or {}).get("barcode")) from exc
|
|
141
|
+
constraint = getattr(getattr(exc, "orig", None), "constraint_name", None)
|
|
142
|
+
if constraint not in (None, "projections_pkey"):
|
|
143
|
+
raise
|
|
134
144
|
projection = await ProjectionEngine._locked_projection(session, entry)
|
|
135
|
-
|
|
145
|
+
if projection is None:
|
|
146
|
+
raise
|
|
147
|
+
fields = ProjectionEngine._next_fields(projection.state, entry, projection.version)
|
|
148
|
+
for column, value in fields.items():
|
|
136
149
|
setattr(projection, column, value)
|
|
150
|
+
# Flush inside a SAVEPOINT so a barcode unique-index violation on an UPDATE
|
|
151
|
+
# (not only a first insert) surfaces as BarcodeConflictError -> 409 instead
|
|
152
|
+
# of escaping to the outer commit masked as a 500. Unrelated integrity errors
|
|
153
|
+
# re-raise unchanged.
|
|
154
|
+
try:
|
|
155
|
+
async with session.begin_nested():
|
|
156
|
+
await session.flush()
|
|
157
|
+
except IntegrityError as exc:
|
|
158
|
+
if is_barcode_unique_violation(exc):
|
|
159
|
+
raise BarcodeConflictError((fields.get("state") or {}).get("barcode")) from exc
|
|
160
|
+
raise
|
|
137
161
|
|
|
138
162
|
@staticmethod
|
|
139
163
|
async def rebuild(session, company_id=None) -> None:
|
|
@@ -10,6 +10,7 @@ and by the fulfillment module's toggle/pick screen.
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
12
|
import uuid as _uuid
|
|
13
|
+
from collections.abc import Awaitable, Callable
|
|
13
14
|
from datetime import datetime, timezone
|
|
14
15
|
from typing import Any
|
|
15
16
|
|
|
@@ -42,16 +43,36 @@ async def execute_fulfill(
|
|
|
42
43
|
company_id,
|
|
43
44
|
user_id,
|
|
44
45
|
doc_type: str = "",
|
|
46
|
+
allocate_barcodes: Callable[[int], Awaitable[list[str]]] | None = None,
|
|
45
47
|
) -> dict[str, Any]:
|
|
46
48
|
"""Execute fulfillment: emit item events, doc event, and COGS JE.
|
|
47
49
|
|
|
48
50
|
Returns: {fulfillment_status, fulfilled_items, total_cogs}
|
|
51
|
+
|
|
52
|
+
A split pick carves a new child parcel off its parent lot; that child is a
|
|
53
|
+
fresh physical item and needs its own barcode. Core must not depend on the
|
|
54
|
+
inventory module, so the calling module injects allocation through
|
|
55
|
+
``allocate_barcodes(count) -> list[str]`` (celerp_inventory allocates under
|
|
56
|
+
its code-namespace lock). When any split is planned and no allocator is
|
|
57
|
+
supplied, this fails before emitting a single event rather than minting a
|
|
58
|
+
barcodeless child.
|
|
49
59
|
"""
|
|
50
60
|
now = datetime.now(timezone.utc).isoformat()
|
|
51
61
|
fulfilled_items: list[dict] = []
|
|
52
62
|
total_cogs = 0.0
|
|
53
63
|
cid = _to_uuid(company_id)
|
|
54
64
|
uid = _to_uuid(user_id)
|
|
65
|
+
|
|
66
|
+
# Allocate every split child's barcode up front, under the caller's lock, and
|
|
67
|
+
# fail clearly before any event is emitted if the allocator is missing.
|
|
68
|
+
split_picks = [p for p in pick_result.picks if p.action == "split"]
|
|
69
|
+
if split_picks and allocate_barcodes is None:
|
|
70
|
+
raise ValueError(
|
|
71
|
+
"Fulfillment must split a lot into a new child parcel that needs a "
|
|
72
|
+
"freshly allocated barcode, but no allocate_barcodes callback was "
|
|
73
|
+
"supplied. The calling module must inject inventory code allocation."
|
|
74
|
+
)
|
|
75
|
+
split_barcodes = iter(await allocate_barcodes(len(split_picks))) if split_picks else iter(())
|
|
55
76
|
# Stable human doc number for the item's history (the entity_id suffix can diverge on
|
|
56
77
|
# finalize/renumber, e.g. PF-... -> INV-...), so capture it from the doc at emit time.
|
|
57
78
|
doc_number = doc_state.get("doc_number") or doc_state.get("ref_id") or ""
|
|
@@ -96,6 +117,7 @@ async def execute_fulfill(
|
|
|
96
117
|
"sku": pick.sku, # child keeps the parent SKU (distinct lot by entity_id)
|
|
97
118
|
"name": pick.sku,
|
|
98
119
|
"quantity": pick.pick_qty,
|
|
120
|
+
"barcode": next(split_barcodes), # fresh per-lot barcode from the injected allocator
|
|
99
121
|
},
|
|
100
122
|
actor_id=uid,
|
|
101
123
|
location_id=None,
|
|
@@ -198,6 +198,22 @@ TAX_REGIMES: dict[str, _T] = {
|
|
|
198
198
|
"description": "Tax-exempt", "is_compound": False, "default_order": 0},
|
|
199
199
|
],
|
|
200
200
|
},
|
|
201
|
+
# ── Africa ────────────────────────────────────────────────────────────
|
|
202
|
+
"ET": {
|
|
203
|
+
"currency": "ETB",
|
|
204
|
+
"taxes": [
|
|
205
|
+
{"name": "VAT 15%", "rate": 15.0, "tax_type": "both", "is_default": True,
|
|
206
|
+
"description": "Ethiopia standard VAT", "is_compound": False, "default_order": 0},
|
|
207
|
+
{"name": "TOT 2%", "rate": 2.0, "tax_type": "sales", "is_default": False,
|
|
208
|
+
"description": "Turnover tax on goods (non-VAT-registered)", "is_compound": False, "default_order": 0},
|
|
209
|
+
{"name": "TOT 10%", "rate": 10.0, "tax_type": "sales", "is_default": False,
|
|
210
|
+
"description": "Turnover tax on services (non-VAT-registered)", "is_compound": False, "default_order": 0},
|
|
211
|
+
{"name": "Exempt", "rate": 0.0, "tax_type": "both", "is_default": False,
|
|
212
|
+
"description": "VAT-exempt", "is_compound": False, "default_order": 0},
|
|
213
|
+
{"name": "WHT 2%", "rate": -2.0, "tax_type": "purchase", "is_default": False,
|
|
214
|
+
"description": "Withholding tax on supply of goods", "is_compound": False, "default_order": 1},
|
|
215
|
+
],
|
|
216
|
+
},
|
|
201
217
|
# ── Fallback ──────────────────────────────────────────────────────────
|
|
202
218
|
"_default": {
|
|
203
219
|
"currency": "USD",
|
|
@@ -20,6 +20,7 @@ celerp/config.py
|
|
|
20
20
|
celerp/constants.py
|
|
21
21
|
celerp/db.py
|
|
22
22
|
celerp/embedded_pg.py
|
|
23
|
+
celerp/inventory_codes.py
|
|
23
24
|
celerp/main.py
|
|
24
25
|
celerp/middleware.py
|
|
25
26
|
celerp/session_gate.py
|
|
@@ -85,6 +86,7 @@ celerp/migrations/versions/a1b2c3d4e5f6_add_doc_share_tokens.py
|
|
|
85
86
|
celerp/migrations/versions/b1c2d3e4f5a6_add_supporter_badges.py
|
|
86
87
|
celerp/migrations/versions/b2c3d4e5f6a7_add_import_batches.py
|
|
87
88
|
celerp/migrations/versions/b3c4d5e6f7a8_expand_role_permissions_to_role_grants.py
|
|
89
|
+
celerp/migrations/versions/bc0d1e2f3a4b_barcode_unique_index.py
|
|
88
90
|
celerp/migrations/versions/c1d2e3f4a5b6_add_marketplace.py
|
|
89
91
|
celerp/migrations/versions/c2d3e4f5a6b7_add_is_sync_to_shopify.py
|
|
90
92
|
celerp/migrations/versions/c4d5e6f7a8b9_account_cash_flow_category.py
|
|
@@ -332,6 +334,8 @@ default_modules/celerp-docs/tests/test_inventory_account_reconciliation.py
|
|
|
332
334
|
default_modules/celerp-docs/tests/test_landed_receive.py
|
|
333
335
|
default_modules/celerp-docs/tests/test_line_delete_persist.py
|
|
334
336
|
default_modules/celerp-docs/tests/test_line_identifier.py
|
|
337
|
+
default_modules/celerp-docs/tests/test_list_concurrency.py
|
|
338
|
+
default_modules/celerp-docs/tests/test_list_outcome_concurrency.py
|
|
335
339
|
default_modules/celerp-docs/tests/test_payment_void_activity.py
|
|
336
340
|
default_modules/celerp-docs/tests/test_receive_sku_batch.py
|
|
337
341
|
default_modules/celerp-docs/tests/test_send_visibility.py
|
|
@@ -388,6 +392,7 @@ default_modules/celerp-manufacturing/celerp_manufacturing/ui_routes.py
|
|
|
388
392
|
default_modules/celerp-manufacturing/tests/test_auto_complete_on_finalize.py
|
|
389
393
|
default_modules/celerp-manufacturing/tests/test_bom_removed.py
|
|
390
394
|
default_modules/celerp-manufacturing/tests/test_build_api.py
|
|
395
|
+
default_modules/celerp-manufacturing/tests/test_completion_lock_order.py
|
|
391
396
|
default_modules/celerp-manufacturing/tests/test_item_recipe_api.py
|
|
392
397
|
default_modules/celerp-manufacturing/tests/test_item_workflow_api.py
|
|
393
398
|
default_modules/celerp-manufacturing/tests/test_labor_providers.py
|
|
@@ -75,6 +75,7 @@
|
|
|
75
75
|
"celerp/importers/__init__.py",
|
|
76
76
|
"celerp/importers/importer.py",
|
|
77
77
|
"celerp/importers/schema.py",
|
|
78
|
+
"celerp/inventory_codes.py",
|
|
78
79
|
"celerp/main.py",
|
|
79
80
|
"celerp/middleware.py",
|
|
80
81
|
"celerp/migrations/README.md",
|
|
@@ -88,6 +89,7 @@
|
|
|
88
89
|
"celerp/migrations/versions/b1c2d3e4f5a6_add_supporter_badges.py",
|
|
89
90
|
"celerp/migrations/versions/b2c3d4e5f6a7_add_import_batches.py",
|
|
90
91
|
"celerp/migrations/versions/b3c4d5e6f7a8_expand_role_permissions_to_role_grants.py",
|
|
92
|
+
"celerp/migrations/versions/bc0d1e2f3a4b_barcode_unique_index.py",
|
|
91
93
|
"celerp/migrations/versions/c1d2e3f4a5b6_add_marketplace.py",
|
|
92
94
|
"celerp/migrations/versions/c2d3e4f5a6b7_add_is_sync_to_shopify.py",
|
|
93
95
|
"celerp/migrations/versions/c4d5e6f7a8b9_account_cash_flow_category.py",
|
|
@@ -339,6 +341,8 @@
|
|
|
339
341
|
"default_modules/celerp-docs/tests/test_landed_receive.py",
|
|
340
342
|
"default_modules/celerp-docs/tests/test_line_delete_persist.py",
|
|
341
343
|
"default_modules/celerp-docs/tests/test_line_identifier.py",
|
|
344
|
+
"default_modules/celerp-docs/tests/test_list_concurrency.py",
|
|
345
|
+
"default_modules/celerp-docs/tests/test_list_outcome_concurrency.py",
|
|
342
346
|
"default_modules/celerp-docs/tests/test_payment_void_activity.py",
|
|
343
347
|
"default_modules/celerp-docs/tests/test_receive_sku_batch.py",
|
|
344
348
|
"default_modules/celerp-docs/tests/test_send_visibility.py",
|
|
@@ -395,6 +399,7 @@
|
|
|
395
399
|
"default_modules/celerp-manufacturing/tests/test_auto_complete_on_finalize.py",
|
|
396
400
|
"default_modules/celerp-manufacturing/tests/test_bom_removed.py",
|
|
397
401
|
"default_modules/celerp-manufacturing/tests/test_build_api.py",
|
|
402
|
+
"default_modules/celerp-manufacturing/tests/test_completion_lock_order.py",
|
|
398
403
|
"default_modules/celerp-manufacturing/tests/test_item_recipe_api.py",
|
|
399
404
|
"default_modules/celerp-manufacturing/tests/test_item_workflow_api.py",
|
|
400
405
|
"default_modules/celerp-manufacturing/tests/test_labor_providers.py",
|
|
@@ -817,6 +822,7 @@
|
|
|
817
822
|
"tests/test_browser/test_reprice_wrong_lot.py",
|
|
818
823
|
"tests/test_browser/test_reserved_conflict_modal.py",
|
|
819
824
|
"tests/test_browser/test_run_records_print.py",
|
|
825
|
+
"tests/test_browser/test_scan_run_conflict_recovery.py",
|
|
820
826
|
"tests/test_browser/test_settings_tabs.py",
|
|
821
827
|
"tests/test_browser/test_sold_price_column.py",
|
|
822
828
|
"tests/test_browser/test_split_ghost_cols.py",
|
|
@@ -950,6 +956,7 @@
|
|
|
950
956
|
"tests/test_merge_resulting_sku.py",
|
|
951
957
|
"tests/test_migrations/__init__.py",
|
|
952
958
|
"tests/test_migrations/conftest.py",
|
|
959
|
+
"tests/test_migrations/test_bc0d1e2f3a4b_barcode_unique_index.py",
|
|
953
960
|
"tests/test_migrations/test_d5e6f7a8b9c0_rename_fx_rounding_to_fx_difference.py",
|
|
954
961
|
"tests/test_migrations/test_dev_to_release_upgrade.py",
|
|
955
962
|
"tests/test_migrations/test_f6a7b8c9d0e1_seed_fx_rounding_account.py",
|
|
@@ -1001,6 +1008,8 @@
|
|
|
1001
1008
|
"tests/test_pricing.py",
|
|
1002
1009
|
"tests/test_proactive_qa.py",
|
|
1003
1010
|
"tests/test_prod_hardening.py",
|
|
1011
|
+
"tests/test_projections/test_barcode_unique.py",
|
|
1012
|
+
"tests/test_projections/test_code_allocation.py",
|
|
1004
1013
|
"tests/test_projections/test_cogs_backfill.py",
|
|
1005
1014
|
"tests/test_projections/test_engine.py",
|
|
1006
1015
|
"tests/test_projections/test_status_doc_backfill.py",
|